1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "core/fxcodec/jbig2/JBig2_HuffmanTable.h"
8
9 #include <limits>
10 #include <vector>
11
12 #include "core/fxcodec/jbig2/JBig2_BitStream.h"
13 #include "core/fxcodec/jbig2/JBig2_Context.h"
14 #include "core/fxcrt/fx_memory.h"
15 #include "third_party/base/numerics/safe_math.h"
16
17 namespace {
18
19 struct JBig2TableLine {
20 uint8_t PREFLEN;
21 uint8_t RANDELEN;
22 int32_t RANGELOW;
23 };
24
25 struct HuffmanTable {
26 bool HTOOB;
27 const JBig2TableLine* lines;
28 size_t size;
29 };
30
31 constexpr JBig2TableLine kTableLine1[] = {{1, 4, 0},
32 {2, 8, 16},
33 {3, 16, 272},
34 {0, 32, -1},
35 {3, 32, 65808}};
36
37 constexpr JBig2TableLine kTableLine2[] = {{1, 0, 0}, {2, 0, 1}, {3, 0, 2},
38 {4, 3, 3}, {5, 6, 11}, {0, 32, -1},
39 {6, 32, 75}, {6, 0, 0}};
40
41 constexpr JBig2TableLine kTableLine3[] = {
42 {8, 8, -256}, {1, 0, 0}, {2, 0, 1}, {3, 0, 2}, {4, 3, 3},
43 {5, 6, 11}, {8, 32, -257}, {7, 32, 75}, {6, 0, 0}};
44
45 constexpr JBig2TableLine kTableLine4[] = {{1, 0, 1}, {2, 0, 2}, {3, 0, 3},
46 {4, 3, 4}, {5, 6, 12}, {0, 32, -1},
47 {5, 32, 76}};
48
49 constexpr JBig2TableLine kTableLine5[] = {{7, 8, -255}, {1, 0, 1}, {2, 0, 2},
50 {3, 0, 3}, {4, 3, 4}, {5, 6, 12},
51 {7, 32, -256}, {6, 32, 76}};
52
53 constexpr JBig2TableLine kTableLine6[] = {
54 {5, 10, -2048}, {4, 9, -1024}, {4, 8, -512}, {4, 7, -256}, {5, 6, -128},
55 {5, 5, -64}, {4, 5, -32}, {2, 7, 0}, {3, 7, 128}, {3, 8, 256},
56 {4, 9, 512}, {4, 10, 1024}, {6, 32, -2049}, {6, 32, 2048}};
57
58 constexpr JBig2TableLine kTableLine7[] = {
59 {4, 9, -1024}, {3, 8, -512}, {4, 7, -256}, {5, 6, -128}, {5, 5, -64},
60 {4, 5, -32}, {4, 5, 0}, {5, 5, 32}, {5, 6, 64}, {4, 7, 128},
61 {3, 8, 256}, {3, 9, 512}, {3, 10, 1024}, {5, 32, -1025}, {5, 32, 2048}};
62
63 constexpr JBig2TableLine kTableLine8[] = {
64 {8, 3, -15}, {9, 1, -7}, {8, 1, -5}, {9, 0, -3}, {7, 0, -2},
65 {4, 0, -1}, {2, 1, 0}, {5, 0, 2}, {6, 0, 3}, {3, 4, 4},
66 {6, 1, 20}, {4, 4, 22}, {4, 5, 38}, {5, 6, 70}, {5, 7, 134},
67 {6, 7, 262}, {7, 8, 390}, {6, 10, 646}, {9, 32, -16}, {9, 32, 1670},
68 {2, 0, 0}};
69
70 constexpr JBig2TableLine kTableLine9[] = {
71 {8, 4, -31}, {9, 2, -15}, {8, 2, -11}, {9, 1, -7}, {7, 1, -5},
72 {4, 1, -3}, {3, 1, -1}, {3, 1, 1}, {5, 1, 3}, {6, 1, 5},
73 {3, 5, 7}, {6, 2, 39}, {4, 5, 43}, {4, 6, 75}, {5, 7, 139},
74 {5, 8, 267}, {6, 8, 523}, {7, 9, 779}, {6, 11, 1291}, {9, 32, -32},
75 {9, 32, 3339}, {2, 0, 0}};
76
77 constexpr JBig2TableLine kTableLine10[] = {
78 {7, 4, -21}, {8, 0, -5}, {7, 0, -4}, {5, 0, -3}, {2, 2, -2},
79 {5, 0, 2}, {6, 0, 3}, {7, 0, 4}, {8, 0, 5}, {2, 6, 6},
80 {5, 5, 70}, {6, 5, 102}, {6, 6, 134}, {6, 7, 198}, {6, 8, 326},
81 {6, 9, 582}, {6, 10, 1094}, {7, 11, 2118}, {8, 32, -22}, {8, 32, 4166},
82 {2, 0, 0}};
83
84 constexpr JBig2TableLine kTableLine11[] = {
85 {1, 0, 1}, {2, 1, 2}, {4, 0, 4}, {4, 1, 5}, {5, 1, 7},
86 {5, 2, 9}, {6, 2, 13}, {7, 2, 17}, {7, 3, 21}, {7, 4, 29},
87 {7, 5, 45}, {7, 6, 77}, {0, 32, 0}, {7, 32, 141}};
88
89 constexpr JBig2TableLine kTableLine12[] = {
90 {1, 0, 1}, {2, 0, 2}, {3, 1, 3}, {5, 0, 5}, {5, 1, 6},
91 {6, 1, 8}, {7, 0, 10}, {7, 1, 11}, {7, 2, 13}, {7, 3, 17},
92 {7, 4, 25}, {8, 5, 41}, {0, 32, 0}, {8, 32, 73}};
93
94 constexpr JBig2TableLine kTableLine13[] = {
95 {1, 0, 1}, {3, 0, 2}, {4, 0, 3}, {5, 0, 4}, {4, 1, 5},
96 {3, 3, 7}, {6, 1, 15}, {6, 2, 17}, {6, 3, 21}, {6, 4, 29},
97 {6, 5, 45}, {7, 6, 77}, {0, 32, 0}, {7, 32, 141}};
98
99 constexpr JBig2TableLine kTableLine14[] = {{3, 0, -2}, {3, 0, -1}, {1, 0, 0},
100 {3, 0, 1}, {3, 0, 2}, {0, 32, -3},
101 {0, 32, 3}};
102
103 constexpr JBig2TableLine kTableLine15[] = {
104 {7, 4, -24}, {6, 2, -8}, {5, 1, -4}, {4, 0, -2}, {3, 0, -1},
105 {1, 0, 0}, {3, 0, 1}, {4, 0, 2}, {5, 1, 3}, {6, 2, 5},
106 {7, 4, 9}, {7, 32, -25}, {7, 32, 25}};
107
108 constexpr HuffmanTable kHuffmanTables[16] = {
109 {false, nullptr, 0}, // Zero dummy to preserve indexing.
110 {false, kTableLine1, FX_ArraySize(kTableLine1)},
111 {true, kTableLine2, FX_ArraySize(kTableLine2)},
112 {true, kTableLine3, FX_ArraySize(kTableLine3)},
113 {false, kTableLine4, FX_ArraySize(kTableLine4)},
114 {false, kTableLine5, FX_ArraySize(kTableLine5)},
115 {false, kTableLine6, FX_ArraySize(kTableLine6)},
116 {false, kTableLine7, FX_ArraySize(kTableLine7)},
117 {true, kTableLine8, FX_ArraySize(kTableLine8)},
118 {true, kTableLine9, FX_ArraySize(kTableLine9)},
119 {true, kTableLine10, FX_ArraySize(kTableLine10)},
120 {false, kTableLine11, FX_ArraySize(kTableLine11)},
121 {false, kTableLine12, FX_ArraySize(kTableLine12)},
122 {false, kTableLine13, FX_ArraySize(kTableLine13)},
123 {false, kTableLine14, FX_ArraySize(kTableLine14)},
124 {false, kTableLine15, FX_ArraySize(kTableLine15)}};
125
126 static_assert(CJBig2_HuffmanTable::kNumHuffmanTables ==
127 FX_ArraySize(kHuffmanTables),
128 "kNumHuffmanTables must be equal to the size of kHuffmanTables");
129
130 } // namespace
131
CJBig2_HuffmanTable(size_t idx)132 CJBig2_HuffmanTable::CJBig2_HuffmanTable(size_t idx) {
133 ASSERT(idx > 0);
134 ASSERT(idx < kNumHuffmanTables);
135 const HuffmanTable& table = kHuffmanTables[idx];
136 HTOOB = table.HTOOB;
137 NTEMP = table.size;
138 m_bOK = ParseFromStandardTable(idx);
139 ASSERT(m_bOK);
140 }
141
CJBig2_HuffmanTable(CJBig2_BitStream * pStream)142 CJBig2_HuffmanTable::CJBig2_HuffmanTable(CJBig2_BitStream* pStream)
143 : HTOOB(false), NTEMP(0) {
144 m_bOK = ParseFromCodedBuffer(pStream);
145 }
146
~CJBig2_HuffmanTable()147 CJBig2_HuffmanTable::~CJBig2_HuffmanTable() {}
148
ParseFromStandardTable(size_t idx)149 bool CJBig2_HuffmanTable::ParseFromStandardTable(size_t idx) {
150 const JBig2TableLine* pTable = kHuffmanTables[idx].lines;
151 CODES.resize(NTEMP);
152 RANGELEN.resize(NTEMP);
153 RANGELOW.resize(NTEMP);
154 for (uint32_t i = 0; i < NTEMP; ++i) {
155 CODES[i].codelen = pTable[i].PREFLEN;
156 RANGELEN[i] = pTable[i].RANDELEN;
157 RANGELOW[i] = pTable[i].RANGELOW;
158 }
159 return CJBig2_Context::HuffmanAssignCode(CODES.data(), NTEMP);
160 }
161
ParseFromCodedBuffer(CJBig2_BitStream * pStream)162 bool CJBig2_HuffmanTable::ParseFromCodedBuffer(CJBig2_BitStream* pStream) {
163 unsigned char cTemp;
164 if (pStream->read1Byte(&cTemp) == -1)
165 return false;
166
167 HTOOB = !!(cTemp & 0x01);
168 unsigned char HTPS = ((cTemp >> 1) & 0x07) + 1;
169 unsigned char HTRS = ((cTemp >> 4) & 0x07) + 1;
170 uint32_t HTLOW;
171 uint32_t HTHIGH;
172 if (pStream->readInteger(&HTLOW) == -1 ||
173 pStream->readInteger(&HTHIGH) == -1) {
174 return false;
175 }
176
177 const int low = static_cast<int>(HTLOW);
178 const int high = static_cast<int>(HTHIGH);
179 if (low > high)
180 return false;
181
182 ExtendBuffers(false);
183 pdfium::base::CheckedNumeric<int> cur_low = low;
184 do {
185 if ((pStream->readNBits(HTPS, &CODES[NTEMP].codelen) == -1) ||
186 (pStream->readNBits(HTRS, &RANGELEN[NTEMP]) == -1) ||
187 (static_cast<size_t>(RANGELEN[NTEMP]) >= 8 * sizeof(cur_low))) {
188 return false;
189 }
190 RANGELOW[NTEMP] = cur_low.ValueOrDie();
191
192 if (RANGELEN[NTEMP] >= 32)
193 return false;
194
195 cur_low += (1 << RANGELEN[NTEMP]);
196 if (!cur_low.IsValid())
197 return false;
198 ExtendBuffers(true);
199 } while (cur_low.ValueOrDie() < high);
200
201 if (pStream->readNBits(HTPS, &CODES[NTEMP].codelen) == -1)
202 return false;
203
204 RANGELEN[NTEMP] = 32;
205 if (low == std::numeric_limits<int>::min())
206 return false;
207
208 RANGELOW[NTEMP] = low - 1;
209 ExtendBuffers(true);
210
211 if (pStream->readNBits(HTPS, &CODES[NTEMP].codelen) == -1)
212 return false;
213
214 RANGELEN[NTEMP] = 32;
215 RANGELOW[NTEMP] = high;
216 ExtendBuffers(true);
217
218 if (HTOOB) {
219 if (pStream->readNBits(HTPS, &CODES[NTEMP].codelen) == -1)
220 return false;
221
222 ++NTEMP;
223 }
224
225 return CJBig2_Context::HuffmanAssignCode(CODES.data(), NTEMP);
226 }
227
ExtendBuffers(bool increment)228 void CJBig2_HuffmanTable::ExtendBuffers(bool increment) {
229 if (increment)
230 ++NTEMP;
231
232 size_t size = CODES.size();
233 if (NTEMP < size)
234 return;
235
236 size += 16;
237 ASSERT(NTEMP < size);
238 CODES.resize(size);
239 RANGELEN.resize(size);
240 RANGELOW.resize(size);
241 }
242