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