Coverage Report

Created: 2023-12-08 06:53

/src/freeimage-svn/FreeImage/trunk/Source/OpenEXR/IlmImf/ImfTileOffsets.cpp
Line
Count
Source (jump to first uncovered line)
1
///////////////////////////////////////////////////////////////////////////
2
//
3
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
4
// Digital Ltd. LLC
5
// 
6
// All rights reserved.
7
// 
8
// Redistribution and use in source and binary forms, with or without
9
// modification, are permitted provided that the following conditions are
10
// met:
11
// *       Redistributions of source code must retain the above copyright
12
// notice, this list of conditions and the following disclaimer.
13
// *       Redistributions in binary form must reproduce the above
14
// copyright notice, this list of conditions and the following disclaimer
15
// in the documentation and/or other materials provided with the
16
// distribution.
17
// *       Neither the name of Industrial Light & Magic nor the names of
18
// its contributors may be used to endorse or promote products derived
19
// from this software without specific prior written permission. 
20
// 
21
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
//
33
///////////////////////////////////////////////////////////////////////////
34
35
36
//-----------------------------------------------------------------------------
37
//
38
//  class TileOffsets
39
//
40
//-----------------------------------------------------------------------------
41
42
#include <ImfTileOffsets.h>
43
#include <ImfXdr.h>
44
#include <ImfIO.h>
45
#include "Iex.h"
46
#include "ImfNamespace.h"
47
#include <algorithm>
48
49
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
50
51
52
TileOffsets::TileOffsets (LevelMode mode,
53
        int numXLevels, int numYLevels,
54
        const int *numXTiles, const int *numYTiles)
55
:
56
    _mode (mode),
57
    _numXLevels (numXLevels),
58
    _numYLevels (numYLevels)
59
0
{
60
0
    switch (_mode)
61
0
    {
62
0
      case ONE_LEVEL:
63
0
      case MIPMAP_LEVELS:
64
65
0
        _offsets.resize (_numXLevels);
66
67
0
        for (unsigned int l = 0; l < _offsets.size(); ++l)
68
0
        {
69
0
            _offsets[l].resize (numYTiles[l]);
70
71
0
            for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
72
0
      {
73
0
                _offsets[l][dy].resize (numXTiles[l]);
74
0
            }
75
0
        }
76
0
        break;
77
78
0
      case RIPMAP_LEVELS:
79
80
0
        _offsets.resize (_numXLevels * _numYLevels);
81
82
0
        for (int ly = 0; ly < _numYLevels; ++ly)
83
0
        {
84
0
            for (int lx = 0; lx < _numXLevels; ++lx)
85
0
            {
86
0
                int l = ly * _numXLevels + lx;
87
0
                _offsets[l].resize (numYTiles[ly]);
88
89
0
                for (size_t dy = 0; dy < _offsets[l].size(); ++dy)
90
0
                {
91
0
                    _offsets[l][dy].resize (numXTiles[lx]);
92
0
                }
93
0
            }
94
0
        }
95
0
        break;
96
97
0
      case NUM_LEVELMODES :
98
0
          throw IEX_NAMESPACE::ArgExc("Bad initialisation of TileOffsets object");
99
0
    }
100
0
}
101
102
103
bool
104
TileOffsets::anyOffsetsAreInvalid () const
105
0
{
106
0
    for (unsigned int l = 0; l < _offsets.size(); ++l)
107
0
  for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
108
0
      for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
109
0
    if (_offsets[l][dy][dx] <= 0)
110
0
        return true;
111
    
112
0
    return false;
113
0
}
114
115
116
void
117
TileOffsets::findTiles (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, bool isMultiPartFile, bool isDeep, bool skipOnly)
118
0
{
119
0
    for (unsigned int l = 0; l < _offsets.size(); ++l)
120
0
    {
121
0
  for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
122
0
  {
123
0
      for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
124
0
      {
125
0
    Int64 tileOffset = is.tellg();
126
127
0
    if (isMultiPartFile)
128
0
    {
129
0
        int partNumber;
130
0
        OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, partNumber);
131
0
    }
132
133
0
    int tileX;
134
0
    OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, tileX);
135
136
0
    int tileY;
137
0
    OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, tileY);
138
139
0
    int levelX;
140
0
    OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, levelX);
141
142
0
    int levelY;
143
0
    OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, levelY);
144
145
0
                if(isDeep)
146
0
                {
147
0
                     Int64 packed_offset_table_size;
148
0
                     Int64 packed_sample_size;
149
                     
150
0
                     OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_offset_table_size);
151
0
                     OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_sample_size);
152
                     
153
                     // next Int64 is unpacked sample size - skip that too
154
0
                     Xdr::skip <StreamIO> (is, packed_offset_table_size+packed_sample_size+8);
155
                    
156
0
                }else{
157
                    
158
0
         int dataSize;
159
0
         OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, dataSize);
160
161
0
         Xdr::skip <StreamIO> (is, dataSize);
162
0
                }
163
0
    if (skipOnly) continue;
164
165
0
    if (!isValidTile(tileX, tileY, levelX, levelY))
166
0
        return;
167
168
0
    operator () (tileX, tileY, levelX, levelY) = tileOffset;
169
0
      }
170
0
  }
171
0
    }
172
0
}
173
174
175
void
176
TileOffsets::reconstructFromFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,bool isMultiPart,bool isDeep)
177
0
{
178
    //
179
    // Try to reconstruct a missing tile offset table by sequentially
180
    // scanning through the file, and recording the offsets in the file
181
    // of the tiles we find.
182
    //
183
184
0
    Int64 position = is.tellg();
185
186
0
    try
187
0
    {
188
0
  findTiles (is,isMultiPart,isDeep,false);
189
0
    }
190
0
    catch (...)
191
0
    {
192
        //
193
        // Suppress all exceptions.  This function is called only to
194
  // reconstruct the tile offset table for incomplete files,
195
  // and exceptions are likely.
196
        //
197
0
    }
198
199
0
    is.clear();
200
0
    is.seekg (position);
201
0
}
202
203
204
void
205
TileOffsets::readFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, bool &complete,bool isMultiPartFile, bool isDeep)
206
0
{
207
    //
208
    // Read in the tile offsets from the file's tile offset table
209
    //
210
211
0
    for (unsigned int l = 0; l < _offsets.size(); ++l)
212
0
  for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
213
0
      for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
214
0
    OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, _offsets[l][dy][dx]);
215
216
    //
217
    // Check if any tile offsets are invalid.
218
    //
219
    // Invalid offsets mean that the file is probably incomplete
220
    // (the offset table is the last thing written to the file).
221
    // Either some process is still busy writing the file, or
222
    // writing the file was aborted.
223
    //
224
    // We should still be able to read the existing parts of the
225
    // file.  In order to do this, we have to make a sequential
226
    // scan over the scan tile to reconstruct the tile offset
227
    // table.
228
    //
229
230
0
    if (anyOffsetsAreInvalid())
231
0
    {
232
0
  complete = false;
233
0
  reconstructFromFile (is,isMultiPartFile,isDeep);
234
0
    }
235
0
    else
236
0
    {
237
0
  complete = true;
238
0
    }
239
240
0
}
241
242
243
void
244
TileOffsets::readFrom (std::vector<Int64> chunkOffsets,bool &complete)
245
0
{
246
0
    size_t totalSize = 0;
247
 
248
0
    for (unsigned int l = 0; l < _offsets.size(); ++l)
249
0
        for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
250
0
            totalSize += _offsets[l][dy].size();
251
252
0
    if (chunkOffsets.size() != totalSize)
253
0
        throw IEX_NAMESPACE::ArgExc ("Wrong offset count, not able to read from this array");
254
255
256
257
0
    int pos = 0;
258
0
    for (size_t l = 0; l < _offsets.size(); ++l)
259
0
        for (size_t dy = 0; dy < _offsets[l].size(); ++dy)
260
0
            for (size_t dx = 0; dx < _offsets[l][dy].size(); ++dx)
261
0
            {
262
0
                _offsets[l][dy][dx] = chunkOffsets[pos];
263
0
                pos++;
264
0
            }
265
266
0
    complete = !anyOffsetsAreInvalid();
267
268
0
}
269
270
271
Int64
272
TileOffsets::writeTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os) const
273
0
{
274
    //
275
    // Write the tile offset table to the file, and
276
    // return the position of the start of the table
277
    // in the file.
278
    //
279
    
280
0
    Int64 pos = os.tellp();
281
282
0
    if (pos == -1)
283
0
  IEX_NAMESPACE::throwErrnoExc ("Cannot determine current file position (%T).");
284
285
0
    for (unsigned int l = 0; l < _offsets.size(); ++l)
286
0
  for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
287
0
      for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
288
0
    OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (os, _offsets[l][dy][dx]);
289
290
0
    return pos;
291
0
}
292
293
namespace {
294
struct tilepos{
295
    Int64 filePos;
296
    int dx;
297
    int dy;
298
    int l;
299
    bool operator <(const tilepos & other) const
300
0
    {
301
0
        return filePos < other.filePos;
302
0
    }
303
};
304
}
305
//-------------------------------------
306
// fill array with tile coordinates in the order they appear in the file
307
//
308
// each input array must be of size (totalTiles)
309
// 
310
//
311
// if the tile order is not RANDOM_Y, it is more efficient to compute the
312
// tile ordering rather than using this function
313
//
314
//-------------------------------------
315
void TileOffsets::getTileOrder(int dx_table[],int dy_table[],int lx_table[],int ly_table[]) const
316
0
{
317
    // 
318
    // helper class
319
    // 
320
321
    // how many entries?
322
0
    size_t entries=0;
323
0
    for (unsigned int l = 0; l < _offsets.size(); ++l)
324
0
        for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
325
0
           entries+=_offsets[l][dy].size();
326
        
327
0
    std::vector<struct tilepos> table(entries);
328
    
329
0
    size_t i = 0;
330
0
    for (unsigned int l = 0; l < _offsets.size(); ++l)
331
0
        for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
332
0
            for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
333
0
            {
334
0
                table[i].filePos = _offsets[l][dy][dx];
335
0
                table[i].dx = dx;
336
0
                table[i].dy = dy;
337
0
                table[i].l = l;
338
339
0
                ++i;
340
                
341
0
            }
342
              
343
0
    std::sort(table.begin(),table.end());
344
    
345
    //
346
    // write out the values
347
    //
348
    
349
    // pass 1: write out dx and dy, since these are independent of level mode
350
    
351
0
    for(size_t i=0;i<entries;i++)
352
0
    {
353
0
        dx_table[i] = table[i].dx;
354
0
        dy_table[i] = table[i].dy;
355
0
    }
356
357
    // now write out the levels, which depend on the level mode
358
    
359
0
    switch (_mode)
360
0
    {
361
0
        case ONE_LEVEL:
362
0
        {
363
0
            for(size_t i=0;i<entries;i++)
364
0
            {
365
0
                lx_table[i] = 0;
366
0
                ly_table[i] = 0;               
367
0
            }
368
0
            break;            
369
0
        }
370
0
        case MIPMAP_LEVELS:
371
0
        {
372
0
            for(size_t i=0;i<entries;i++)
373
0
            {
374
0
                lx_table[i]= table[i].l;
375
0
                ly_table[i] =table[i].l;               
376
                
377
0
            }
378
0
            break;
379
0
        }
380
            
381
0
        case RIPMAP_LEVELS:
382
0
        {
383
0
            for(size_t i=0;i<entries;i++)
384
0
            {
385
0
                lx_table[i]= table[i].l % _numXLevels;
386
0
                ly_table[i] = table[i].l / _numXLevels; 
387
                
388
0
            }
389
0
            break;
390
0
        }
391
0
        case NUM_LEVELMODES :
392
0
            throw IEX_NAMESPACE::LogicExc("Bad level mode getting tile order");
393
0
    }
394
    
395
    
396
    
397
0
}
398
399
400
bool
401
TileOffsets::isEmpty () const
402
0
{
403
0
    for (unsigned int l = 0; l < _offsets.size(); ++l)
404
0
  for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
405
0
      for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
406
0
    if (_offsets[l][dy][dx] != 0)
407
0
        return false;
408
0
    return true;
409
0
}
410
411
412
bool
413
TileOffsets::isValidTile (int dx, int dy, int lx, int ly) const
414
0
{
415
0
    if(lx<0 || ly < 0 || dx<0 || dy < 0) return false;
416
0
    switch (_mode)
417
0
    {
418
0
      case ONE_LEVEL:
419
420
0
        if (lx == 0 &&
421
0
      ly == 0 &&
422
0
      _offsets.size() > 0 &&
423
0
            int(_offsets[0].size()) > dy &&
424
0
            int(_offsets[0][dy].size()) > dx)
425
0
  {
426
0
            return true;
427
0
  }
428
429
0
        break;
430
431
0
      case MIPMAP_LEVELS:
432
433
0
        if (lx < _numXLevels &&
434
0
      ly < _numYLevels &&
435
0
            int(_offsets.size()) > lx &&
436
0
            int(_offsets[lx].size()) > dy &&
437
0
            int(_offsets[lx][dy].size()) > dx)
438
0
  {
439
0
            return true;
440
0
  }
441
442
0
        break;
443
444
0
      case RIPMAP_LEVELS:
445
446
0
        if (lx < _numXLevels &&
447
0
      ly < _numYLevels &&
448
0
      (_offsets.size() > (size_t) lx+  ly *  (size_t) _numXLevels) &&
449
0
            int(_offsets[lx + ly * _numXLevels].size()) > dy &&
450
0
            int(_offsets[lx + ly * _numXLevels][dy].size()) > dx)
451
0
  {
452
0
            return true;
453
0
  }
454
455
0
        break;
456
457
0
      default:
458
459
0
        return false;
460
0
    }
461
    
462
0
    return false;
463
0
}
464
465
466
Int64 &
467
TileOffsets::operator () (int dx, int dy, int lx, int ly)
468
0
{
469
    //
470
    // Looks up the value of the tile with tile coordinate (dx, dy)
471
    // and level number (lx, ly) in the _offsets array, and returns
472
    // the cooresponding offset.
473
    //
474
475
0
    switch (_mode)
476
0
    {
477
0
      case ONE_LEVEL:
478
479
0
        return _offsets[0][dy][dx];
480
0
        break;
481
482
0
      case MIPMAP_LEVELS:
483
484
0
        return _offsets[lx][dy][dx];
485
0
        break;
486
487
0
      case RIPMAP_LEVELS:
488
489
0
        return _offsets[lx + ly * _numXLevels][dy][dx];
490
0
        break;
491
492
0
      default:
493
494
0
        throw IEX_NAMESPACE::ArgExc ("Unknown LevelMode format.");
495
0
    }
496
0
}
497
498
499
Int64 &
500
TileOffsets::operator () (int dx, int dy, int l)
501
0
{
502
0
    return operator () (dx, dy, l, l);
503
0
}
504
505
506
const Int64 &
507
TileOffsets::operator () (int dx, int dy, int lx, int ly) const
508
0
{
509
    //
510
    // Looks up the value of the tile with tile coordinate (dx, dy)
511
    // and level number (lx, ly) in the _offsets array, and returns
512
    // the cooresponding offset.
513
    //
514
515
0
    switch (_mode)
516
0
    {
517
0
      case ONE_LEVEL:
518
519
0
        return _offsets[0][dy][dx];
520
0
        break;
521
522
0
      case MIPMAP_LEVELS:
523
524
0
        return _offsets[lx][dy][dx];
525
0
        break;
526
527
0
      case RIPMAP_LEVELS:
528
529
0
        return _offsets[lx + ly * _numXLevels][dy][dx];
530
0
        break;
531
532
0
      default:
533
534
0
        throw IEX_NAMESPACE::ArgExc ("Unknown LevelMode format.");
535
0
    }
536
0
}
537
538
539
const Int64 &
540
TileOffsets::operator () (int dx, int dy, int l) const
541
0
{
542
0
    return operator () (dx, dy, l, l);
543
0
}
544
545
const std::vector<std::vector<std::vector <Int64> > >&
546
TileOffsets::getOffsets() const
547
0
{
548
0
    return _offsets;
549
0
}
550
551
552
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT