Coverage Report

Created: 2025-09-08 07:52

/src/LibRaw/src/decompressors/losslessjpeg.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- C++ -*-
2
 * File: huffmandec.cpp
3
 * Copyright (C) 2024 Alex Tutubalin, LibRaw LLC
4
 *
5
   Lossless JPEG decoder
6
7
   Code partially backported from DNGLab's rust code
8
   DNGLab was originally created in 2021 by Daniel Vogelbacher.
9
10
LibRaw is free software; you can redistribute it and/or modify
11
it under the terms of the one of two licenses as you choose:
12
13
1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
14
   (See file LICENSE.LGPL provided in LibRaw distribution archive for details).
15
16
2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
17
   (See file LICENSE.CDDL provided in LibRaw distribution archive for details).
18
19
 */
20
21
#include "../../internal/losslessjpeg.h"
22
#include <string.h>
23
24
0
#define ZERO(a) do { memset(a,0,sizeof(a));} while(0)
25
26
bool ByteStreamBE::skip_to_marker() // true: success, false - no marker
27
0
{
28
0
  if (pos + 2 > size) return false;
29
0
  while (!(buffer[pos] == 0xff && buffer[pos + 1] != 0 && buffer[pos + 1] != 0xff))
30
0
  {
31
0
    pos++;
32
0
    if (pos + 2 > size)
33
0
      return false;
34
0
  }
35
0
  pos++;
36
0
  return true;
37
0
}
38
39
0
LibRaw_LjpegDecompressor::LibRaw_LjpegDecompressor(uint8_t *b, unsigned bs, bool dngbug, bool csfix): buffer(b,bs),
40
0
  state(State::NotInited)
41
0
{
42
0
  initialize(dngbug,csfix);
43
0
}
44
45
0
LibRaw_LjpegDecompressor::LibRaw_LjpegDecompressor(uint8_t *b, unsigned bs): buffer(b,bs),
46
0
  state(State::NotInited)
47
0
{
48
0
  initialize(false,false);
49
0
}
50
51
52
void LibRaw_LjpegDecompressor::initialize(bool dngbug, bool csfix)
53
0
{
54
0
  sof.csfix = csfix;
55
0
  bool dht_init[4] = { false,false,false,false };
56
0
  uint32_t dht_bits[4][17];
57
0
  uint32_t dht_huffval[4][256];
58
0
  ZERO(dht_bits);
59
0
    ZERO(dht_huffval);
60
0
    if (next_marker(false) != Marker::SOI)
61
0
    {
62
0
      state = State::NoSOI;
63
0
      return;
64
0
    }
65
0
  while (1)
66
0
  {
67
0
    uint8_t marker = next_marker(true);
68
0
    if (marker == Marker::SOF3)
69
0
    {
70
0
      if (!sof.parse_sof(buffer))
71
0
      {
72
0
              state = State::InvalidSOF;
73
0
              return;
74
0
      }
75
0
      if (sof.precision > 16 || sof.precision < 12)
76
0
      {
77
0
        state = State::IncorrectPrecision;
78
0
        return;
79
0
      }
80
0
    }
81
0
        else if (marker == Marker::DHT)
82
0
        {
83
0
          bool hres = parse_dht(dht_init, dht_bits, dht_huffval);
84
0
      if(!hres)
85
0
      {
86
0
        state = State::InvalidDHT;
87
0
        return;
88
0
      }
89
0
        }
90
0
        else if ( marker == Marker::SOS)
91
0
        {
92
0
          uint32_t val = sof.parse_sos(buffer);
93
0
          if (val < 0x10000)
94
0
          {
95
0
            predictor = (val >> 8) & 0xff;
96
0
            point_transform = val & 0xff;
97
0
          }
98
0
          else
99
0
          {
100
0
            state = State::InvalidSOS;
101
0
            return;
102
0
          }
103
0
      break;
104
0
        }
105
0
    else if (marker == Marker::EOI)
106
0
    {
107
0
      state = State::EOIReached;
108
0
      return;
109
0
    }
110
0
    else if (marker == Marker::DQT)
111
0
    {
112
0
          state = State::DQTPresent;
113
0
          return;
114
0
    }
115
0
    else if(marker == Marker::Fill)
116
0
    {
117
0
          state = State::EOIReached;
118
0
          return;
119
0
    }
120
0
  }
121
122
0
  dhts.resize(4);
123
0
  for (int i = 0; i < 4; i++)
124
0
    if (dht_init[i])
125
0
      dhts[i].initval(dht_bits[i], dht_huffval[i], dngbug);
126
0
  datastart = buffer.pos;
127
0
    state = State::OK;
128
0
}
129
130
uint8_t LibRaw_LjpegDecompressor::next_marker(bool allowskip)
131
0
{
132
0
  if (!allowskip)
133
0
  {
134
0
    if (buffer.get_u8() != 0xff)
135
0
      return Marker::Fill; // Error;
136
0
    uint8_t mark = buffer.get_u8();
137
0
    return mark;
138
0
  }
139
0
  if (buffer.skip_to_marker())
140
0
    return buffer.get_u8();
141
0
  else
142
0
    return Marker::Fill;
143
0
}
144
145
bool LibRaw_LjpegDecompressor::parse_dht(bool init[4], uint32_t bits[4][17], uint32_t huffval[4][256])
146
0
{
147
0
  uint16_t length = buffer.get_u16() - 2u;
148
149
0
  while (length > 0)
150
0
  {
151
0
    uint8_t b = buffer.get_u8();
152
0
    uint8_t tc = b >> 4;
153
0
    uint8_t th = b & 0xf;
154
155
0
    if (tc != 0)
156
0
      return false;
157
158
0
    if (th > 3)
159
0
      return false;
160
161
0
    uint32_t acc = 0;
162
0
    for (int i = 0; i < 16; i++)
163
0
    {
164
0
      bits[th][i + 1] = buffer.get_u8();
165
0
      acc += bits[th][i + 1];
166
0
    }
167
0
    bits[th][0] = 0;
168
169
0
    if (acc > 256)
170
0
      return false;
171
172
0
    if (length < 1 + 16 + acc)
173
0
      return false;
174
0
  for (uint32_t i = 0; i < acc; i++)
175
0
    huffval[th][i] = buffer.get_u8();
176
177
0
    init[th] = true;
178
0
    length -= 1 + 16 + acc;
179
0
  }
180
0
  return true;
181
0
}
182
183
static
184
#ifdef _MSC_VER
185
__forceinline
186
#else
187
inline
188
#endif
189
void copy_yuv_422(uint16_t *out, uint32_t row, uint32_t col, uint32_t width, int32_t y1, int32_t y2,
190
   int32_t cb, int32_t cr)
191
0
{
192
0
  uint32_t pix1 = row * width + col;
193
0
  uint32_t pix2 = pix1 + 3;
194
0
  out[pix1 + 0] = uint16_t(y1);
195
0
  out[pix1 + 1] = uint16_t(cb);
196
0
  out[pix1 + 2] = uint16_t(cr);
197
0
  out[pix2 + 0] = uint16_t(y2);
198
0
  out[pix2 + 1] = uint16_t(cb);
199
0
  out[pix2 + 2] = uint16_t(cr);
200
0
}
201
202
203
bool LibRaw_LjpegDecompressor::decode_ljpeg_422(std::vector<uint16_t> &_dest, int width, int height)
204
0
{
205
0
  if (sof.width * 3u != unsigned(width) || sof.height != unsigned(height))
206
0
    return false;
207
0
  if (width % 2 || width % 6 || height % 2)
208
0
    return false;
209
210
0
  if (_dest.size() < size_t(width * height))
211
0
    return false;
212
213
0
  if(width < 1 || height < 1)
214
0
    return false;
215
216
0
  uint16_t *dest = _dest.data();
217
218
0
  HuffTable &h1 = dhts[sof.components[0].dc_tbl];
219
0
  HuffTable &h2 = dhts[sof.components[1].dc_tbl];
220
0
  HuffTable &h3 = dhts[sof.components[2].dc_tbl];
221
222
0
  if (!h1.initialized || !h2.initialized || !h3.initialized)
223
0
    return false;
224
225
0
  BitPumpJpeg pump(buffer);
226
227
0
  int32_t base = 1 << (sof.precision - point_transform - 1);
228
0
  int32_t y1 = base + h1.decode(pump);
229
0
  int32_t y2 = y1 + h1.decode(pump);
230
0
  int32_t cb = base + h2.decode(pump);
231
0
  int32_t cr = base + h3.decode(pump);
232
0
  copy_yuv_422(dest, 0, 0, width, y1, y2, cb, cr);
233
234
0
  for (uint32_t row = 0; row < uint32_t(height); row++)
235
0
  {
236
0
    uint32_t startcol = row == 0 ? 6 : 0;
237
0
    for (uint32_t col = startcol; col < uint32_t(width); col += 6)
238
0
    {
239
0
        uint32_t pos = (col == 0) ? (row - 1) * width : row * width + col - 3;
240
0
        int32_t py = dest[pos],
241
0
      pcb = dest[pos + 1],
242
0
      pcr = dest[pos + 2];
243
0
        int32_t _y1 = py + h1.decode(pump);
244
0
        int32_t _y2 = _y1 + h1.decode(pump);
245
0
        int32_t _cb = pcb + h2.decode(pump);
246
0
        int32_t _cr = pcr + h3.decode(pump);
247
0
        copy_yuv_422(dest, row, col, width, _y1, _y2, _cb, _cr);
248
0
    }
249
0
  }
250
0
  return true;
251
0
}
252
253
bool LibRaw_SOFInfo::parse_sof(ByteStreamBE& input)
254
0
{
255
0
  uint32_t header_length = input.get_u16();
256
0
  precision = input.get_u8();
257
0
    height = input.get_u16();
258
0
  width = input.get_u16();
259
0
  cps = input.get_u8();
260
261
0
  if (precision > 16)
262
0
    return false;
263
0
  if (cps > 4 || cps < 1)
264
0
    return false;
265
0
  if (header_length != 8 + cps * 3)
266
0
    return false;
267
268
0
  components.clear();
269
0
  for (unsigned i = 0; i < cps; i++)
270
0
  {
271
0
      unsigned id = input.get_u8();
272
0
    unsigned subs = input.get_u8();
273
0
    components.push_back(LibRaw_JpegComponentInfo(id, i, 0, (subs >> 4), (subs & 0xf) ));
274
0
      input.get_u8(); 
275
0
  }
276
0
  return true;
277
0
}
278
279
uint32_t LibRaw_SOFInfo::parse_sos(ByteStreamBE& input)
280
0
{
281
0
  if (width == 0)
282
0
    return 0x10000;
283
284
0
  input.get_u16();
285
286
0
  uint32_t soscps = input.get_u8();
287
0
  if (cps != soscps)
288
0
    return 0x10000;
289
0
  for (uint32_t csi = 0; csi < cps; csi++)
290
0
  {
291
0
    uint32_t readcs = input.get_u8();
292
0
  uint32_t cs = csfix ? csi : readcs; // csfix might be used in MOS decoder
293
0
  int cid = -1;
294
0
  for(unsigned c = 0; c < components.size(); c++)
295
0
    if (components[c].id == cs)
296
0
    {
297
0
      cid = c;
298
0
      break;
299
0
    }
300
0
  if (cid < 0)
301
0
    return 0x10000;
302
303
0
    uint8_t td = input.get_u8() >> 4;
304
0
  if (td > 3)
305
0
    return 0x10000;
306
0
  components[cid].dc_tbl = td;
307
0
  }
308
0
  uint8_t pred = input.get_u8();
309
0
  input.get_u8();
310
0
  uint8_t pt = input.get_u8() & 0xf;
311
0
  return (pred << 8 | pt);
312
0
}
313
314
HuffTable::HuffTable()
315
0
{
316
0
  ZERO(bits);
317
0
  ZERO(huffval);
318
0
  ZERO(shiftval);
319
0
  dng_bug = false;
320
0
  disable_cache = false;
321
0
  nbits = 0;
322
0
  initialized = false;
323
0
}
324
325
struct PseudoPump : public BitPump
326
{
327
  uint64_t bits;
328
  int32_t nbits;
329
0
  PseudoPump() : bits(0), nbits(0) {}
330
331
  void set(uint32_t _bits, uint32_t nb)
332
0
  {
333
0
    bits = uint64_t(_bits) << 32;
334
0
    nbits = nb + 32;
335
0
  }
336
0
  int32_t valid() { return nbits - 32; }
337
338
  uint32_t peek(uint32_t num)
339
0
  {
340
0
    return uint32_t((bits >> (nbits - num)) & 0xffffffffUL);
341
0
  }
342
343
    void consume(uint32_t num)
344
0
    {
345
0
      nbits -= num;
346
0
      bits &= (uint64_t(1) << nbits) - 1UL;
347
0
    }
348
};
349
350
void HuffTable::initval(uint32_t _bits[17], uint32_t _huffval[256], bool _dng_bug)
351
0
{
352
0
  memmove(bits, _bits, sizeof(bits));
353
0
  memmove(huffval, _huffval, sizeof(huffval));
354
0
  dng_bug = _dng_bug;
355
356
0
  nbits = 16;
357
0
    for(int i = 0; i < 16; i++)
358
0
      {
359
0
        if(bits[16 - i] != 0)
360
0
      break;
361
0
    nbits--;
362
0
      }
363
0
  hufftable.resize( size_t(1ULL << nbits));
364
0
  for (unsigned i = 0; i < hufftable.size(); i++) hufftable[i] = 0;
365
366
0
  int h = 0;
367
0
    int pos = 0;
368
0
    for (uint8_t len = 0; len < nbits; len++)
369
0
    {
370
0
      for (uint32_t i = 0; i < bits[len + 1]; i++)
371
0
      {
372
0
        for (int j = 0; j < (1 << (nbits - len - 1)); j++)
373
0
        {
374
0
          hufftable[h] = ((len+1) << 16) | (uint8_t(huffval[pos] & 0xff) << 8) | uint8_t(shiftval[pos] & 0xff);
375
0
          h++;
376
0
        }
377
0
        pos++;
378
0
      }
379
0
    }
380
0
  if (!disable_cache)
381
0
  {
382
0
    PseudoPump pump;
383
0
    decodecache = std::vector<uint64_t>(1 << LIBRAW_DECODE_CACHE_BITS,0);
384
0
    for(uint32_t i = 0; i < 1 << LIBRAW_DECODE_CACHE_BITS; i++)
385
0
    {
386
0
          pump.set(i, LIBRAW_DECODE_CACHE_BITS);
387
0
      uint32_t len;
388
0
      int16_t val16 = int16_t(decode_slow2(pump,len));
389
0
      if (pump.valid() >= 0)
390
0
        decodecache[i] = LIBRAW_CACHE_PRESENT_FLAG | uint64_t(((len & 0xff) << 16) | uint16_t(val16));
391
0
    }
392
0
  }
393
0
    initialized = true;
394
0
}