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