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