Skip to content

Commit 9798506

Browse files
committed
PanasonicV8Decompressor: sink getDecoderLUT() back into decompressor
1 parent 21fa8ef commit 9798506

File tree

4 files changed

+99
-108
lines changed

4 files changed

+99
-108
lines changed

fuzz/librawspeed/decompressors/PanasonicV8Decompressor.cpp

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,14 @@ 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 numDecoderLUTEntries = bs.getU32();
80+
uint32_t numDefineCodesSize = 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 decoderLUTEntriesInput =
88-
bs.getStream(numDecoderLUTEntries, 2 * sizeof(uint8_t));
87+
auto defineCodes = bs.getStream(numDefineCodesSize);
8988
const auto initialPrediction = bs.getArray<uint16_t, 4>();
9089

9190
// The rest of the bs are the input strips.
@@ -118,21 +117,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
118117
PanasonicV8Decompressor::DecompressorParamsBuilder builder(
119118
imgDim, initialPrediction, getAsArray1DRef(strips),
120119
getAsArray1DRef(stripLineOffsets), getAsArray1DRef(stripWidths),
121-
getAsArray1DRef(stripHeights));
120+
getAsArray1DRef(stripHeights), defineCodes);
122121

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>();
128-
129-
decoderLUT.emplace_back(PanasonicV8Decompressor::DecoderLUTEntry{
130-
.bitcount = bitcount, .diffCat = diffCat});
131-
}
132-
invariant(decoderLUTEntriesInput.getRemainSize() == 0);
133-
134-
PanasonicV8Decompressor v8(mRaw, builder.getDecompressorParams(),
135-
getAsArray1DRef(decoderLUT));
122+
PanasonicV8Decompressor v8(mRaw, builder.getDecompressorParams());
136123
mRaw->createData();
137124
v8.decompress();
138125
MSan::CheckMemIsInitialized(mRaw->getByteDataAsUncroppedArray2DRef());

src/librawspeed/decoders/Rw2Decoder.cpp

Lines changed: 3 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323
#include "adt/Array1DRef.h"
2424
#include "adt/Array1DRefExtras.h"
2525
#include "adt/Array2DRef.h"
26-
#include "adt/Bit.h"
27-
#include "adt/Casts.h"
2826
#include "adt/Point.h"
2927
#include "bitstreams/BitStreams.h"
3028
#include "common/BayerPhase.h"
@@ -182,64 +180,6 @@ DecompressorV8Params::DecompressorV8Params(const TiffIFD& ifd) {
182180
validate();
183181
}
184182

185-
std::vector<PanasonicV8Decompressor::DecoderLUTEntry>
186-
populateDecoderLUT(const TiffIFD& ifd) {
187-
std::vector<PanasonicV8Decompressor::DecoderLUTEntry> mDecoderLUT;
188-
189-
ByteStream stream = ifd.getEntry(TiffTag::PANASONIC_V8_HUF_TABLE)->getData();
190-
191-
const auto numSymbols = stream.getU16();
192-
if (numSymbols < 1 || numSymbols > 17)
193-
ThrowRDE("Unexpected number of symbols: %u", numSymbols);
194-
195-
struct Entry {
196-
uint8_t bitcount;
197-
uint16_t symbol, mask;
198-
uint8_t codeValue;
199-
};
200-
std::vector<Entry> table;
201-
table.reserve(numSymbols);
202-
203-
for (unsigned symbolIndex = 0; symbolIndex != numSymbols; ++symbolIndex) {
204-
const auto len = stream.getU16(); // Number of bits in symbol
205-
if (len < 1 || len > 16)
206-
ThrowRDE("Unexpected symbol length");
207-
const auto code = stream.getU16();
208-
if (!isIntN<uint32_t>(code, len))
209-
ThrowRDE("Bad symbol code");
210-
Entry entry;
211-
entry.bitcount = implicit_cast<uint8_t>(len);
212-
entry.symbol = uint16_t(code << (16U - entry.bitcount));
213-
entry.codeValue = implicit_cast<uint8_t>(symbolIndex);
214-
entry.mask = uint16_t(
215-
0xffffU << (16U -
216-
entry.bitcount)); // mask of the bits overlapping symbol
217-
if (entry.bitcount == PanasonicV8Decompressor::DecoderLUTEntry().bitcount &&
218-
entry.codeValue == PanasonicV8Decompressor::DecoderLUTEntry().diffCat)
219-
ThrowRDE("Sentinel symbol encountered");
220-
table.emplace_back(entry);
221-
}
222-
assert(table.size() == numSymbols);
223-
224-
// Cache of decoding results for all possible 16-bit values.
225-
mDecoderLUT.resize(1 + UINT16_MAX);
226-
227-
// Populates LUT by checking for a bitwise match between each value and the
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) {
232-
if ((uint16_t(li) & ti.mask) == ti.symbol) {
233-
lutVal.bitcount = ti.bitcount;
234-
lutVal.diffCat = ti.codeValue;
235-
break; // NOTE: not a prefix code!
236-
}
237-
}
238-
}
239-
240-
return mDecoderLUT;
241-
}
242-
243183
/// Maybe the most complicated part of the entire file format, and seemingly,
244184
/// completely unused.
245185
void populateGammaLUT(const DecompressorV8Params& mParams, const TiffIFD& ifd) {
@@ -306,8 +246,6 @@ RawImage Rw2Decoder::decodeRawV8(const TiffIFD& raw) const {
306246
ThrowRDE("Unexpected CFA, only RGGB is supported");
307247

308248
const DecompressorV8Params mParams(raw);
309-
const std::vector<PanasonicV8Decompressor::DecoderLUTEntry> mDecoderLUT =
310-
populateDecoderLUT(raw);
311249
populateGammaLUT(mParams, raw);
312250
const std::vector<Array1DRef<const uint8_t>> mStrips =
313251
getInputStrips(mParams, mFile);
@@ -318,10 +256,10 @@ RawImage Rw2Decoder::decodeRawV8(const TiffIFD& raw) const {
318256
imgDim, mParams.initialPrediction, getAsArray1DRef(mStrips),
319257
getAsArray1DRef(mParams.stripLineOffsets),
320258
getAsArray1DRef(mParams.stripWidths),
321-
getAsArray1DRef(mParams.stripHeights));
259+
getAsArray1DRef(mParams.stripHeights),
260+
raw.getEntry(TiffTag::PANASONIC_V8_HUF_TABLE)->getData());
322261

323-
PanasonicV8Decompressor v8(mRaw, b.getDecompressorParams(),
324-
getAsArray1DRef(mDecoderLUT));
262+
PanasonicV8Decompressor v8(mRaw, b.getDecompressorParams());
325263
mRaw->createData();
326264
v8.decompress();
327265
return mRaw;

src/librawspeed/decompressors/PanasonicV8Decompressor.cpp

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
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"
@@ -39,9 +41,11 @@
3941
#include "common/RawImage.h"
4042
#include "common/RawspeedException.h"
4143
#include "decoders/RawDecoderException.h"
44+
#include "io/ByteStream.h"
4245
#include "io/IOException.h"
4346
#include <algorithm>
4447
#include <array>
48+
#include <cassert>
4549
#include <climits>
4650
#include <cstddef>
4751
#include <cstdint>
@@ -218,6 +222,63 @@ int minBitsPerPixelNeeded(
218222

219223
} // namespace
220224

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+
221282
std::vector<iRectangle2D>
222283
PanasonicV8Decompressor::DecompressorParamsBuilder::getOutRects(
223284
iRectangle2D imgDim, Array1DRef<const uint32_t> stripLineOffsets,
@@ -256,19 +317,17 @@ PanasonicV8Decompressor::DecompressorParamsBuilder::getOutRects(
256317

257318
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
258319

259-
PanasonicV8Decompressor::PanasonicV8Decompressor(
260-
RawImage outputImg, DecompressorParams mParams_,
261-
Array1DRef<const DecoderLUTEntry> mHDecoderLUT_)
262-
: mRawOutput(std::move(outputImg)), mParams(std::move(mParams_)),
263-
mDecoderLUT(mHDecoderLUT_) {
320+
PanasonicV8Decompressor::PanasonicV8Decompressor(RawImage outputImg,
321+
DecompressorParams mParams_)
322+
: mRawOutput(std::move(outputImg)), mParams(std::move(mParams_)) {
264323
if (mRawOutput->getCpp() != 1 ||
265324
mRawOutput->getDataType() != RawImageType::UINT16 ||
266325
mRawOutput->getBpp() != sizeof(uint16_t)) {
267326
ThrowRDE("Unexpected component count / data type");
268327
}
269328
if (!mRawOutput->dim.hasPositiveArea())
270329
ThrowRDE("Unexpected image dimensions");
271-
const auto minBpp = minBitsPerPixelNeeded(mDecoderLUT);
330+
const auto minBpp = minBitsPerPixelNeeded(mParams.mDecoderLUT);
272331
for (int stripIdx = 0; stripIdx < mParams.mStrips.size(); ++stripIdx) {
273332
const auto strip = mParams.mStrips(stripIdx);
274333
const auto maxPixelsInStrip = (uint64_t{CHAR_BIT} * strip.size()) / minBpp;
@@ -300,7 +359,7 @@ void PanasonicV8Decompressor::decompress() const {
300359
/*croppedHeight=*/outRect.dim.y)
301360
.getAsArray2DRef();
302361

303-
InternalDecoder decoder(mDecoderLUT, strip);
362+
InternalDecoder decoder(mParams.mDecoderLUT, strip);
304363

305364
decompressStrip(out, decoder);
306365
} catch (const RawspeedException& err) {

src/librawspeed/decompressors/PanasonicV8Decompressor.h

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "common/RawImage.h"
3030
#include "decoders/RawDecoderException.h"
3131
#include "decompressors/AbstractDecompressor.h"
32+
#include "io/ByteStream.h"
3233
#include <array>
3334
#include <cstdint>
3435
#include <vector>
@@ -52,14 +53,25 @@ class PanasonicV8Decompressor final : public AbstractDecompressor {
5253
/// Four values, one for each component of the sensor's color filter array.
5354
using Bayer2x2 = std::array<uint16_t, 4>;
5455

56+
// Pre-cached decoded values for rapid lookup.
57+
struct DecoderLUTEntry {
58+
uint8_t bitcount = 7;
59+
uint8_t diffCat = 0;
60+
61+
[[nodiscard]] bool isSentinel() const {
62+
constexpr auto sentinel = DecoderLUTEntry();
63+
return bitcount == sentinel.bitcount && diffCat == sentinel.diffCat;
64+
}
65+
};
66+
5567
/// Decompressor parameters populated from tags. They remain constant after
5668
/// construction.
5769
struct DecompressorParamsBuilder;
5870

5971
struct DecompressorParams {
6072
const Array1DRef<const Array1DRef<const uint8_t>> mStrips;
6173
const Array1DRef<const iRectangle2D> mOutRect;
62-
74+
const Array1DRef<const DecoderLUTEntry> mDecoderLUT;
6375
const Bayer2x2 initialPrediction;
6476

6577
DecompressorParams() = delete;
@@ -69,29 +81,36 @@ class PanasonicV8Decompressor final : public AbstractDecompressor {
6981

7082
DecompressorParams(Array1DRef<const Array1DRef<const uint8_t>> mStrips_,
7183
Array1DRef<const iRectangle2D> mOutRect_,
84+
Array1DRef<const DecoderLUTEntry> mDecoderLUT_,
7285
Bayer2x2 initialPrediction_)
73-
: mStrips(mStrips_), mOutRect(mOutRect_),
86+
: mStrips(mStrips_), mOutRect(mOutRect_), mDecoderLUT(mDecoderLUT_),
7487
initialPrediction(initialPrediction_) {}
7588
};
7689

7790
struct DecompressorParamsBuilder {
91+
const std::vector<PanasonicV8Decompressor::DecoderLUTEntry> mDecoderLUT;
7892
const Array1DRef<const Array1DRef<const uint8_t>> mStrips;
7993
const Bayer2x2 initialPrediction;
8094

8195
const std::vector<iRectangle2D> mOutRects;
8296

97+
std::vector<PanasonicV8Decompressor::DecoderLUTEntry> static getDecoderLUT(
98+
ByteStream bs);
99+
83100
std::vector<iRectangle2D> static getOutRects(
84101
iRectangle2D imgDim, Array1DRef<const uint32_t> stripLineOffsets,
85102
Array1DRef<const uint16_t> stripWidths,
86103
Array1DRef<const uint16_t> stripHeights);
87104

105+
// NOLINTNEXTLINE(readability-function-size)
88106
DecompressorParamsBuilder(
89107
iRectangle2D imgDim, Bayer2x2 initialPrediction_,
90108
Array1DRef<const Array1DRef<const uint8_t>> mStrips_,
91109
Array1DRef<const uint32_t> stripLineOffsets,
92110
Array1DRef<const uint16_t> stripWidths,
93-
Array1DRef<const uint16_t> stripHeights)
94-
: mStrips(mStrips_), initialPrediction(initialPrediction_),
111+
Array1DRef<const uint16_t> stripHeights, ByteStream defineCodes)
112+
: mDecoderLUT(getDecoderLUT(defineCodes)), mStrips(mStrips_),
113+
initialPrediction(initialPrediction_),
95114
mOutRects(getOutRects(imgDim, stripLineOffsets, stripWidths,
96115
stripHeights)) {
97116
if (mStrips.size() != implicit_cast<int>(mOutRects.size()))
@@ -103,24 +122,13 @@ class PanasonicV8Decompressor final : public AbstractDecompressor {
103122
}
104123

105124
[[nodiscard]] DecompressorParams getDecompressorParams() const {
106-
return {mStrips, getAsArray1DRef(mOutRects), initialPrediction};
107-
}
108-
};
109-
110-
// Pre-cached decoded values for rapid lookup.
111-
struct DecoderLUTEntry {
112-
uint8_t bitcount = 7;
113-
uint8_t diffCat = 0;
114-
115-
[[nodiscard]] bool isSentinel() const {
116-
constexpr auto sentinel = DecoderLUTEntry();
117-
return bitcount == sentinel.bitcount && diffCat == sentinel.diffCat;
125+
return {mStrips, getAsArray1DRef(mOutRects), getAsArray1DRef(mDecoderLUT),
126+
initialPrediction};
118127
}
119128
};
120129

121130
private:
122131
const DecompressorParams mParams;
123-
const Array1DRef<const DecoderLUTEntry> mDecoderLUT;
124132

125133
/// Decoder helper class. Defined only in the cpp file.
126134
class InternalDecoder;
@@ -130,8 +138,7 @@ class PanasonicV8Decompressor final : public AbstractDecompressor {
130138
void decompressStrip(Array2DRef<uint16_t> out, InternalDecoder decoder) const;
131139

132140
public:
133-
PanasonicV8Decompressor(RawImage outputImg, DecompressorParams mParams_,
134-
Array1DRef<const DecoderLUTEntry> mDecoderLUT_);
141+
PanasonicV8Decompressor(RawImage outputImg, DecompressorParams mParams_);
135142

136143
/// Run the decompressor on the provided raw image
137144
void decompress() const;

0 commit comments

Comments
 (0)