ImfMultiPartInputFile.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  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.what());
  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.what());
  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