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