Coverage Report

Created: 2025-06-16 07:00

/src/libraw/internal/losslessjpeg.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- C++ -*-
2
 * File: huffmandec.h
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
#pragma  once
21
#include <stdint.h>
22
#include <vector>
23
24
struct BitPump // generic bit source
25
{
26
  virtual uint32_t peek(uint32_t num) = 0;
27
  virtual void consume(uint32_t num) = 0;
28
29
  uint32_t get(uint32_t num)
30
0
  {
31
0
    if(num == 0) { return 0u; }
32
0
    uint32_t val = peek(num);
33
0
    consume(num);
34
0
  return val;
35
0
  }
36
};
37
38
struct ByteStreamBE // Jpeg is always big endian
39
{
40
  enum Exceptions
41
  {
42
    OK = 0,
43
    EndOfBuffer = 1
44
  };
45
46
  uint8_t *buffer;
47
  unsigned size, pos;
48
0
  ByteStreamBE(uint8_t *b, unsigned s) : buffer(b), size(s), pos(0) {}
49
0
  ByteStreamBE() : buffer(0),size(0),pos(0){}
50
  bool skip_to_marker();
51
52
  uint8_t get_u8()
53
0
  {
54
0
    if (pos >= size)
55
0
      throw EndOfBuffer;
56
0
    uint8_t ret = buffer[pos];
57
0
    pos++;
58
0
    return ret;
59
0
  }
60
  uint16_t get_u16()
61
0
  {
62
0
    if (pos + 2 > size)
63
0
      throw EndOfBuffer;
64
0
    uint8_t r1 = buffer[pos];
65
0
    uint8_t r2 = buffer[pos + 1];
66
0
    pos += 2;
67
0
    return (r1 << 8) | r2;
68
0
  }
69
};
70
71
struct BitPumpJpeg : public BitPump
72
{
73
  uint8_t *buffer;
74
  unsigned size, pos;
75
  uint64_t bits;
76
  uint32_t nbits;
77
  bool finished;
78
79
  void consume(uint32_t num)
80
0
  {
81
0
    if (num <= nbits)
82
0
    {
83
0
      nbits -= num;
84
0
      bits &= (uint64_t(1) << nbits) - 1UL;
85
0
    }
86
0
  }
87
    uint32_t peek(uint32_t num)
88
0
    {
89
0
    if (num > nbits && !finished)
90
0
    {
91
0
      if ((size >= 4) && pos < size && buffer[pos] != 0xff && buffer[pos + 1] != 0xff && buffer[pos + 2] != 0xff &&
92
0
        buffer[pos + 3] != 0xff)
93
0
      {
94
0
        uint64_t inbits = (uint32_t(buffer[pos]) << 24) | (uint32_t(buffer[pos + 1]) << 16) |
95
0
          (uint32_t(buffer[pos + 2]) << 8) | (uint32_t(buffer[pos + 3]));
96
0
        bits = (bits << 32) | inbits;
97
0
        pos += 4;
98
0
        nbits += 32;
99
0
      }
100
0
      else
101
0
      {
102
0
        int read_bytes = 0;
103
0
        while (read_bytes < 4 && !finished)
104
0
        {
105
0
          uint8_t byte = 0;
106
0
          if (pos >= size)
107
0
            finished = true;
108
0
          else
109
0
          {
110
0
            uint8_t nextbyte = buffer[pos];
111
0
            if (nextbyte != 0xff)
112
0
              byte = nextbyte;
113
0
            else if (buffer[pos + 1] == 0x00)
114
0
            {
115
0
              pos += 1;
116
0
              byte = nextbyte;
117
0
            }
118
0
            else
119
0
              finished = true;
120
0
          };
121
0
          bits = (bits << 8) | uint64_t(byte);
122
0
          pos += 1;
123
0
          nbits += 8;
124
0
          read_bytes += 1;
125
0
        }
126
0
      }
127
0
    }
128
0
    if(num > nbits && finished)
129
0
        {
130
0
          bits <<= 32;
131
0
          nbits += 32;
132
0
        }
133
0
    return uint32_t(bits >> (nbits - num));
134
0
    }
135
136
0
  BitPumpJpeg(ByteStreamBE& s): buffer(s.buffer+s.pos),size(s.size-s.pos),pos(0),bits(0),nbits(0),finished(false){}
137
};
138
139
140
const uint32_t LIBRAW_DECODE_CACHE_BITS = 13;
141
const uint64_t LIBRAW_CACHE_PRESENT_FLAG = 0x100000000L;
142
143
struct HuffTable
144
{
145
  uint32_t bits[17];
146
  uint32_t huffval[256];
147
  uint32_t shiftval[256];
148
  bool dng_bug;
149
  bool disable_cache;
150
  uint32_t nbits;
151
    std::vector<uint32_t> hufftable; // len:8 << 16| huffval:8  << 8 | shift:8
152
  std::vector<uint64_t> decodecache;
153
  bool initialized;
154
  HuffTable();
155
  void initval(uint32_t bits[17], uint32_t huffval[256], bool dng_bug);
156
157
  int32_t decode(BitPump& pump)
158
0
    {
159
0
      uint64_t cached = disable_cache ? 0 : decodecache[pump.peek(LIBRAW_DECODE_CACHE_BITS)];
160
0
      if (cached & LIBRAW_CACHE_PRESENT_FLAG)
161
0
      {
162
0
        uint32_t _bits = (cached >> 16) & 0xff;
163
0
        int16_t val = int16_t(cached & 0xffff);
164
0
        if (val == -32768 && dng_bug)
165
0
        {
166
0
          if (_bits > 16)
167
0
            pump.consume(_bits - 16);
168
0
        }
169
0
        else
170
0
          pump.consume(_bits);
171
0
        return val;
172
0
      }
173
0
      else
174
0
        return decode_slow1(pump);
175
0
    }
176
177
  int32_t decode_slow1(BitPump &pump)
178
0
    {
179
0
      int32_t _diff = diff(pump, len(pump));
180
0
      return _diff;
181
0
    }
182
183
    int32_t decode_slow2(BitPump & pump, uint32_t& outlen) // output:  (len+shift):8, code:16
184
0
    {
185
0
      uint32_t _len = len(pump);
186
0
      int32_t _diff = diff(pump, _len);
187
0
      uint8_t bits8 = (_len >> 16) & 0xff;
188
0
      uint8_t len8 = (_len >> 8) & 0xff;
189
0
      outlen = bits8 + len8;
190
0
      return _diff;
191
0
    }
192
193
    uint32_t len(BitPump & pump) //bits:8, len:8, shift:8
194
0
    {
195
0
      uint32_t code = pump.peek(nbits);
196
0
      uint32_t huffdata = hufftable[code];
197
0
      uint32_t _bits = (huffdata >> 16) & 0xff;
198
0
      pump.consume(_bits);
199
0
      return huffdata;
200
0
    }
201
202
    int32_t diff(BitPump & pump, uint32_t hentry) // input: bits:8, len:8, shift:8; output:  diff:i32
203
0
    {
204
0
      uint32_t len = (hentry >> 8) & 0xff;
205
0
      if (len == 0)
206
0
        return 0;
207
0
      if (len == 16)
208
0
      {
209
0
        if (dng_bug)
210
0
          pump.get(16);
211
0
        return -32768;
212
0
      }
213
0
      uint32_t shift = hentry & 0xff;
214
0
    uint32_t fulllen = len + shift;
215
0
      uint32_t _bits = pump.get(len);
216
0
      int32_t diff = ((_bits << 1) + 1) << shift >> 1;
217
0
      if ((diff & (1 << (fulllen - 1))) == 0)
218
0
      {
219
0
        diff -= int32_t((1 << fulllen) - ((shift == 0)));
220
0
      }
221
0
      return diff;
222
0
    }
223
};
224
225
struct LibRaw_JpegComponentInfo
226
{
227
  unsigned id;
228
  unsigned index;
229
  unsigned dc_tbl;
230
  unsigned subsample_h, subsample_v;
231
0
  LibRaw_JpegComponentInfo() : id(0), index(0), dc_tbl(0), subsample_h(0), subsample_v(0) {};
232
  LibRaw_JpegComponentInfo(unsigned _id, unsigned _index, unsigned _dcn, unsigned _sh, unsigned _sv)
233
0
    : id(_id), index(_index), dc_tbl(_dcn), subsample_h(_sh), subsample_v(_sv){};
234
0
  LibRaw_JpegComponentInfo(const LibRaw_JpegComponentInfo& q): id(q.id), index(q.index), dc_tbl(q.dc_tbl),
235
0
      subsample_h(q.subsample_h),subsample_v(q.subsample_v){}
236
};
237
238
struct LibRaw_SOFInfo
239
{
240
  unsigned width, height;
241
  unsigned cps, precision;
242
  std::vector<LibRaw_JpegComponentInfo> components;
243
  bool csfix;
244
0
  LibRaw_SOFInfo(): width(0),height(0),cps(0),precision(0),csfix(false){}
245
  bool parse_sof(ByteStreamBE&); // true => OK, false => not OK
246
  uint32_t parse_sos(ByteStreamBE&); // returns (predictor << 8 | point transform); if above 0xffff => error
247
};
248
249
struct LibRaw_LjpegDecompressor 
250
{
251
  ByteStreamBE buffer;
252
  LibRaw_SOFInfo sof;
253
  uint32_t predictor, point_transform;
254
  uint32_t datastart;
255
  std::vector<HuffTable> dhts;
256
  LibRaw_LjpegDecompressor(uint8_t *b, unsigned s);
257
  LibRaw_LjpegDecompressor(uint8_t *b, unsigned bs, bool dngbug, bool csfix);
258
  void  initialize(bool dngbug, bool csfix);
259
    uint8_t next_marker(bool allowskip);
260
  bool  parse_dht(bool init[4], uint32_t dht_bits[4][17], uint32_t dht_huffval[4][256]); // return true on OK;
261
  bool decode_ljpeg_422(std::vector<uint16_t> &dest, int width, int height);
262
263
  struct State {
264
      enum States
265
      {
266
        OK = 0,
267
    NotInited = 1,
268
    NoSOI = 2,
269
    IncorrectPrecision = 3,
270
    EOIReached = 4,
271
    InvalidDHT = 5,
272
    InvalidSOF = 6,
273
        InvalidSOS = 7,
274
    DQTPresent = 8
275
      };
276
277
  };
278
  struct Marker {
279
    enum Markers {
280
      Stuff = 0x00,
281
      SOF3 = 0xc3, // lossless
282
      DHT = 0xc4,  // huffman tables
283
      SOI = 0xd8,  // start of image
284
      EOI = 0xd9,  // end of image
285
      SOS = 0xda,  // start of scan
286
      DQT = 0xdb,  // quantization tables
287
      Fill = 0xff,
288
    };
289
  };
290
  enum State::States state;
291
};
292