Skip to content

Commit 71518e8

Browse files
committed
PanasonicV8Decompressor: these aren't Huffman codes, not even Prefix codes
1 parent 4db68ef commit 71518e8

File tree

4 files changed

+55
-58
lines changed

4 files changed

+55
-58
lines changed

fuzz/librawspeed/decompressors/PanasonicV8Decompressor.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,15 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
7777
uint32_t numStripLineOffsets = bs.getU32();
7878
uint32_t numStripWidths = bs.getU32();
7979
uint32_t numStripHeights = bs.getU32();
80-
uint32_t numHuffmanLUTEntries = bs.getU32();
80+
uint32_t numDecoderLUTEntries = bs.getU32();
8181

8282
auto stripSizes = bs.getStream(numStrips, sizeof(uint32_t));
8383
auto stripLineOffsetsInput =
8484
bs.getStream(numStripLineOffsets, sizeof(uint32_t));
8585
auto stripWidthsInput = bs.getStream(numStripWidths, sizeof(uint16_t));
8686
auto stripHeightsInput = bs.getStream(numStripHeights, sizeof(uint16_t));
87-
auto huffmanLUTEntriesInput =
88-
bs.getStream(numHuffmanLUTEntries, 2 * sizeof(uint8_t));
87+
auto decoderLUTEntriesInput =
88+
bs.getStream(numDecoderLUTEntries, 2 * sizeof(uint8_t));
8989
const auto initialPrediction = bs.getArray<uint16_t, 4>();
9090

9191
// The rest of the bs are the input strips.
@@ -120,19 +120,19 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
120120
getAsArray1DRef(stripLineOffsets), getAsArray1DRef(stripWidths),
121121
getAsArray1DRef(stripHeights));
122122

123-
std::vector<PanasonicV8Decompressor::HuffmanLUTEntry> huffmanLUT;
124-
huffmanLUT.reserve(std::max(1U, numHuffmanLUTEntries));
125-
for (uint32_t entryIdx = 0; entryIdx < numHuffmanLUTEntries; ++entryIdx) {
126-
const auto bitcount = huffmanLUTEntriesInput.get<uint8_t>();
127-
const auto diffCat = huffmanLUTEntriesInput.get<uint8_t>();
123+
std::vector<PanasonicV8Decompressor::DecoderLUTEntry> decoderLUT;
124+
decoderLUT.reserve(std::max(1U, numDecoderLUTEntries));
125+
for (uint32_t entryIdx = 0; entryIdx < numDecoderLUTEntries; ++entryIdx) {
126+
const auto bitcount = decoderLUTEntriesInput.get<uint8_t>();
127+
const auto diffCat = decoderLUTEntriesInput.get<uint8_t>();
128128

129-
huffmanLUT.emplace_back(PanasonicV8Decompressor::HuffmanLUTEntry{
129+
decoderLUT.emplace_back(PanasonicV8Decompressor::DecoderLUTEntry{
130130
.bitcount = bitcount, .diffCat = diffCat});
131131
}
132-
invariant(huffmanLUTEntriesInput.getRemainSize() == 0);
132+
invariant(decoderLUTEntriesInput.getRemainSize() == 0);
133133

134134
PanasonicV8Decompressor v8(mRaw, builder.getDecompressorParams(),
135-
getAsArray1DRef(huffmanLUT));
135+
getAsArray1DRef(decoderLUT));
136136
mRaw->createData();
137137
v8.decompress();
138138
MSan::CheckMemIsInitialized(mRaw->getByteDataAsUncroppedArray2DRef());

src/librawspeed/decoders/Rw2Decoder.cpp

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ struct DecompressorV8Params {
9999

100100
PanasonicV8Decompressor::Bayer2x2 initialPrediction;
101101

102-
/// Huffman decoding shift down value. Appears to be unused.
103-
std::vector<uint16_t> huffShiftDown;
102+
/// Decoding shift down value. Appears to be unused.
103+
std::vector<uint16_t> shiftDown;
104104

105105
uint16_t gammaClipVal;
106106

@@ -131,7 +131,7 @@ void DecompressorV8Params::validate() const {
131131
ThrowRDE("Strip bit length list does not have enough entries for the "
132132
"number of strips!");
133133

134-
if (std::any_of(huffShiftDown.begin(), huffShiftDown.end(),
134+
if (std::any_of(shiftDown.begin(), shiftDown.end(),
135135
[](uint16_t x) { return x != 0; })) {
136136
ThrowRDE("Non-zero shift down value encountered! Shift down decoding has "
137137
"never been tested!");
@@ -174,32 +174,31 @@ DecompressorV8Params::DecompressorV8Params(const TiffIFD& ifd) {
174174
initialPrediction[3] =
175175
ifd.getEntry(TiffTag::PANASONIC_V8_INIT_PRED_BLUE)->getU16();
176176

177-
getPanasonicTiffVector(ifd, TiffTag::PANASONIC_V8_HUF_SHIFT_DOWN,
178-
huffShiftDown);
177+
getPanasonicTiffVector(ifd, TiffTag::PANASONIC_V8_HUF_SHIFT_DOWN, shiftDown);
179178

180179
gammaClipVal = ifd.getEntry(TiffTag::PANASONIC_V8_CLIP_VAL)->getU16();
181180
// NOLINTEND(cppcoreguidelines-prefer-member-initializer)
182181

183182
validate();
184183
}
185184

186-
std::vector<PanasonicV8Decompressor::HuffmanLUTEntry>
187-
populateHuffmanLUT(const TiffIFD& ifd) {
188-
std::vector<PanasonicV8Decompressor::HuffmanLUTEntry> mHuffmanLUT;
185+
std::vector<PanasonicV8Decompressor::DecoderLUTEntry>
186+
populateDecoderLUT(const TiffIFD& ifd) {
187+
std::vector<PanasonicV8Decompressor::DecoderLUTEntry> mDecoderLUT;
189188

190189
ByteStream stream = ifd.getEntry(TiffTag::PANASONIC_V8_HUF_TABLE)->getData();
191190

192191
const auto numSymbols = stream.getU16();
193192
if (numSymbols < 1 || numSymbols > 17)
194193
ThrowRDE("Unexpected number of symbols: %u", numSymbols);
195194

196-
struct HuffEntry {
195+
struct Entry {
197196
uint8_t bitcount;
198197
uint16_t symbol, mask;
199198
uint8_t codeValue;
200199
};
201-
std::vector<HuffEntry> huffTable;
202-
huffTable.reserve(numSymbols);
200+
std::vector<Entry> table;
201+
table.reserve(numSymbols);
203202

204203
for (unsigned symbolIndex = 0; symbolIndex != numSymbols; ++symbolIndex) {
205204
const auto len = stream.getU16(); // Number of bits in symbol
@@ -208,28 +207,28 @@ populateHuffmanLUT(const TiffIFD& ifd) {
208207
const auto code = stream.getU16();
209208
if (!isIntN<uint32_t>(code, len))
210209
ThrowRDE("Bad symbol code");
211-
HuffEntry entry;
210+
Entry entry;
212211
entry.bitcount = implicit_cast<uint8_t>(len);
213212
entry.symbol = uint16_t(code << (16U - entry.bitcount));
214213
entry.codeValue = implicit_cast<uint8_t>(symbolIndex);
215214
entry.mask = uint16_t(
216215
0xffffU << (16U -
217216
entry.bitcount)); // mask of the bits overlapping symbol
218-
if (entry.bitcount == PanasonicV8Decompressor::HuffmanLUTEntry().bitcount &&
219-
entry.codeValue == PanasonicV8Decompressor::HuffmanLUTEntry().diffCat)
217+
if (entry.bitcount == PanasonicV8Decompressor::DecoderLUTEntry().bitcount &&
218+
entry.codeValue == PanasonicV8Decompressor::DecoderLUTEntry().diffCat)
220219
ThrowRDE("Sentinel symbol encountered");
221-
huffTable.emplace_back(entry);
220+
table.emplace_back(entry);
222221
}
223222
assert(table.size() == numSymbols);
224223

225-
// Cache of Huffman table results for all possible 16-bit values.
226-
mHuffmanLUT.resize(1 + UINT16_MAX);
224+
// Cache of decoding results for all possible 16-bit values.
225+
mDecoderLUT.resize(1 + UINT16_MAX);
227226

228227
// Populates LUT by checking for a bitwise match between each value and the
229-
// prefix codes recorded in the table.
230-
for (unsigned li = 0; li < mHuffmanLUT.size(); ++li) {
231-
PanasonicV8Decompressor::HuffmanLUTEntry& lutVal = mHuffmanLUT[li];
232-
for (const auto& ti : huffTable) {
228+
// codes recorded in the table.
229+
for (unsigned li = 0; li < mDecoderLUT.size(); ++li) {
230+
PanasonicV8Decompressor::DecoderLUTEntry& lutVal = mDecoderLUT[li];
231+
for (const auto& ti : table) {
233232
if ((uint16_t(li) & ti.mask) == ti.symbol) {
234233
lutVal.bitcount = ti.bitcount;
235234
lutVal.diffCat = ti.codeValue;
@@ -238,7 +237,7 @@ populateHuffmanLUT(const TiffIFD& ifd) {
238237
}
239238
}
240239

241-
return mHuffmanLUT;
240+
return mDecoderLUT;
242241
}
243242

244243
/// Maybe the most complicated part of the entire file format, and seemingly,
@@ -307,8 +306,8 @@ RawImage Rw2Decoder::decodeRawV8(const TiffIFD& raw) const {
307306
ThrowRDE("Unexpected CFA, only RGGB is supported");
308307

309308
const DecompressorV8Params mParams(raw);
310-
const std::vector<PanasonicV8Decompressor::HuffmanLUTEntry> mHuffmanLUT =
311-
populateHuffmanLUT(raw);
309+
const std::vector<PanasonicV8Decompressor::DecoderLUTEntry> mDecoderLUT =
310+
populateDecoderLUT(raw);
312311
populateGammaLUT(mParams, raw);
313312
const std::vector<Array1DRef<const uint8_t>> mStrips =
314313
getInputStrips(mParams, mFile);
@@ -322,7 +321,7 @@ RawImage Rw2Decoder::decodeRawV8(const TiffIFD& raw) const {
322321
getAsArray1DRef(mParams.stripHeights));
323322

324323
PanasonicV8Decompressor v8(mRaw, b.getDecompressorParams(),
325-
getAsArray1DRef(mHuffmanLUT));
324+
getAsArray1DRef(mDecoderLUT));
326325
mRaw->createData();
327326
v8.decompress();
328327
return mRaw;

src/librawspeed/decompressors/PanasonicV8Decompressor.cpp

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -130,15 +130,15 @@ class BitStreamerRevMSB final
130130
};
131131

132132
/// Utility class for Panasonic V8 entropy decoding
133-
class PanasonicV8Decompressor::InternalHuffDecoder {
133+
class PanasonicV8Decompressor::InternalDecoder {
134134
private:
135-
const Array1DRef<const HuffmanLUTEntry>
136-
mLUT; // Reference to PanasonicV8Decompressor::mHuffmanLUT
135+
// Reference to PanasonicV8Decompressor::mDecoderLUT
136+
const Array1DRef<const DecoderLUTEntry> mLUT;
137137
BitStreamerRevMSB mBitPump;
138138

139139
public:
140-
InternalHuffDecoder(const Array1DRef<const HuffmanLUTEntry>& LUT,
141-
Array1DRef<const uint8_t> bitStream)
140+
InternalDecoder(const Array1DRef<const DecoderLUTEntry>& LUT,
141+
Array1DRef<const uint8_t> bitStream)
142142
: mLUT(LUT), mBitPump(bitStream) {}
143143

144144
int32_t decodeNextDiffValue();
@@ -238,9 +238,9 @@ PanasonicV8Decompressor::DecompressorParamsBuilder::getOutRects(
238238

239239
PanasonicV8Decompressor::PanasonicV8Decompressor(
240240
RawImage outputImg, DecompressorParams mParams_,
241-
Array1DRef<const HuffmanLUTEntry> mHuffmanLUT_)
241+
Array1DRef<const DecoderLUTEntry> mHDecoderLUT_)
242242
: mRawOutput(std::move(outputImg)), mParams(std::move(mParams_)),
243-
mHuffmanLUT(mHuffmanLUT_) {
243+
mDecoderLUT(mHDecoderLUT_) {
244244
if (mRawOutput->getCpp() != 1 ||
245245
mRawOutput->getDataType() != RawImageType::UINT16 ||
246246
mRawOutput->getBpp() != sizeof(uint16_t)) {
@@ -272,7 +272,7 @@ void PanasonicV8Decompressor::decompress() const {
272272
/*croppedHeight=*/outRect.dim.y)
273273
.getAsArray2DRef();
274274

275-
InternalHuffDecoder decoder(mHuffmanLUT, strip);
275+
InternalDecoder decoder(mDecoderLUT, strip);
276276

277277
decompressStrip(out, decoder);
278278
} catch (const RawspeedException& err) {
@@ -285,8 +285,8 @@ void PanasonicV8Decompressor::decompress() const {
285285
}
286286
}
287287

288-
void PanasonicV8Decompressor::decompressStrip(
289-
const Array2DRef<uint16_t> out, InternalHuffDecoder decoder) const {
288+
void PanasonicV8Decompressor::decompressStrip(const Array2DRef<uint16_t> out,
289+
InternalDecoder decoder) const {
290290
Bayer2x2 predictedStorage = mParams.initialPrediction;
291291
const auto pred = Array2DRef(predictedStorage.data(), 2, 2);
292292

@@ -337,14 +337,13 @@ void PanasonicV8Decompressor::decompressStrip(
337337
}
338338
}
339339

340-
int32_t inline PanasonicV8Decompressor::InternalHuffDecoder::
341-
decodeNextDiffValue() {
340+
int32_t inline PanasonicV8Decompressor::InternalDecoder::decodeNextDiffValue() {
342341
// Retrieve the difference category, which indicates magnitude of the
343342
// difference between the predicted and actual value.
344343
const auto next16 = uint16_t(mBitPump.peekBits(16));
345344
const auto& [codeLen, codeValue] = mLUT(next16);
346345
if (codeValue == 0 && codeLen == 7)
347-
ThrowRDE("Huffman decoding encountered an invalid value!");
346+
ThrowRDE("Decoding encountered an invalid value!");
348347
mBitPump.skipBits(
349348
codeLen); // Skip the bits that encoded the difference category
350349
int diffLen = codeValue;

src/librawspeed/decompressors/PanasonicV8Decompressor.h

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ namespace rawspeed {
4141
/// Each raw file is broken up into a number of separate strips, each of which
4242
/// was separately encoded, and which can be decoded independently. For each
4343
/// strip, an initial predicted value is provided. The strip's data buffer is
44-
/// then decoded using the Huffman table provided in metadata. Each value
44+
/// then decoded using the decoding table provided in metadata. Each value
4545
/// decoded from the strip is a difference between the predicted value and
4646
/// actual value, allowing the actual value to be reconstructed.
4747
class PanasonicV8Decompressor final : public AbstractDecompressor {
@@ -107,27 +107,26 @@ class PanasonicV8Decompressor final : public AbstractDecompressor {
107107
}
108108
};
109109

110-
// Pre-cached Huffman decoded values for rapid lookup.
111-
struct HuffmanLUTEntry {
110+
// Pre-cached decoded values for rapid lookup.
111+
struct DecoderLUTEntry {
112112
uint8_t bitcount = 7;
113113
uint8_t diffCat = 0;
114114
};
115115

116116
private:
117117
const DecompressorParams mParams;
118-
const Array1DRef<const HuffmanLUTEntry> mHuffmanLUT;
118+
const Array1DRef<const DecoderLUTEntry> mDecoderLUT;
119119

120-
/// Huffman decoder helper class. Defined only in the cpp file.
121-
class InternalHuffDecoder;
120+
/// Decoder helper class. Defined only in the cpp file.
121+
class InternalDecoder;
122122

123123
/// Thread safe function for decompressing a single data-stripstrip within a
124124
/// Rw2V8 raw image.
125-
void decompressStrip(Array2DRef<uint16_t> out,
126-
InternalHuffDecoder decoder) const;
125+
void decompressStrip(Array2DRef<uint16_t> out, InternalDecoder decoder) const;
127126

128127
public:
129128
PanasonicV8Decompressor(RawImage outputImg, DecompressorParams mParams_,
130-
Array1DRef<const HuffmanLUTEntry> mHuffmanLUT_);
129+
Array1DRef<const DecoderLUTEntry> mDecoderLUT_);
131130

132131
/// Run the decompressor on the provided raw image
133132
void decompress() const;

0 commit comments

Comments
 (0)