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