2525#include " adt/Array1DRef.h"
2626#include " adt/Array1DRefExtras.h"
2727#include " adt/Array2DRef.h"
28+ #include " adt/Bit.h"
29+ #include " adt/Casts.h"
2830#include " adt/CroppedArray2DRef.h"
2931#include " adt/Invariant.h"
3032#include " adt/Point.h"
3335#include " bitstreams/BitStreamer.h"
3436#include " bitstreams/BitStreamerMSB.h" // IWYU pragma: keep
3537#include " bitstreams/BitStreams.h"
38+ #include " codes/AbstractPrefixCode.h"
39+ #include " codes/AbstractPrefixCodeDecoder.h"
3640#include " common/Common.h"
3741#include " common/RawImage.h"
3842#include " common/RawspeedException.h"
3943#include " decoders/RawDecoderException.h"
44+ #include " io/ByteStream.h"
4045#include " io/IOException.h"
4146#include < algorithm>
4247#include < array>
48+ #include < cassert>
49+ #include < climits>
4350#include < cstddef>
4451#include < cstdint>
4552#include < limits>
53+ #include < numeric>
4654#include < utility>
4755#include < vector>
4856
@@ -128,15 +136,15 @@ class BitStreamerRevMSB final
128136};
129137
130138// / Utility class for Panasonic V8 entropy decoding
131- class PanasonicV8Decompressor ::InternalHuffDecoder {
139+ class PanasonicV8Decompressor ::InternalDecoder {
132140private:
133- const Array1DRef< const HuffmanLUTEntry>
134- mLUT ; // Reference to PanasonicV8Decompressor::mHuffmanLUT
141+ // Reference to PanasonicV8Decompressor::mDecoderLUT
142+ const Array1DRef< const DecoderLUTEntry> mLUT ;
135143 BitStreamerRevMSB mBitPump ;
136144
137145public:
138- InternalHuffDecoder (const Array1DRef<const HuffmanLUTEntry >& LUT,
139- Array1DRef<const uint8_t > bitStream)
146+ InternalDecoder (const Array1DRef<const DecoderLUTEntry >& LUT,
147+ Array1DRef<const uint8_t > bitStream)
140148 : mLUT (LUT), mBitPump (bitStream) {}
141149
142150 int32_t decodeNextDiffValue ();
@@ -194,8 +202,83 @@ void isValidImageGrid(iRectangle2D imgDim,
194202 ThrowRDE (" Tiles do not cover whole output image" );
195203}
196204
205+ int minBitsPerPixelNeeded (
206+ Array1DRef<const PanasonicV8Decompressor::DecoderLUTEntry> mDecoderLUT ) {
207+ invariant (mDecoderLUT .size () > 0 );
208+ const auto r = std::accumulate (
209+ mDecoderLUT .begin (), mDecoderLUT .end (), std::numeric_limits<int >::max (),
210+ [](int init, const PanasonicV8Decompressor::DecoderLUTEntry& e) {
211+ if (e.isSentinel ())
212+ return init;
213+ invariant (e.bitcount > 0 );
214+ const auto total = e.bitcount + e.diffCat ;
215+ invariant (total > 0 );
216+ return std::min (init, total);
217+ });
218+ invariant (r > 0 );
219+ invariant (r <= (16 + 17 ));
220+ return r;
221+ }
222+
197223} // namespace
198224
225+ std::vector<PanasonicV8Decompressor::DecoderLUTEntry>
226+ PanasonicV8Decompressor::DecompressorParamsBuilder::getDecoderLUT (
227+ ByteStream stream) {
228+ std::vector<PanasonicV8Decompressor::DecoderLUTEntry> mDecoderLUT ;
229+
230+ const auto numSymbols = stream.getU16 ();
231+ if (numSymbols < 1 || numSymbols > 17 )
232+ ThrowRDE (" Unexpected number of symbols: %u" , numSymbols);
233+
234+ struct Entry {
235+ uint8_t bitcount;
236+ uint16_t symbol, mask;
237+ uint8_t codeValue;
238+ };
239+ std::vector<Entry> table;
240+ table.reserve (numSymbols);
241+
242+ for (unsigned symbolIndex = 0 ; symbolIndex != numSymbols; ++symbolIndex) {
243+ const auto len = stream.getU16 (); // Number of bits in symbol
244+ if (len < 1 || len > 16 )
245+ ThrowRDE (" Unexpected symbol length" );
246+ const auto code = stream.getU16 ();
247+ if (!isIntN<uint32_t >(code, len))
248+ ThrowRDE (" Bad symbol code" );
249+ Entry entry;
250+ entry.bitcount = implicit_cast<uint8_t >(len);
251+ entry.symbol = uint16_t (code << (16U - entry.bitcount ));
252+ entry.codeValue = implicit_cast<uint8_t >(symbolIndex);
253+ entry.mask = uint16_t (
254+ 0xffffU << (16U -
255+ entry.bitcount )); // mask of the bits overlapping symbol
256+ if (entry.bitcount == PanasonicV8Decompressor::DecoderLUTEntry ().bitcount &&
257+ entry.codeValue == PanasonicV8Decompressor::DecoderLUTEntry ().diffCat )
258+ ThrowRDE (" Sentinel symbol encountered" );
259+ table.emplace_back (entry);
260+ }
261+ assert (table.size () == numSymbols);
262+
263+ // Cache of decoding results for all possible 16-bit values.
264+ mDecoderLUT .resize (1 + UINT16_MAX);
265+
266+ // Populates LUT by checking for a bitwise match between each value and the
267+ // codes recorded in the table.
268+ for (unsigned li = 0 ; li < mDecoderLUT .size (); ++li) {
269+ PanasonicV8Decompressor::DecoderLUTEntry& lutVal = mDecoderLUT [li];
270+ for (const auto & ti : table) {
271+ if ((uint16_t (li) & ti.mask ) == ti.symbol ) {
272+ lutVal.bitcount = ti.bitcount ;
273+ lutVal.diffCat = ti.codeValue ;
274+ break ; // NOTE: not a prefix code!
275+ }
276+ }
277+ }
278+
279+ return mDecoderLUT ;
280+ }
281+
199282std::vector<iRectangle2D>
200283PanasonicV8Decompressor::DecompressorParamsBuilder::getOutRects (
201284 iRectangle2D imgDim, Array1DRef<const uint32_t > stripLineOffsets,
@@ -234,18 +317,24 @@ PanasonicV8Decompressor::DecompressorParamsBuilder::getOutRects(
234317
235318// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
236319
237- PanasonicV8Decompressor::PanasonicV8Decompressor (
238- RawImage outputImg, DecompressorParams mParams_ ,
239- Array1DRef<const HuffmanLUTEntry> mHuffmanLUT_ )
240- : mRawOutput (std::move(outputImg)), mParams (std::move(mParams_ )),
241- mHuffmanLUT (mHuffmanLUT_ ) {
320+ PanasonicV8Decompressor::PanasonicV8Decompressor (RawImage outputImg,
321+ DecompressorParams mParams_ )
322+ : mRawOutput (std::move(outputImg)), mParams (std::move(mParams_ )) {
242323 if (mRawOutput ->getCpp () != 1 ||
243324 mRawOutput ->getDataType () != RawImageType::UINT16 ||
244325 mRawOutput ->getBpp () != sizeof (uint16_t )) {
245326 ThrowRDE (" Unexpected component count / data type" );
246327 }
247328 if (!mRawOutput ->dim .hasPositiveArea ())
248329 ThrowRDE (" Unexpected image dimensions" );
330+ const auto minBpp = minBitsPerPixelNeeded (mParams .mDecoderLUT );
331+ for (int stripIdx = 0 ; stripIdx < mParams .mStrips .size (); ++stripIdx) {
332+ const auto strip = mParams .mStrips (stripIdx);
333+ const auto maxPixelsInStrip = (uint64_t {CHAR_BIT} * strip.size ()) / minBpp;
334+ const auto outRect = mParams .mOutRect (stripIdx);
335+ if (outRect.dim .area () > maxPixelsInStrip)
336+ ThrowRDE (" Input strip is unsufficient to produce requested tile" );
337+ }
249338}
250339
251340void PanasonicV8Decompressor::decompress () const {
@@ -270,7 +359,7 @@ void PanasonicV8Decompressor::decompress() const {
270359 /* croppedHeight=*/ outRect.dim .y )
271360 .getAsArray2DRef ();
272361
273- InternalHuffDecoder decoder (mHuffmanLUT , strip);
362+ InternalDecoder decoder (mParams . mDecoderLUT , strip);
274363
275364 decompressStrip (out, decoder);
276365 } catch (const RawspeedException& err) {
@@ -283,8 +372,8 @@ void PanasonicV8Decompressor::decompress() const {
283372 }
284373}
285374
286- void PanasonicV8Decompressor::decompressStrip (
287- const Array2DRef< uint16_t > out, InternalHuffDecoder decoder) const {
375+ void PanasonicV8Decompressor::decompressStrip (const Array2DRef< uint16_t > out,
376+ InternalDecoder decoder) const {
288377 Bayer2x2 predictedStorage = mParams .initialPrediction ;
289378 const auto pred = Array2DRef (predictedStorage.data (), 2 , 2 );
290379
@@ -335,35 +424,23 @@ void PanasonicV8Decompressor::decompressStrip(
335424 }
336425}
337426
338- int32_t inline PanasonicV8Decompressor::InternalHuffDecoder::
339- decodeNextDiffValue () {
427+ int32_t inline PanasonicV8Decompressor::InternalDecoder::decodeNextDiffValue () {
340428 // Retrieve the difference category, which indicates magnitude of the
341429 // difference between the predicted and actual value.
342430 const auto next16 = uint16_t (mBitPump .peekBits (16 ));
343- const auto & [bits, diffCat] = mLUT (next16);
344- if (diffCat == 0 && bits == 7 )
345- ThrowRDE (" Huffman decoding encountered an invalid value!" );
346- mBitPump .skipBits (bits); // Skip the bits that encoded the difference category
347-
348- if (diffCat > 0 ) {
349- // Decode difference value. The scheme here encodes signed integers in a
350- // manner similar to offset binary encoding. Here, the encoding is biased by
351- // the difference category such that abs(diff) is in the range
352- // [2^{diffCat-1}, 2^{diffCat}).
353- const uint32_t rawDiffBits = mBitPump .getBits (diffCat);
354- const uint32_t sign = rawDiffBits >> (diffCat - 1 );
355- const uint32_t val = rawDiffBits << 0 ;
356-
357- // In comments below, n = diffCat
358- if (sign == 1 )
359- // Positive value in range [2^{n-1}, 2^{n})
360- return val;
361- // Negative value in interval (-2^{n}, -2^{n-1}]
362- return static_cast <int32_t >(val) + static_cast <int32_t >(~0U << diffCat) + 1 ;
363- }
364- // diffBitCount of zero indicates no difference (next pixel is same as
365- // predicted)
366- return 0 ;
431+ invariant (mLUT .size () == 1 + UINT16_MAX);
432+ const auto & [codeLen, codeValue] = mLUT (next16);
433+ if (codeValue == 0 && codeLen == 7 )
434+ ThrowRDE (" Decoding encountered an invalid value!" );
435+ mBitPump .skipBits (
436+ codeLen); // Skip the bits that encoded the difference category
437+ int diffLen = codeValue;
438+
439+ if (diffLen == 0 )
440+ return 0 ;
441+
442+ const uint32_t diff = mBitPump .getBits (diffLen);
443+ return AbstractPrefixCodeDecoder<BaselineCodeTag>::extend (diff, diffLen);
367444}
368445
369446} // namespace rawspeed
0 commit comments