Home | History | Annotate | Download | only in IlmImf
      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 
     47 namespace Imf {
     48 
     49 
     50 TileOffsets::TileOffsets (LevelMode mode,
     51               int numXLevels, int numYLevels,
     52               const int *numXTiles, const int *numYTiles)
     53 :
     54     _mode (mode),
     55     _numXLevels (numXLevels),
     56     _numYLevels (numYLevels)
     57 {
     58     switch (_mode)
     59     {
     60       case ONE_LEVEL:
     61       case MIPMAP_LEVELS:
     62 
     63         _offsets.resize (_numXLevels);
     64 
     65         for (unsigned int l = 0; l < _offsets.size(); ++l)
     66         {
     67             _offsets[l].resize (numYTiles[l]);
     68 
     69             for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
     70         {
     71                 _offsets[l][dy].resize (numXTiles[l]);
     72             }
     73         }
     74         break;
     75 
     76       case RIPMAP_LEVELS:
     77 
     78         _offsets.resize (_numXLevels * _numYLevels);
     79 
     80         for (unsigned int ly = 0; ly < _numYLevels; ++ly)
     81         {
     82             for (unsigned int lx = 0; lx < _numXLevels; ++lx)
     83             {
     84                 int l = ly * _numXLevels + lx;
     85                 _offsets[l].resize (numYTiles[ly]);
     86 
     87                 for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
     88                 {
     89                     _offsets[l][dy].resize (numXTiles[lx]);
     90                 }
     91             }
     92         }
     93         break;
     94     }
     95 }
     96 
     97 
     98 bool
     99 TileOffsets::anyOffsetsAreInvalid () const
    100 {
    101     for (unsigned int l = 0; l < _offsets.size(); ++l)
    102     for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
    103         for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
    104         if (_offsets[l][dy][dx] <= 0)
    105             return true;
    106 
    107     return false;
    108 }
    109 
    110 
    111 void
    112 TileOffsets::findTiles (IStream &is)
    113 {
    114     for (unsigned int l = 0; l < _offsets.size(); ++l)
    115     {
    116     for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
    117     {
    118         for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
    119         {
    120         Int64 tileOffset = is.tellg();
    121 
    122         int tileX;
    123         Xdr::read <StreamIO> (is, tileX);
    124 
    125         int tileY;
    126         Xdr::read <StreamIO> (is, tileY);
    127 
    128         int levelX;
    129         Xdr::read <StreamIO> (is, levelX);
    130 
    131         int levelY;
    132         Xdr::read <StreamIO> (is, levelY);
    133 
    134         int dataSize;
    135         Xdr::read <StreamIO> (is, dataSize);
    136 
    137         Xdr::skip <StreamIO> (is, dataSize);
    138 
    139         if (!isValidTile(tileX, tileY, levelX, levelY))
    140             return;
    141 
    142         operator () (tileX, tileY, levelX, levelY) = tileOffset;
    143         }
    144     }
    145     }
    146 }
    147 
    148 
    149 void
    150 TileOffsets::reconstructFromFile (IStream &is)
    151 {
    152     //
    153     // Try to reconstruct a missing tile offset table by sequentially
    154     // scanning through the file, and recording the offsets in the file
    155     // of the tiles we find.
    156     //
    157 
    158     Int64 position = is.tellg();
    159 
    160     try
    161     {
    162     findTiles (is);
    163     }
    164     catch (...)
    165     {
    166         //
    167         // Suppress all exceptions.  This function is called only to
    168     // reconstruct the tile offset table for incomplete files,
    169     // and exceptions are likely.
    170         //
    171     }
    172 
    173     is.clear();
    174     is.seekg (position);
    175 }
    176 
    177 
    178 void
    179 TileOffsets::readFrom (IStream &is, bool &complete)
    180 {
    181     //
    182     // Read in the tile offsets from the file's tile offset table
    183     //
    184 
    185     for (unsigned int l = 0; l < _offsets.size(); ++l)
    186     for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
    187         for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
    188         Xdr::read <StreamIO> (is, _offsets[l][dy][dx]);
    189 
    190     //
    191     // Check if any tile offsets are invalid.
    192     //
    193     // Invalid offsets mean that the file is probably incomplete
    194     // (the offset table is the last thing written to the file).
    195     // Either some process is still busy writing the file, or
    196     // writing the file was aborted.
    197     //
    198     // We should still be able to read the existing parts of the
    199     // file.  In order to do this, we have to make a sequential
    200     // scan over the scan tile to reconstruct the tile offset
    201     // table.
    202     //
    203 
    204     if (anyOffsetsAreInvalid())
    205     {
    206     complete = false;
    207     reconstructFromFile (is);
    208     }
    209     else
    210     {
    211     complete = true;
    212     }
    213 
    214 }
    215 
    216 
    217 Int64
    218 TileOffsets::writeTo (OStream &os) const
    219 {
    220     //
    221     // Write the tile offset table to the file, and
    222     // return the position of the start of the table
    223     // in the file.
    224     //
    225 
    226     Int64 pos = os.tellp();
    227 
    228     if (pos == -1)
    229     Iex::throwErrnoExc ("Cannot determine current file position (%T).");
    230 
    231     for (unsigned int l = 0; l < _offsets.size(); ++l)
    232     for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
    233         for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
    234         Xdr::write <StreamIO> (os, _offsets[l][dy][dx]);
    235 
    236     return pos;
    237 }
    238 
    239 
    240 bool
    241 TileOffsets::isEmpty () const
    242 {
    243     for (unsigned int l = 0; l < _offsets.size(); ++l)
    244     for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
    245         for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
    246         if (_offsets[l][dy][dx] != 0)
    247             return false;
    248     return true;
    249 }
    250 
    251 
    252 bool
    253 TileOffsets::isValidTile (int dx, int dy, int lx, int ly) const
    254 {
    255     switch (_mode)
    256     {
    257       case ONE_LEVEL:
    258 
    259         if (lx == 0 &&
    260         ly == 0 &&
    261         _offsets.size() > 0 &&
    262             _offsets[0].size() > dy &&
    263             _offsets[0][dy].size() > dx)
    264     {
    265             return true;
    266     }
    267 
    268         break;
    269 
    270       case MIPMAP_LEVELS:
    271 
    272         if (lx < _numXLevels &&
    273         ly < _numYLevels &&
    274             _offsets.size() > lx &&
    275             _offsets[lx].size() > dy &&
    276             _offsets[lx][dy].size() > dx)
    277     {
    278             return true;
    279     }
    280 
    281         break;
    282 
    283       case RIPMAP_LEVELS:
    284 
    285         if (lx < _numXLevels &&
    286         ly < _numYLevels &&
    287             _offsets.size() > lx + ly * _numXLevels &&
    288             _offsets[lx + ly * _numXLevels].size() > dy &&
    289             _offsets[lx + ly * _numXLevels][dy].size() > dx)
    290     {
    291             return true;
    292     }
    293 
    294         break;
    295 
    296       default:
    297 
    298         return false;
    299     }
    300 
    301     return false;
    302 }
    303 
    304 
    305 Int64 &
    306 TileOffsets::operator () (int dx, int dy, int lx, int ly)
    307 {
    308     //
    309     // Looks up the value of the tile with tile coordinate (dx, dy)
    310     // and level number (lx, ly) in the _offsets array, and returns
    311     // the cooresponding offset.
    312     //
    313 
    314     switch (_mode)
    315     {
    316       case ONE_LEVEL:
    317 
    318         return _offsets[0][dy][dx];
    319         break;
    320 
    321       case MIPMAP_LEVELS:
    322 
    323         return _offsets[lx][dy][dx];
    324         break;
    325 
    326       case RIPMAP_LEVELS:
    327 
    328         return _offsets[lx + ly * _numXLevels][dy][dx];
    329         break;
    330 
    331       default:
    332 
    333         throw Iex::ArgExc ("Unknown LevelMode format.");
    334     }
    335 }
    336 
    337 
    338 Int64 &
    339 TileOffsets::operator () (int dx, int dy, int l)
    340 {
    341     return operator () (dx, dy, l, l);
    342 }
    343 
    344 
    345 const Int64 &
    346 TileOffsets::operator () (int dx, int dy, int lx, int ly) const
    347 {
    348     //
    349     // Looks up the value of the tile with tile coordinate (dx, dy)
    350     // and level number (lx, ly) in the _offsets array, and returns
    351     // the cooresponding offset.
    352     //
    353 
    354     switch (_mode)
    355     {
    356       case ONE_LEVEL:
    357 
    358         return _offsets[0][dy][dx];
    359         break;
    360 
    361       case MIPMAP_LEVELS:
    362 
    363         return _offsets[lx][dy][dx];
    364         break;
    365 
    366       case RIPMAP_LEVELS:
    367 
    368         return _offsets[lx + ly * _numXLevels][dy][dx];
    369         break;
    370 
    371       default:
    372 
    373         throw Iex::ArgExc ("Unknown LevelMode format.");
    374     }
    375 }
    376 
    377 
    378 const Int64 &
    379 TileOffsets::operator () (int dx, int dy, int l) const
    380 {
    381     return operator () (dx, dy, l, l);
    382 }
    383 
    384 
    385 } // namespace Imf
    386