void TileOffsets::reconstructFromFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,bool isMultiPart,bool isDeep) { // // Try to reconstruct a missing tile offset table by sequentially // scanning through the file, and recording the offsets in the file // of the tiles we find. // Int64 position = is.tellg(); try { findTiles (is,isMultiPart,isDeep,false); } catch (...) { // // Suppress all exceptions. This function is called only to // reconstruct the tile offset table for incomplete files, // and exceptions are likely. // } is.clear(); is.seekg (position); }
void TileOffsets::findTiles (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, bool isMultiPartFile, bool isDeep, bool skipOnly) { for (unsigned int l = 0; l < _offsets.size(); ++l) { for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy) { for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx) { Int64 tileOffset = is.tellg(); if (isMultiPartFile) { int partNumber; OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, partNumber); } int tileX; OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, tileX); int tileY; OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, tileY); int levelX; OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, levelX); int levelY; OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, levelY); if(isDeep) { Int64 packed_offset_table_size; Int64 packed_sample_size; OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_offset_table_size); OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_sample_size); // next Int64 is unpacked sample size - skip that too Xdr::skip <StreamIO> (is, packed_offset_table_size+packed_sample_size+8); }else{ int dataSize; OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, dataSize); Xdr::skip <StreamIO> (is, dataSize); } if (skipOnly) continue; if (!isValidTile(tileX, tileY, levelX, levelY)) return; operator () (tileX, tileY, levelX, levelY) = tileOffset; } } } }
void MultiPartInputFile::Data::chunkOffsetReconstruction(OPENEXR_IMF_INTERNAL_NAMESPACE::IStream& is, const vector<InputPartData*>& parts) { // // Reconstruct broken chunk offset tables. Stop once we received any exception. // Int64 position = is.tellg(); // // check we understand all the parts available: if not, we cannot continue // exceptions thrown here should trickle back up to the constructor // for (size_t i = 0; i < parts.size(); i++) { Header& header=parts[i]->header; // // do we have a valid type entry? // we only need them for true multipart files or single part non-image (deep) files // if(!header.hasType() && (isMultiPart(version) || isNonImage(version))) { throw IEX_NAMESPACE::ArgExc("cannot reconstruct incomplete file: part with missing type"); } if(!isSupportedType(header.type())) { throw IEX_NAMESPACE::ArgExc("cannot reconstruct incomplete file: part with unknown type "+header.type()); } } // how many chunks should we read? We should stop when we reach the end size_t total_chunks = 0; // for tiled-based parts, array of (pointers to) tileOffsets objects // to create mapping between tile coordinates and chunk table indices vector<TileOffsets*> tileOffsets(parts.size()); // for scanline-based parts, number of scanlines in each part vector<int> rowsizes(parts.size()); for(size_t i = 0 ; i < parts.size() ; i++) { total_chunks += parts[i]->chunkOffsets.size(); if (isTiled(parts[i]->header.type())) { tileOffsets[i] = createTileOffsets(parts[i]->header); }else{ tileOffsets[i] = NULL; switch(parts[i]->header.compression()) { case PIZ_COMPRESSION : case B44_COMPRESSION : case B44A_COMPRESSION : rowsizes[i]=32; case ZIP_COMPRESSION : case PXR24_COMPRESSION : rowsizes[i]=16; break; case ZIPS_COMPRESSION : case RLE_COMPRESSION : case NO_COMPRESSION : rowsizes[i]=1; break; default : throw(IEX_NAMESPACE::ArgExc("Unknown compression method in chunk offset reconstruction")); } } } try { // // // Int64 chunk_start = position; for (size_t i = 0; i < total_chunks ; i++) { // // do we have a part number? // int partNumber = 0; if(isMultiPart(version)) { OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, partNumber); } if(partNumber<0 || partNumber>int(parts.size())) { // bail here - bad part number throw int(); } Header& header = parts[partNumber]->header; // size of chunk NOT including multipart field Int64 size_of_chunk=0; if (isTiled(header.type())) { // // // int tilex,tiley,levelx,levely; OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, tilex); OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, tiley); OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, levelx); OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, levely); //std::cout << "chunk_start for " << tilex <<',' << tiley << ',' << levelx << ' ' << levely << ':' << chunk_start << std::endl; if(!tileOffsets[partNumber]) { // this shouldn't actually happen - we should have allocated a valid // tileOffsets for any part which isTiled throw int(); } if(!tileOffsets[partNumber]->isValidTile(tilex,tiley,levelx,levely)) { //std::cout << "invalid tile : aborting\n"; throw int(); } (*tileOffsets[partNumber])(tilex,tiley,levelx,levely)=chunk_start; // compute chunk sizes - different procedure for deep tiles and regular // ones if(header.type()==DEEPTILE) { Int64 packed_offset; Int64 packed_sample; OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_offset); OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_sample); //add 40 byte header to packed sizes (tile coordinates, packed sizes, unpacked size) size_of_chunk=packed_offset+packed_sample+40; } else { // regular image has 20 bytes of header, 4 byte chunksize; int chunksize; OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, chunksize); size_of_chunk=chunksize+20; } } else { int y_coordinate; OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, y_coordinate); y_coordinate -= header.dataWindow().min.y; y_coordinate /= rowsizes[partNumber]; if(y_coordinate<0 || y_coordinate>int(parts[partNumber]->chunkOffsets.size())) { //std::cout << "aborting reconstruction: bad data " << y_coordinate << endl; //bail to exception catcher: broken scanline throw int(); } parts[partNumber]->chunkOffsets[y_coordinate]=chunk_start; //std::cout << "chunk_start for " << y_coordinate << ':' << chunk_start << std::endl; if(header.type()==DEEPSCANLINE) { Int64 packed_offset; Int64 packed_sample; OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_offset); OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_sample); size_of_chunk=packed_offset+packed_sample+28; } else { int chunksize; OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, chunksize); size_of_chunk=chunksize+8; } } if(isMultiPart(version)) { chunk_start+=4; } chunk_start+=size_of_chunk; //std::cout << " next chunk +"<<size_of_chunk << " = " << chunk_start << std::endl; is.seekg(chunk_start); } } catch (...) { // // Suppress all exceptions. This functions is // called only to reconstruct the line offset // table for incomplete files, and exceptions // are likely. // } // copy tiled part data back to chunk offsets for(size_t partNumber=0;partNumber<parts.size();partNumber++) { if(tileOffsets[partNumber]) { size_t pos=0; vector<vector<vector <Int64> > > offsets = tileOffsets[partNumber]->getOffsets(); for (size_t l = 0; l < offsets.size(); l++) for (size_t y = 0; y < offsets[l].size(); y++) for (size_t x = 0; x < offsets[l][y].size(); x++) { parts[ partNumber ]->chunkOffsets[pos] = offsets[l][y][x]; pos++; } delete tileOffsets[partNumber]; } } is.clear(); is.seekg (position); }