From 407216ad7397d9087007063d53bede7271445530 Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Wed, 16 Sep 2020 15:45:44 +1200 Subject: [PATCH 01/23] ignore unused bits in B44 mode detection Signed-off-by: Peter Hillman --- OpenEXR/IlmImf/ImfB44Compressor.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/OpenEXR/IlmImf/ImfB44Compressor.cpp b/OpenEXR/IlmImf/ImfB44Compressor.cpp index 3b18ba8551..30cd55a739 100644 --- a/OpenEXR/IlmImf/ImfB44Compressor.cpp +++ b/OpenEXR/IlmImf/ImfB44Compressor.cpp @@ -951,7 +951,10 @@ B44Compressor::uncompress (const char *inPtr, if (inSize < 3) notEnoughData(); - if (((const unsigned char *)inPtr)[2] == 0xfc) + // + // If shift exponent is 63, call unpack14 (ignoring unused bits) + // + if (((const unsigned char *)inPtr)[2] >= (13<<2) ) { unpack3 ((const unsigned char *)inPtr, s); inPtr += 3; From cb661b201edbec9f5da5f79d1be96e8452a6ae8a Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Wed, 9 Sep 2020 15:46:19 +1200 Subject: [PATCH 02/23] apply #832: use unsigned values in shift to prevent undefined behavior Signed-off-by: Peter Hillman --- OpenEXR/IlmImf/ImfB44Compressor.cpp | 32 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/OpenEXR/IlmImf/ImfB44Compressor.cpp b/OpenEXR/IlmImf/ImfB44Compressor.cpp index 30cd55a739..0725659dbf 100644 --- a/OpenEXR/IlmImf/ImfB44Compressor.cpp +++ b/OpenEXR/IlmImf/ImfB44Compressor.cpp @@ -381,26 +381,26 @@ unpack14 (const unsigned char b[14], unsigned short s[16]) s[ 0] = (b[0] << 8) | b[1]; unsigned short shift = (b[ 2] >> 2); - unsigned short bias = (0x20 << shift); + unsigned short bias = (0x20u << shift); - s[ 4] = s[ 0] + ((((b[ 2] << 4) | (b[ 3] >> 4)) & 0x3f) << shift) - bias; - s[ 8] = s[ 4] + ((((b[ 3] << 2) | (b[ 4] >> 6)) & 0x3f) << shift) - bias; - s[12] = s[ 8] + ((b[ 4] & 0x3f) << shift) - bias; + s[ 4] = s[ 0] + ((((b[ 2] << 4) | (b[ 3] >> 4)) & 0x3fu) << shift) - bias; + s[ 8] = s[ 4] + ((((b[ 3] << 2) | (b[ 4] >> 6)) & 0x3fu) << shift) - bias; + s[12] = s[ 8] + ((b[ 4] & 0x3fu) << shift) - bias; - s[ 1] = s[ 0] + ((b[ 5] >> 2) << shift) - bias; - s[ 5] = s[ 4] + ((((b[ 5] << 4) | (b[ 6] >> 4)) & 0x3f) << shift) - bias; - s[ 9] = s[ 8] + ((((b[ 6] << 2) | (b[ 7] >> 6)) & 0x3f) << shift) - bias; - s[13] = s[12] + ((b[ 7] & 0x3f) << shift) - bias; + s[ 1] = s[ 0] + ((unsigned int) (b[ 5] >> 2) << shift) - bias; + s[ 5] = s[ 4] + ((((b[ 5] << 4) | (b[ 6] >> 4)) & 0x3fu) << shift) - bias; + s[ 9] = s[ 8] + ((((b[ 6] << 2) | (b[ 7] >> 6)) & 0x3fu) << shift) - bias; + s[13] = s[12] + ((b[ 7] & 0x3fu) << shift) - bias; - s[ 2] = s[ 1] + ((b[ 8] >> 2) << shift) - bias; - s[ 6] = s[ 5] + ((((b[ 8] << 4) | (b[ 9] >> 4)) & 0x3f) << shift) - bias; - s[10] = s[ 9] + ((((b[ 9] << 2) | (b[10] >> 6)) & 0x3f) << shift) - bias; - s[14] = s[13] + ((b[10] & 0x3f) << shift) - bias; + s[ 2] = s[ 1] + ((unsigned int)(b[ 8] >> 2) << shift) - bias; + s[ 6] = s[ 5] + ((((b[ 8] << 4) | (b[ 9] >> 4)) & 0x3fu) << shift) - bias; + s[10] = s[ 9] + ((((b[ 9] << 2) | (b[10] >> 6)) & 0x3fu) << shift) - bias; + s[14] = s[13] + ((b[10] & 0x3fu) << shift) - bias; - s[ 3] = s[ 2] + ((b[11] >> 2) << shift) - bias; - s[ 7] = s[ 6] + ((((b[11] << 4) | (b[12] >> 4)) & 0x3f) << shift) - bias; - s[11] = s[10] + ((((b[12] << 2) | (b[13] >> 6)) & 0x3f) << shift) - bias; - s[15] = s[14] + ((b[13] & 0x3f) << shift) - bias; + s[ 3] = s[ 2] + ((unsigned int)(b[11] >> 2) << shift) - bias; + s[ 7] = s[ 6] + ((((b[11] << 4) | (b[12] >> 4)) & 0x3fu) << shift) - bias; + s[11] = s[10] + ((((b[12] << 2) | (b[13] >> 6)) & 0x3fu) << shift) - bias; + s[15] = s[14] + ((b[13] & 0x3fu) << shift) - bias; for (int i = 0; i < 16; ++i) { From 1cb83bbf0beefff6f8f529bb471e755480eb57dd Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Mon, 17 Aug 2020 12:29:03 +1200 Subject: [PATCH 03/23] apply #818: compute Huf codelengths using 64 bit to prevent shift overflow Signed-off-by: Peter Hillman --- OpenEXR/IlmImf/ImfFastHuf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenEXR/IlmImf/ImfFastHuf.cpp b/OpenEXR/IlmImf/ImfFastHuf.cpp index 9ccf2e15d5..c04b56e75b 100644 --- a/OpenEXR/IlmImf/ImfFastHuf.cpp +++ b/OpenEXR/IlmImf/ImfFastHuf.cpp @@ -205,7 +205,7 @@ FastHufDecoder::FastHufDecoder for (int l = _minCodeLength; l <= _maxCodeLength; ++l) { countTmp[l] = (double)codeCount[l] * - (double)(2 << (_maxCodeLength-l)); + (double)(2ll << (_maxCodeLength-l)); } for (int l = _minCodeLength; l <= _maxCodeLength; ++l) @@ -215,7 +215,7 @@ FastHufDecoder::FastHufDecoder for (int k =l + 1; k <= _maxCodeLength; ++k) tmp += countTmp[k]; - tmp /= (double)(2 << (_maxCodeLength - l)); + tmp /= (double)(2ll << (_maxCodeLength - l)); base[l] = (Int64)ceil (tmp); } From accc96bbc54a6dbb213e598c7dbd922f58823cb6 Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Mon, 17 Aug 2020 08:17:57 +1200 Subject: [PATCH 04/23] apply #817: double-check unpackedBuffer created in DWA uncompress Signed-off-by: Peter Hillman --- OpenEXR/IlmImf/ImfDwaCompressor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenEXR/IlmImf/ImfDwaCompressor.cpp b/OpenEXR/IlmImf/ImfDwaCompressor.cpp index 4eb4f06e54..da2d95068b 100644 --- a/OpenEXR/IlmImf/ImfDwaCompressor.cpp +++ b/OpenEXR/IlmImf/ImfDwaCompressor.cpp @@ -2535,7 +2535,7 @@ DwaCompressor::uncompress if (acCompressedSize > 0) { - if (totalAcUncompressedCount*sizeof(unsigned short) > _packedAcBufferSize) + if ( !_packedAcBuffer || totalAcUncompressedCount*sizeof(unsigned short) > _packedAcBufferSize) { throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data" "(corrupt header)."); From 1632a37543e1264bbbafca368f7292dd1bb26b05 Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Wed, 19 Aug 2020 09:40:36 +1200 Subject: [PATCH 05/23] apply #820: suppress sanitizer warnings when writing invalid enums Signed-off-by: Peter Hillman --- OpenEXR/IlmImf/ImfDeepImageStateAttribute.cpp | 6 ++++++ OpenEXR/IlmImf/ImfEnvmapAttribute.cpp | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/OpenEXR/IlmImf/ImfDeepImageStateAttribute.cpp b/OpenEXR/IlmImf/ImfDeepImageStateAttribute.cpp index 05a03571ef..7171795b6d 100644 --- a/OpenEXR/IlmImf/ImfDeepImageStateAttribute.cpp +++ b/OpenEXR/IlmImf/ImfDeepImageStateAttribute.cpp @@ -58,6 +58,12 @@ template <> void DeepImageStateAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const +#if defined (__clang__) + // _value may be an invalid value, which the clang sanitizer reports + // as undefined behavior, even though the value is acceptable in this + // context. + __attribute__((no_sanitize ("undefined"))) +#endif { unsigned char tmp = _value; Xdr::write (os, tmp); diff --git a/OpenEXR/IlmImf/ImfEnvmapAttribute.cpp b/OpenEXR/IlmImf/ImfEnvmapAttribute.cpp index a08e45e021..ad500a71d6 100644 --- a/OpenEXR/IlmImf/ImfEnvmapAttribute.cpp +++ b/OpenEXR/IlmImf/ImfEnvmapAttribute.cpp @@ -57,6 +57,12 @@ EnvmapAttribute::staticTypeName () template <> void EnvmapAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const +#if defined (__clang__) + // _value may be an invalid value, which the clang sanitizer reports + // as undefined behavior, even though the value is acceptable in this + // context. + __attribute__((no_sanitize ("undefined"))) +#endif { unsigned char tmp = _value; Xdr::write (os, tmp); From 10b1c6ad2169cbbd531a1368c71c12c274362741 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Sun, 30 Aug 2020 16:15:10 -0700 Subject: [PATCH 06/23] apply #825: Avoid overflow in calculateNumTiles when size=MAX_INT Signed-off-by: Peter Hillman --- OpenEXR/IlmImf/ImfTiledMisc.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/OpenEXR/IlmImf/ImfTiledMisc.cpp b/OpenEXR/IlmImf/ImfTiledMisc.cpp index c9e8731f11..b8e195fd86 100644 --- a/OpenEXR/IlmImf/ImfTiledMisc.cpp +++ b/OpenEXR/IlmImf/ImfTiledMisc.cpp @@ -301,10 +301,8 @@ calculateNumTiles (int *numTiles, { for (int i = 0; i < numLevels; i++) { - int l = levelSize (min, max, i, rmode); - if (l > std::numeric_limits::max() - size + 1) - throw IEX_NAMESPACE::ArgExc ("Invalid size."); - + // use 64 bits to avoid int overflow if size is large. + Int64 l = levelSize (min, max, i, rmode); numTiles[i] = (l + size - 1) / size; } } From acececb78d40083821810ac6d2439c33a548e66a Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Mon, 31 Aug 2020 09:29:11 +1200 Subject: [PATCH 07/23] apply #826: restrict maximum tile size to INT_MAX byte limit Signed-off-by: Peter Hillman --- OpenEXR/IlmImf/ImfTiledInputFile.cpp | 10 ++++++++++ OpenEXR/IlmImf/ImfTiledOutputFile.cpp | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/OpenEXR/IlmImf/ImfTiledInputFile.cpp b/OpenEXR/IlmImf/ImfTiledInputFile.cpp index e1159797cc..3e7fda333c 100644 --- a/OpenEXR/IlmImf/ImfTiledInputFile.cpp +++ b/OpenEXR/IlmImf/ImfTiledInputFile.cpp @@ -999,6 +999,16 @@ TiledInputFile::initialize () _data->tileBufferSize = _data->maxBytesPerTileLine * _data->tileDesc.ySize; + // + // OpenEXR has a limit of INT_MAX compressed bytes per tile + // disallow uncompressed tile sizes above INT_MAX too to guarantee file is written + // + if( _data->tileBufferSize > INT_MAX ) + { + throw IEX_NAMESPACE::ArgExc ("Tile size too large for OpenEXR format"); + } + + // // Create all the TileBuffers and allocate their internal buffers // diff --git a/OpenEXR/IlmImf/ImfTiledOutputFile.cpp b/OpenEXR/IlmImf/ImfTiledOutputFile.cpp index 0f24381eaa..52f7577ab6 100644 --- a/OpenEXR/IlmImf/ImfTiledOutputFile.cpp +++ b/OpenEXR/IlmImf/ImfTiledOutputFile.cpp @@ -1035,6 +1035,17 @@ TiledOutputFile::initialize (const Header &header) _data->tileBufferSize = _data->maxBytesPerTileLine * _data->tileDesc.ySize; + // + // OpenEXR has a limit of INT_MAX compressed bytes per tile + // disallow uncompressed tile sizes above INT_MAX too to guarantee file is written + // + if( _data->tileBufferSize > INT_MAX ) + { + throw IEX_NAMESPACE::ArgExc ("Tile size too large for OpenEXR format"); + } + + + // // Create all the TileBuffers and allocate their internal buffers // From c72ec2733bde201ca2318162e80d8e870ca63c3d Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Tue, 1 Sep 2020 15:58:07 +1200 Subject: [PATCH 08/23] apply #827: lighter weight reading of Luma-only images via RgbaInputFile Signed-off-by: Peter Hillman --- OpenEXR/IlmImf/ImfRgbaFile.cpp | 89 ++++++++++++++++++++++++---------- OpenEXR/IlmImfTest/testYca.cpp | 1 + 2 files changed, 64 insertions(+), 26 deletions(-) diff --git a/OpenEXR/IlmImf/ImfRgbaFile.cpp b/OpenEXR/IlmImf/ImfRgbaFile.cpp index 1b7c8670aa..68fa51cb52 100644 --- a/OpenEXR/IlmImf/ImfRgbaFile.cpp +++ b/OpenEXR/IlmImf/ImfRgbaFile.cpp @@ -1180,7 +1180,7 @@ RgbaInputFile::RgbaInputFile (const char name[], int numThreads): { RgbaChannels rgbaChannels = channels(); - if (rgbaChannels & (WRITE_Y | WRITE_C)) + if (rgbaChannels & WRITE_C) _fromYca = new FromYca (*_inputFile, rgbaChannels); } @@ -1192,7 +1192,7 @@ RgbaInputFile::RgbaInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int n { RgbaChannels rgbaChannels = channels(); - if (rgbaChannels & (WRITE_Y | WRITE_C)) + if (rgbaChannels & WRITE_C) _fromYca = new FromYca (*_inputFile, rgbaChannels); } @@ -1207,7 +1207,7 @@ RgbaInputFile::RgbaInputFile (const char name[], { RgbaChannels rgbaChannels = channels(); - if (rgbaChannels & (WRITE_Y | WRITE_C)) + if (rgbaChannels & WRITE_C) _fromYca = new FromYca (*_inputFile, rgbaChannels); } @@ -1222,7 +1222,7 @@ RgbaInputFile::RgbaInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, { RgbaChannels rgbaChannels = channels(); - if (rgbaChannels & (WRITE_Y | WRITE_C)) + if (rgbaChannels & WRITE_C) _fromYca = new FromYca (*_inputFile, rgbaChannels); } @@ -1249,27 +1249,42 @@ RgbaInputFile::setFrameBuffer (Rgba *base, size_t xStride, size_t yStride) FrameBuffer fb; - fb.insert (_channelNamePrefix + "R", - Slice (HALF, - (char *) &base[0].r, - xs, ys, - 1, 1, // xSampling, ySampling - 0.0)); // fillValue - - fb.insert (_channelNamePrefix + "G", - Slice (HALF, - (char *) &base[0].g, - xs, ys, - 1, 1, // xSampling, ySampling - 0.0)); // fillValue - - fb.insert (_channelNamePrefix + "B", - Slice (HALF, - (char *) &base[0].b, - xs, ys, - 1, 1, // xSampling, ySampling - 0.0)); // fillValue - + if( channels() & WRITE_Y ) + { + fb.insert (_channelNamePrefix + "Y", + Slice (HALF, + (char *) &base[0].r, + xs, ys, + 1, 1, // xSampling, ySampling + 0.0)); // fillValue + } + else + { + + + fb.insert (_channelNamePrefix + "R", + Slice (HALF, + (char *) &base[0].r, + xs, ys, + 1, 1, // xSampling, ySampling + 0.0)); // fillValue + + + + fb.insert (_channelNamePrefix + "G", + Slice (HALF, + (char *) &base[0].g, + xs, ys, + 1, 1, // xSampling, ySampling + 0.0)); // fillValue + + fb.insert (_channelNamePrefix + "B", + Slice (HALF, + (char *) &base[0].b, + xs, ys, + 1, 1, // xSampling, ySampling + 0.0)); // fillValue + } fb.insert (_channelNamePrefix + "A", Slice (HALF, (char *) &base[0].a, @@ -1292,7 +1307,7 @@ RgbaInputFile::setLayerName (const string &layerName) RgbaChannels rgbaChannels = channels(); - if (rgbaChannels & (WRITE_Y | WRITE_C)) + if (rgbaChannels & WRITE_C) _fromYca = new FromYca (*_inputFile, rgbaChannels); FrameBuffer fb; @@ -1311,6 +1326,28 @@ RgbaInputFile::readPixels (int scanLine1, int scanLine2) else { _inputFile->readPixels (scanLine1, scanLine2); + + if (channels() & WRITE_Y) + { + // + // Luma channel has been written into red channel + // Duplicate into green and blue channel to create gray image + // + const Slice* s = _inputFile->frameBuffer().findSlice(_channelNamePrefix + "Y"); + Box2i dataWindow = _inputFile->header().dataWindow(); + + for( int scanLine = scanLine1 ; scanLine <= scanLine2 ; scanLine++ ) + { + char* rowBase = s->base + scanLine*s->yStride; + for(int x = dataWindow.min.x ; x <= dataWindow.max.x ; ++x ) + { + Rgba* pixel = reinterpret_cast(rowBase+x*s->xStride); + pixel->g = pixel->r; + pixel->b = pixel->r; + } + + } + } } } diff --git a/OpenEXR/IlmImfTest/testYca.cpp b/OpenEXR/IlmImfTest/testYca.cpp index 573abd26ce..0c00e14390 100644 --- a/OpenEXR/IlmImfTest/testYca.cpp +++ b/OpenEXR/IlmImfTest/testYca.cpp @@ -195,6 +195,7 @@ writeReadYca (const char fileName[], else { assert (p1.g == p2.g); + assert (p1.b == p2.b); } if (channels & WRITE_A) From f88eea43686f69896d0e9916a2359f0790fa4706 Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Mon, 7 Sep 2020 15:38:12 +1200 Subject: [PATCH 09/23] refactor channel filling in InputFile API with tiled source Signed-off-by: Peter Hillman --- OpenEXR/IlmImf/ImfInputFile.cpp | 264 ++++++++++++++++--------- OpenEXR/IlmImfTest/testScanLineApi.cpp | 134 ++++++++++++- 2 files changed, 304 insertions(+), 94 deletions(-) diff --git a/OpenEXR/IlmImf/ImfInputFile.cpp b/OpenEXR/IlmImf/ImfInputFile.cpp index 8695c65bf9..e9c116d0c3 100644 --- a/OpenEXR/IlmImf/ImfInputFile.cpp +++ b/OpenEXR/IlmImf/ImfInputFile.cpp @@ -289,55 +289,133 @@ bufferedReadPixels (InputFile::Data* ifd, int scanLine1, int scanLine2) // framebuffer. // - for (FrameBuffer::ConstIterator k = ifd->cachedBuffer->begin(); - k != ifd->cachedBuffer->end(); + for (FrameBuffer::ConstIterator k = ifd->tFileBuffer.begin(); + k != ifd->tFileBuffer.end(); ++k) { - Slice fromSlice = k.slice(); // slice to write from - Slice toSlice = ifd->tFileBuffer[k.name()]; // slice to write to - char *fromPtr, *toPtr; - int size = pixelTypeSize (toSlice.type); - int xStart = levelRange.min.x; - int yStart = minYThisRow; + Slice toSlice = k.slice(); // slice to read from + char* toPtr; - while (modp (xStart, toSlice.xSampling) != 0) - ++xStart; + int xStart = levelRange.min.x; + int yStart = minYThisRow; - while (modp (yStart, toSlice.ySampling) != 0) - ++yStart; + while (modp (xStart, toSlice.xSampling) != 0) + ++xStart; - for (int y = yStart; - y <= maxYThisRow; - y += toSlice.ySampling) + while (modp (yStart, toSlice.ySampling) != 0) + ++yStart; + + FrameBuffer::ConstIterator c = ifd->cachedBuffer->find(k.name()); + + + if( c!=ifd->cachedBuffer->end()) + { + // + // copy channel from source slice to output slice + // + Slice fromSlice = c.slice(); // slice to write to + + int size = pixelTypeSize (toSlice.type); + char* fromPtr; + + for (int y = yStart; + y <= maxYThisRow; + y += toSlice.ySampling) + { + // + // Set the pointers to the start of the y scanline in + // this row of tiles + // + + fromPtr = fromSlice.base + + (y - tileRange.min.y) * fromSlice.yStride + + xStart * fromSlice.xStride; + + toPtr = toSlice.base + + divp (y, toSlice.ySampling) * toSlice.yStride + + divp (xStart, toSlice.xSampling) * toSlice.xStride; + + // + // Copy all pixels for the scanline in this row of tiles + // + + for (int x = xStart; + x <= levelRange.max.x; + x += toSlice.xSampling) + { + for (int i = 0; i < size; ++i) + toPtr[i] = fromPtr[i]; + + fromPtr += fromSlice.xStride * toSlice.xSampling; + toPtr += toSlice.xStride; + } + } + } + else { - // - // Set the pointers to the start of the y scanline in - // this row of tiles - // - - fromPtr = fromSlice.base + - (y - tileRange.min.y) * fromSlice.yStride + - xStart * fromSlice.xStride; - - toPtr = toSlice.base + - divp (y, toSlice.ySampling) * toSlice.yStride + - divp (xStart, toSlice.xSampling) * toSlice.xStride; - - // - // Copy all pixels for the scanline in this row of tiles - // - - for (int x = xStart; - x <= levelRange.max.x; - x += toSlice.xSampling) + + // + // fill output slice + // + for (int y = yStart; + y <= maxYThisRow; + y += toSlice.ySampling) { - for (int i = 0; i < size; ++i) - toPtr[i] = fromPtr[i]; - fromPtr += fromSlice.xStride * toSlice.xSampling; - toPtr += toSlice.xStride; + toPtr = toSlice.base + + divp (y, toSlice.ySampling) * toSlice.yStride + + divp (xStart, toSlice.xSampling) * toSlice.xStride; + + // + // Copy all pixels for the scanline in this row of tiles + // + + switch ( toSlice.type) + { + case UINT: + { + unsigned int fill = toSlice.fillValue; + for (int x = xStart; + x <= levelRange.max.x; + x += toSlice.xSampling) + { + * reinterpret_cast(toPtr) = fill; + toPtr += toSlice.xStride; + } + break; + } + case HALF : + { + half fill = toSlice.fillValue; + for (int x = xStart; + x <= levelRange.max.x; + x += toSlice.xSampling) + { + * reinterpret_cast(toPtr) = fill; + toPtr += toSlice.xStride; + } + break; + } + case FLOAT : + { + float fill = toSlice.fillValue; + for (int x = xStart; + x <= levelRange.max.x; + x += toSlice.xSampling) + { + * reinterpret_cast(toPtr) = fill; + toPtr += toSlice.xStride; + } + break; + } + case NUM_PIXELTYPES : + { + break; + } + + } } } } @@ -703,57 +781,63 @@ InputFile::setFrameBuffer (const FrameBuffer &frameBuffer) { Slice s = k.slice(); - switch (s.type) - { - case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT: - - _data->cachedBuffer->insert - (k.name(), - Slice (UINT, - (char *)(new unsigned int[tileRowSize] - - _data->offset), - sizeof (unsigned int), - sizeof (unsigned int) * - _data->tFile->levelWidth(0), - 1, 1, - s.fillValue, - false, true)); - break; - - case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF: - - _data->cachedBuffer->insert - (k.name(), - Slice (HALF, - (char *)(new half[tileRowSize] - - _data->offset), - sizeof (half), - sizeof (half) * - _data->tFile->levelWidth(0), - 1, 1, - s.fillValue, - false, true)); - break; - - case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT: - - _data->cachedBuffer->insert - (k.name(), - Slice (OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT, - (char *)(new float[tileRowSize] - - _data->offset), - sizeof(float), - sizeof(float) * - _data->tFile->levelWidth(0), - 1, 1, - s.fillValue, - false, true)); - break; - - default: - - throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type."); - } + // + // omit adding channels that are not listed - 'fill' channels are added later + // + if ( _data->header.channels().find(k.name()) != _data->header.channels().end() ) + { + switch (s.type) + { + case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT: + + _data->cachedBuffer->insert + (k.name(), + Slice (UINT, + (char *)(new unsigned int[tileRowSize] - + _data->offset), + sizeof (unsigned int), + sizeof (unsigned int) * + _data->tFile->levelWidth(0), + 1, 1, + s.fillValue, + false, true)); + break; + + case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF: + + _data->cachedBuffer->insert + (k.name(), + Slice (HALF, + (char *)(new half[tileRowSize] - + _data->offset), + sizeof (half), + sizeof (half) * + _data->tFile->levelWidth(0), + 1, 1, + s.fillValue, + false, true)); + break; + + case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT: + + _data->cachedBuffer->insert + (k.name(), + Slice (OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT, + (char *)(new float[tileRowSize] - + _data->offset), + sizeof(float), + sizeof(float) * + _data->tFile->levelWidth(0), + 1, 1, + s.fillValue, + false, true)); + break; + + default: + + throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type."); + } + } } _data->tFile->setFrameBuffer (*_data->cachedBuffer); diff --git a/OpenEXR/IlmImfTest/testScanLineApi.cpp b/OpenEXR/IlmImfTest/testScanLineApi.cpp index 354d2dccf1..720351ea5d 100644 --- a/OpenEXR/IlmImfTest/testScanLineApi.cpp +++ b/OpenEXR/IlmImfTest/testScanLineApi.cpp @@ -93,7 +93,9 @@ writeRead (const Array2D &pi1, int yOffset, Compression comp, LevelMode mode, - LevelRoundingMode rmode) + LevelRoundingMode rmode, + bool fillChannel + ) { // // Write the pixel data in pi1, ph1 and ph2 to a tiled @@ -263,6 +265,16 @@ writeRead (const Array2D &pi1, Array2D ph2 (h, w); Array2D pf2 (h, w); + Array2D fi2 (fillChannel ? h : 1 , fillChannel ? w : 1); + Array2D fh2 (fillChannel ? h : 1 , fillChannel ? w : 1); + Array2D ff2 (fillChannel ? h : 1 , fillChannel ? w : 1); + + + const unsigned int fillInt = 12; + const half fillHalf = 4.5; + const float fillFloat = M_PI; + + FrameBuffer fb; fb.insert ("I", // name @@ -286,6 +298,30 @@ writeRead (const Array2D &pi1, sizeof (pf2[0][0]) * w) // yStride ); + if(fillChannel) + { + fb.insert ("FI", // name + Slice (IMF::UINT, // type + (char *) &fi2[-dwy][-dwx],// base + sizeof (fi2[0][0]), // xStride + sizeof (fi2[0][0]) * w,1,1,fillInt) // yStride + ); + + fb.insert ("FH", // name + Slice (IMF::HALF, // type + (char *) &fh2[-dwy][-dwx],// base + sizeof (fh2[0][0]), // xStride + sizeof (fh2[0][0]) * w,1,1,fillHalf) // yStride + ); + + fb.insert ("FF", // name + Slice (IMF::FLOAT, // type + (char *) &ff2[-dwy][-dwx],// base + sizeof (ff2[0][0]), // xStride + sizeof (ff2[0][0]) * w,1,1,fillFloat) // yStride + ); + } + in.setFrameBuffer (fb); for (int y = dw.min.y; y <= dw.max.y; ++y) in.readPixels (y); @@ -323,6 +359,13 @@ writeRead (const Array2D &pi1, assert (pi1[y][x] == pi2[y][x]); assert (ph1[y][x] == ph2[y][x]); assert (pf1[y][x] == pf2[y][x]); + + if (fillChannel) + { + assert(fi2[y][x] == fillInt); + assert(fh2[y][x] == fillHalf); + assert(ff2[y][x] == fillFloat); + } } } } @@ -342,6 +385,10 @@ writeRead (const Array2D &pi1, Array2D ph2 (h, w); Array2D pf2 (h, w); + Array2D fi2 (fillChannel ? h : 1 , fillChannel ? w : 1); + Array2D fh2 (fillChannel ? h : 1 , fillChannel ? w : 1); + Array2D ff2 (fillChannel ? h : 1 , fillChannel ? w : 1); + FrameBuffer fb; fb.insert ("I", // name @@ -364,6 +411,34 @@ writeRead (const Array2D &pi1, sizeof (pf2[0][0]), // xStride sizeof (pf2[0][0]) * w) // yStride ); + const unsigned int fillInt = 21; + const half fillHalf = 42; + const float fillFloat = 2.8; + + if (fillChannel) + { + fb.insert ("FI", // name + Slice (IMF::UINT, // type + (char *) &fi2[-dwy][-dwx],// base + sizeof (fi2[0][0]), // xStride + sizeof (fi2[0][0]) * w,1,1,fillInt) // yStride + ); + + fb.insert ("FH", // name + Slice (IMF::HALF, // type + (char *) &fh2[-dwy][-dwx],// base + sizeof (fh2[0][0]), // xStride + sizeof (fh2[0][0]) * w,1,1,fillHalf) // yStride + ); + + fb.insert ("FF", // name + Slice (IMF::FLOAT, // type + (char *) &ff2[-dwy][-dwx],// base + sizeof (ff2[0][0]), // xStride + sizeof (ff2[0][0]) * w,1,1,fillFloat) // yStride + ); + + } in.setFrameBuffer (fb); for (int y = dw.max.y; y >= dw.min.y; --y) @@ -402,6 +477,12 @@ writeRead (const Array2D &pi1, assert (pi1[y][x] == pi2[y][x]); assert (ph1[y][x] == ph2[y][x]); assert (pf1[y][x] == pf2[y][x]); + if (fillChannel) + { + assert(fi2[y][x] == fillInt); + assert(fh2[y][x] == fillHalf); + assert(ff2[y][x] == fillFloat); + } } } } @@ -422,6 +503,17 @@ writeRead (const Array2D &pi1, Array2D ph2 (h, w); Array2D pf2 (h, w); + + Array2D fi2 (fillChannel ? h : 1 , fillChannel ? w : 1); + Array2D fh2 (fillChannel ? h : 1 , fillChannel ? w : 1); + Array2D ff2 (fillChannel ? h : 1 , fillChannel ? w : 1); + + + const unsigned int fillInt = 81; + const half fillHalf = 0.5; + const float fillFloat = 7.8; + + for (int y = dw.min.y; y <= dw.max.y; ++y) { FrameBuffer fb; @@ -447,6 +539,31 @@ writeRead (const Array2D &pi1, 0) // yStride ); + if (fillChannel) + { + fb.insert ("FI", // name + Slice (IMF::UINT, // type + (char *) &fi2[y - dwy][-dwx], // base + sizeof (fi2[0][0]), // xStride + 0,1,1,fillInt) // yStride + ); + + fb.insert ("FH", // name + Slice (IMF::HALF, // type + (char *) &fh2[y - dwy][-dwx], // base + sizeof (fh2[0][0]), // xStride + 0,1,1,fillHalf) // yStride + ); + + fb.insert ("FF", // name + Slice (IMF::FLOAT, // type + (char *) &ff2[y - dwy][-dwx], // base + sizeof (ff2[0][0]), // xStride + 0,1,1,fillFloat) // yStride + ); + + } + in.setFrameBuffer (fb); in.readPixels (y); } @@ -484,7 +601,14 @@ writeRead (const Array2D &pi1, assert (pi1[y][x] == pi2[y][x]); assert (ph1[y][x] == ph2[y][x]); assert (pf1[y][x] == pf2[y][x]); + if (fillChannel) + { + assert (fi2[y][x] == fillInt); + assert (fh2[y][x] == fillHalf); + assert (ff2[y][x] == fillFloat); + } } + } } @@ -509,11 +633,13 @@ writeRead (const std::string &tempDir, std::string filename = tempDir + "imf_test_scanline_api.exr"; writeRead (pi, ph, pf, filename.c_str(), lorder, W, H, - xSize, ySize, dx, dy, comp, ONE_LEVEL, rmode); + xSize, ySize, dx, dy, comp, ONE_LEVEL, rmode , false); + writeRead (pi, ph, pf, filename.c_str(), lorder, W, H, + xSize, ySize, dx, dy, comp, MIPMAP_LEVELS, rmode , false ); writeRead (pi, ph, pf, filename.c_str(), lorder, W, H, - xSize, ySize, dx, dy, comp, MIPMAP_LEVELS, rmode); + xSize, ySize, dx, dy, comp, RIPMAP_LEVELS, rmode , false); writeRead (pi, ph, pf, filename.c_str(), lorder, W, H, - xSize, ySize, dx, dy, comp, RIPMAP_LEVELS, rmode); + xSize, ySize, dx, dy, comp, ONE_LEVEL, rmode , true); } } // namespace From 6c458f7f4ff62d145886bc5abc357611a4c38d72 Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Mon, 7 Sep 2020 16:33:48 +1200 Subject: [PATCH 10/23] handle edge-case of empty framebuffer Signed-off-by: Peter Hillman --- OpenEXR/IlmImf/ImfInputFile.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/OpenEXR/IlmImf/ImfInputFile.cpp b/OpenEXR/IlmImf/ImfInputFile.cpp index e9c116d0c3..fbf9f40e26 100644 --- a/OpenEXR/IlmImf/ImfInputFile.cpp +++ b/OpenEXR/IlmImf/ImfInputFile.cpp @@ -278,9 +278,14 @@ bufferedReadPixels (InputFile::Data* ifd, int scanLine1, int scanLine2) // // We don't have any valid buffered info, so we need to read in // from the file. + // if no channels are being read that are present in file, cachedBuffer will be empty // - ifd->tFile->readTiles (0, ifd->tFile->numXTiles (0) - 1, j, j); + if (ifd->cachedBuffer->begin() != ifd->cachedBuffer->end()) + { + ifd->tFile->readTiles (0, ifd->tFile->numXTiles (0) - 1, j, j); + } + ifd->cachedTileY = j; } @@ -313,7 +318,7 @@ bufferedReadPixels (InputFile::Data* ifd, int scanLine1, int scanLine2) if( c!=ifd->cachedBuffer->end()) { // - // copy channel from source slice to output slice + // output channel was read from source image: copy to output slice // Slice fromSlice = c.slice(); // slice to write to @@ -357,7 +362,7 @@ bufferedReadPixels (InputFile::Data* ifd, int scanLine1, int scanLine2) { // - // fill output slice + // channel wasn't present in source file: fill output slice // for (int y = yStart; y <= maxYThisRow; @@ -841,6 +846,7 @@ InputFile::setFrameBuffer (const FrameBuffer &frameBuffer) } _data->tFile->setFrameBuffer (*_data->cachedBuffer); + } _data->tFileBuffer = frameBuffer; From 453cc69ef175051dfabfac983086b4b87d847231 Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Fri, 4 Sep 2020 16:44:58 +1200 Subject: [PATCH 11/23] apply #829: fix buffer overflow check in PIZ decompression Signed-off-by: Peter Hillman --- OpenEXR/IlmImf/ImfFastHuf.cpp | 4 ++-- OpenEXR/IlmImf/ImfPizCompressor.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenEXR/IlmImf/ImfFastHuf.cpp b/OpenEXR/IlmImf/ImfFastHuf.cpp index c04b56e75b..fc67bdc6ad 100644 --- a/OpenEXR/IlmImf/ImfFastHuf.cpp +++ b/OpenEXR/IlmImf/ImfFastHuf.cpp @@ -127,7 +127,7 @@ FastHufDecoder::FastHufDecoder for (Int64 symbol = static_cast(minSymbol); symbol <= static_cast(maxSymbol); symbol++) { - if (currByte - table > numBytes) + if (currByte - table >= numBytes) { throw IEX_NAMESPACE::InputExc ("Error decoding Huffman table " "(Truncated table data)."); @@ -144,7 +144,7 @@ FastHufDecoder::FastHufDecoder if (codeLen == (Int64) LONG_ZEROCODE_RUN) { - if (currByte - table > numBytes) + if (currByte - table >= numBytes) { throw IEX_NAMESPACE::InputExc ("Error decoding Huffman table " "(Truncated table data)."); diff --git a/OpenEXR/IlmImf/ImfPizCompressor.cpp b/OpenEXR/IlmImf/ImfPizCompressor.cpp index edc141ad9d..ffcd9e9aa9 100644 --- a/OpenEXR/IlmImf/ImfPizCompressor.cpp +++ b/OpenEXR/IlmImf/ImfPizCompressor.cpp @@ -594,7 +594,7 @@ Xdr::read (inPtr, (char *) &bitmap[0] + minNonZero, int length; Xdr::read (inPtr, length); - if (length > inSize) + if (inPtr + length > inputEnd || length<0 ) { throw InputExc ("Error in header for PIZ-compressed data " "(invalid array length)."); From fc439bc726dff44eb4677ee8c6e245f60f6feeaa Mon Sep 17 00:00:00 2001 From: peterhillman Date: Fri, 11 Sep 2020 11:03:48 +1200 Subject: [PATCH 12/23] Use Int64 in dataWindowForTile to prevent integer overflow (#831) * Use Int64 in dataWindowForTile to prevent integer overflow Signed-off-by: Peter Hillman * use signed 64 bit instead for dataWindow calculation Signed-off-by: Peter Hillman Co-authored-by: Cary Phillips Signed-off-by: Peter Hillman --- OpenEXR/IlmImf/ImfTiledMisc.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/OpenEXR/IlmImf/ImfTiledMisc.cpp b/OpenEXR/IlmImf/ImfTiledMisc.cpp index b8e195fd86..89ef97cb5c 100644 --- a/OpenEXR/IlmImf/ImfTiledMisc.cpp +++ b/OpenEXR/IlmImf/ImfTiledMisc.cpp @@ -97,13 +97,14 @@ dataWindowForTile (const TileDescription &tileDesc, V2i tileMin = V2i (minX + dx * tileDesc.xSize, minY + dy * tileDesc.ySize); - V2i tileMax = tileMin + V2i (tileDesc.xSize - 1, tileDesc.ySize - 1); + int64_t tileMaxX = int64_t(tileMin[0]) + tileDesc.xSize - 1; + int64_t tileMaxY = int64_t(tileMin[1]) + tileDesc.ySize - 1; V2i levelMax = dataWindowForLevel (tileDesc, minX, maxX, minY, maxY, lx, ly).max; - tileMax = V2i (std::min (tileMax[0], levelMax[0]), - std::min (tileMax[1], levelMax[1])); + V2i tileMax = V2i (std::min (tileMaxX, int64_t(levelMax[0])), + std::min (tileMaxY, int64_t(levelMax[1]))); return Box2i (tileMin, tileMax); } From d63b19d6d6558389103cb918943029df75d7d1be Mon Sep 17 00:00:00 2001 From: peterhillman Date: Thu, 17 Sep 2020 08:42:39 +1200 Subject: [PATCH 13/23] prevent overflow in hufUncompress if nBits is large (#836) Signed-off-by: Peter Hillman --- OpenEXR/IlmImf/ImfHuf.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/OpenEXR/IlmImf/ImfHuf.cpp b/OpenEXR/IlmImf/ImfHuf.cpp index 7bd7fc00d0..23cfcfd6cb 100644 --- a/OpenEXR/IlmImf/ImfHuf.cpp +++ b/OpenEXR/IlmImf/ImfHuf.cpp @@ -1093,7 +1093,9 @@ hufUncompress (const char compressed[], const char *ptr = compressed + 20; - if ( ptr + (nBits+7 )/8 > compressed+nCompressed) + uint64_t nBytes = (static_cast(nBits)+7) / 8 ; + + if ( ptr + nBytes > compressed+nCompressed) { notEnoughData(); return; From a72909fab28ed5e27f10bd1a2162ff18b6830380 Mon Sep 17 00:00:00 2001 From: peterhillman Date: Tue, 22 Sep 2020 18:52:57 +1200 Subject: [PATCH 14/23] add sanity check for reading multipart files with no parts (#840) Signed-off-by: Peter Hillman --- OpenEXR/IlmImf/ImfMultiPartInputFile.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/OpenEXR/IlmImf/ImfMultiPartInputFile.cpp b/OpenEXR/IlmImf/ImfMultiPartInputFile.cpp index 1e04726984..f271f9e9a7 100644 --- a/OpenEXR/IlmImf/ImfMultiPartInputFile.cpp +++ b/OpenEXR/IlmImf/ImfMultiPartInputFile.cpp @@ -340,6 +340,11 @@ MultiPartInputFile::initialize() // Perform usual check on headers. // + if ( _data->_headers.size() == 0) + { + throw IEX_NAMESPACE::ArgExc ("Files must contain at least one header"); + } + for (size_t i = 0; i < _data->_headers.size(); i++) { // From 713d9c4a0f16da685d178863ccfed4b0d5b0aefa Mon Sep 17 00:00:00 2001 From: peterhillman Date: Wed, 7 Oct 2020 14:38:59 +1300 Subject: [PATCH 15/23] reduce B44 _tmpBufferSize (was allocating two bytes per byte) (#843) Signed-off-by: Peter Hillman --- OpenEXR/IlmImf/ImfB44Compressor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenEXR/IlmImf/ImfB44Compressor.cpp b/OpenEXR/IlmImf/ImfB44Compressor.cpp index 0725659dbf..5e2ab9ea50 100644 --- a/OpenEXR/IlmImf/ImfB44Compressor.cpp +++ b/OpenEXR/IlmImf/ImfB44Compressor.cpp @@ -494,7 +494,7 @@ B44Compressor::B44Compressor // _tmpBuffer = new unsigned short - [checkArraySize (uiMult (maxScanLineSize, numScanLines), + [checkArraySize (uiMult (maxScanLineSize / sizeof(unsigned short), numScanLines), sizeof (unsigned short))]; const ChannelList &channels = header().channels(); From 8debdfa46b4cd4d683dd5700b1610d9132d15247 Mon Sep 17 00:00:00 2001 From: peterhillman Date: Tue, 13 Oct 2020 08:03:57 +1300 Subject: [PATCH 16/23] check for valid Huf code lengths (#849) * check for valid Huf code lengths * test non-fast huf decoder in testHuf Signed-off-by: Peter Hillman --- OpenEXR/IlmImf/ImfHuf.cpp | 9 +++ OpenEXR/IlmImfTest/testHuf.cpp | 144 ++++++++++++++++++--------------- 2 files changed, 89 insertions(+), 64 deletions(-) diff --git a/OpenEXR/IlmImf/ImfHuf.cpp b/OpenEXR/IlmImf/ImfHuf.cpp index 23cfcfd6cb..1cc09d63fa 100644 --- a/OpenEXR/IlmImf/ImfHuf.cpp +++ b/OpenEXR/IlmImf/ImfHuf.cpp @@ -910,6 +910,11 @@ hufDecode // lc -= pl.len; + + if ( lc < 0 ) + { + invalidCode(); // code length too long + } getCode (pl.lit, rlc, c, lc, in, out, outb, oe); } else @@ -967,6 +972,10 @@ hufDecode if (pl.len) { lc -= pl.len; + if ( lc < 0 ) + { + invalidCode(); // code length too long + } getCode (pl.lit, rlc, c, lc, in, out, outb, oe); } else diff --git a/OpenEXR/IlmImfTest/testHuf.cpp b/OpenEXR/IlmImfTest/testHuf.cpp index a93b8ea968..beb4edefac 100644 --- a/OpenEXR/IlmImfTest/testHuf.cpp +++ b/OpenEXR/IlmImfTest/testHuf.cpp @@ -245,70 +245,86 @@ testHuf (const std::string&) IMATH_NAMESPACE::Rand48 rand48 (0); - const int N = 1000000; - Array raw (N); - - fill1 (raw, N, 1, rand48); // test various symbol distributions - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - fill1 (raw, N, 10, rand48); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - fill1 (raw, N, 100, rand48); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - fill1 (raw, N, 1000, rand48); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - - fill2 (raw, N, 1, rand48); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - fill2 (raw, N, 10, rand48); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - fill2 (raw, N, 100, rand48); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - fill2 (raw, N, 1000, rand48); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - - fill3 (raw, N, 0); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - fill3 (raw, N, 1); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - fill3 (raw, N, USHRT_MAX - 1); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - fill3 (raw, N, USHRT_MAX); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - - fill4 (raw, USHRT_MAX + 1); - compressVerify(raw, USHRT_MAX + 1, HUF_COMPRESS_DEK_HASH_FOR_FILL4_USHRT_MAX_PLUS_ONE); - compressUncompress (raw, USHRT_MAX + 1); - compressUncompressSubset (raw, USHRT_MAX + 1); - fill4 (raw, N); - compressVerify(raw, N, HUF_COMPRESS_DEK_HASH_FOR_FILL4_N); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - - fill4 (raw, 0); - compressUncompress (raw, 0); // test small input data sets - fill4 (raw, 1); - compressUncompress (raw, 1); - fill4 (raw, 2); - compressUncompress (raw, 2); - fill4 (raw, 3); - compressUncompress (raw, 3); - - fill5 (raw, N); // test run-length coding of code table - compressVerify(raw, N, HUF_COMPRESS_DEK_HASH_FOR_FILL5_N); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); + // + // FastHufDecoder is used for more than 128 bits, so first test with fewer than 128 bits, + // then test FastHufDecoder + // + for (int pass = 0 ; pass < 2 ; ++pass) + { + + int N = pass==0 ? 12 : 1000000; + Array raw (N); + + fill1 (raw, N, 1, rand48); // test various symbol distributions + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + fill1 (raw, N, 10, rand48); + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + fill1 (raw, N, 100, rand48); + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + fill1 (raw, N, 1000, rand48); + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + + fill2 (raw, N, 1, rand48); + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + fill2 (raw, N, 10, rand48); + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + fill2 (raw, N, 100, rand48); + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + fill2 (raw, N, 1000, rand48); + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + + fill3 (raw, N, 0); + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + fill3 (raw, N, 1); + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + fill3 (raw, N, USHRT_MAX - 1); + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + fill3 (raw, N, USHRT_MAX); + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + + if (pass==1) + { + fill4 (raw, USHRT_MAX + 1); + compressVerify(raw, USHRT_MAX + 1, HUF_COMPRESS_DEK_HASH_FOR_FILL4_USHRT_MAX_PLUS_ONE); + + compressUncompress (raw, USHRT_MAX + 1); + compressUncompressSubset (raw, USHRT_MAX + 1); + fill4 (raw, N); + compressVerify(raw, N, HUF_COMPRESS_DEK_HASH_FOR_FILL4_N); + } + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + + fill4 (raw, 0); + compressUncompress (raw, 0); // test small input data sets + fill4 (raw, 1); + compressUncompress (raw, 1); + fill4 (raw, 2); + compressUncompress (raw, 2); + fill4 (raw, 3); + compressUncompress (raw, 3); + + fill5 (raw, N); // test run-length coding of code table + if (pass==1) + { + compressVerify(raw, N, HUF_COMPRESS_DEK_HASH_FOR_FILL5_N); + } + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + + } cout << "ok\n" << endl; } From 888eb71b46ed2d40abc8594a52e296c0b11d38ad Mon Sep 17 00:00:00 2001 From: peterhillman Date: Fri, 20 Nov 2020 08:23:58 +1300 Subject: [PATCH 17/23] check 1 part files with 'nonimage' bit have type attribute (#860) Signed-off-by: Peter Hillman Co-authored-by: Cary Phillips Signed-off-by: Peter Hillman --- OpenEXR/IlmImf/ImfInputFile.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/OpenEXR/IlmImf/ImfInputFile.cpp b/OpenEXR/IlmImf/ImfInputFile.cpp index fbf9f40e26..ea70ef4e4c 100644 --- a/OpenEXR/IlmImf/ImfInputFile.cpp +++ b/OpenEXR/IlmImf/ImfInputFile.cpp @@ -456,6 +456,14 @@ InputFile::InputFile (const char fileName[], int numThreads): _data->_streamData->is = is; _data->header.readFrom (*_data->_streamData->is, _data->version); + if(isNonImage(_data->version)) + { + if(!_data->header.hasType()) + { + throw(IEX_NAMESPACE::InputExc("Non-image files must have a 'type' attribute")); + } + } + // fix type attribute in single part regular image types // (may be wrong if an old version of OpenEXR converts // a tiled image to scanline or vice versa) @@ -524,6 +532,14 @@ InputFile::InputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int numThread _data->_streamData->is = &is; _data->header.readFrom (*_data->_streamData->is, _data->version); + if(isNonImage(_data->version)) + { + if(!_data->header.hasType()) + { + throw(IEX_NAMESPACE::InputExc("Non-image files must have a 'type' attribute")); + } + } + // fix type attribute in single part regular image types // (may be wrong if an old version of OpenEXR converts // a tiled image to scanline or vice versa) From b0e080bb290cb71dbe4c0e9139eef6934912f337 Mon Sep 17 00:00:00 2001 From: peterhillman Date: Tue, 10 Nov 2020 08:35:59 +1300 Subject: [PATCH 18/23] Fix overflow computing deeptile sample table size (#861) Signed-off-by: Peter Hillman --- OpenEXR/IlmImf/ImfDeepTiledInputFile.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenEXR/IlmImf/ImfDeepTiledInputFile.cpp b/OpenEXR/IlmImf/ImfDeepTiledInputFile.cpp index 6be42cb784..c81de6cf0b 100644 --- a/OpenEXR/IlmImf/ImfDeepTiledInputFile.cpp +++ b/OpenEXR/IlmImf/ImfDeepTiledInputFile.cpp @@ -990,8 +990,8 @@ DeepTiledInputFile::initialize () for (size_t i = 0; i < _data->tileBuffers.size(); i++) _data->tileBuffers[i] = new TileBuffer (); - _data->maxSampleCountTableSize = _data->tileDesc.ySize * - _data->tileDesc.xSize * + _data->maxSampleCountTableSize = static_cast(_data->tileDesc.ySize) * + static_cast(_data->tileDesc.xSize) * sizeof(int); _data->sampleCountTableBuffer.resizeErase(_data->maxSampleCountTableSize); From 14725782636de27bef280c688cf9b59b43dabc42 Mon Sep 17 00:00:00 2001 From: peterhillman Date: Wed, 19 Aug 2020 09:53:56 +1200 Subject: [PATCH 19/23] re-order shift/compare in FastHuf to prevent undefined shift overflow warning (#819) Signed-off-by: Peter Hillman Co-authored-by: Cary Phillips Signed-off-by: Peter Hillman --- OpenEXR/IlmImf/ImfFastHuf.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/OpenEXR/IlmImf/ImfFastHuf.cpp b/OpenEXR/IlmImf/ImfFastHuf.cpp index fc67bdc6ad..97782f8051 100644 --- a/OpenEXR/IlmImf/ImfFastHuf.cpp +++ b/OpenEXR/IlmImf/ImfFastHuf.cpp @@ -538,18 +538,24 @@ FastHufDecoder::refill buffer |= bufferBack >> (64 - numBits); } - - bufferBack = bufferBack << numBits; - bufferBackNumBits -= numBits; - // - // We can have cases where the previous shift of bufferBack is << 64 - - // in which case no shift occurs. The bit count math still works though, - // so if we don't have any bits left, zero out bufferBack. + + // + // We can have cases where the previous shift of bufferBack is << 64 - + // this is an undefined operation but tends to create just zeroes. + // so if we won't have any bits left, zero out bufferBack insetad of computing the shift // - if (bufferBackNumBits == 0) + if (bufferBackNumBits <= numBits) + { bufferBack = 0; + }else + { + bufferBack = bufferBack << numBits; + } + bufferBackNumBits -= numBits; + + } // From 9bda4635f0e3c81b9a71ef1b39fbcf3a14d7e9dd Mon Sep 17 00:00:00 2001 From: peterhillman Date: Thu, 24 Sep 2020 10:34:03 +1200 Subject: [PATCH 20/23] more elegant exception handling in exrmaketiled (#841) Signed-off-by: Peter Hillman --- OpenEXR/exrmaketiled/main.cpp | 37 ++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/OpenEXR/exrmaketiled/main.cpp b/OpenEXR/exrmaketiled/main.cpp index 72568a8ae7..2d0fab9b21 100644 --- a/OpenEXR/exrmaketiled/main.cpp +++ b/OpenEXR/exrmaketiled/main.cpp @@ -393,31 +393,32 @@ main(int argc, char **argv) int exitStatus = 0; - // - // check input - // + try { - MultiPartInputFile input (inFile); - int parts = input.parts(); + // + // check input + // + { + MultiPartInputFile input (inFile); + int parts = input.parts(); - if (partnum < 0 || partnum >= parts){ - cerr << "ERROR: you asked for part " << partnum << " in " << inFile; - cerr << ", which only has " << parts << " parts\n"; - exit(1); - } + if (partnum < 0 || partnum >= parts){ + cerr << "ERROR: you asked for part " << partnum << " in " << inFile; + cerr << ", which only has " << parts << " parts\n"; + exit(1); + } + + Header h = input.header (partnum); + if (h.type() == DEEPTILE || h.type() == DEEPSCANLINE) + { + cerr << "Cannot make tile for deep data" << endl; + exit(1); + } - Header h = input.header (partnum); - if (h.type() == DEEPTILE || h.type() == DEEPSCANLINE) - { - cerr << "Cannot make tile for deep data" << endl; - exit(1); } - } - try - { makeTiled (inFile, outFile, partnum, mode, roundingMode, compression, tileSizeX, tileSizeY, From 1327e0653cd688556db565c451e8e07909e26a58 Mon Sep 17 00:00:00 2001 From: peterhillman Date: Fri, 25 Sep 2020 19:11:02 +1200 Subject: [PATCH 21/23] check EXRAllocAligned succeeded to allocate ScanlineInputFile lineBuffers (#844) Signed-off-by: Peter Hillman --- OpenEXR/IlmImf/ImfScanLineInputFile.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/OpenEXR/IlmImf/ImfScanLineInputFile.cpp b/OpenEXR/IlmImf/ImfScanLineInputFile.cpp index 1ef4eba3f4..d5d72ef79c 100644 --- a/OpenEXR/IlmImf/ImfScanLineInputFile.cpp +++ b/OpenEXR/IlmImf/ImfScanLineInputFile.cpp @@ -1145,6 +1145,10 @@ void ScanLineInputFile::initialize(const Header& header) for (size_t i = 0; i < _data->lineBuffers.size(); i++) { _data->lineBuffers[i]->buffer = (char *) EXRAllocAligned(_data->lineBufferSize*sizeof(char),16); + if (!_data->lineBuffers[i]->buffer) + { + throw IEX_NAMESPACE::LogicExc("Failed to allocate memory for scanline buffers"); + } } } _data->nextLineBufferMinY = _data->minY - 1; From e0af7a8a7708a3ab85777359a3039f59bf4d0437 Mon Sep 17 00:00:00 2001 From: peterhillman Date: Wed, 7 Oct 2020 12:09:14 +1300 Subject: [PATCH 22/23] test channels are DCT compressed before DWA decompression (#845) Signed-off-by: Peter Hillman --- OpenEXR/IlmImf/ImfDwaCompressor.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/OpenEXR/IlmImf/ImfDwaCompressor.cpp b/OpenEXR/IlmImf/ImfDwaCompressor.cpp index da2d95068b..d8c66dd27c 100644 --- a/OpenEXR/IlmImf/ImfDwaCompressor.cpp +++ b/OpenEXR/IlmImf/ImfDwaCompressor.cpp @@ -2681,6 +2681,10 @@ DwaCompressor::uncompress int gChan = _cscSets[csc].idx[1]; int bChan = _cscSets[csc].idx[2]; + if (_channelData[rChan].compression != LOSSY_DCT || _channelData[gChan].compression != LOSSY_DCT || _channelData[bChan].compression != LOSSY_DCT) + { + throw IEX_NAMESPACE::BaseExc("Bad DWA compression type detected"); + } LossyDctDecoderCsc decoder (rowPtrs[rChan], From 23170c828485a91146a156e2939687c4b479633c Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Mon, 7 Dec 2020 13:42:55 +1300 Subject: [PATCH 23/23] Merge ABI-compatible changes from #842 Signed-off-by: Peter Hillman --- OpenEXR/IlmImf/ImfDeepScanLineInputFile.cpp | 8 +++++--- OpenEXR/IlmImf/ImfInputFile.cpp | 2 +- OpenEXR/IlmImf/ImfTiledInputFile.cpp | 5 ++++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/OpenEXR/IlmImf/ImfDeepScanLineInputFile.cpp b/OpenEXR/IlmImf/ImfDeepScanLineInputFile.cpp index 0844d23495..c094fa79cc 100644 --- a/OpenEXR/IlmImf/ImfDeepScanLineInputFile.cpp +++ b/OpenEXR/IlmImf/ImfDeepScanLineInputFile.cpp @@ -721,10 +721,12 @@ LineBufferTask::execute () int width = (_ifd->maxX - _ifd->minX + 1); + ptrdiff_t base = reinterpret_cast(&_ifd->sampleCount[0][0]); + base -= sizeof(unsigned int)*_ifd->minX; + base -= sizeof(unsigned int)*static_cast(_ifd->minY) * static_cast(width); + copyIntoDeepFrameBuffer (readPtr, slice.base, - (char*) (&_ifd->sampleCount[0][0] - - _ifd->minX - - _ifd->minY * width), + reinterpret_cast(base), sizeof(unsigned int) * 1, sizeof(unsigned int) * width, y, _ifd->minX, _ifd->maxX, diff --git a/OpenEXR/IlmImf/ImfInputFile.cpp b/OpenEXR/IlmImf/ImfInputFile.cpp index ea70ef4e4c..600c7023f6 100644 --- a/OpenEXR/IlmImf/ImfInputFile.cpp +++ b/OpenEXR/IlmImf/ImfInputFile.cpp @@ -281,7 +281,7 @@ bufferedReadPixels (InputFile::Data* ifd, int scanLine1, int scanLine2) // if no channels are being read that are present in file, cachedBuffer will be empty // - if (ifd->cachedBuffer->begin() != ifd->cachedBuffer->end()) + if (ifd->cachedBuffer && ifd->cachedBuffer->begin() != ifd->cachedBuffer->end()) { ifd->tFile->readTiles (0, ifd->tFile->numXTiles (0) - 1, j, j); } diff --git a/OpenEXR/IlmImf/ImfTiledInputFile.cpp b/OpenEXR/IlmImf/ImfTiledInputFile.cpp index 3e7fda333c..091ad623a3 100644 --- a/OpenEXR/IlmImf/ImfTiledInputFile.cpp +++ b/OpenEXR/IlmImf/ImfTiledInputFile.cpp @@ -958,7 +958,10 @@ TiledInputFile::initialize () { if (!isTiled (_data->version)) throw IEX_NAMESPACE::ArgExc ("Expected a tiled file but the file is not tiled."); - + + if (isNonImage (_data->version)) + throw IEX_NAMESPACE::ArgExc ("File is not a regular tiled image."); + } else {