|
29 | 29 | #include "adt/Casts.h" |
30 | 30 | #include "adt/CroppedArray2DRef.h" |
31 | 31 | #include "adt/Invariant.h" |
| 32 | +#include "adt/Optional.h" |
32 | 33 | #include "adt/Point.h" |
33 | 34 | #include "adt/TiledArray2DRef.h" |
34 | 35 | #include "bitstreams/BitStream.h" |
@@ -202,22 +203,37 @@ void isValidImageGrid(iRectangle2D imgDim, |
202 | 203 | ThrowRDE("Tiles do not cover whole output image"); |
203 | 204 | } |
204 | 205 |
|
205 | | -int minBitsPerPixelNeeded( |
206 | | - Array1DRef<const PanasonicV8Decompressor::DecoderLUTEntry> mDecoderLUT) { |
| 206 | +template <typename T> |
| 207 | +int bitsPerPixelNeeded( |
| 208 | + Array1DRef<const PanasonicV8Decompressor::DecoderLUTEntry> mDecoderLUT, |
| 209 | + T cb) { |
207 | 210 | invariant(mDecoderLUT.size() > 0); |
208 | 211 | const auto r = std::accumulate( |
209 | | - mDecoderLUT.begin(), mDecoderLUT.end(), std::numeric_limits<int>::max(), |
210 | | - [](int init, const PanasonicV8Decompressor::DecoderLUTEntry& e) { |
| 212 | + mDecoderLUT.begin(), mDecoderLUT.end(), Optional<int>(), |
| 213 | + [cb](auto init, const PanasonicV8Decompressor::DecoderLUTEntry& e) { |
211 | 214 | if (e.isSentinel()) |
212 | 215 | return init; |
213 | 216 | invariant(e.bitcount > 0); |
214 | 217 | const auto total = e.bitcount + e.diffCat; |
215 | 218 | invariant(total > 0); |
216 | | - return std::min(init, total); |
| 219 | + init = init.has_value() ? cb(*init, total) : total; |
| 220 | + return init; |
217 | 221 | }); |
218 | | - invariant(r > 0); |
219 | | - invariant(r <= (16 + 17)); |
220 | | - return r; |
| 222 | + const auto bit = *r; |
| 223 | + invariant(bit > 0); |
| 224 | + return bit; |
| 225 | +} |
| 226 | + |
| 227 | +int minBitsPerPixelNeeded( |
| 228 | + Array1DRef<const PanasonicV8Decompressor::DecoderLUTEntry> mDecoderLUT) { |
| 229 | + return bitsPerPixelNeeded(mDecoderLUT, |
| 230 | + [](auto a, auto b) { return std::min(a, b); }); |
| 231 | +} |
| 232 | + |
| 233 | +int maxBitsPerPixelNeeded( |
| 234 | + Array1DRef<const PanasonicV8Decompressor::DecoderLUTEntry> mDecoderLUT) { |
| 235 | + return bitsPerPixelNeeded(mDecoderLUT, |
| 236 | + [](auto a, auto b) { return std::max(a, b); }); |
221 | 237 | } |
222 | 238 |
|
223 | 239 | } // namespace |
@@ -327,6 +343,10 @@ PanasonicV8Decompressor::PanasonicV8Decompressor(RawImage outputImg, |
327 | 343 | } |
328 | 344 | if (!mRawOutput->dim.hasPositiveArea()) |
329 | 345 | ThrowRDE("Unexpected image dimensions"); |
| 346 | + const auto maxBpp = maxBitsPerPixelNeeded(mParams.mDecoderLUT); |
| 347 | + if (maxBpp > 32) { |
| 348 | + ThrowRDE("Single pixel decode may consume more than 32 bits"); |
| 349 | + } |
330 | 350 | const auto minBpp = minBitsPerPixelNeeded(mParams.mDecoderLUT); |
331 | 351 | for (int stripIdx = 0; stripIdx < mParams.mStrips.size(); ++stripIdx) { |
332 | 352 | const auto strip = mParams.mStrips(stripIdx); |
@@ -427,19 +447,20 @@ void PanasonicV8Decompressor::decompressStrip(const Array2DRef<uint16_t> out, |
427 | 447 | int32_t inline PanasonicV8Decompressor::InternalDecoder::decodeNextDiffValue() { |
428 | 448 | // Retrieve the difference category, which indicates magnitude of the |
429 | 449 | // difference between the predicted and actual value. |
430 | | - const auto next16 = uint16_t(mBitPump.peekBits(16)); |
| 450 | + mBitPump.fill(32); |
| 451 | + const auto next16 = uint16_t(mBitPump.peekBitsNoFill(16)); |
431 | 452 | invariant(mLUT.size() == 1 + UINT16_MAX); |
432 | 453 | const auto& [codeLen, codeValue] = mLUT(next16); |
433 | 454 | if (codeValue == 0 && codeLen == 7) |
434 | 455 | ThrowRDE("Decoding encountered an invalid value!"); |
435 | | - mBitPump.skipBits( |
436 | | - codeLen); // Skip the bits that encoded the difference category |
| 456 | + // Skip the bits that encoded the difference category |
| 457 | + mBitPump.skipBitsNoFill(codeLen); |
437 | 458 | int diffLen = codeValue; |
438 | 459 |
|
439 | 460 | if (diffLen == 0) |
440 | 461 | return 0; |
441 | 462 |
|
442 | | - const uint32_t diff = mBitPump.getBits(diffLen); |
| 463 | + const uint32_t diff = mBitPump.getBitsNoFill(diffLen); |
443 | 464 | return AbstractPrefixCodeDecoder<BaselineCodeTag>::extend(diff, diffLen); |
444 | 465 | } |
445 | 466 |
|
|
0 commit comments