88e2269c7ad81e724fcd723a32e0ccc7d3132c16
[pdfium.git] / core / src / fpdfapi / fpdf_page / fpdf_page_parser_old.cpp
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 "../../../include/fpdfapi/fpdf_page.h"
8 #include "../../../include/fpdfapi/fpdf_module.h"
9 #include "../../../include/fxcodec/fx_codec.h"
10 #include "../../../include/fxcrt/fx_ext.h"
11 #include "pageint.h"
12 #include <limits.h>
13
14 namespace {
15
16 const char kPathOperatorSubpath = 'm';
17 const char kPathOperatorLine = 'l';
18 const char kPathOperatorCubicBezier1 = 'c';
19 const char kPathOperatorCubicBezier2 = 'v';
20 const char kPathOperatorCubicBezier3 = 'y';
21 const char kPathOperatorClosePath = 'h';
22 const char kPathOperatorRectangle[] = "re";
23
24 }  // namespace
25
26 class CPDF_StreamParserAutoClearer {
27  public:
28   CPDF_StreamParserAutoClearer(CPDF_StreamParser** scoped_variable,
29                                CPDF_StreamParser* new_parser)
30       : scoped_variable_(scoped_variable) {
31     *scoped_variable_ = new_parser;
32   }
33   ~CPDF_StreamParserAutoClearer() { *scoped_variable_ = NULL; }
34
35  private:
36   CPDF_StreamParser** scoped_variable_;
37 };
38 FX_DWORD CPDF_StreamContentParser::Parse(const uint8_t* pData,
39                                          FX_DWORD dwSize,
40                                          FX_DWORD max_cost) {
41   if (m_Level > _FPDF_MAX_FORM_LEVEL_) {
42     return dwSize;
43   }
44   FX_DWORD InitObjCount = m_pObjectList->CountObjects();
45   CPDF_StreamParser syntax(pData, dwSize);
46   CPDF_StreamParserAutoClearer auto_clearer(&m_pSyntax, &syntax);
47   m_CompatCount = 0;
48   while (1) {
49     FX_DWORD cost = m_pObjectList->CountObjects() - InitObjCount;
50     if (max_cost && cost >= max_cost) {
51       break;
52     }
53     switch (syntax.ParseNextElement()) {
54       case CPDF_StreamParser::EndOfData:
55         return m_pSyntax->GetPos();
56       case CPDF_StreamParser::Keyword:
57         OnOperator((char*)syntax.GetWordBuf());
58         ClearAllParams();
59         break;
60       case CPDF_StreamParser::Number:
61         AddNumberParam((char*)syntax.GetWordBuf(), syntax.GetWordSize());
62         break;
63       case CPDF_StreamParser::Name:
64         AddNameParam((const FX_CHAR*)syntax.GetWordBuf() + 1,
65                      syntax.GetWordSize() - 1);
66         break;
67       default:
68         AddObjectParam(syntax.GetObject());
69     }
70   }
71   return m_pSyntax->GetPos();
72 }
73 void _PDF_ReplaceAbbr(CPDF_Object* pObj);
74 void CPDF_StreamContentParser::Handle_BeginImage() {
75   FX_FILESIZE savePos = m_pSyntax->GetPos();
76   CPDF_Dictionary* pDict = CPDF_Dictionary::Create();
77   while (1) {
78     CPDF_StreamParser::SyntaxType type = m_pSyntax->ParseNextElement();
79     if (type == CPDF_StreamParser::Keyword) {
80       CFX_ByteString bsKeyword(m_pSyntax->GetWordBuf(),
81                                m_pSyntax->GetWordSize());
82       if (bsKeyword != FX_BSTRC("ID")) {
83         m_pSyntax->SetPos(savePos);
84         pDict->Release();
85         return;
86       }
87     }
88     if (type != CPDF_StreamParser::Name) {
89       break;
90     }
91     CFX_ByteString key((const FX_CHAR*)m_pSyntax->GetWordBuf() + 1,
92                        m_pSyntax->GetWordSize() - 1);
93     nonstd::unique_ptr<CPDF_Object, ReleaseDeleter<CPDF_Object>> pObj(
94         m_pSyntax->ReadNextObject());
95     if (!key.IsEmpty()) {
96       FX_DWORD dwObjNum = pObj->GetObjNum();
97       if (dwObjNum)
98         pDict->SetAtReference(key, m_pDocument, dwObjNum);
99       else
100         pDict->SetAt(key, pObj.release());
101     }
102   }
103   _PDF_ReplaceAbbr(pDict);
104   CPDF_Object* pCSObj = NULL;
105   if (pDict->KeyExist(FX_BSTRC("ColorSpace"))) {
106     pCSObj = pDict->GetElementValue(FX_BSTRC("ColorSpace"));
107     if (pCSObj->IsName()) {
108       CFX_ByteString name = pCSObj->GetString();
109       if (name != FX_BSTRC("DeviceRGB") && name != FX_BSTRC("DeviceGray") &&
110           name != FX_BSTRC("DeviceCMYK")) {
111         pCSObj = FindResourceObj(FX_BSTRC("ColorSpace"), name);
112         if (pCSObj && !pCSObj->GetObjNum()) {
113           pCSObj = pCSObj->Clone();
114           pDict->SetAt(FX_BSTRC("ColorSpace"), pCSObj);
115         }
116       }
117     }
118   }
119   CPDF_Stream* pStream = m_pSyntax->ReadInlineStream(
120       m_pDocument, pDict, pCSObj, m_Options.m_bDecodeInlineImage);
121   while (1) {
122     CPDF_StreamParser::SyntaxType type = m_pSyntax->ParseNextElement();
123     if (type == CPDF_StreamParser::EndOfData) {
124       break;
125     }
126     if (type != CPDF_StreamParser::Keyword) {
127       continue;
128     }
129     if (m_pSyntax->GetWordSize() == 2 && m_pSyntax->GetWordBuf()[0] == 'E' &&
130         m_pSyntax->GetWordBuf()[1] == 'I') {
131       break;
132     }
133   }
134   if (m_Options.m_bTextOnly) {
135     if (pStream) {
136       pStream->Release();
137     } else {
138       pDict->Release();
139     }
140     return;
141   }
142   pDict->SetAtName(FX_BSTRC("Subtype"), FX_BSTRC("Image"));
143   CPDF_ImageObject* pImgObj = AddImage(pStream, NULL, TRUE);
144   if (!pImgObj) {
145     if (pStream) {
146       pStream->Release();
147     } else {
148       pDict->Release();
149     }
150   }
151 }
152 void CPDF_StreamContentParser::ParsePathObject() {
153   FX_FLOAT params[6] = {};
154   int nParams = 0;
155   int last_pos = m_pSyntax->GetPos();
156   while (1) {
157     CPDF_StreamParser::SyntaxType type = m_pSyntax->ParseNextElement();
158     FX_BOOL bProcessed = TRUE;
159     switch (type) {
160       case CPDF_StreamParser::EndOfData:
161         return;
162       case CPDF_StreamParser::Keyword: {
163         int len = m_pSyntax->GetWordSize();
164         if (len == 1) {
165           switch (m_pSyntax->GetWordBuf()[0]) {
166             case kPathOperatorSubpath:
167               AddPathPoint(params[0], params[1], FXPT_MOVETO);
168               nParams = 0;
169               break;
170             case kPathOperatorLine:
171               AddPathPoint(params[0], params[1], FXPT_LINETO);
172               nParams = 0;
173               break;
174             case kPathOperatorCubicBezier1:
175               AddPathPoint(params[0], params[1], FXPT_BEZIERTO);
176               AddPathPoint(params[2], params[3], FXPT_BEZIERTO);
177               AddPathPoint(params[4], params[5], FXPT_BEZIERTO);
178               nParams = 0;
179               break;
180             case kPathOperatorCubicBezier2:
181               AddPathPoint(m_PathCurrentX, m_PathCurrentY, FXPT_BEZIERTO);
182               AddPathPoint(params[0], params[1], FXPT_BEZIERTO);
183               AddPathPoint(params[2], params[3], FXPT_BEZIERTO);
184               nParams = 0;
185               break;
186             case kPathOperatorCubicBezier3:
187               AddPathPoint(params[0], params[1], FXPT_BEZIERTO);
188               AddPathPoint(params[2], params[3], FXPT_BEZIERTO);
189               AddPathPoint(params[2], params[3], FXPT_BEZIERTO);
190               nParams = 0;
191               break;
192             case kPathOperatorClosePath:
193               Handle_ClosePath();
194               nParams = 0;
195               break;
196             default:
197               bProcessed = FALSE;
198               break;
199           }
200         } else if (len == 2) {
201           if (m_pSyntax->GetWordBuf()[0] == kPathOperatorRectangle[0] &&
202               m_pSyntax->GetWordBuf()[1] == kPathOperatorRectangle[1]) {
203             AddPathRect(params[0], params[1], params[2], params[3]);
204             nParams = 0;
205           } else {
206             bProcessed = FALSE;
207           }
208         } else {
209           bProcessed = FALSE;
210         }
211         if (bProcessed) {
212           last_pos = m_pSyntax->GetPos();
213         }
214         break;
215       }
216       case CPDF_StreamParser::Number: {
217         if (nParams == 6) {
218           break;
219         }
220         FX_BOOL bInteger;
221         int value;
222         FX_atonum(
223             CFX_ByteStringC(m_pSyntax->GetWordBuf(), m_pSyntax->GetWordSize()),
224             bInteger, &value);
225         params[nParams++] = bInteger ? (FX_FLOAT)value : *(FX_FLOAT*)&value;
226         break;
227       }
228       default:
229         bProcessed = FALSE;
230     }
231     if (!bProcessed) {
232       m_pSyntax->SetPos(last_pos);
233       return;
234     }
235   }
236 }
237 CPDF_StreamParser::CPDF_StreamParser(const uint8_t* pData, FX_DWORD dwSize) {
238   m_pBuf = pData;
239   m_Size = dwSize;
240   m_Pos = 0;
241   m_pLastObj = NULL;
242 }
243 CPDF_StreamParser::~CPDF_StreamParser() {
244   if (m_pLastObj) {
245     m_pLastObj->Release();
246   }
247 }
248 FX_DWORD _DecodeAllScanlines(ICodec_ScanlineDecoder* pDecoder,
249                              uint8_t*& dest_buf,
250                              FX_DWORD& dest_size) {
251   if (pDecoder == NULL) {
252     return (FX_DWORD)-1;
253   }
254   int ncomps = pDecoder->CountComps();
255   int bpc = pDecoder->GetBPC();
256   int width = pDecoder->GetWidth();
257   int height = pDecoder->GetHeight();
258   int pitch = (width * ncomps * bpc + 7) / 8;
259   if (height == 0 || pitch > (1 << 30) / height) {
260     delete pDecoder;
261     return -1;
262   }
263   dest_buf = FX_Alloc2D(uint8_t, pitch, height);
264   dest_size = pitch * height;  // Safe since checked alloc returned.
265   for (int row = 0; row < height; row++) {
266     const uint8_t* pLine = pDecoder->GetScanline(row);
267     if (!pLine)
268       break;
269
270     FXSYS_memcpy(dest_buf + row * pitch, pLine, pitch);
271   }
272   FX_DWORD srcoff = pDecoder->GetSrcOffset();
273   delete pDecoder;
274   return srcoff;
275 }
276 ICodec_ScanlineDecoder* FPDFAPI_CreateFaxDecoder(
277     const uint8_t* src_buf,
278     FX_DWORD src_size,
279     int width,
280     int height,
281     const CPDF_Dictionary* pParams);
282 FX_DWORD _A85Decode(const uint8_t* src_buf,
283                     FX_DWORD src_size,
284                     uint8_t*& dest_buf,
285                     FX_DWORD& dest_size);
286 FX_DWORD _HexDecode(const uint8_t* src_buf,
287                     FX_DWORD src_size,
288                     uint8_t*& dest_buf,
289                     FX_DWORD& dest_size);
290 FX_DWORD FPDFAPI_FlateOrLZWDecode(FX_BOOL bLZW,
291                                   const uint8_t* src_buf,
292                                   FX_DWORD src_size,
293                                   CPDF_Dictionary* pParams,
294                                   FX_DWORD estimated_size,
295                                   uint8_t*& dest_buf,
296                                   FX_DWORD& dest_size);
297 FX_DWORD PDF_DecodeInlineStream(const uint8_t* src_buf,
298                                 FX_DWORD limit,
299                                 int width,
300                                 int height,
301                                 CFX_ByteString& decoder,
302                                 CPDF_Dictionary* pParam,
303                                 uint8_t*& dest_buf,
304                                 FX_DWORD& dest_size) {
305   if (decoder == FX_BSTRC("CCITTFaxDecode") || decoder == FX_BSTRC("CCF")) {
306     ICodec_ScanlineDecoder* pDecoder =
307         FPDFAPI_CreateFaxDecoder(src_buf, limit, width, height, pParam);
308     return _DecodeAllScanlines(pDecoder, dest_buf, dest_size);
309   }
310   if (decoder == FX_BSTRC("ASCII85Decode") || decoder == FX_BSTRC("A85")) {
311     return _A85Decode(src_buf, limit, dest_buf, dest_size);
312   }
313   if (decoder == FX_BSTRC("ASCIIHexDecode") || decoder == FX_BSTRC("AHx")) {
314     return _HexDecode(src_buf, limit, dest_buf, dest_size);
315   }
316   if (decoder == FX_BSTRC("FlateDecode") || decoder == FX_BSTRC("Fl")) {
317     return FPDFAPI_FlateOrLZWDecode(FALSE, src_buf, limit, pParam, dest_size,
318                                     dest_buf, dest_size);
319   }
320   if (decoder == FX_BSTRC("LZWDecode") || decoder == FX_BSTRC("LZW")) {
321     return FPDFAPI_FlateOrLZWDecode(TRUE, src_buf, limit, pParam, 0, dest_buf,
322                                     dest_size);
323   }
324   if (decoder == FX_BSTRC("DCTDecode") || decoder == FX_BSTRC("DCT")) {
325     ICodec_ScanlineDecoder* pDecoder =
326         CPDF_ModuleMgr::Get()->GetJpegModule()->CreateDecoder(
327             src_buf, limit, width, height, 0,
328             pParam ? pParam->GetInteger(FX_BSTRC("ColorTransform"), 1) : 1);
329     return _DecodeAllScanlines(pDecoder, dest_buf, dest_size);
330   }
331   if (decoder == FX_BSTRC("RunLengthDecode") || decoder == FX_BSTRC("RL")) {
332     return RunLengthDecode(src_buf, limit, dest_buf, dest_size);
333   }
334   dest_size = 0;
335   dest_buf = 0;
336   return (FX_DWORD)-1;
337 }
338 CPDF_Stream* CPDF_StreamParser::ReadInlineStream(CPDF_Document* pDoc,
339                                                  CPDF_Dictionary* pDict,
340                                                  CPDF_Object* pCSObj,
341                                                  FX_BOOL bDecode) {
342   if (m_Pos == m_Size)
343     return nullptr;
344
345   if (PDFCharIsWhitespace(m_pBuf[m_Pos]))
346     m_Pos++;
347
348   CFX_ByteString Decoder;
349   CPDF_Dictionary* pParam = nullptr;
350   CPDF_Object* pFilter = pDict->GetElementValue(FX_BSTRC("Filter"));
351   if (pFilter) {
352     if (CPDF_Array* pArray = pFilter->AsArray()) {
353       Decoder = pArray->GetString(0);
354       CPDF_Array* pParams = pDict->GetArray(FX_BSTRC("DecodeParms"));
355       if (pParams)
356         pParam = pParams->GetDict(0);
357     } else {
358       Decoder = pFilter->GetString();
359       pParam = pDict->GetDict(FX_BSTRC("DecodeParms"));
360     }
361   }
362   FX_DWORD width = pDict->GetInteger(FX_BSTRC("Width"));
363   FX_DWORD height = pDict->GetInteger(FX_BSTRC("Height"));
364   FX_DWORD OrigSize = 0;
365   if (pCSObj != NULL) {
366     FX_DWORD bpc = pDict->GetInteger(FX_BSTRC("BitsPerComponent"));
367     FX_DWORD nComponents = 1;
368     CPDF_ColorSpace* pCS = pDoc->LoadColorSpace(pCSObj);
369     if (pCS == NULL) {
370       nComponents = 3;
371     } else {
372       nComponents = pCS->CountComponents();
373       pDoc->GetPageData()->ReleaseColorSpace(pCSObj);
374     }
375     FX_DWORD pitch = width;
376     if (bpc && pitch > INT_MAX / bpc) {
377       return NULL;
378     }
379     pitch *= bpc;
380     if (nComponents && pitch > INT_MAX / nComponents) {
381       return NULL;
382     }
383     pitch *= nComponents;
384     if (pitch > INT_MAX - 7) {
385       return NULL;
386     }
387     pitch += 7;
388     pitch /= 8;
389     OrigSize = pitch;
390   } else {
391     if (width > INT_MAX - 7) {
392       return NULL;
393     }
394     OrigSize = ((width + 7) / 8);
395   }
396   if (height && OrigSize > INT_MAX / height) {
397     return NULL;
398   }
399   OrigSize *= height;
400   uint8_t* pData = NULL;
401   FX_DWORD dwStreamSize;
402   if (Decoder.IsEmpty()) {
403     if (OrigSize > m_Size - m_Pos) {
404       OrigSize = m_Size - m_Pos;
405     }
406     pData = FX_Alloc(uint8_t, OrigSize);
407     FXSYS_memcpy(pData, m_pBuf + m_Pos, OrigSize);
408     dwStreamSize = OrigSize;
409     m_Pos += OrigSize;
410   } else {
411     FX_DWORD dwDestSize = OrigSize;
412     dwStreamSize =
413         PDF_DecodeInlineStream(m_pBuf + m_Pos, m_Size - m_Pos, width, height,
414                                Decoder, pParam, pData, dwDestSize);
415     if ((int)dwStreamSize < 0) {
416       FX_Free(pData);
417       return NULL;
418     }
419     if (bDecode) {
420       m_Pos += dwStreamSize;
421       dwStreamSize = dwDestSize;
422       if (CPDF_Array* pArray = pFilter->AsArray()) {
423         pArray->RemoveAt(0);
424         CPDF_Array* pParams = pDict->GetArray(FX_BSTRC("DecodeParms"));
425         if (pParams)
426           pParams->RemoveAt(0);
427       } else {
428         pDict->RemoveAt(FX_BSTRC("Filter"));
429         pDict->RemoveAt(FX_BSTRC("DecodeParms"));
430       }
431     } else {
432       FX_Free(pData);
433       FX_DWORD dwSavePos = m_Pos;
434       m_Pos += dwStreamSize;
435       while (1) {
436         FX_DWORD dwPrevPos = m_Pos;
437         CPDF_StreamParser::SyntaxType type = ParseNextElement();
438         if (type == CPDF_StreamParser::EndOfData) {
439           break;
440         }
441         if (type != CPDF_StreamParser::Keyword) {
442           dwStreamSize += m_Pos - dwPrevPos;
443           continue;
444         }
445         if (GetWordSize() == 2 && GetWordBuf()[0] == 'E' &&
446             GetWordBuf()[1] == 'I') {
447           m_Pos = dwPrevPos;
448           break;
449         }
450         dwStreamSize += m_Pos - dwPrevPos;
451       }
452       m_Pos = dwSavePos;
453       pData = FX_Alloc(uint8_t, dwStreamSize);
454       FXSYS_memcpy(pData, m_pBuf + m_Pos, dwStreamSize);
455       m_Pos += dwStreamSize;
456     }
457   }
458   pDict->SetAtInteger(FX_BSTRC("Length"), (int)dwStreamSize);
459   return CPDF_Stream::Create(pData, dwStreamSize, pDict);
460 }
461 #define MAX_WORD_BUFFER 256
462 #define MAX_STRING_LENGTH 32767
463 #define FXDWORD_TRUE FXDWORD_FROM_LSBFIRST(0x65757274)
464 #define FXDWORD_NULL FXDWORD_FROM_LSBFIRST(0x6c6c756e)
465 #define FXDWORD_FALS FXDWORD_FROM_LSBFIRST(0x736c6166)
466 CPDF_StreamParser::SyntaxType CPDF_StreamParser::ParseNextElement() {
467   if (m_pLastObj) {
468     m_pLastObj->Release();
469     m_pLastObj = nullptr;
470   }
471
472   m_WordSize = 0;
473   FX_BOOL bIsNumber = TRUE;
474   if (!PositionIsInBounds())
475     return EndOfData;
476
477   int ch = m_pBuf[m_Pos++];
478   while (1) {
479     while (PDFCharIsWhitespace(ch)) {
480       if (!PositionIsInBounds())
481         return EndOfData;
482
483       ch = m_pBuf[m_Pos++];
484     }
485
486     if (ch != '%')
487       break;
488
489     while (1) {
490       if (!PositionIsInBounds())
491         return EndOfData;
492
493       ch = m_pBuf[m_Pos++];
494       if (PDFCharIsLineEnding(ch))
495         break;
496     }
497   }
498
499   if (PDFCharIsDelimiter(ch) && ch != '/') {
500     m_Pos--;
501     m_pLastObj = ReadNextObject();
502     return Others;
503   }
504
505   while (1) {
506     if (m_WordSize < MAX_WORD_BUFFER)
507       m_WordBuffer[m_WordSize++] = ch;
508
509     if (!PDFCharIsNumeric(ch))
510       bIsNumber = FALSE;
511
512     if (!PositionIsInBounds())
513       break;
514
515     ch = m_pBuf[m_Pos++];
516
517     if (PDFCharIsDelimiter(ch) || PDFCharIsWhitespace(ch)) {
518       m_Pos--;
519       break;
520     }
521   }
522
523   m_WordBuffer[m_WordSize] = 0;
524   if (bIsNumber)
525     return Number;
526   if (m_WordBuffer[0] == '/')
527     return Name;
528
529   if (m_WordSize == 4) {
530     if (*(FX_DWORD*)m_WordBuffer == FXDWORD_TRUE) {
531       m_pLastObj = CPDF_Boolean::Create(TRUE);
532       return Others;
533     }
534     if (*(FX_DWORD*)m_WordBuffer == FXDWORD_NULL) {
535       m_pLastObj = CPDF_Null::Create();
536       return Others;
537     }
538   } else if (m_WordSize == 5) {
539     if (*(FX_DWORD*)m_WordBuffer == FXDWORD_FALS && m_WordBuffer[4] == 'e') {
540       m_pLastObj = CPDF_Boolean::Create(FALSE);
541       return Others;
542     }
543   }
544   return Keyword;
545 }
546
547 void CPDF_StreamParser::SkipPathObject() {
548   FX_DWORD command_startpos = m_Pos;
549   if (!PositionIsInBounds())
550     return;
551
552   int ch = m_pBuf[m_Pos++];
553   while (1) {
554     while (PDFCharIsWhitespace(ch)) {
555       if (!PositionIsInBounds())
556         return;
557       ch = m_pBuf[m_Pos++];
558     }
559
560     if (!PDFCharIsNumeric(ch)) {
561       m_Pos = command_startpos;
562       return;
563     }
564
565     while (1) {
566       while (!PDFCharIsWhitespace(ch)) {
567         if (!PositionIsInBounds())
568           return;
569         ch = m_pBuf[m_Pos++];
570       }
571
572       while (PDFCharIsWhitespace(ch)) {
573         if (!PositionIsInBounds())
574           return;
575         ch = m_pBuf[m_Pos++];
576       }
577
578       if (PDFCharIsNumeric(ch))
579         continue;
580
581       FX_DWORD op_startpos = m_Pos - 1;
582       while (!PDFCharIsWhitespace(ch) && !PDFCharIsDelimiter(ch)) {
583         if (!PositionIsInBounds())
584           return;
585         ch = m_pBuf[m_Pos++];
586       }
587
588       if (m_Pos - op_startpos == 2) {
589         int op = m_pBuf[op_startpos];
590         if (op == kPathOperatorSubpath || op == kPathOperatorLine ||
591             op == kPathOperatorCubicBezier1 ||
592             op == kPathOperatorCubicBezier2 ||
593             op == kPathOperatorCubicBezier3) {
594           command_startpos = m_Pos;
595           break;
596         }
597       } else if (m_Pos - op_startpos == 3) {
598         if (m_pBuf[op_startpos] == kPathOperatorRectangle[0] &&
599             m_pBuf[op_startpos + 1] == kPathOperatorRectangle[1]) {
600           command_startpos = m_Pos;
601           break;
602         }
603       }
604       m_Pos = command_startpos;
605       return;
606     }
607   }
608 }
609 CPDF_Object* CPDF_StreamParser::ReadNextObject(FX_BOOL bAllowNestedArray,
610                                                FX_BOOL bInArray) {
611   FX_BOOL bIsNumber;
612   GetNextWord(bIsNumber);
613   if (m_WordSize == 0) {
614     return NULL;
615   }
616   if (bIsNumber) {
617     m_WordBuffer[m_WordSize] = 0;
618     return CPDF_Number::Create(CFX_ByteStringC(m_WordBuffer, m_WordSize));
619   }
620   int first_char = m_WordBuffer[0];
621   if (first_char == '/') {
622     return CPDF_Name::Create(
623         PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1)));
624   }
625   if (first_char == '(') {
626     return CPDF_String::Create(ReadString());
627   }
628   if (first_char == '<') {
629     if (m_WordSize == 1) {
630       return CPDF_String::Create(ReadHexString(), TRUE);
631     }
632     CPDF_Dictionary* pDict = CPDF_Dictionary::Create();
633     while (1) {
634       GetNextWord(bIsNumber);
635       if (m_WordSize == 0) {
636         pDict->Release();
637         return NULL;
638       }
639       if (m_WordSize == 2 && m_WordBuffer[0] == '>') {
640         break;
641       }
642       if (m_WordBuffer[0] != '/') {
643         pDict->Release();
644         return NULL;
645       }
646       CFX_ByteString key =
647           PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1));
648       CPDF_Object* pObj = ReadNextObject(TRUE);
649       if (pObj == NULL) {
650         if (pDict) {
651           pDict->Release();
652         }
653         return NULL;
654       }
655       if (!key.IsEmpty()) {
656         pDict->SetAt(key, pObj);
657       } else {
658         pObj->Release();
659       }
660     }
661     return pDict;
662   }
663   if (first_char == '[') {
664     if (!bAllowNestedArray && bInArray) {
665       return NULL;
666     }
667     CPDF_Array* pArray = CPDF_Array::Create();
668     while (1) {
669       CPDF_Object* pObj = ReadNextObject(bAllowNestedArray, TRUE);
670       if (pObj == NULL) {
671         if (m_WordSize == 0 || m_WordBuffer[0] == ']') {
672           return pArray;
673         }
674         if (m_WordBuffer[0] == '[') {
675           continue;
676         }
677       } else {
678         pArray->Add(pObj);
679       }
680     }
681   }
682   if (m_WordSize == 4) {
683     if (*(FX_DWORD*)m_WordBuffer == FXDWORD_TRUE) {
684       return CPDF_Boolean::Create(TRUE);
685     }
686     if (*(FX_DWORD*)m_WordBuffer == FXDWORD_NULL) {
687       return CPDF_Null::Create();
688     }
689   } else if (m_WordSize == 5) {
690     if (*(FX_DWORD*)m_WordBuffer == FXDWORD_FALS && m_WordBuffer[4] == 'e') {
691       return CPDF_Boolean::Create(FALSE);
692     }
693   }
694   return NULL;
695 }
696 void CPDF_StreamParser::GetNextWord(FX_BOOL& bIsNumber) {
697   m_WordSize = 0;
698   bIsNumber = TRUE;
699   if (!PositionIsInBounds())
700     return;
701
702   int ch = m_pBuf[m_Pos++];
703   while (1) {
704     while (PDFCharIsWhitespace(ch)) {
705       if (!PositionIsInBounds()) {
706         return;
707       }
708       ch = m_pBuf[m_Pos++];
709     }
710
711     if (ch != '%')
712       break;
713
714     while (1) {
715       if (!PositionIsInBounds())
716         return;
717       ch = m_pBuf[m_Pos++];
718       if (PDFCharIsLineEnding(ch))
719         break;
720     }
721   }
722
723   if (PDFCharIsDelimiter(ch)) {
724     bIsNumber = FALSE;
725     m_WordBuffer[m_WordSize++] = ch;
726     if (ch == '/') {
727       while (1) {
728         if (!PositionIsInBounds())
729           return;
730         ch = m_pBuf[m_Pos++];
731         if (!PDFCharIsOther(ch) && !PDFCharIsNumeric(ch)) {
732           m_Pos--;
733           return;
734         }
735
736         if (m_WordSize < MAX_WORD_BUFFER)
737           m_WordBuffer[m_WordSize++] = ch;
738       }
739     } else if (ch == '<') {
740       if (!PositionIsInBounds())
741         return;
742       ch = m_pBuf[m_Pos++];
743       if (ch == '<')
744         m_WordBuffer[m_WordSize++] = ch;
745       else
746         m_Pos--;
747     } else if (ch == '>') {
748       if (!PositionIsInBounds())
749         return;
750       ch = m_pBuf[m_Pos++];
751       if (ch == '>')
752         m_WordBuffer[m_WordSize++] = ch;
753       else
754         m_Pos--;
755     }
756     return;
757   }
758
759   while (1) {
760     if (m_WordSize < MAX_WORD_BUFFER)
761       m_WordBuffer[m_WordSize++] = ch;
762     if (!PDFCharIsNumeric(ch))
763       bIsNumber = FALSE;
764
765     if (!PositionIsInBounds())
766       return;
767     ch = m_pBuf[m_Pos++];
768     if (PDFCharIsDelimiter(ch) || PDFCharIsWhitespace(ch)) {
769       m_Pos--;
770       break;
771     }
772   }
773 }
774
775 CFX_ByteString CPDF_StreamParser::ReadString() {
776   if (!PositionIsInBounds())
777     return CFX_ByteString();
778
779   int ch = m_pBuf[m_Pos++];
780   CFX_ByteTextBuf buf;
781   int parlevel = 0;
782   int status = 0, iEscCode = 0;
783   while (1) {
784     switch (status) {
785       case 0:
786         if (ch == ')') {
787           if (parlevel == 0) {
788             if (buf.GetLength() > MAX_STRING_LENGTH) {
789               return CFX_ByteString(buf.GetBuffer(), MAX_STRING_LENGTH);
790             }
791             return buf.GetByteString();
792           }
793           parlevel--;
794           buf.AppendChar(')');
795         } else if (ch == '(') {
796           parlevel++;
797           buf.AppendChar('(');
798         } else if (ch == '\\') {
799           status = 1;
800         } else {
801           buf.AppendChar((char)ch);
802         }
803         break;
804       case 1:
805         if (ch >= '0' && ch <= '7') {
806           iEscCode = ch - '0';
807           status = 2;
808           break;
809         }
810         if (ch == 'n') {
811           buf.AppendChar('\n');
812         } else if (ch == 'r') {
813           buf.AppendChar('\r');
814         } else if (ch == 't') {
815           buf.AppendChar('\t');
816         } else if (ch == 'b') {
817           buf.AppendChar('\b');
818         } else if (ch == 'f') {
819           buf.AppendChar('\f');
820         } else if (ch == '\r') {
821           status = 4;
822           break;
823         } else if (ch == '\n') {
824         } else {
825           buf.AppendChar(ch);
826         }
827         status = 0;
828         break;
829       case 2:
830         if (ch >= '0' && ch <= '7') {
831           iEscCode = iEscCode * 8 + ch - '0';
832           status = 3;
833         } else {
834           buf.AppendChar(iEscCode);
835           status = 0;
836           continue;
837         }
838         break;
839       case 3:
840         if (ch >= '0' && ch <= '7') {
841           iEscCode = iEscCode * 8 + ch - '0';
842           buf.AppendChar(iEscCode);
843           status = 0;
844         } else {
845           buf.AppendChar(iEscCode);
846           status = 0;
847           continue;
848         }
849         break;
850       case 4:
851         status = 0;
852         if (ch != '\n') {
853           continue;
854         }
855         break;
856     }
857     if (!PositionIsInBounds())
858       break;
859
860     ch = m_pBuf[m_Pos++];
861   }
862   if (PositionIsInBounds())
863     ch = m_pBuf[m_Pos++];
864
865   if (buf.GetLength() > MAX_STRING_LENGTH) {
866     return CFX_ByteString(buf.GetBuffer(), MAX_STRING_LENGTH);
867   }
868   return buf.GetByteString();
869 }
870 CFX_ByteString CPDF_StreamParser::ReadHexString() {
871   if (!PositionIsInBounds())
872     return CFX_ByteString();
873
874   int ch = m_pBuf[m_Pos++];
875   CFX_ByteTextBuf buf;
876   FX_BOOL bFirst = TRUE;
877   int code = 0;
878   while (1) {
879     if (ch == '>')
880       break;
881
882     if (std::isxdigit(ch)) {
883       int val = HexCharToDigit(ch);
884       if (bFirst) {
885         code = val * 16;
886       } else {
887         code += val;
888         buf.AppendByte((uint8_t)code);
889       }
890       bFirst = !bFirst;
891     }
892
893     if (!PositionIsInBounds())
894       break;
895
896     ch = m_pBuf[m_Pos++];
897   }
898   if (!bFirst) {
899     buf.AppendChar((char)code);
900   }
901   if (buf.GetLength() > MAX_STRING_LENGTH) {
902     return CFX_ByteString(buf.GetBuffer(), MAX_STRING_LENGTH);
903   }
904   return buf.GetByteString();
905 }
906
907 bool CPDF_StreamParser::PositionIsInBounds() const {
908   return m_Pos < m_Size;
909 }
910
911 #define PAGEPARSE_STAGE_GETCONTENT 1
912 #define PAGEPARSE_STAGE_PARSE 2
913 #define PAGEPARSE_STAGE_CHECKCLIP 3
914 CPDF_ContentParser::CPDF_ContentParser() {
915   m_pParser = NULL;
916   m_pStreamArray = NULL;
917   m_pSingleStream = NULL;
918   m_pData = NULL;
919   m_Status = Ready;
920   m_pType3Char = NULL;
921 }
922 CPDF_ContentParser::~CPDF_ContentParser() {
923   Clear();
924 }
925 void CPDF_ContentParser::Clear() {
926   delete m_pParser;
927   delete m_pSingleStream;
928   if (m_pStreamArray) {
929     for (FX_DWORD i = 0; i < m_nStreams; i++)
930       delete m_pStreamArray[i];
931     FX_Free(m_pStreamArray);
932   }
933   if (!m_pSingleStream)
934     FX_Free(m_pData);
935   m_pParser = NULL;
936   m_pStreamArray = NULL;
937   m_pSingleStream = NULL;
938   m_pData = NULL;
939   m_Status = Ready;
940 }
941 void CPDF_ContentParser::Start(CPDF_Page* pPage, CPDF_ParseOptions* pOptions) {
942   if (m_Status != Ready || pPage == NULL || pPage->m_pDocument == NULL ||
943       pPage->m_pFormDict == NULL) {
944     m_Status = Done;
945     return;
946   }
947   m_pObjects = pPage;
948   m_bForm = FALSE;
949   if (pOptions) {
950     m_Options = *pOptions;
951   }
952   m_Status = ToBeContinued;
953   m_InternalStage = PAGEPARSE_STAGE_GETCONTENT;
954   m_CurrentOffset = 0;
955   CPDF_Object* pContent =
956       pPage->m_pFormDict->GetElementValue(FX_BSTRC("Contents"));
957   if (pContent == NULL) {
958     m_Status = Done;
959     return;
960   }
961   if (CPDF_Stream* pStream = pContent->AsStream()) {
962     m_nStreams = 0;
963     m_pSingleStream = new CPDF_StreamAcc;
964     m_pSingleStream->LoadAllData(pStream, FALSE);
965   } else if (CPDF_Array* pArray = pContent->AsArray()) {
966     m_nStreams = pArray->GetCount();
967     if (m_nStreams == 0) {
968       m_Status = Done;
969       return;
970     }
971     m_pStreamArray = FX_Alloc(CPDF_StreamAcc*, m_nStreams);
972   } else {
973     m_Status = Done;
974     return;
975   }
976 }
977 void CPDF_ContentParser::Start(CPDF_Form* pForm,
978                                CPDF_AllStates* pGraphicStates,
979                                CFX_AffineMatrix* pParentMatrix,
980                                CPDF_Type3Char* pType3Char,
981                                CPDF_ParseOptions* pOptions,
982                                int level) {
983   m_pType3Char = pType3Char;
984   m_pObjects = pForm;
985   m_bForm = TRUE;
986   CFX_AffineMatrix form_matrix =
987       pForm->m_pFormDict->GetMatrix(FX_BSTRC("Matrix"));
988   if (pGraphicStates) {
989     form_matrix.Concat(pGraphicStates->m_CTM);
990   }
991   CPDF_Array* pBBox = pForm->m_pFormDict->GetArray(FX_BSTRC("BBox"));
992   CFX_FloatRect form_bbox;
993   CPDF_Path ClipPath;
994   if (pBBox) {
995     form_bbox = pBBox->GetRect();
996     ClipPath.New();
997     ClipPath.AppendRect(form_bbox.left, form_bbox.bottom, form_bbox.right,
998                         form_bbox.top);
999     ClipPath.Transform(&form_matrix);
1000     if (pParentMatrix) {
1001       ClipPath.Transform(pParentMatrix);
1002     }
1003     form_bbox.Transform(&form_matrix);
1004     if (pParentMatrix) {
1005       form_bbox.Transform(pParentMatrix);
1006     }
1007   }
1008   CPDF_Dictionary* pResources =
1009       pForm->m_pFormDict->GetDict(FX_BSTRC("Resources"));
1010   m_pParser = new CPDF_StreamContentParser(
1011       pForm->m_pDocument, pForm->m_pPageResources, pForm->m_pResources,
1012       pParentMatrix, pForm, pResources, &form_bbox, pOptions, pGraphicStates,
1013       level);
1014
1015   m_pParser->GetCurStates()->m_CTM = form_matrix;
1016   m_pParser->GetCurStates()->m_ParentMatrix = form_matrix;
1017   if (ClipPath.NotNull()) {
1018     m_pParser->GetCurStates()->m_ClipPath.AppendPath(ClipPath, FXFILL_WINDING,
1019                                                      TRUE);
1020   }
1021   if (pForm->m_Transparency & PDFTRANS_GROUP) {
1022     CPDF_GeneralStateData* pData =
1023         m_pParser->GetCurStates()->m_GeneralState.GetModify();
1024     pData->m_BlendType = FXDIB_BLEND_NORMAL;
1025     pData->m_StrokeAlpha = 1.0f;
1026     pData->m_FillAlpha = 1.0f;
1027     pData->m_pSoftMask = NULL;
1028   }
1029   m_nStreams = 0;
1030   m_pSingleStream = new CPDF_StreamAcc;
1031   if (pForm->m_pDocument) {
1032     m_pSingleStream->LoadAllData(pForm->m_pFormStream, FALSE);
1033   } else {
1034     m_pSingleStream->LoadAllData(pForm->m_pFormStream, FALSE);
1035   }
1036   m_pData = (uint8_t*)m_pSingleStream->GetData();
1037   m_Size = m_pSingleStream->GetSize();
1038   m_Status = ToBeContinued;
1039   m_InternalStage = PAGEPARSE_STAGE_PARSE;
1040   m_CurrentOffset = 0;
1041 }
1042 void CPDF_ContentParser::Continue(IFX_Pause* pPause) {
1043   int steps = 0;
1044   while (m_Status == ToBeContinued) {
1045     if (m_InternalStage == PAGEPARSE_STAGE_GETCONTENT) {
1046       if (m_CurrentOffset == m_nStreams) {
1047         if (m_pStreamArray) {
1048           m_Size = 0;
1049           FX_DWORD i;
1050           for (i = 0; i < m_nStreams; i++) {
1051             FX_DWORD size = m_pStreamArray[i]->GetSize();
1052             if (m_Size + size + 1 <= m_Size) {
1053               m_Status = Done;
1054               return;
1055             }
1056             m_Size += size + 1;
1057           }
1058           m_pData = FX_Alloc(uint8_t, m_Size);
1059           FX_DWORD pos = 0;
1060           for (i = 0; i < m_nStreams; i++) {
1061             FXSYS_memcpy(m_pData + pos, m_pStreamArray[i]->GetData(),
1062                          m_pStreamArray[i]->GetSize());
1063             pos += m_pStreamArray[i]->GetSize() + 1;
1064             m_pData[pos - 1] = ' ';
1065             delete m_pStreamArray[i];
1066           }
1067           FX_Free(m_pStreamArray);
1068           m_pStreamArray = NULL;
1069         } else {
1070           m_pData = (uint8_t*)m_pSingleStream->GetData();
1071           m_Size = m_pSingleStream->GetSize();
1072         }
1073         m_InternalStage = PAGEPARSE_STAGE_PARSE;
1074         m_CurrentOffset = 0;
1075       } else {
1076         CPDF_Array* pContent =
1077             m_pObjects->m_pFormDict->GetArray(FX_BSTRC("Contents"));
1078         m_pStreamArray[m_CurrentOffset] = new CPDF_StreamAcc;
1079         CPDF_Stream* pStreamObj = ToStream(
1080             pContent ? pContent->GetElementValue(m_CurrentOffset) : nullptr);
1081         m_pStreamArray[m_CurrentOffset]->LoadAllData(pStreamObj, FALSE);
1082         m_CurrentOffset++;
1083       }
1084     }
1085     if (m_InternalStage == PAGEPARSE_STAGE_PARSE) {
1086       if (!m_pParser) {
1087         m_pParser = new CPDF_StreamContentParser(
1088             m_pObjects->m_pDocument, m_pObjects->m_pPageResources, nullptr,
1089             nullptr, m_pObjects, m_pObjects->m_pResources, &m_pObjects->m_BBox,
1090             &m_Options, nullptr, 0);
1091         m_pParser->GetCurStates()->m_ColorState.GetModify()->Default();
1092       }
1093       if (m_CurrentOffset >= m_Size) {
1094         m_InternalStage = PAGEPARSE_STAGE_CHECKCLIP;
1095       } else {
1096         m_CurrentOffset +=
1097             m_pParser->Parse(m_pData + m_CurrentOffset,
1098                              m_Size - m_CurrentOffset, PARSE_STEP_LIMIT);
1099       }
1100     }
1101     if (m_InternalStage == PAGEPARSE_STAGE_CHECKCLIP) {
1102       if (m_pType3Char) {
1103         m_pType3Char->m_bColored = m_pParser->IsColored();
1104         m_pType3Char->m_Width =
1105             FXSYS_round(m_pParser->GetType3Data()[0] * 1000);
1106         m_pType3Char->m_BBox.left =
1107             FXSYS_round(m_pParser->GetType3Data()[2] * 1000);
1108         m_pType3Char->m_BBox.bottom =
1109             FXSYS_round(m_pParser->GetType3Data()[3] * 1000);
1110         m_pType3Char->m_BBox.right =
1111             FXSYS_round(m_pParser->GetType3Data()[4] * 1000);
1112         m_pType3Char->m_BBox.top =
1113             FXSYS_round(m_pParser->GetType3Data()[5] * 1000);
1114       }
1115       FX_POSITION pos = m_pObjects->m_ObjectList.GetHeadPosition();
1116       while (pos) {
1117         CPDF_PageObject* pObj =
1118             (CPDF_PageObject*)m_pObjects->m_ObjectList.GetNext(pos);
1119         if (pObj->m_ClipPath.IsNull()) {
1120           continue;
1121         }
1122         if (pObj->m_ClipPath.GetPathCount() != 1) {
1123           continue;
1124         }
1125         if (pObj->m_ClipPath.GetTextCount()) {
1126           continue;
1127         }
1128         CPDF_Path ClipPath = pObj->m_ClipPath.GetPath(0);
1129         if (!ClipPath.IsRect() || pObj->m_Type == PDFPAGE_SHADING) {
1130           continue;
1131         }
1132         CFX_FloatRect old_rect(ClipPath.GetPointX(0), ClipPath.GetPointY(0),
1133                                ClipPath.GetPointX(2), ClipPath.GetPointY(2));
1134         CFX_FloatRect obj_rect(pObj->m_Left, pObj->m_Bottom, pObj->m_Right,
1135                                pObj->m_Top);
1136         if (old_rect.Contains(obj_rect)) {
1137           pObj->m_ClipPath.SetNull();
1138         }
1139       }
1140       m_Status = Done;
1141       return;
1142     }
1143     steps++;
1144     if (pPause && pPause->NeedToPauseNow()) {
1145       break;
1146     }
1147   }
1148 }