78169614bdde09637cf15c5da7810a58559cff93
[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       if (pData) {
443         FX_Free(pData);
444       }
445       FX_DWORD dwSavePos = m_Pos;
446       m_Pos += dwStreamSize;
447       while (1) {
448         FX_DWORD dwPrevPos = m_Pos;
449         CPDF_StreamParser::SyntaxType type = ParseNextElement();
450         if (type == CPDF_StreamParser::EndOfData) {
451           break;
452         }
453         if (type != CPDF_StreamParser::Keyword) {
454           dwStreamSize += m_Pos - dwPrevPos;
455           continue;
456         }
457         if (GetWordSize() == 2 && GetWordBuf()[0] == 'E' &&
458             GetWordBuf()[1] == 'I') {
459           m_Pos = dwPrevPos;
460           break;
461         }
462         dwStreamSize += m_Pos - dwPrevPos;
463       }
464       m_Pos = dwSavePos;
465       pData = FX_Alloc(uint8_t, dwStreamSize);
466       FXSYS_memcpy(pData, m_pBuf + m_Pos, dwStreamSize);
467       m_Pos += dwStreamSize;
468     }
469   }
470   pDict->SetAtInteger(FX_BSTRC("Length"), (int)dwStreamSize);
471   return CPDF_Stream::Create(pData, dwStreamSize, pDict);
472 }
473 #define MAX_WORD_BUFFER 256
474 #define MAX_STRING_LENGTH 32767
475 #define FXDWORD_TRUE FXDWORD_FROM_LSBFIRST(0x65757274)
476 #define FXDWORD_NULL FXDWORD_FROM_LSBFIRST(0x6c6c756e)
477 #define FXDWORD_FALS FXDWORD_FROM_LSBFIRST(0x736c6166)
478 CPDF_StreamParser::SyntaxType CPDF_StreamParser::ParseNextElement() {
479   if (m_pLastObj) {
480     m_pLastObj->Release();
481     m_pLastObj = NULL;
482   }
483   m_WordSize = 0;
484   FX_BOOL bIsNumber = TRUE;
485   if (m_Pos >= m_Size) {
486     return EndOfData;
487   }
488   int ch = m_pBuf[m_Pos++];
489   int type = PDF_CharType[ch];
490   while (1) {
491     while (type == 'W') {
492       if (m_Size <= m_Pos) {
493         return EndOfData;
494       }
495       ch = m_pBuf[m_Pos++];
496       type = PDF_CharType[ch];
497     }
498     if (ch != '%') {
499       break;
500     }
501     while (1) {
502       if (m_Size <= m_Pos) {
503         return EndOfData;
504       }
505       ch = m_pBuf[m_Pos++];
506       if (ch == '\r' || ch == '\n') {
507         break;
508       }
509     }
510     type = PDF_CharType[ch];
511   }
512   if (type == 'D' && ch != '/') {
513     m_Pos--;
514     m_pLastObj = ReadNextObject();
515     return Others;
516   }
517   while (1) {
518     if (m_WordSize < MAX_WORD_BUFFER) {
519       m_WordBuffer[m_WordSize++] = ch;
520     }
521     if (type != 'N') {
522       bIsNumber = FALSE;
523     }
524     if (m_Size <= m_Pos) {
525       break;
526     }
527     ch = m_pBuf[m_Pos++];
528     type = PDF_CharType[ch];
529     if (type == 'D' || type == 'W') {
530       m_Pos--;
531       break;
532     }
533   }
534   m_WordBuffer[m_WordSize] = 0;
535   if (bIsNumber) {
536     return Number;
537   }
538   if (m_WordBuffer[0] == '/') {
539     return Name;
540   }
541   if (m_WordSize == 4) {
542     if (*(FX_DWORD*)m_WordBuffer == FXDWORD_TRUE) {
543       m_pLastObj = CPDF_Boolean::Create(TRUE);
544       return Others;
545     }
546     if (*(FX_DWORD*)m_WordBuffer == FXDWORD_NULL) {
547       m_pLastObj = CPDF_Null::Create();
548       return Others;
549     }
550   } else if (m_WordSize == 5) {
551     if (*(FX_DWORD*)m_WordBuffer == FXDWORD_FALS && m_WordBuffer[4] == 'e') {
552       m_pLastObj = CPDF_Boolean::Create(FALSE);
553       return Others;
554     }
555   }
556   return Keyword;
557 }
558 void CPDF_StreamParser::SkipPathObject() {
559   FX_DWORD command_startpos = m_Pos;
560   if (m_Pos >= m_Size) {
561     return;
562   }
563   int ch = m_pBuf[m_Pos++];
564   int type = PDF_CharType[ch];
565   while (1) {
566     while (type == 'W') {
567       if (m_Pos >= m_Size) {
568         return;
569       }
570       ch = m_pBuf[m_Pos++];
571       type = PDF_CharType[ch];
572     }
573     if (type != 'N') {
574       m_Pos = command_startpos;
575       return;
576     }
577     while (1) {
578       while (type != 'W') {
579         if (m_Pos >= m_Size) {
580           return;
581         }
582         ch = m_pBuf[m_Pos++];
583         type = PDF_CharType[ch];
584       }
585       while (type == 'W') {
586         if (m_Pos >= m_Size) {
587           return;
588         }
589         ch = m_pBuf[m_Pos++];
590         type = PDF_CharType[ch];
591       }
592       if (type == 'N') {
593         continue;
594       }
595       FX_DWORD op_startpos = m_Pos - 1;
596       while (type != 'W' && type != 'D') {
597         if (m_Pos >= m_Size) {
598           return;
599         }
600         ch = m_pBuf[m_Pos++];
601         type = PDF_CharType[ch];
602       }
603       if (m_Pos - op_startpos == 2) {
604         int op = m_pBuf[op_startpos];
605         if (op == 'm' || op == 'l' || op == 'c' || op == 'v' || op == 'y') {
606           command_startpos = m_Pos;
607           break;
608         }
609       } else if (m_Pos - op_startpos == 3) {
610         if (m_pBuf[op_startpos] == 'r' && m_pBuf[op_startpos + 1] == 'e') {
611           command_startpos = m_Pos;
612           break;
613         }
614       }
615       m_Pos = command_startpos;
616       return;
617     }
618   }
619 }
620 CPDF_Object* CPDF_StreamParser::ReadNextObject(FX_BOOL bAllowNestedArray,
621                                                FX_BOOL bInArray) {
622   FX_BOOL bIsNumber;
623   GetNextWord(bIsNumber);
624   if (m_WordSize == 0) {
625     return NULL;
626   }
627   if (bIsNumber) {
628     m_WordBuffer[m_WordSize] = 0;
629     return CPDF_Number::Create(CFX_ByteStringC(m_WordBuffer, m_WordSize));
630   }
631   int first_char = m_WordBuffer[0];
632   if (first_char == '/') {
633     return CPDF_Name::Create(
634         PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1)));
635   }
636   if (first_char == '(') {
637     return CPDF_String::Create(ReadString());
638   }
639   if (first_char == '<') {
640     if (m_WordSize == 1) {
641       return CPDF_String::Create(ReadHexString(), TRUE);
642     }
643     CPDF_Dictionary* pDict = CPDF_Dictionary::Create();
644     while (1) {
645       GetNextWord(bIsNumber);
646       if (m_WordSize == 0) {
647         pDict->Release();
648         return NULL;
649       }
650       if (m_WordSize == 2 && m_WordBuffer[0] == '>') {
651         break;
652       }
653       if (m_WordBuffer[0] != '/') {
654         pDict->Release();
655         return NULL;
656       }
657       CFX_ByteString key =
658           PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1));
659       CPDF_Object* pObj = ReadNextObject(TRUE);
660       if (pObj == NULL) {
661         if (pDict) {
662           pDict->Release();
663         }
664         return NULL;
665       }
666       if (!key.IsEmpty()) {
667         pDict->SetAt(key, pObj);
668       } else {
669         pObj->Release();
670       }
671     }
672     return pDict;
673   }
674   if (first_char == '[') {
675     if (!bAllowNestedArray && bInArray) {
676       return NULL;
677     }
678     CPDF_Array* pArray = CPDF_Array::Create();
679     while (1) {
680       CPDF_Object* pObj = ReadNextObject(bAllowNestedArray, TRUE);
681       if (pObj == NULL) {
682         if (m_WordSize == 0 || m_WordBuffer[0] == ']') {
683           return pArray;
684         }
685         if (m_WordBuffer[0] == '[') {
686           continue;
687         }
688       } else {
689         pArray->Add(pObj);
690       }
691     }
692   }
693   if (m_WordSize == 4) {
694     if (*(FX_DWORD*)m_WordBuffer == FXDWORD_TRUE) {
695       return CPDF_Boolean::Create(TRUE);
696     }
697     if (*(FX_DWORD*)m_WordBuffer == FXDWORD_NULL) {
698       return CPDF_Null::Create();
699     }
700   } else if (m_WordSize == 5) {
701     if (*(FX_DWORD*)m_WordBuffer == FXDWORD_FALS && m_WordBuffer[4] == 'e') {
702       return CPDF_Boolean::Create(FALSE);
703     }
704   }
705   return NULL;
706 }
707 void CPDF_StreamParser::GetNextWord(FX_BOOL& bIsNumber) {
708   m_WordSize = 0;
709   bIsNumber = TRUE;
710   if (m_Size <= m_Pos) {
711     return;
712   }
713   int ch = m_pBuf[m_Pos++];
714   int type = PDF_CharType[ch];
715   while (1) {
716     while (type == 'W') {
717       if (m_Size <= m_Pos) {
718         return;
719       }
720       ch = m_pBuf[m_Pos++];
721       type = PDF_CharType[ch];
722     }
723     if (ch != '%') {
724       break;
725     }
726     while (1) {
727       if (m_Size <= m_Pos) {
728         return;
729       }
730       ch = m_pBuf[m_Pos++];
731       if (ch == '\r' || ch == '\n') {
732         break;
733       }
734     }
735     type = PDF_CharType[ch];
736   }
737   if (type == 'D') {
738     bIsNumber = FALSE;
739     m_WordBuffer[m_WordSize++] = ch;
740     if (ch == '/') {
741       while (1) {
742         if (m_Size <= m_Pos) {
743           return;
744         }
745         ch = m_pBuf[m_Pos++];
746         type = PDF_CharType[ch];
747         if (type != 'R' && type != 'N') {
748           m_Pos--;
749           return;
750         }
751         if (m_WordSize < MAX_WORD_BUFFER) {
752           m_WordBuffer[m_WordSize++] = ch;
753         }
754       }
755     } else if (ch == '<') {
756       if (m_Size <= m_Pos) {
757         return;
758       }
759       ch = m_pBuf[m_Pos++];
760       if (ch == '<') {
761         m_WordBuffer[m_WordSize++] = ch;
762       } else {
763         m_Pos--;
764       }
765     } else if (ch == '>') {
766       if (m_Size <= m_Pos) {
767         return;
768       }
769       ch = m_pBuf[m_Pos++];
770       if (ch == '>') {
771         m_WordBuffer[m_WordSize++] = ch;
772       } else {
773         m_Pos--;
774       }
775     }
776     return;
777   }
778   while (1) {
779     if (m_WordSize < MAX_WORD_BUFFER) {
780       m_WordBuffer[m_WordSize++] = ch;
781     }
782     if (type != 'N') {
783       bIsNumber = FALSE;
784     }
785     if (m_Size <= m_Pos) {
786       return;
787     }
788     ch = m_pBuf[m_Pos++];
789     type = PDF_CharType[ch];
790     if (type == 'D' || type == 'W') {
791       m_Pos--;
792       break;
793     }
794   }
795 }
796 CFX_ByteString CPDF_StreamParser::ReadString() {
797   if (m_Size <= m_Pos) {
798     return CFX_ByteString();
799   }
800   int ch = m_pBuf[m_Pos++];
801   CFX_ByteTextBuf buf;
802   int parlevel = 0;
803   int status = 0, iEscCode = 0;
804   while (1) {
805     switch (status) {
806       case 0:
807         if (ch == ')') {
808           if (parlevel == 0) {
809             if (buf.GetLength() > MAX_STRING_LENGTH) {
810               return CFX_ByteString(buf.GetBuffer(), MAX_STRING_LENGTH);
811             }
812             return buf.GetByteString();
813           }
814           parlevel--;
815           buf.AppendChar(')');
816         } else if (ch == '(') {
817           parlevel++;
818           buf.AppendChar('(');
819         } else if (ch == '\\') {
820           status = 1;
821         } else {
822           buf.AppendChar((char)ch);
823         }
824         break;
825       case 1:
826         if (ch >= '0' && ch <= '7') {
827           iEscCode = ch - '0';
828           status = 2;
829           break;
830         }
831         if (ch == 'n') {
832           buf.AppendChar('\n');
833         } else if (ch == 'r') {
834           buf.AppendChar('\r');
835         } else if (ch == 't') {
836           buf.AppendChar('\t');
837         } else if (ch == 'b') {
838           buf.AppendChar('\b');
839         } else if (ch == 'f') {
840           buf.AppendChar('\f');
841         } else if (ch == '\r') {
842           status = 4;
843           break;
844         } else if (ch == '\n') {
845         } else {
846           buf.AppendChar(ch);
847         }
848         status = 0;
849         break;
850       case 2:
851         if (ch >= '0' && ch <= '7') {
852           iEscCode = iEscCode * 8 + ch - '0';
853           status = 3;
854         } else {
855           buf.AppendChar(iEscCode);
856           status = 0;
857           continue;
858         }
859         break;
860       case 3:
861         if (ch >= '0' && ch <= '7') {
862           iEscCode = iEscCode * 8 + ch - '0';
863           buf.AppendChar(iEscCode);
864           status = 0;
865         } else {
866           buf.AppendChar(iEscCode);
867           status = 0;
868           continue;
869         }
870         break;
871       case 4:
872         status = 0;
873         if (ch != '\n') {
874           continue;
875         }
876         break;
877     }
878     if (m_Size <= m_Pos) {
879       break;
880     }
881     ch = m_pBuf[m_Pos++];
882   }
883   if (m_Size > m_Pos) {
884     ch = m_pBuf[m_Pos++];
885   }
886   if (buf.GetLength() > MAX_STRING_LENGTH) {
887     return CFX_ByteString(buf.GetBuffer(), MAX_STRING_LENGTH);
888   }
889   return buf.GetByteString();
890 }
891 CFX_ByteString CPDF_StreamParser::ReadHexString() {
892   if (m_Size <= m_Pos) {
893     return CFX_ByteString();
894   }
895   int ch = m_pBuf[m_Pos++];
896   CFX_ByteTextBuf buf;
897   FX_BOOL bFirst = TRUE;
898   int code = 0;
899   while (1) {
900     if (ch == '>') {
901       break;
902     }
903     if (ch >= '0' && ch <= '9') {
904       if (bFirst) {
905         code = (ch - '0') * 16;
906       } else {
907         code += ch - '0';
908         buf.AppendChar((char)code);
909       }
910       bFirst = !bFirst;
911     } else if (ch >= 'A' && ch <= 'F') {
912       if (bFirst) {
913         code = (ch - 'A' + 10) * 16;
914       } else {
915         code += ch - 'A' + 10;
916         buf.AppendChar((char)code);
917       }
918       bFirst = !bFirst;
919     } else if (ch >= 'a' && ch <= 'f') {
920       if (bFirst) {
921         code = (ch - 'a' + 10) * 16;
922       } else {
923         code += ch - 'a' + 10;
924         buf.AppendChar((char)code);
925       }
926       bFirst = !bFirst;
927     }
928     if (m_Size <= m_Pos) {
929       break;
930     }
931     ch = m_pBuf[m_Pos++];
932   }
933   if (!bFirst) {
934     buf.AppendChar((char)code);
935   }
936   if (buf.GetLength() > MAX_STRING_LENGTH) {
937     return CFX_ByteString(buf.GetBuffer(), MAX_STRING_LENGTH);
938   }
939   return buf.GetByteString();
940 }
941 #define PAGEPARSE_STAGE_GETCONTENT 1
942 #define PAGEPARSE_STAGE_PARSE 2
943 #define PAGEPARSE_STAGE_CHECKCLIP 3
944 CPDF_ContentParser::CPDF_ContentParser() {
945   m_pParser = NULL;
946   m_pStreamArray = NULL;
947   m_pSingleStream = NULL;
948   m_pData = NULL;
949   m_Status = Ready;
950   m_pType3Char = NULL;
951 }
952 CPDF_ContentParser::~CPDF_ContentParser() {
953   Clear();
954 }
955 void CPDF_ContentParser::Clear() {
956   delete m_pParser;
957   delete m_pSingleStream;
958   if (m_pStreamArray) {
959     for (FX_DWORD i = 0; i < m_nStreams; i++)
960       delete m_pStreamArray[i];
961     FX_Free(m_pStreamArray);
962   }
963   if (m_pData && m_pSingleStream == NULL) {
964     FX_Free((void*)m_pData);
965   }
966   m_pParser = NULL;
967   m_pStreamArray = NULL;
968   m_pSingleStream = NULL;
969   m_pData = NULL;
970   m_Status = Ready;
971 }
972 void CPDF_ContentParser::Start(CPDF_Page* pPage, CPDF_ParseOptions* pOptions) {
973   if (m_Status != Ready || pPage == NULL || pPage->m_pDocument == NULL ||
974       pPage->m_pFormDict == NULL) {
975     m_Status = Done;
976     return;
977   }
978   m_pObjects = pPage;
979   m_bForm = FALSE;
980   if (pOptions) {
981     m_Options = *pOptions;
982   }
983   m_Status = ToBeContinued;
984   m_InternalStage = PAGEPARSE_STAGE_GETCONTENT;
985   m_CurrentOffset = 0;
986   CPDF_Object* pContent =
987       pPage->m_pFormDict->GetElementValue(FX_BSTRC("Contents"));
988   if (pContent == NULL) {
989     m_Status = Done;
990     return;
991   }
992   if (pContent->GetType() == PDFOBJ_STREAM) {
993     m_nStreams = 0;
994     m_pSingleStream = new CPDF_StreamAcc;
995     m_pSingleStream->LoadAllData((CPDF_Stream*)pContent, FALSE);
996   } else if (pContent->GetType() == PDFOBJ_ARRAY) {
997     CPDF_Array* pArray = (CPDF_Array*)pContent;
998     m_nStreams = pArray->GetCount();
999     if (m_nStreams == 0) {
1000       m_Status = Done;
1001       return;
1002     }
1003     m_pStreamArray = FX_Alloc(CPDF_StreamAcc*, m_nStreams);
1004   } else {
1005     m_Status = Done;
1006     return;
1007   }
1008 }
1009 void CPDF_ContentParser::Start(CPDF_Form* pForm,
1010                                CPDF_AllStates* pGraphicStates,
1011                                CFX_AffineMatrix* pParentMatrix,
1012                                CPDF_Type3Char* pType3Char,
1013                                CPDF_ParseOptions* pOptions,
1014                                int level) {
1015   m_pType3Char = pType3Char;
1016   m_pObjects = pForm;
1017   m_bForm = TRUE;
1018   CFX_AffineMatrix form_matrix =
1019       pForm->m_pFormDict->GetMatrix(FX_BSTRC("Matrix"));
1020   if (pGraphicStates) {
1021     form_matrix.Concat(pGraphicStates->m_CTM);
1022   }
1023   CPDF_Array* pBBox = pForm->m_pFormDict->GetArray(FX_BSTRC("BBox"));
1024   CFX_FloatRect form_bbox;
1025   CPDF_Path ClipPath;
1026   if (pBBox) {
1027     form_bbox = pBBox->GetRect();
1028     ClipPath.New();
1029     ClipPath.AppendRect(form_bbox.left, form_bbox.bottom, form_bbox.right,
1030                         form_bbox.top);
1031     ClipPath.Transform(&form_matrix);
1032     if (pParentMatrix) {
1033       ClipPath.Transform(pParentMatrix);
1034     }
1035     form_bbox.Transform(&form_matrix);
1036     if (pParentMatrix) {
1037       form_bbox.Transform(pParentMatrix);
1038     }
1039   }
1040   CPDF_Dictionary* pResources =
1041       pForm->m_pFormDict->GetDict(FX_BSTRC("Resources"));
1042   m_pParser = new CPDF_StreamContentParser(
1043       pForm->m_pDocument, pForm->m_pPageResources, pForm->m_pResources,
1044       pParentMatrix, pForm, pResources, &form_bbox, pOptions, pGraphicStates,
1045       level);
1046
1047   m_pParser->GetCurStates()->m_CTM = form_matrix;
1048   m_pParser->GetCurStates()->m_ParentMatrix = form_matrix;
1049   if (ClipPath.NotNull()) {
1050     m_pParser->GetCurStates()->m_ClipPath.AppendPath(ClipPath, FXFILL_WINDING,
1051                                                      TRUE);
1052   }
1053   if (pForm->m_Transparency & PDFTRANS_GROUP) {
1054     CPDF_GeneralStateData* pData =
1055         m_pParser->GetCurStates()->m_GeneralState.GetModify();
1056     pData->m_BlendType = FXDIB_BLEND_NORMAL;
1057     pData->m_StrokeAlpha = 1.0f;
1058     pData->m_FillAlpha = 1.0f;
1059     pData->m_pSoftMask = NULL;
1060   }
1061   m_nStreams = 0;
1062   m_pSingleStream = new CPDF_StreamAcc;
1063   if (pForm->m_pDocument) {
1064     m_pSingleStream->LoadAllData(pForm->m_pFormStream, FALSE);
1065   } else {
1066     m_pSingleStream->LoadAllData(pForm->m_pFormStream, FALSE);
1067   }
1068   m_pData = (uint8_t*)m_pSingleStream->GetData();
1069   m_Size = m_pSingleStream->GetSize();
1070   m_Status = ToBeContinued;
1071   m_InternalStage = PAGEPARSE_STAGE_PARSE;
1072   m_CurrentOffset = 0;
1073 }
1074 void CPDF_ContentParser::Continue(IFX_Pause* pPause) {
1075   int steps = 0;
1076   while (m_Status == ToBeContinued) {
1077     if (m_InternalStage == PAGEPARSE_STAGE_GETCONTENT) {
1078       if (m_CurrentOffset == m_nStreams) {
1079         if (m_pStreamArray) {
1080           m_Size = 0;
1081           FX_DWORD i;
1082           for (i = 0; i < m_nStreams; i++) {
1083             FX_DWORD size = m_pStreamArray[i]->GetSize();
1084             if (m_Size + size + 1 <= m_Size) {
1085               m_Status = Done;
1086               return;
1087             }
1088             m_Size += size + 1;
1089           }
1090           m_pData = FX_Alloc(uint8_t, m_Size);
1091           FX_DWORD pos = 0;
1092           for (i = 0; i < m_nStreams; i++) {
1093             FXSYS_memcpy(m_pData + pos, m_pStreamArray[i]->GetData(),
1094                          m_pStreamArray[i]->GetSize());
1095             pos += m_pStreamArray[i]->GetSize() + 1;
1096             m_pData[pos - 1] = ' ';
1097             delete m_pStreamArray[i];
1098           }
1099           FX_Free(m_pStreamArray);
1100           m_pStreamArray = NULL;
1101         } else {
1102           m_pData = (uint8_t*)m_pSingleStream->GetData();
1103           m_Size = m_pSingleStream->GetSize();
1104         }
1105         m_InternalStage = PAGEPARSE_STAGE_PARSE;
1106         m_CurrentOffset = 0;
1107       } else {
1108         CPDF_Array* pContent =
1109             m_pObjects->m_pFormDict->GetArray(FX_BSTRC("Contents"));
1110         m_pStreamArray[m_CurrentOffset] = new CPDF_StreamAcc;
1111         CPDF_Stream* pStreamObj =
1112             (CPDF_Stream*)(pContent ? pContent->GetElementValue(m_CurrentOffset)
1113                                     : NULL);
1114         m_pStreamArray[m_CurrentOffset]->LoadAllData(pStreamObj, FALSE);
1115         m_CurrentOffset++;
1116       }
1117     }
1118     if (m_InternalStage == PAGEPARSE_STAGE_PARSE) {
1119       if (!m_pParser) {
1120         m_pParser = new CPDF_StreamContentParser(
1121             m_pObjects->m_pDocument, m_pObjects->m_pPageResources, nullptr,
1122             nullptr, m_pObjects, m_pObjects->m_pResources, &m_pObjects->m_BBox,
1123             &m_Options, nullptr, 0);
1124         m_pParser->GetCurStates()->m_ColorState.GetModify()->Default();
1125       }
1126       if (m_CurrentOffset >= m_Size) {
1127         m_InternalStage = PAGEPARSE_STAGE_CHECKCLIP;
1128       } else {
1129         m_CurrentOffset +=
1130             m_pParser->Parse(m_pData + m_CurrentOffset,
1131                              m_Size - m_CurrentOffset, PARSE_STEP_LIMIT);
1132         if (m_pParser->ShouldAbort()) {
1133           m_InternalStage = PAGEPARSE_STAGE_CHECKCLIP;
1134           continue;
1135         }
1136       }
1137     }
1138     if (m_InternalStage == PAGEPARSE_STAGE_CHECKCLIP) {
1139       if (m_pType3Char) {
1140         m_pType3Char->m_bColored = m_pParser->IsColored();
1141         m_pType3Char->m_Width =
1142             FXSYS_round(m_pParser->GetType3Data()[0] * 1000);
1143         m_pType3Char->m_BBox.left =
1144             FXSYS_round(m_pParser->GetType3Data()[2] * 1000);
1145         m_pType3Char->m_BBox.bottom =
1146             FXSYS_round(m_pParser->GetType3Data()[3] * 1000);
1147         m_pType3Char->m_BBox.right =
1148             FXSYS_round(m_pParser->GetType3Data()[4] * 1000);
1149         m_pType3Char->m_BBox.top =
1150             FXSYS_round(m_pParser->GetType3Data()[5] * 1000);
1151       }
1152       FX_POSITION pos = m_pObjects->m_ObjectList.GetHeadPosition();
1153       while (pos) {
1154         CPDF_PageObject* pObj =
1155             (CPDF_PageObject*)m_pObjects->m_ObjectList.GetNext(pos);
1156         if (pObj->m_ClipPath.IsNull()) {
1157           continue;
1158         }
1159         if (pObj->m_ClipPath.GetPathCount() != 1) {
1160           continue;
1161         }
1162         if (pObj->m_ClipPath.GetTextCount()) {
1163           continue;
1164         }
1165         CPDF_Path ClipPath = pObj->m_ClipPath.GetPath(0);
1166         if (!ClipPath.IsRect() || pObj->m_Type == PDFPAGE_SHADING) {
1167           continue;
1168         }
1169         CFX_FloatRect old_rect(ClipPath.GetPointX(0), ClipPath.GetPointY(0),
1170                                ClipPath.GetPointX(2), ClipPath.GetPointY(2));
1171         CFX_FloatRect obj_rect(pObj->m_Left, pObj->m_Bottom, pObj->m_Right,
1172                                pObj->m_Top);
1173         if (old_rect.Contains(obj_rect)) {
1174           pObj->m_ClipPath.SetNull();
1175         }
1176       }
1177       m_Status = Done;
1178       return;
1179     }
1180     steps++;
1181     if (pPause && pPause->NeedToPauseNow()) {
1182       break;
1183     }
1184   }
1185 }