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