PageRenderTime 57ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/Source/OpenEXR/IlmImf/ImfMultiPartInputFile.cpp

https://gitlab.com/seranth/FreeImage
C++ | 783 lines | 506 code | 147 blank | 130 comment | 77 complexity | 594beb9f0ca4327420a304bdcad641f0 MD5 | raw file
  1. ///////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2011, 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. #include "ImfMultiPartInputFile.h"
  35. #include "ImfTimeCodeAttribute.h"
  36. #include "ImfChromaticitiesAttribute.h"
  37. #include "ImfBoxAttribute.h"
  38. #include "ImfFloatAttribute.h"
  39. #include "ImfStdIO.h"
  40. #include "ImfTileOffsets.h"
  41. #include "ImfMisc.h"
  42. #include "ImfTiledMisc.h"
  43. #include "ImfInputStreamMutex.h"
  44. #include "ImfInputPartData.h"
  45. #include "ImfPartType.h"
  46. #include "ImfInputFile.h"
  47. #include "ImfScanLineInputFile.h"
  48. #include "ImfTiledInputFile.h"
  49. #include "ImfDeepScanLineInputFile.h"
  50. #include "ImfDeepTiledInputFile.h"
  51. #include "ImfVersion.h"
  52. #include <OpenEXRConfig.h>
  53. #include <IlmThread.h>
  54. #include <IlmThreadMutex.h>
  55. #include <Iex.h>
  56. #include <map>
  57. #include <set>
  58. OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
  59. using ILMTHREAD_NAMESPACE::Mutex;
  60. using ILMTHREAD_NAMESPACE::Lock;
  61. using IMATH_NAMESPACE::Box2i;
  62. using std::vector;
  63. using std::map;
  64. using std::set;
  65. using std::string;
  66. namespace
  67. {
  68. // Controls whether we error out in the event of shared attribute
  69. // inconsistency in the input file
  70. static const bool strictSharedAttribute = true;
  71. }
  72. struct MultiPartInputFile::Data: public InputStreamMutex
  73. {
  74. int version; // Version of this file.
  75. bool deleteStream; // If we should delete the stream during destruction.
  76. vector<InputPartData*> parts; // Data to initialize Output files.
  77. int numThreads; // Number of threads
  78. bool reconstructChunkOffsetTable; // If we should reconstruct
  79. // the offset table if it's broken.
  80. std::map<int,GenericInputFile*> _inputFiles;
  81. std::vector<Header> _headers;
  82. void chunkOffsetReconstruction(OPENEXR_IMF_INTERNAL_NAMESPACE::IStream& is, const std::vector<InputPartData*>& parts);
  83. void readChunkOffsetTables(bool reconstructChunkOffsetTable);
  84. bool checkSharedAttributesValues(const Header & src,
  85. const Header & dst,
  86. std::vector<std::string> & conflictingAttributes) const;
  87. TileOffsets* createTileOffsets(const Header& header);
  88. InputPartData* getPart(int partNumber);
  89. Data (bool deleteStream, int numThreads, bool reconstructChunkOffsetTable):
  90. InputStreamMutex(),
  91. deleteStream (deleteStream),
  92. numThreads (numThreads),
  93. reconstructChunkOffsetTable(reconstructChunkOffsetTable)
  94. {
  95. }
  96. ~Data()
  97. {
  98. if (deleteStream) delete is;
  99. for (size_t i = 0; i < parts.size(); i++)
  100. delete parts[i];
  101. }
  102. template <class T>
  103. T* createInputPartT(int partNumber)
  104. {
  105. }
  106. };
  107. MultiPartInputFile::MultiPartInputFile(const char fileName[],
  108. int numThreads,
  109. bool reconstructChunkOffsetTable):
  110. _data(new Data(true, numThreads, reconstructChunkOffsetTable))
  111. {
  112. try
  113. {
  114. _data->is = new StdIFStream (fileName);
  115. initialize();
  116. }
  117. catch (IEX_NAMESPACE::BaseExc &e)
  118. {
  119. delete _data;
  120. REPLACE_EXC (e, "Cannot read image file "
  121. "\"" << fileName << "\". " << e);
  122. throw;
  123. }
  124. catch (...)
  125. {
  126. delete _data;
  127. throw;
  128. }
  129. }
  130. MultiPartInputFile::MultiPartInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream& is,
  131. int numThreads,
  132. bool reconstructChunkOffsetTable):
  133. _data(new Data(false, numThreads, reconstructChunkOffsetTable))
  134. {
  135. try
  136. {
  137. _data->is = &is;
  138. initialize();
  139. }
  140. catch (IEX_NAMESPACE::BaseExc &e)
  141. {
  142. delete _data;
  143. REPLACE_EXC (e, "Cannot read image file "
  144. "\"" << is.fileName() << "\". " << e);
  145. throw;
  146. }
  147. catch (...)
  148. {
  149. delete _data;
  150. throw;
  151. }
  152. }
  153. template<class T>
  154. T*
  155. MultiPartInputFile::getInputPart(int partNumber)
  156. {
  157. Lock lock(*_data);
  158. if (_data->_inputFiles.find(partNumber) == _data->_inputFiles.end())
  159. {
  160. T* file = new T(_data->getPart(partNumber));
  161. _data->_inputFiles.insert(std::make_pair(partNumber, (GenericInputFile*) file));
  162. return file;
  163. }
  164. else return (T*) _data->_inputFiles[partNumber];
  165. }
  166. template InputFile* MultiPartInputFile::getInputPart<InputFile>(int);
  167. template TiledInputFile* MultiPartInputFile::getInputPart<TiledInputFile>(int);
  168. template DeepScanLineInputFile* MultiPartInputFile::getInputPart<DeepScanLineInputFile>(int);
  169. template DeepTiledInputFile* MultiPartInputFile::getInputPart<DeepTiledInputFile>(int);
  170. InputPartData*
  171. MultiPartInputFile::getPart(int partNumber)
  172. {
  173. return _data->getPart(partNumber);
  174. }
  175. const Header &
  176. MultiPartInputFile::header(int n) const
  177. {
  178. return _data->_headers[n];
  179. }
  180. MultiPartInputFile::~MultiPartInputFile()
  181. {
  182. for (map<int, GenericInputFile*>::iterator it = _data->_inputFiles.begin();
  183. it != _data->_inputFiles.end(); it++)
  184. {
  185. delete it->second;
  186. }
  187. delete _data;
  188. }
  189. bool
  190. MultiPartInputFile::Data::checkSharedAttributesValues(const Header & src,
  191. const Header & dst,
  192. vector<string> & conflictingAttributes) const
  193. {
  194. conflictingAttributes.clear();
  195. bool conflict = false;
  196. //
  197. // Display Window
  198. //
  199. if (src.displayWindow() != dst.displayWindow())
  200. {
  201. conflict = true;
  202. conflictingAttributes.push_back ("displayWindow");
  203. }
  204. //
  205. // Pixel Aspect Ratio
  206. //
  207. if (src.pixelAspectRatio() != dst.pixelAspectRatio())
  208. {
  209. conflict = true;
  210. conflictingAttributes.push_back ("pixelAspectRatio");
  211. }
  212. //
  213. // Timecode
  214. //
  215. const TimeCodeAttribute * srcTimeCode = src.findTypedAttribute<
  216. TimeCodeAttribute> (TimeCodeAttribute::staticTypeName());
  217. const TimeCodeAttribute * dstTimeCode = dst.findTypedAttribute<
  218. TimeCodeAttribute> (TimeCodeAttribute::staticTypeName());
  219. if (dstTimeCode)
  220. {
  221. if ( (srcTimeCode && (srcTimeCode->value() != dstTimeCode->value())) ||
  222. (!srcTimeCode))
  223. {
  224. conflict = true;
  225. conflictingAttributes.push_back (TimeCodeAttribute::staticTypeName());
  226. }
  227. }
  228. //
  229. // Chromaticities
  230. //
  231. const ChromaticitiesAttribute * srcChrom = src.findTypedAttribute<
  232. ChromaticitiesAttribute> (ChromaticitiesAttribute::staticTypeName());
  233. const ChromaticitiesAttribute * dstChrom = dst.findTypedAttribute<
  234. ChromaticitiesAttribute> (ChromaticitiesAttribute::staticTypeName());
  235. if (dstChrom)
  236. {
  237. if ( (srcChrom && (srcChrom->value() != dstChrom->value())) ||
  238. (!srcChrom))
  239. {
  240. conflict = true;
  241. conflictingAttributes.push_back (ChromaticitiesAttribute::staticTypeName());
  242. }
  243. }
  244. return conflict;
  245. }
  246. void
  247. MultiPartInputFile::initialize()
  248. {
  249. readMagicNumberAndVersionField(*_data->is, _data->version);
  250. bool multipart = isMultiPart(_data->version);
  251. bool tiled = isTiled(_data->version);
  252. //
  253. // Multipart files don't have and shouldn't have the tiled bit set.
  254. //
  255. if (tiled && multipart)
  256. throw IEX_NAMESPACE::InputExc ("Multipart files cannot have the tiled bit set");
  257. int pos = 0;
  258. while (true)
  259. {
  260. Header header;
  261. header.readFrom(*_data->is, _data->version);
  262. //
  263. // If we read nothing then we stop reading.
  264. //
  265. if (header.readsNothing())
  266. {
  267. pos++;
  268. break;
  269. }
  270. _data->_headers.push_back(header);
  271. if(multipart == false)
  272. break;
  273. }
  274. //
  275. // Perform usual check on headers.
  276. //
  277. for (size_t i = 0; i < _data->_headers.size(); i++)
  278. {
  279. //
  280. // Silently invent a type if the file is a single part regular image.
  281. //
  282. if( _data->_headers[i].hasType() == false )
  283. {
  284. if(multipart)
  285. throw IEX_NAMESPACE::ArgExc ("Every header in a multipart file should have a type");
  286. _data->_headers[i].setType(tiled ? TILEDIMAGE : SCANLINEIMAGE);
  287. }
  288. else
  289. {
  290. //
  291. // Silently fix the header type if it's wrong
  292. // (happens when a regular Image file written by EXR_2.0 is rewritten by an older library,
  293. // so doesn't effect deep image types)
  294. //
  295. if(!multipart && !isNonImage(_data->version))
  296. {
  297. _data->_headers[i].setType(tiled ? TILEDIMAGE : SCANLINEIMAGE);
  298. }
  299. }
  300. if( _data->_headers[i].hasName() == false )
  301. {
  302. if(multipart)
  303. throw IEX_NAMESPACE::ArgExc ("Every header in a multipart file should have a name");
  304. }
  305. if (isTiled(_data->_headers[i].type()))
  306. _data->_headers[i].sanityCheck(true, multipart);
  307. else
  308. _data->_headers[i].sanityCheck(false, multipart);
  309. }
  310. //
  311. // Check name uniqueness.
  312. //
  313. if (multipart)
  314. {
  315. set<string> names;
  316. for (size_t i = 0; i < _data->_headers.size(); i++)
  317. {
  318. if (names.find(_data->_headers[i].name()) != names.end())
  319. {
  320. throw IEX_NAMESPACE::InputExc ("Header name " + _data->_headers[i].name() +
  321. " is not a unique name.");
  322. }
  323. names.insert(_data->_headers[i].name());
  324. }
  325. }
  326. //
  327. // Check shared attributes compliance.
  328. //
  329. if (multipart && strictSharedAttribute)
  330. {
  331. for (size_t i = 1; i < _data->_headers.size(); i++)
  332. {
  333. vector <string> attrs;
  334. if (_data->checkSharedAttributesValues (_data->_headers[0], _data->_headers[i], attrs))
  335. {
  336. string attrNames;
  337. for (size_t j=0; j<attrs.size(); j++)
  338. attrNames += " " + attrs[j];
  339. throw IEX_NAMESPACE::InputExc ("Header name " + _data->_headers[i].name() +
  340. " has non-conforming shared attributes: "+
  341. attrNames);
  342. }
  343. }
  344. }
  345. //
  346. // Create InputParts and read chunk offset tables.
  347. //
  348. for (size_t i = 0; i < _data->_headers.size(); i++)
  349. _data->parts.push_back(
  350. new InputPartData(_data, _data->_headers[i], i, _data->numThreads, _data->version));
  351. _data->readChunkOffsetTables(_data->reconstructChunkOffsetTable);
  352. }
  353. TileOffsets*
  354. MultiPartInputFile::Data::createTileOffsets(const Header& header)
  355. {
  356. //
  357. // Get the dataWindow information
  358. //
  359. const Box2i &dataWindow = header.dataWindow();
  360. int minX = dataWindow.min.x;
  361. int maxX = dataWindow.max.x;
  362. int minY = dataWindow.min.y;
  363. int maxY = dataWindow.max.y;
  364. //
  365. // Precompute level and tile information
  366. //
  367. int* numXTiles;
  368. int* numYTiles;
  369. int numXLevels, numYLevels;
  370. TileDescription tileDesc = header.tileDescription();
  371. precalculateTileInfo (tileDesc,
  372. minX, maxX,
  373. minY, maxY,
  374. numXTiles, numYTiles,
  375. numXLevels, numYLevels);
  376. TileOffsets* tileOffsets = new TileOffsets (tileDesc.mode,
  377. numXLevels,
  378. numYLevels,
  379. numXTiles,
  380. numYTiles);
  381. delete [] numXTiles;
  382. delete [] numYTiles;
  383. return tileOffsets;
  384. }
  385. void
  386. MultiPartInputFile::Data::chunkOffsetReconstruction(OPENEXR_IMF_INTERNAL_NAMESPACE::IStream& is, const vector<InputPartData*>& parts)
  387. {
  388. //
  389. // Reconstruct broken chunk offset tables. Stop once we received any exception.
  390. //
  391. Int64 position = is.tellg();
  392. //
  393. // check we understand all the parts available: if not, we cannot continue
  394. // exceptions thrown here should trickle back up to the constructor
  395. //
  396. for (size_t i = 0; i < parts.size(); i++)
  397. {
  398. Header& header=parts[i]->header;
  399. //
  400. // do we have a valid type entry?
  401. // we only need them for true multipart files or single part non-image (deep) files
  402. //
  403. if(!header.hasType() && (isMultiPart(version) || isNonImage(version)))
  404. {
  405. throw IEX_NAMESPACE::ArgExc("cannot reconstruct incomplete file: part with missing type");
  406. }
  407. if(!isSupportedType(header.type()))
  408. {
  409. throw IEX_NAMESPACE::ArgExc("cannot reconstruct incomplete file: part with unknown type "+header.type());
  410. }
  411. }
  412. // how many chunks should we read? We should stop when we reach the end
  413. size_t total_chunks = 0;
  414. // for tiled-based parts, array of (pointers to) tileOffsets objects
  415. // to create mapping between tile coordinates and chunk table indices
  416. vector<TileOffsets*> tileOffsets(parts.size());
  417. // for scanline-based parts, number of scanlines in each part
  418. vector<int> rowsizes(parts.size());
  419. for(size_t i = 0 ; i < parts.size() ; i++)
  420. {
  421. total_chunks += parts[i]->chunkOffsets.size();
  422. if (isTiled(parts[i]->header.type()))
  423. {
  424. tileOffsets[i] = createTileOffsets(parts[i]->header);
  425. }else{
  426. tileOffsets[i] = NULL;
  427. // (TODO) fix this so that it doesn't need to be revised for future compression types.
  428. switch(parts[i]->header.compression())
  429. {
  430. case DWAB_COMPRESSION :
  431. rowsizes[i] = 256;
  432. break;
  433. case PIZ_COMPRESSION :
  434. case B44_COMPRESSION :
  435. case B44A_COMPRESSION :
  436. case DWAA_COMPRESSION :
  437. rowsizes[i]=32;
  438. break;
  439. case ZIP_COMPRESSION :
  440. case PXR24_COMPRESSION :
  441. rowsizes[i]=16;
  442. break;
  443. case ZIPS_COMPRESSION :
  444. case RLE_COMPRESSION :
  445. case NO_COMPRESSION :
  446. rowsizes[i]=1;
  447. break;
  448. default :
  449. throw(IEX_NAMESPACE::ArgExc("Unknown compression method in chunk offset reconstruction"));
  450. }
  451. }
  452. }
  453. try
  454. {
  455. //
  456. //
  457. //
  458. Int64 chunk_start = position;
  459. for (size_t i = 0; i < total_chunks ; i++)
  460. {
  461. //
  462. // do we have a part number?
  463. //
  464. int partNumber = 0;
  465. if(isMultiPart(version))
  466. {
  467. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, partNumber);
  468. }
  469. if(partNumber<0 || partNumber>int(parts.size()))
  470. {
  471. // bail here - bad part number
  472. throw int();
  473. }
  474. Header& header = parts[partNumber]->header;
  475. // size of chunk NOT including multipart field
  476. Int64 size_of_chunk=0;
  477. if (isTiled(header.type()))
  478. {
  479. //
  480. //
  481. //
  482. int tilex,tiley,levelx,levely;
  483. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, tilex);
  484. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, tiley);
  485. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, levelx);
  486. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, levely);
  487. //std::cout << "chunk_start for " << tilex <<',' << tiley << ',' << levelx << ' ' << levely << ':' << chunk_start << std::endl;
  488. if(!tileOffsets[partNumber])
  489. {
  490. // this shouldn't actually happen - we should have allocated a valid
  491. // tileOffsets for any part which isTiled
  492. throw int();
  493. }
  494. if(!tileOffsets[partNumber]->isValidTile(tilex,tiley,levelx,levely))
  495. {
  496. //std::cout << "invalid tile : aborting\n";
  497. throw int();
  498. }
  499. (*tileOffsets[partNumber])(tilex,tiley,levelx,levely)=chunk_start;
  500. // compute chunk sizes - different procedure for deep tiles and regular
  501. // ones
  502. if(header.type()==DEEPTILE)
  503. {
  504. Int64 packed_offset;
  505. Int64 packed_sample;
  506. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_offset);
  507. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_sample);
  508. //add 40 byte header to packed sizes (tile coordinates, packed sizes, unpacked size)
  509. size_of_chunk=packed_offset+packed_sample+40;
  510. }
  511. else
  512. {
  513. // regular image has 20 bytes of header, 4 byte chunksize;
  514. int chunksize;
  515. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, chunksize);
  516. size_of_chunk=chunksize+20;
  517. }
  518. }
  519. else
  520. {
  521. int y_coordinate;
  522. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, y_coordinate);
  523. y_coordinate -= header.dataWindow().min.y;
  524. y_coordinate /= rowsizes[partNumber];
  525. if(y_coordinate < 0 || y_coordinate >= int(parts[partNumber]->chunkOffsets.size()))
  526. {
  527. //std::cout << "aborting reconstruction: bad data " << y_coordinate << endl;
  528. //bail to exception catcher: broken scanline
  529. throw int();
  530. }
  531. parts[partNumber]->chunkOffsets[y_coordinate]=chunk_start;
  532. //std::cout << "chunk_start for " << y_coordinate << ':' << chunk_start << std::endl;
  533. if(header.type()==DEEPSCANLINE)
  534. {
  535. Int64 packed_offset;
  536. Int64 packed_sample;
  537. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_offset);
  538. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_sample);
  539. size_of_chunk=packed_offset+packed_sample+28;
  540. }
  541. else
  542. {
  543. int chunksize;
  544. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, chunksize);
  545. size_of_chunk=chunksize+8;
  546. }
  547. }
  548. if(isMultiPart(version))
  549. {
  550. chunk_start+=4;
  551. }
  552. chunk_start+=size_of_chunk;
  553. //std::cout << " next chunk +"<<size_of_chunk << " = " << chunk_start << std::endl;
  554. is.seekg(chunk_start);
  555. }
  556. }
  557. catch (...)
  558. {
  559. //
  560. // Suppress all exceptions. This functions is
  561. // called only to reconstruct the line offset
  562. // table for incomplete files, and exceptions
  563. // are likely.
  564. //
  565. }
  566. // copy tiled part data back to chunk offsets
  567. for(size_t partNumber=0;partNumber<parts.size();partNumber++)
  568. {
  569. if(tileOffsets[partNumber])
  570. {
  571. size_t pos=0;
  572. vector<vector<vector <Int64> > > offsets = tileOffsets[partNumber]->getOffsets();
  573. for (size_t l = 0; l < offsets.size(); l++)
  574. for (size_t y = 0; y < offsets[l].size(); y++)
  575. for (size_t x = 0; x < offsets[l][y].size(); x++)
  576. {
  577. parts[ partNumber ]->chunkOffsets[pos] = offsets[l][y][x];
  578. pos++;
  579. }
  580. delete tileOffsets[partNumber];
  581. }
  582. }
  583. is.clear();
  584. is.seekg (position);
  585. }
  586. InputPartData*
  587. MultiPartInputFile::Data::getPart(int partNumber)
  588. {
  589. if (partNumber < 0 || partNumber >= (int) parts.size())
  590. throw IEX_NAMESPACE::ArgExc ("Part number is not in valid range.");
  591. return parts[partNumber];
  592. }
  593. void
  594. MultiPartInputFile::Data::readChunkOffsetTables(bool reconstructChunkOffsetTable)
  595. {
  596. bool brokenPartsExist = false;
  597. for (size_t i = 0; i < parts.size(); i++)
  598. {
  599. int chunkOffsetTableSize = getChunkOffsetTableSize(parts[i]->header,false);
  600. parts[i]->chunkOffsets.resize(chunkOffsetTableSize);
  601. for (int j = 0; j < chunkOffsetTableSize; j++)
  602. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*is, parts[i]->chunkOffsets[j]);
  603. //
  604. // Check chunk offsets, reconstruct if broken.
  605. // At first we assume the table is complete.
  606. //
  607. parts[i]->completed = true;
  608. for (int j = 0; j < chunkOffsetTableSize; j++)
  609. {
  610. if (parts[i]->chunkOffsets[j] <= 0)
  611. {
  612. brokenPartsExist = true;
  613. parts[i]->completed = false;
  614. break;
  615. }
  616. }
  617. }
  618. if (brokenPartsExist && reconstructChunkOffsetTable)
  619. chunkOffsetReconstruction(*is, parts);
  620. }
  621. int
  622. MultiPartInputFile::version() const
  623. {
  624. return _data->version;
  625. }
  626. bool
  627. MultiPartInputFile::partComplete(int part) const
  628. {
  629. return _data->parts[part]->completed;
  630. }
  631. int
  632. MultiPartInputFile::parts() const
  633. {
  634. return int(_data->_headers.size());
  635. }
  636. OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT