1 // Copyright 2015 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_TrdProc.h"
8 
9 #include <memory>
10 
11 #include "core/fxcodec/jbig2/JBig2_ArithDecoder.h"
12 #include "core/fxcodec/jbig2/JBig2_ArithIntDecoder.h"
13 #include "core/fxcodec/jbig2/JBig2_GrrdProc.h"
14 #include "core/fxcodec/jbig2/JBig2_HuffmanDecoder.h"
15 #include "core/fxcrt/fx_safe_types.h"
16 #include "core/fxcrt/maybe_owned.h"
17 #include "third_party/base/optional.h"
18 #include "third_party/base/ptr_util.h"
19 
20 namespace {
21 
CheckTRDDimension(uint32_t dimension,int32_t delta)22 Optional<uint32_t> CheckTRDDimension(uint32_t dimension, int32_t delta) {
23   FX_SAFE_UINT32 result = dimension;
24   result += delta;
25   if (!result.IsValid())
26     return {};
27   return {result.ValueOrDie()};
28 }
29 
CheckTRDReferenceDimension(int32_t dimension,uint32_t shift,int32_t offset)30 Optional<int32_t> CheckTRDReferenceDimension(int32_t dimension,
31                                              uint32_t shift,
32                                              int32_t offset) {
33   FX_SAFE_INT32 result = offset;
34   result += dimension >> shift;
35   if (!result.IsValid())
36     return {};
37   return {result.ValueOrDie()};
38 }
39 
40 }  // namespace
41 
42 JBig2IntDecoderState::JBig2IntDecoderState() = default;
43 
44 JBig2IntDecoderState::~JBig2IntDecoderState() = default;
45 
46 CJBig2_TRDProc::CJBig2_TRDProc() = default;
47 
48 CJBig2_TRDProc::~CJBig2_TRDProc() = default;
49 
DecodeHuffman(CJBig2_BitStream * pStream,JBig2ArithCtx * grContext)50 std::unique_ptr<CJBig2_Image> CJBig2_TRDProc::DecodeHuffman(
51     CJBig2_BitStream* pStream,
52     JBig2ArithCtx* grContext) {
53   auto SBREG = pdfium::MakeUnique<CJBig2_Image>(SBW, SBH);
54   if (!SBREG->data())
55     return nullptr;
56 
57   SBREG->Fill(SBDEFPIXEL);
58   int32_t INITIAL_STRIPT;
59   auto pHuffmanDecoder = pdfium::MakeUnique<CJBig2_HuffmanDecoder>(pStream);
60   if (pHuffmanDecoder->DecodeAValue(SBHUFFDT.Get(), &INITIAL_STRIPT) != 0)
61     return nullptr;
62 
63   FX_SAFE_INT32 STRIPT = INITIAL_STRIPT;
64   STRIPT *= SBSTRIPS;
65   STRIPT = -STRIPT;
66   FX_SAFE_INT32 FIRSTS = 0;
67   uint32_t NINSTANCES = 0;
68   while (NINSTANCES < SBNUMINSTANCES) {
69     int32_t INITIAL_DT;
70     if (pHuffmanDecoder->DecodeAValue(SBHUFFDT.Get(), &INITIAL_DT) != 0)
71       return nullptr;
72 
73     FX_SAFE_INT32 DT = INITIAL_DT;
74     DT *= SBSTRIPS;
75     STRIPT += DT;
76     bool bFirst = true;
77     FX_SAFE_INT32 CURS = 0;
78     for (;;) {
79       if (bFirst) {
80         int32_t DFS;
81         if (pHuffmanDecoder->DecodeAValue(SBHUFFFS.Get(), &DFS) != 0)
82           return nullptr;
83 
84         FIRSTS += DFS;
85         CURS = FIRSTS;
86         bFirst = false;
87       } else {
88         int32_t IDS;
89         int32_t nVal = pHuffmanDecoder->DecodeAValue(SBHUFFDS.Get(), &IDS);
90         if (nVal == JBIG2_OOB)
91           break;
92 
93         if (nVal != 0)
94           return nullptr;
95 
96         CURS += IDS;
97         CURS += SBDSOFFSET;
98       }
99       uint8_t CURT = 0;
100       if (SBSTRIPS != 1) {
101         uint32_t nTmp = 1;
102         while (static_cast<uint32_t>(1 << nTmp) < SBSTRIPS)
103           ++nTmp;
104         int32_t nVal;
105         if (pStream->readNBits(nTmp, &nVal) != 0)
106           return nullptr;
107 
108         CURT = nVal;
109       }
110       FX_SAFE_INT32 SAFE_TI = STRIPT + CURT;
111       if (!SAFE_TI.IsValid())
112         return nullptr;
113 
114       int32_t TI = SAFE_TI.ValueOrDie();
115       FX_SAFE_INT32 nSafeVal = 0;
116       int32_t nBits = 0;
117       uint32_t IDI;
118       for (;;) {
119         uint32_t nTmp;
120         if (pStream->read1Bit(&nTmp) != 0)
121           return nullptr;
122 
123         nSafeVal <<= 1;
124         if (!nSafeVal.IsValid())
125           return nullptr;
126 
127         nSafeVal |= nTmp;
128         ++nBits;
129         const int32_t nVal = nSafeVal.ValueOrDie();
130         for (IDI = 0; IDI < SBNUMSYMS; ++IDI) {
131           if (nBits == SBSYMCODES[IDI].codelen && nVal == SBSYMCODES[IDI].code)
132             break;
133         }
134         if (IDI < SBNUMSYMS)
135           break;
136       }
137       bool RI = 0;
138       if (SBREFINE != 0 && pStream->read1Bit(&RI) != 0)
139         return nullptr;
140 
141       MaybeOwned<CJBig2_Image> IBI;
142       if (RI == 0) {
143         IBI = SBSYMS[IDI];
144       } else {
145         int32_t RDWI;
146         int32_t RDHI;
147         int32_t RDXI;
148         int32_t RDYI;
149         int32_t HUFFRSIZE;
150         if ((pHuffmanDecoder->DecodeAValue(SBHUFFRDW.Get(), &RDWI) != 0) ||
151             (pHuffmanDecoder->DecodeAValue(SBHUFFRDH.Get(), &RDHI) != 0) ||
152             (pHuffmanDecoder->DecodeAValue(SBHUFFRDX.Get(), &RDXI) != 0) ||
153             (pHuffmanDecoder->DecodeAValue(SBHUFFRDY.Get(), &RDYI) != 0) ||
154             (pHuffmanDecoder->DecodeAValue(SBHUFFRSIZE.Get(), &HUFFRSIZE) !=
155              0)) {
156           return nullptr;
157         }
158         pStream->alignByte();
159         uint32_t nTmp = pStream->getOffset();
160         CJBig2_Image* IBOI = SBSYMS[IDI];
161         if (!IBOI)
162           return nullptr;
163 
164         Optional<uint32_t> WOI = CheckTRDDimension(IBOI->width(), RDWI);
165         Optional<uint32_t> HOI = CheckTRDDimension(IBOI->height(), RDHI);
166         if (!WOI || !HOI)
167           return nullptr;
168 
169         Optional<int32_t> GRREFERENCEDX =
170             CheckTRDReferenceDimension(RDWI, 2, RDXI);
171         Optional<int32_t> GRREFERENCEDY =
172             CheckTRDReferenceDimension(RDHI, 2, RDYI);
173         if (!GRREFERENCEDX || !GRREFERENCEDY)
174           return nullptr;
175 
176         auto pGRRD = pdfium::MakeUnique<CJBig2_GRRDProc>();
177         pGRRD->GRW = WOI.value();
178         pGRRD->GRH = HOI.value();
179         pGRRD->GRTEMPLATE = SBRTEMPLATE;
180         pGRRD->GRREFERENCE = IBOI;
181         pGRRD->GRREFERENCEDX = GRREFERENCEDX.value();
182         pGRRD->GRREFERENCEDY = GRREFERENCEDY.value();
183         pGRRD->TPGRON = 0;
184         pGRRD->GRAT[0] = SBRAT[0];
185         pGRRD->GRAT[1] = SBRAT[1];
186         pGRRD->GRAT[2] = SBRAT[2];
187         pGRRD->GRAT[3] = SBRAT[3];
188 
189         auto pArithDecoder = pdfium::MakeUnique<CJBig2_ArithDecoder>(pStream);
190         IBI = pGRRD->Decode(pArithDecoder.get(), grContext);
191         if (!IBI)
192           return nullptr;
193 
194         pStream->alignByte();
195         pStream->offset(2);
196         if (static_cast<uint32_t>(HUFFRSIZE) != (pStream->getOffset() - nTmp))
197           return nullptr;
198       }
199       if (!IBI)
200         continue;
201 
202       uint32_t WI = IBI->width();
203       uint32_t HI = IBI->height();
204       if (TRANSPOSED == 0 && ((REFCORNER == JBIG2_CORNER_TOPRIGHT) ||
205                               (REFCORNER == JBIG2_CORNER_BOTTOMRIGHT))) {
206         CURS += WI - 1;
207       } else if (TRANSPOSED == 1 && ((REFCORNER == JBIG2_CORNER_BOTTOMLEFT) ||
208                                      (REFCORNER == JBIG2_CORNER_BOTTOMRIGHT))) {
209         CURS += HI - 1;
210       }
211       if (!CURS.IsValid())
212         return nullptr;
213 
214       int32_t SI = CURS.ValueOrDie();
215       ComposeData compose = GetComposeData(SI, TI, WI, HI);
216       IBI.Get()->ComposeTo(SBREG.get(), compose.x, compose.y, SBCOMBOP);
217       if (compose.increment)
218         CURS += compose.increment;
219       ++NINSTANCES;
220     }
221   }
222   return SBREG;
223 }
224 
DecodeArith(CJBig2_ArithDecoder * pArithDecoder,JBig2ArithCtx * grContext,JBig2IntDecoderState * pIDS)225 std::unique_ptr<CJBig2_Image> CJBig2_TRDProc::DecodeArith(
226     CJBig2_ArithDecoder* pArithDecoder,
227     JBig2ArithCtx* grContext,
228     JBig2IntDecoderState* pIDS) {
229   auto SBREG = pdfium::MakeUnique<CJBig2_Image>(SBW, SBH);
230   if (!SBREG->data())
231     return nullptr;
232 
233   MaybeOwned<CJBig2_ArithIntDecoder> pIADT;
234   if (pIDS)
235     pIADT = pIDS->IADT;
236   else
237     pIADT = pdfium::MakeUnique<CJBig2_ArithIntDecoder>();
238   int32_t INITIAL_STRIPT;
239   if (!pIADT->Decode(pArithDecoder, &INITIAL_STRIPT))
240     return nullptr;
241 
242   MaybeOwned<CJBig2_ArithIntDecoder> pIAFS;
243   MaybeOwned<CJBig2_ArithIntDecoder> pIADS;
244   MaybeOwned<CJBig2_ArithIntDecoder> pIAIT;
245   MaybeOwned<CJBig2_ArithIntDecoder> pIARI;
246   MaybeOwned<CJBig2_ArithIntDecoder> pIARDW;
247   MaybeOwned<CJBig2_ArithIntDecoder> pIARDH;
248   MaybeOwned<CJBig2_ArithIntDecoder> pIARDX;
249   MaybeOwned<CJBig2_ArithIntDecoder> pIARDY;
250   MaybeOwned<CJBig2_ArithIaidDecoder> pIAID;
251   if (pIDS) {
252     pIAFS = pIDS->IAFS;
253     pIADS = pIDS->IADS;
254     pIAIT = pIDS->IAIT;
255     pIARI = pIDS->IARI;
256     pIARDW = pIDS->IARDW;
257     pIARDH = pIDS->IARDH;
258     pIARDX = pIDS->IARDX;
259     pIARDY = pIDS->IARDY;
260     pIAID = pIDS->IAID;
261   } else {
262     pIAFS = pdfium::MakeUnique<CJBig2_ArithIntDecoder>();
263     pIADS = pdfium::MakeUnique<CJBig2_ArithIntDecoder>();
264     pIAIT = pdfium::MakeUnique<CJBig2_ArithIntDecoder>();
265     pIARI = pdfium::MakeUnique<CJBig2_ArithIntDecoder>();
266     pIARDW = pdfium::MakeUnique<CJBig2_ArithIntDecoder>();
267     pIARDH = pdfium::MakeUnique<CJBig2_ArithIntDecoder>();
268     pIARDX = pdfium::MakeUnique<CJBig2_ArithIntDecoder>();
269     pIARDY = pdfium::MakeUnique<CJBig2_ArithIntDecoder>();
270     pIAID = pdfium::MakeUnique<CJBig2_ArithIaidDecoder>(SBSYMCODELEN);
271   }
272 
273   SBREG->Fill(SBDEFPIXEL);
274 
275   FX_SAFE_INT32 STRIPT = INITIAL_STRIPT;
276   STRIPT *= SBSTRIPS;
277   STRIPT = -STRIPT;
278   FX_SAFE_INT32 FIRSTS = 0;
279   uint32_t NINSTANCES = 0;
280   while (NINSTANCES < SBNUMINSTANCES) {
281     FX_SAFE_INT32 CURS = 0;
282     int32_t INITIAL_DT;
283     if (!pIADT->Decode(pArithDecoder, &INITIAL_DT))
284       return nullptr;
285 
286     FX_SAFE_INT32 DT = INITIAL_DT;
287     DT *= SBSTRIPS;
288     STRIPT += DT;
289     bool bFirst = true;
290     for (;;) {
291       if (bFirst) {
292         int32_t DFS;
293         pIAFS->Decode(pArithDecoder, &DFS);
294         FIRSTS += DFS;
295         CURS = FIRSTS;
296         bFirst = false;
297       } else {
298         int32_t IDS;
299         if (!pIADS->Decode(pArithDecoder, &IDS))
300           break;
301 
302         CURS += IDS;
303         CURS += SBDSOFFSET;
304       }
305       if (NINSTANCES >= SBNUMINSTANCES)
306         break;
307 
308       int CURT = 0;
309       if (SBSTRIPS != 1)
310         pIAIT->Decode(pArithDecoder, &CURT);
311 
312       FX_SAFE_INT32 SAFE_TI = STRIPT + CURT;
313       if (!SAFE_TI.IsValid())
314         return nullptr;
315 
316       int32_t TI = SAFE_TI.ValueOrDie();
317       uint32_t IDI;
318       pIAID->Decode(pArithDecoder, &IDI);
319       if (IDI >= SBNUMSYMS)
320         return nullptr;
321 
322       int RI;
323       if (SBREFINE == 0)
324         RI = 0;
325       else
326         pIARI->Decode(pArithDecoder, &RI);
327 
328       MaybeOwned<CJBig2_Image> pIBI;
329       if (RI == 0) {
330         pIBI = SBSYMS[IDI];
331       } else {
332         int32_t RDWI;
333         int32_t RDHI;
334         int32_t RDXI;
335         int32_t RDYI;
336         pIARDW->Decode(pArithDecoder, &RDWI);
337         pIARDH->Decode(pArithDecoder, &RDHI);
338         pIARDX->Decode(pArithDecoder, &RDXI);
339         pIARDY->Decode(pArithDecoder, &RDYI);
340         CJBig2_Image* IBOI = SBSYMS[IDI];
341         if (!IBOI)
342           return nullptr;
343 
344         Optional<uint32_t> WOI = CheckTRDDimension(IBOI->width(), RDWI);
345         Optional<uint32_t> HOI = CheckTRDDimension(IBOI->height(), RDHI);
346         if (!WOI || !HOI)
347           return nullptr;
348 
349         Optional<int32_t> GRREFERENCEDX =
350             CheckTRDReferenceDimension(RDWI, 1, RDXI);
351         Optional<int32_t> GRREFERENCEDY =
352             CheckTRDReferenceDimension(RDHI, 1, RDYI);
353         if (!GRREFERENCEDX || !GRREFERENCEDY)
354           return nullptr;
355 
356         auto pGRRD = pdfium::MakeUnique<CJBig2_GRRDProc>();
357         pGRRD->GRW = WOI.value();
358         pGRRD->GRH = HOI.value();
359         pGRRD->GRTEMPLATE = SBRTEMPLATE;
360         pGRRD->GRREFERENCE = IBOI;
361         pGRRD->GRREFERENCEDX = GRREFERENCEDX.value();
362         pGRRD->GRREFERENCEDY = GRREFERENCEDY.value();
363         pGRRD->TPGRON = 0;
364         pGRRD->GRAT[0] = SBRAT[0];
365         pGRRD->GRAT[1] = SBRAT[1];
366         pGRRD->GRAT[2] = SBRAT[2];
367         pGRRD->GRAT[3] = SBRAT[3];
368         pIBI = pGRRD->Decode(pArithDecoder, grContext);
369       }
370       if (!pIBI)
371         return nullptr;
372 
373       uint32_t WI = pIBI->width();
374       uint32_t HI = pIBI->height();
375       if (TRANSPOSED == 0 && ((REFCORNER == JBIG2_CORNER_TOPRIGHT) ||
376                               (REFCORNER == JBIG2_CORNER_BOTTOMRIGHT))) {
377         CURS += WI - 1;
378       } else if (TRANSPOSED == 1 && ((REFCORNER == JBIG2_CORNER_BOTTOMLEFT) ||
379                                      (REFCORNER == JBIG2_CORNER_BOTTOMRIGHT))) {
380         CURS += HI - 1;
381       }
382       if (!CURS.IsValid())
383         return nullptr;
384 
385       int32_t SI = CURS.ValueOrDie();
386       ComposeData compose = GetComposeData(SI, TI, WI, HI);
387       pIBI.Get()->ComposeTo(SBREG.get(), compose.x, compose.y, SBCOMBOP);
388       if (compose.increment)
389         CURS += compose.increment;
390       ++NINSTANCES;
391     }
392   }
393   return SBREG;
394 }
395 
GetComposeData(int32_t SI,int32_t TI,uint32_t WI,uint32_t HI) const396 CJBig2_TRDProc::ComposeData CJBig2_TRDProc::GetComposeData(int32_t SI,
397                                                            int32_t TI,
398                                                            uint32_t WI,
399                                                            uint32_t HI) const {
400   ComposeData results;
401   if (TRANSPOSED == 0) {
402     switch (REFCORNER) {
403       case JBIG2_CORNER_TOPLEFT:
404         results.x = SI;
405         results.y = TI;
406         results.increment = WI - 1;
407         break;
408       case JBIG2_CORNER_TOPRIGHT:
409         results.x = SI - WI + 1;
410         results.y = TI;
411         break;
412       case JBIG2_CORNER_BOTTOMLEFT:
413         results.x = SI;
414         results.y = TI - HI + 1;
415         results.increment = WI - 1;
416         break;
417       case JBIG2_CORNER_BOTTOMRIGHT:
418         results.x = SI - WI + 1;
419         results.y = TI - HI + 1;
420         break;
421     }
422   } else {
423     switch (REFCORNER) {
424       case JBIG2_CORNER_TOPLEFT:
425         results.x = TI;
426         results.y = SI;
427         results.increment = HI - 1;
428         break;
429       case JBIG2_CORNER_TOPRIGHT:
430         results.x = TI - WI + 1;
431         results.y = SI;
432         results.increment = HI - 1;
433         break;
434       case JBIG2_CORNER_BOTTOMLEFT:
435         results.x = TI;
436         results.y = SI - HI + 1;
437         break;
438       case JBIG2_CORNER_BOTTOMRIGHT:
439         results.x = TI - WI + 1;
440         results.y = SI - HI + 1;
441         break;
442     }
443   }
444   return results;
445 }
446