Coverage Report

Created: 2025-06-22 08:04

/src/libjxl/lib/jxl/icc_codec_common.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) the JPEG XL Project Authors. All rights reserved.
2
//
3
// Use of this source code is governed by a BSD-style
4
// license that can be found in the LICENSE file.
5
6
#include "lib/jxl/icc_codec_common.h"
7
8
#include <cstdint>
9
#include <tuple>
10
11
#include "lib/jxl/base/byte_order.h"
12
#include "lib/jxl/base/status.h"
13
#include "lib/jxl/padded_bytes.h"
14
15
namespace jxl {
16
namespace {
17
24.4M
uint8_t ByteKind1(uint8_t b) {
18
24.4M
  if ('a' <= b && b <= 'z') return 0;
19
22.5M
  if ('A' <= b && b <= 'Z') return 0;
20
21.2M
  if ('0' <= b && b <= '9') return 1;
21
20.6M
  if (b == '.' || b == ',') return 1;
22
20.5M
  if (b == 0) return 2;
23
10.6M
  if (b == 1) return 3;
24
8.66M
  if (b < 16) return 4;
25
7.08M
  if (b == 255) return 6;
26
6.61M
  if (b > 240) return 5;
27
6.14M
  return 7;
28
6.61M
}
29
30
24.4M
uint8_t ByteKind2(uint8_t b) {
31
24.4M
  if ('a' <= b && b <= 'z') return 0;
32
22.5M
  if ('A' <= b && b <= 'Z') return 0;
33
21.2M
  if ('0' <= b && b <= '9') return 1;
34
20.6M
  if (b == '.' || b == ',') return 1;
35
20.5M
  if (b < 16) return 2;
36
7.08M
  if (b > 240) return 3;
37
6.14M
  return 4;
38
7.08M
}
39
40
template <typename T>
41
20.5k
T PredictValue(T p1, T p2, T p3, int order) {
42
20.5k
  if (order == 0) return p1;
43
10.3k
  if (order == 1) return 2 * p1 - p2;
44
4.46k
  if (order == 2) return 3 * p1 - 3 * p2 + p3;
45
0
  return 0;
46
4.46k
}
icc_codec_common.cc:unsigned char jxl::(anonymous namespace)::PredictValue<unsigned char>(unsigned char, unsigned char, unsigned char, int)
Line
Count
Source
41
6.03k
T PredictValue(T p1, T p2, T p3, int order) {
42
6.03k
  if (order == 0) return p1;
43
4.75k
  if (order == 1) return 2 * p1 - p2;
44
1.36k
  if (order == 2) return 3 * p1 - 3 * p2 + p3;
45
0
  return 0;
46
1.36k
}
icc_codec_common.cc:unsigned short jxl::(anonymous namespace)::PredictValue<unsigned short>(unsigned short, unsigned short, unsigned short, int)
Line
Count
Source
41
7.82k
T PredictValue(T p1, T p2, T p3, int order) {
42
7.82k
  if (order == 0) return p1;
43
2.44k
  if (order == 1) return 2 * p1 - p2;
44
1.82k
  if (order == 2) return 3 * p1 - 3 * p2 + p3;
45
0
  return 0;
46
1.82k
}
icc_codec_common.cc:unsigned int jxl::(anonymous namespace)::PredictValue<unsigned int>(unsigned int, unsigned int, unsigned int, int)
Line
Count
Source
41
6.65k
T PredictValue(T p1, T p2, T p3, int order) {
42
6.65k
  if (order == 0) return p1;
43
3.16k
  if (order == 1) return 2 * p1 - p2;
44
1.28k
  if (order == 2) return 3 * p1 - 3 * p2 + p3;
45
0
  return 0;
46
1.28k
}
47
}  // namespace
48
49
19.9k
uint32_t DecodeUint32(const uint8_t* data, size_t size, size_t pos) {
50
19.9k
  return pos + 4 > size ? 0 : LoadBE32(data + pos);
51
19.9k
}
52
53
164k
Status AppendUint32(uint32_t value, PaddedBytes* data) {
54
164k
  size_t pos = data->size();
55
164k
  JXL_RETURN_IF_ERROR(data->resize(pos + 4));
56
164k
  StoreBE32(value, data->data() + pos);
57
164k
  return true;
58
164k
}
59
60
typedef std::array<uint8_t, 4> Tag;
61
62
3.86k
Tag DecodeKeyword(const uint8_t* data, size_t size, size_t pos) {
63
3.86k
  if (pos + 4 > size) return {{' ', ' ', ' ', ' '}};
64
3.86k
  return {{data[pos], data[pos + 1], data[pos + 2], data[pos + 3]}};
65
3.86k
}
66
67
0
void EncodeKeyword(const Tag& keyword, uint8_t* data, size_t size, size_t pos) {
68
0
  if (keyword.size() != 4 || pos + 3 >= size) return;
69
0
  for (size_t i = 0; i < 4; ++i) data[pos + i] = keyword[i];
70
0
}
71
72
137k
Status AppendKeyword(const Tag& keyword, PaddedBytes* data) {
73
137k
  static_assert(std::tuple_size<Tag>{} == 4);
74
137k
  return data->append(keyword);
75
137k
}
76
77
// Checks if a + b > size, taking possible integer overflow into account.
78
91.3k
Status CheckOutOfBounds(uint64_t a, uint64_t b, uint64_t size) {
79
91.3k
  uint64_t pos = a + b;
80
91.3k
  if (pos > size) return JXL_FAILURE("Out of bounds");
81
91.2k
  if (pos < a) return JXL_FAILURE("Out of bounds");  // overflow happened
82
91.2k
  return true;
83
91.2k
}
84
85
216k
Status CheckIs32Bit(uint64_t v) {
86
216k
  static constexpr const uint64_t kUpper32 = ~static_cast<uint64_t>(0xFFFFFFFF);
87
216k
  if ((v & kUpper32) != 0) return JXL_FAILURE("32-bit value expected");
88
216k
  return true;
89
216k
}
90
91
const std::array<uint8_t, kICCHeaderSize> kIccInitialHeaderPrediction = {
92
    0,   0,   0,   0,   0,   0,   0,   0,   4, 0, 0, 0, 'm', 'n', 't', 'r',
93
    'R', 'G', 'B', ' ', 'X', 'Y', 'Z', ' ', 0, 0, 0, 0, 0,   0,   0,   0,
94
    0,   0,   0,   0,   'a', 'c', 's', 'p', 0, 0, 0, 0, 0,   0,   0,   0,
95
    0,   0,   0,   0,   0,   0,   0,   0,   0, 0, 0, 0, 0,   0,   0,   0,
96
    0,   0,   0,   0,   0,   0,   246, 214, 0, 1, 0, 0, 0,   0,   211, 45,
97
    0,   0,   0,   0,   0,   0,   0,   0,   0, 0, 0, 0, 0,   0,   0,   0,
98
    0,   0,   0,   0,   0,   0,   0,   0,   0, 0, 0, 0, 0,   0,   0,   0,
99
    0,   0,   0,   0,   0,   0,   0,   0,   0, 0, 0, 0, 0,   0,   0,   0,
100
};
101
102
6.37k
std::array<uint8_t, kICCHeaderSize> ICCInitialHeaderPrediction(uint32_t size) {
103
6.37k
  std::array<uint8_t, kICCHeaderSize> copy(kIccInitialHeaderPrediction);
104
6.37k
  StoreBE32(size, copy.data());
105
6.37k
  return copy;
106
6.37k
}
107
108
void ICCPredictHeader(const uint8_t* icc, size_t size, uint8_t* header,
109
791k
                      size_t pos) {
110
791k
  if (pos == 8 && size >= 8) {
111
6.20k
    header[80] = icc[4];
112
6.20k
    header[81] = icc[5];
113
6.20k
    header[82] = icc[6];
114
6.20k
    header[83] = icc[7];
115
6.20k
  }
116
791k
  if (pos == 41 && size >= 41) {
117
6.19k
    if (icc[40] == 'A') {
118
3.09k
      header[41] = 'P';
119
3.09k
      header[42] = 'P';
120
3.09k
      header[43] = 'L';
121
3.09k
    }
122
6.19k
    if (icc[40] == 'M') {
123
1.20k
      header[41] = 'S';
124
1.20k
      header[42] = 'F';
125
1.20k
      header[43] = 'T';
126
1.20k
    }
127
6.19k
  }
128
791k
  if (pos == 42 && size >= 42) {
129
6.19k
    if (icc[40] == 'S' && icc[41] == 'G') {
130
6
      header[42] = 'I';
131
6
      header[43] = ' ';
132
6
    }
133
6.19k
    if (icc[40] == 'S' && icc[41] == 'U') {
134
6
      header[42] = 'N';
135
6
      header[43] = 'W';
136
6
    }
137
6.19k
  }
138
791k
}
139
140
// Predicts a value with linear prediction of given order (0-2), for integers
141
// with width bytes and given stride in bytes between values.
142
// The start position is at start + i, and the relevant modulus of i describes
143
// which byte of the multi-byte integer is being handled.
144
// The value start + i must be at least stride * 4.
145
uint8_t LinearPredictICCValue(const uint8_t* data, size_t start, size_t i,
146
20.5k
                              size_t stride, size_t width, int order) {
147
20.5k
  size_t pos = start + i;
148
20.5k
  if (width == 1) {
149
6.03k
    uint8_t p1 = data[pos - stride];
150
6.03k
    uint8_t p2 = data[pos - stride * 2];
151
6.03k
    uint8_t p3 = data[pos - stride * 3];
152
6.03k
    return PredictValue(p1, p2, p3, order);
153
14.4k
  } else if (width == 2) {
154
7.82k
    size_t p = start + (i & ~1);
155
7.82k
    uint16_t p1 = (data[p - stride * 1] << 8) + data[p - stride * 1 + 1];
156
7.82k
    uint16_t p2 = (data[p - stride * 2] << 8) + data[p - stride * 2 + 1];
157
7.82k
    uint16_t p3 = (data[p - stride * 3] << 8) + data[p - stride * 3 + 1];
158
7.82k
    uint16_t pred = PredictValue(p1, p2, p3, order);
159
7.82k
    return (i & 1) ? (pred & 255) : ((pred >> 8) & 255);
160
7.82k
  } else {
161
6.65k
    size_t p = start + (i & ~3);
162
6.65k
    uint32_t p1 = DecodeUint32(data, pos, p - stride);
163
6.65k
    uint32_t p2 = DecodeUint32(data, pos, p - stride * 2);
164
6.65k
    uint32_t p3 = DecodeUint32(data, pos, p - stride * 3);
165
6.65k
    uint32_t pred = PredictValue(p1, p2, p3, order);
166
6.65k
    unsigned shiftbytes = 3 - (i & 3);
167
6.65k
    return (pred >> (shiftbytes * 8)) & 255;
168
6.65k
  }
169
20.5k
}
170
171
25.3M
size_t ICCANSContext(size_t i, size_t b1, size_t b2) {
172
25.3M
  if (i <= 128) return 0;
173
24.4M
  return 1 + ByteKind1(b1) + ByteKind2(b2) * 8;
174
25.3M
}
175
176
}  // namespace jxl