Don't leave dangling pointer to out-of-scope local in CPDF_StreamContentParser::Parse.
[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 extern const FX_LPCSTR _PDF_OpCharType =
13     "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII"
14     "IIVIIIIVIIVIIIIIVVIIIIIIIIIIIIII"
15     "IIVVVVVVIVVVVVVIVVVVVIIVVIIIIIII"
16     "IIVVVVVVVVVVVVVVIVVVIIVVIVVIIIII"
17     "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII"
18     "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII"
19     "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII"
20     "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII";
21 FX_BOOL _PDF_HasInvalidOpChar(FX_LPCSTR op)
22 {
23     if(!op) {
24         return FALSE;
25     }
26     FX_BYTE 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(FX_LPCBYTE 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((FX_LPCSTR)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((FX_LPCSTR)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] = {0};
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 FX_BYTE* 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, FX_LPBYTE& 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_size = pitch * height;
266     dest_buf = FX_Alloc( FX_BYTE, dest_size);
267     for (int row = 0; row < height; row ++) {
268         FX_LPBYTE pLine = pDecoder->GetScanline(row);
269         if (pLine == NULL) {
270             break;
271         }
272         FXSYS_memcpy32(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(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height,
279         const CPDF_Dictionary* pParams);
280 FX_DWORD _A85Decode(const FX_BYTE* src_buf, FX_DWORD src_size, FX_LPBYTE& dest_buf, FX_DWORD& dest_size);
281 FX_DWORD _HexDecode(const FX_BYTE* src_buf, FX_DWORD src_size, FX_LPBYTE& dest_buf, FX_DWORD& dest_size);
282 FX_DWORD FPDFAPI_FlateOrLZWDecode(FX_BOOL bLZW, const FX_BYTE* src_buf, FX_DWORD src_size, CPDF_Dictionary* pParams,
283                                   FX_DWORD estimated_size, FX_LPBYTE& dest_buf, FX_DWORD& dest_size);
284 FX_DWORD PDF_DecodeInlineStream(const FX_BYTE* src_buf, FX_DWORD limit,
285                                 int width, int height, CFX_ByteString& decoder,
286                                 CPDF_Dictionary* pParam, FX_LPBYTE& 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     } else if (decoder == FX_BSTRC("ASCII85Decode") || decoder == FX_BSTRC("A85")) {
292         return _A85Decode(src_buf, limit, dest_buf, dest_size);
293     } else if (decoder == FX_BSTRC("ASCIIHexDecode") || decoder == FX_BSTRC("AHx")) {
294         return _HexDecode(src_buf, limit, dest_buf, dest_size);
295     } else if (decoder == FX_BSTRC("FlateDecode") || decoder == FX_BSTRC("Fl")) {
296         return FPDFAPI_FlateOrLZWDecode(FALSE, src_buf, limit, pParam, dest_size, dest_buf, dest_size);
297     } else if (decoder == FX_BSTRC("LZWDecode") || decoder == FX_BSTRC("LZW")) {
298         return FPDFAPI_FlateOrLZWDecode(TRUE, src_buf, limit, pParam, 0, dest_buf, dest_size);
299     } else if (decoder == FX_BSTRC("DCTDecode") || decoder == FX_BSTRC("DCT")) {
300         ICodec_ScanlineDecoder* pDecoder = CPDF_ModuleMgr::Get()->GetJpegModule()->CreateDecoder(
301                                                src_buf, limit, width, height, 0, pParam ? pParam->GetInteger(FX_BSTRC("ColorTransform"), 1) : 1);
302         return _DecodeAllScanlines(pDecoder, dest_buf, dest_size);
303     } else if (decoder == FX_BSTRC("RunLengthDecode") || decoder == FX_BSTRC("RL")) {
304         return RunLengthDecode(src_buf, limit, dest_buf, dest_size);
305     }
306     dest_size = 0;
307     dest_buf = 0;
308     return (FX_DWORD) - 1;
309 }
310 extern const FX_LPCSTR _PDF_CharType;
311 CPDF_Stream* CPDF_StreamParser::ReadInlineStream(CPDF_Document* pDoc, CPDF_Dictionary* pDict, CPDF_Object* pCSObj, FX_BOOL bDecode)
312 {
313     if (m_Pos == m_Size) {
314         return NULL;
315     }
316     if (_PDF_CharType[m_pBuf[m_Pos]] == 'W') {
317         m_Pos ++;
318     }
319     CFX_ByteString Decoder;
320     CPDF_Dictionary* pParam = NULL;
321     CPDF_Object* pFilter = pDict->GetElementValue(FX_BSTRC("Filter"));
322     if (pFilter == NULL) {
323     } else if (pFilter->GetType() == PDFOBJ_ARRAY) {
324         Decoder = ((CPDF_Array*)pFilter)->GetString(0);
325         CPDF_Array* pParams = pDict->GetArray(FX_BSTRC("DecodeParms"));
326         if (pParams) {
327             pParam = pParams->GetDict(0);
328         }
329     } else {
330         Decoder = pFilter->GetString();
331         pParam = pDict->GetDict(FX_BSTRC("DecodeParms"));
332     }
333     FX_DWORD width = pDict->GetInteger(FX_BSTRC("Width"));
334     FX_DWORD height = pDict->GetInteger(FX_BSTRC("Height"));
335     FX_DWORD OrigSize = 0;
336     if (pCSObj != NULL) {
337         FX_DWORD bpc = pDict->GetInteger(FX_BSTRC("BitsPerComponent"));
338         FX_DWORD nComponents = 1;
339         CPDF_ColorSpace* pCS = pDoc->LoadColorSpace(pCSObj);
340         if (pCS == NULL) {
341             nComponents = 3;
342         } else {
343             nComponents = pCS->CountComponents();
344             pDoc->GetPageData()->ReleaseColorSpace(pCSObj);
345         }
346         FX_DWORD pitch = width;
347         if (bpc && pitch > INT_MAX / bpc) {
348             return NULL;
349         }
350         pitch *= bpc;
351         if (nComponents && pitch > INT_MAX / nComponents) {
352             return NULL;
353         }
354         pitch *= nComponents;
355         if (pitch > INT_MAX - 7) {
356             return NULL;
357         }
358         pitch += 7;
359         pitch /= 8;
360         OrigSize = pitch;
361     } else {
362         if (width > INT_MAX - 7) {
363             return NULL;
364         }
365         OrigSize = ((width + 7) / 8);
366     }
367     if (height && OrigSize > INT_MAX / height) {
368         return NULL;
369     }
370     OrigSize *= height;
371     FX_LPBYTE pData = NULL;
372     FX_DWORD dwStreamSize;
373     if (Decoder.IsEmpty()) {
374         if (OrigSize > m_Size - m_Pos) {
375             OrigSize = m_Size - m_Pos;
376         }
377         pData = FX_Alloc(FX_BYTE, OrigSize);
378         FXSYS_memcpy32(pData, m_pBuf + m_Pos, OrigSize);
379         dwStreamSize = OrigSize;
380         m_Pos += OrigSize;
381     } else {
382         FX_DWORD dwDestSize = OrigSize;
383         dwStreamSize = PDF_DecodeInlineStream(m_pBuf + m_Pos, m_Size - m_Pos, width, height, Decoder, pParam,
384                                               pData, dwDestSize);
385         if ((int)dwStreamSize < 0) {
386             return NULL;
387         }
388         if (bDecode) {
389             m_Pos += dwStreamSize;
390             dwStreamSize = dwDestSize;
391             if (pFilter->GetType() == PDFOBJ_ARRAY) {
392                 ((CPDF_Array*)pFilter)->RemoveAt(0);
393                 CPDF_Array* pParams = pDict->GetArray(FX_BSTRC("DecodeParms"));
394                 if (pParams) {
395                     pParams->RemoveAt(0);
396                 }
397             } else {
398                 pDict->RemoveAt(FX_BSTRC("Filter"));
399                 pDict->RemoveAt(FX_BSTRC("DecodeParms"));
400             }
401         } else {
402             if (pData) {
403                 FX_Free(pData);
404             }
405             FX_DWORD dwSavePos = m_Pos;
406             m_Pos += dwStreamSize;
407             while (1) {
408                 FX_DWORD dwPrevPos = m_Pos;
409                 CPDF_StreamParser::SyntaxType type = ParseNextElement();
410                 if (type == CPDF_StreamParser::EndOfData) {
411                     break;
412                 }
413                 if (type != CPDF_StreamParser::Keyword) {
414                     dwStreamSize += m_Pos - dwPrevPos;
415                     continue;
416                 }
417                 if (GetWordSize() == 2 && GetWordBuf()[0] == 'E' &&
418                         GetWordBuf()[1] == 'I') {
419                     m_Pos = dwPrevPos;
420                     break;
421                 }
422                 dwStreamSize += m_Pos - dwPrevPos;
423             }
424             m_Pos = dwSavePos;
425             pData = FX_Alloc(FX_BYTE, dwStreamSize);
426             FXSYS_memcpy32(pData, m_pBuf + m_Pos, dwStreamSize);
427             m_Pos += dwStreamSize;
428         }
429     }
430     pDict->SetAtInteger(FX_BSTRC("Length"), (int)dwStreamSize);
431     return CPDF_Stream::Create(pData, dwStreamSize, pDict);
432 }
433 #define MAX_WORD_BUFFER 256
434 #define MAX_STRING_LENGTH       32767
435 #define FXDWORD_TRUE FXDWORD_FROM_LSBFIRST(0x65757274)
436 #define FXDWORD_NULL FXDWORD_FROM_LSBFIRST(0x6c6c756e)
437 #define FXDWORD_FALS FXDWORD_FROM_LSBFIRST(0x736c6166)
438 CPDF_StreamParser::SyntaxType CPDF_StreamParser::ParseNextElement()
439 {
440     if (m_pLastObj) {
441         m_pLastObj->Release();
442         m_pLastObj = NULL;
443     }
444     m_WordSize = 0;
445     FX_BOOL bIsNumber = TRUE;
446     if (m_Pos >= m_Size) {
447         return EndOfData;
448     }
449     int ch = m_pBuf[m_Pos++];
450     int type = _PDF_CharType[ch];
451     while (1) {
452         while (type == 'W') {
453             if (m_Size <= m_Pos) {
454                 return EndOfData;
455             }
456             ch = m_pBuf[m_Pos++];
457             type = _PDF_CharType[ch];
458         }
459         if (ch != '%') {
460             break;
461         }
462         while (1) {
463             if (m_Size <= m_Pos) {
464                 return EndOfData;
465             }
466             ch = m_pBuf[m_Pos++];
467             if (ch == '\r' || ch == '\n') {
468                 break;
469             }
470         }
471         type = _PDF_CharType[ch];
472     }
473     if (type == 'D' && ch != '/') {
474         m_Pos --;
475         m_pLastObj = ReadNextObject();
476         return Others;
477     }
478     while (1) {
479         if (m_WordSize < MAX_WORD_BUFFER) {
480             m_WordBuffer[m_WordSize++] = ch;
481         }
482         if (type != 'N') {
483             bIsNumber = FALSE;
484         }
485         if (m_Size <= m_Pos) {
486             break;
487         }
488         ch = m_pBuf[m_Pos++];
489         type = _PDF_CharType[ch];
490         if (type == 'D' || type == 'W') {
491             m_Pos --;
492             break;
493         }
494     }
495     m_WordBuffer[m_WordSize] = 0;
496     if (bIsNumber) {
497         return Number;
498     }
499     if (m_WordBuffer[0] == '/') {
500         return Name;
501     }
502     if (m_WordSize == 4) {
503         if (*(FX_DWORD*)m_WordBuffer == FXDWORD_TRUE) {
504             m_pLastObj = CPDF_Boolean::Create(TRUE);
505             return Others;
506         }
507         if (*(FX_DWORD*)m_WordBuffer == FXDWORD_NULL) {
508             m_pLastObj = CPDF_Null::Create();
509             return Others;
510         }
511     } else if (m_WordSize == 5) {
512         if (*(FX_DWORD*)m_WordBuffer == FXDWORD_FALS && m_WordBuffer[4] == 'e') {
513             m_pLastObj = CPDF_Boolean::Create(FALSE);
514             return Others;
515         }
516     }
517     return Keyword;
518 }
519 void CPDF_StreamParser::SkipPathObject()
520 {
521     FX_DWORD command_startpos = m_Pos;
522     if (m_Pos >= m_Size) {
523         return;
524     }
525     int ch = m_pBuf[m_Pos++];
526     int type = _PDF_CharType[ch];
527     while (1) {
528         while (type == 'W') {
529             if (m_Pos >= m_Size) {
530                 return;
531             }
532             ch = m_pBuf[m_Pos++];
533             type = _PDF_CharType[ch];
534         }
535         if (type != 'N') {
536             m_Pos = command_startpos;
537             return;
538         }
539         while (1) {
540             while (type != 'W') {
541                 if (m_Pos >= m_Size) {
542                     return;
543                 }
544                 ch = m_pBuf[m_Pos++];
545                 type = _PDF_CharType[ch];
546             }
547             while (type == 'W') {
548                 if (m_Pos >= m_Size) {
549                     return;
550                 }
551                 ch = m_pBuf[m_Pos++];
552                 type = _PDF_CharType[ch];
553             }
554             if (type == 'N') {
555                 continue;
556             }
557             FX_DWORD op_startpos = m_Pos - 1;
558             while (type != 'W' && type != 'D') {
559                 if (m_Pos >= m_Size) {
560                     return;
561                 }
562                 ch = m_pBuf[m_Pos++];
563                 type = _PDF_CharType[ch];
564             }
565             if (m_Pos - op_startpos == 2) {
566                 int op = m_pBuf[op_startpos];
567                 if (op == 'm' || op == 'l' || op == 'c' || op == 'v' || op == 'y') {
568                     command_startpos = m_Pos;
569                     break;
570                 }
571             } else if (m_Pos - op_startpos == 3) {
572                 if (m_pBuf[op_startpos] == 'r' && m_pBuf[op_startpos + 1] == 'e') {
573                     command_startpos = m_Pos;
574                     break;
575                 }
576             }
577             m_Pos = command_startpos;
578             return;
579         }
580     }
581 }
582 CPDF_Object* CPDF_StreamParser::ReadNextObject(FX_BOOL bAllowNestedArray, FX_BOOL bInArray)
583 {
584     FX_BOOL bIsNumber;
585     GetNextWord(bIsNumber);
586     if (m_WordSize == 0) {
587         return NULL;
588     }
589     if (bIsNumber) {
590         m_WordBuffer[m_WordSize] = 0;
591         return CPDF_Number::Create(CFX_ByteStringC(m_WordBuffer, m_WordSize));
592     }
593     int first_char = m_WordBuffer[0];
594     if (first_char == '/') {
595         return CPDF_Name::Create(PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1)));
596     }
597     if (first_char == '(') {
598         return CPDF_String::Create(ReadString());
599     }
600     if (first_char == '<') {
601         if (m_WordSize == 1) {
602             return CPDF_String::Create(ReadHexString(), TRUE);
603         }
604         CPDF_Dictionary* pDict = CPDF_Dictionary::Create();
605         while (1) {
606             GetNextWord(bIsNumber);
607             if (m_WordSize == 0) {
608                 pDict->Release();
609                 return NULL;
610             }
611             if (m_WordSize == 2 && m_WordBuffer[0] == '>') {
612                 break;
613             }
614             if (m_WordBuffer[0] != '/') {
615                 pDict->Release();
616                 return NULL;
617             }
618             CFX_ByteString key = PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1));
619             CPDF_Object* pObj = ReadNextObject(TRUE);
620             if (pObj == NULL) {
621                 if (pDict) {
622                     pDict->Release();
623                 }
624                 return NULL;
625             }
626             if (!key.IsEmpty()) {
627                 pDict->SetAt(key, pObj);
628             } else {
629                 pObj->Release();
630             }
631         }
632         return pDict;
633     }
634     if (first_char == '[') {
635         if (!bAllowNestedArray && bInArray) {
636             return NULL;
637         }
638         CPDF_Array* pArray = CPDF_Array::Create();
639         while (1) {
640             CPDF_Object* pObj = ReadNextObject(bAllowNestedArray, TRUE);
641             if (pObj == NULL) {
642                 if (m_WordSize == 0 || m_WordBuffer[0] == ']') {
643                     return pArray;
644                 }
645                 if (m_WordBuffer[0] == '[') {
646                     continue;
647                 }
648             } else {
649                 pArray->Add(pObj);
650             }
651         }
652     }
653     if (m_WordSize == 4) {
654         if (*(FX_DWORD*)m_WordBuffer == FXDWORD_TRUE) {
655             return CPDF_Boolean::Create(TRUE);
656         }
657         if (*(FX_DWORD*)m_WordBuffer == FXDWORD_NULL) {
658             return CPDF_Null::Create();
659         }
660     } else if (m_WordSize == 5) {
661         if (*(FX_DWORD*)m_WordBuffer == FXDWORD_FALS && m_WordBuffer[4] == 'e') {
662             return CPDF_Boolean::Create(FALSE);
663         }
664     }
665     return NULL;
666 }
667 void CPDF_StreamParser::GetNextWord(FX_BOOL& bIsNumber)
668 {
669     m_WordSize = 0;
670     bIsNumber = TRUE;
671     if (m_Size <= m_Pos) {
672         return;
673     }
674     int ch = m_pBuf[m_Pos++];
675     int type = _PDF_CharType[ch];
676     while (1) {
677         while (type == 'W') {
678             if (m_Size <= m_Pos) {
679                 return;
680             }
681             ch = m_pBuf[m_Pos++];
682             type = _PDF_CharType[ch];
683         }
684         if (ch != '%') {
685             break;
686         }
687         while (1) {
688             if (m_Size <= m_Pos) {
689                 return;
690             }
691             ch = m_pBuf[m_Pos++];
692             if (ch == '\r' || ch == '\n') {
693                 break;
694             }
695         }
696         type = _PDF_CharType[ch];
697     }
698     if (type == 'D') {
699         bIsNumber = FALSE;
700         m_WordBuffer[m_WordSize++] = ch;
701         if (ch == '/') {
702             while (1) {
703                 if (m_Size <= m_Pos) {
704                     return;
705                 }
706                 ch = m_pBuf[m_Pos++];
707                 type = _PDF_CharType[ch];
708                 if (type != 'R' && type != 'N') {
709                     m_Pos --;
710                     return;
711                 }
712                 if (m_WordSize < MAX_WORD_BUFFER) {
713                     m_WordBuffer[m_WordSize++] = ch;
714                 }
715             }
716         } else if (ch == '<') {
717             if (m_Size <= m_Pos) {
718                 return;
719             }
720             ch = m_pBuf[m_Pos++];
721             if (ch == '<') {
722                 m_WordBuffer[m_WordSize++] = ch;
723             } else {
724                 m_Pos --;
725             }
726         } else if (ch == '>') {
727             if (m_Size <= m_Pos) {
728                 return;
729             }
730             ch = m_pBuf[m_Pos++];
731             if (ch == '>') {
732                 m_WordBuffer[m_WordSize++] = ch;
733             } else {
734                 m_Pos --;
735             }
736         }
737         return;
738     }
739     while (1) {
740         if (m_WordSize < MAX_WORD_BUFFER) {
741             m_WordBuffer[m_WordSize++] = ch;
742         }
743         if (type != 'N') {
744             bIsNumber = FALSE;
745         }
746         if (m_Size <= m_Pos) {
747             return;
748         }
749         ch = m_pBuf[m_Pos++];
750         type = _PDF_CharType[ch];
751         if (type == 'D' || type == 'W') {
752             m_Pos --;
753             break;
754         }
755     }
756 }
757 CFX_ByteString CPDF_StreamParser::ReadString()
758 {
759     if (m_Size <= m_Pos) {
760         return CFX_ByteString();
761     }
762     int ch = m_pBuf[m_Pos++];
763     CFX_ByteTextBuf buf;
764     int parlevel = 0;
765     int status = 0, iEscCode = 0;
766     while (1) {
767         switch (status) {
768             case 0:
769                 if (ch == ')') {
770                     if (parlevel == 0) {
771                         if (buf.GetLength() > MAX_STRING_LENGTH) {
772                             return CFX_ByteString(buf.GetBuffer(), MAX_STRING_LENGTH);
773                         }
774                         return buf.GetByteString();
775                     }
776                     parlevel --;
777                     buf.AppendChar(')');
778                 } else if (ch == '(') {
779                     parlevel ++;
780                     buf.AppendChar('(');
781                 } else if (ch == '\\') {
782                     status = 1;
783                 } else {
784                     buf.AppendChar((char)ch);
785                 }
786                 break;
787             case 1:
788                 if (ch >= '0' && ch <= '7') {
789                     iEscCode = ch - '0';
790                     status = 2;
791                     break;
792                 }
793                 if (ch == 'n') {
794                     buf.AppendChar('\n');
795                 } else if (ch == 'r') {
796                     buf.AppendChar('\r');
797                 } else if (ch == 't') {
798                     buf.AppendChar('\t');
799                 } else if (ch == 'b') {
800                     buf.AppendChar('\b');
801                 } else if (ch == 'f') {
802                     buf.AppendChar('\f');
803                 } else if (ch == '\r') {
804                     status = 4;
805                     break;
806                 } else if (ch == '\n') {
807                 } else {
808                     buf.AppendChar(ch);
809                 }
810                 status = 0;
811                 break;
812             case 2:
813                 if (ch >= '0' && ch <= '7') {
814                     iEscCode = iEscCode * 8 + ch - '0';
815                     status = 3;
816                 } else {
817                     buf.AppendChar(iEscCode);
818                     status = 0;
819                     continue;
820                 }
821                 break;
822             case 3:
823                 if (ch >= '0' && ch <= '7') {
824                     iEscCode = iEscCode * 8 + ch - '0';
825                     buf.AppendChar(iEscCode);
826                     status = 0;
827                 } else {
828                     buf.AppendChar(iEscCode);
829                     status = 0;
830                     continue;
831                 }
832                 break;
833             case 4:
834                 status = 0;
835                 if (ch != '\n') {
836                     continue;
837                 }
838                 break;
839         }
840         if (m_Size <= m_Pos) {
841             break;
842         }
843         ch = m_pBuf[m_Pos++];
844     }
845     if (m_Size > m_Pos) {
846         ch = m_pBuf[m_Pos++];
847     }
848     if (buf.GetLength() > MAX_STRING_LENGTH) {
849         return CFX_ByteString(buf.GetBuffer(), MAX_STRING_LENGTH);
850     }
851     return buf.GetByteString();
852 }
853 CFX_ByteString CPDF_StreamParser::ReadHexString()
854 {
855     if (m_Size <= m_Pos) {
856         return CFX_ByteString();
857     }
858     int ch = m_pBuf[m_Pos++];
859     CFX_ByteTextBuf buf;
860     FX_BOOL bFirst = TRUE;
861     int code = 0;
862     while (1) {
863         if (ch == '>') {
864             break;
865         }
866         if (ch >= '0' && ch <= '9') {
867             if (bFirst) {
868                 code = (ch - '0') * 16;
869             } else {
870                 code += ch - '0';
871                 buf.AppendChar((char)code);
872             }
873             bFirst = !bFirst;
874         } else if (ch >= 'A' && ch <= 'F') {
875             if (bFirst) {
876                 code = (ch - 'A' + 10) * 16;
877             } else {
878                 code += ch - 'A' + 10;
879                 buf.AppendChar((char)code);
880             }
881             bFirst = !bFirst;
882         } else if (ch >= 'a' && ch <= 'f') {
883             if (bFirst) {
884                 code = (ch - 'a' + 10) * 16;
885             } else {
886                 code += ch - 'a' + 10;
887                 buf.AppendChar((char)code);
888             }
889             bFirst = !bFirst;
890         }
891         if (m_Size <= m_Pos) {
892             break;
893         }
894         ch = m_pBuf[m_Pos++];
895     }
896     if (!bFirst) {
897         buf.AppendChar((char)code);
898     }
899     if (buf.GetLength() > MAX_STRING_LENGTH) {
900         return CFX_ByteString(buf.GetBuffer(), MAX_STRING_LENGTH);
901     }
902     return buf.GetByteString();
903 }
904 #define PAGEPARSE_STAGE_GETCONTENT              1
905 #define PAGEPARSE_STAGE_PARSE                   2
906 #define PAGEPARSE_STAGE_CHECKCLIP               3
907 CPDF_ContentParser::CPDF_ContentParser()
908 {
909     m_pParser = NULL;
910     m_pStreamArray = NULL;
911     m_pSingleStream = NULL;
912     m_pData = NULL;
913     m_Status = Ready;
914     m_pType3Char = NULL;
915 }
916 CPDF_ContentParser::~CPDF_ContentParser()
917 {
918     Clear();
919 }
920 void CPDF_ContentParser::Clear()
921 {
922     if (m_pParser) {
923         delete m_pParser;
924     }
925     if (m_pSingleStream) {
926         delete m_pSingleStream;
927     }
928     if (m_pStreamArray) {
929         for (FX_DWORD i = 0; i < m_nStreams; i ++)
930             if (m_pStreamArray[i]) {
931                 delete m_pStreamArray[i];
932             }
933         FX_Free(m_pStreamArray);
934     }
935     if (m_pData && m_pSingleStream == NULL) {
936         FX_Free((void*)m_pData);
937     }
938     m_pParser = NULL;
939     m_pStreamArray = NULL;
940     m_pSingleStream = NULL;
941     m_pData = NULL;
942     m_Status = Ready;
943 }
944 void CPDF_ContentParser::Start(CPDF_Page* pPage, CPDF_ParseOptions* pOptions)
945 {
946     if (m_Status != Ready || pPage == NULL || pPage->m_pDocument == NULL || pPage->m_pFormDict == NULL) {
947         m_Status = Done;
948         return;
949     }
950     m_pObjects = pPage;
951     m_bForm = FALSE;
952     if (pOptions) {
953         m_Options = *pOptions;
954     }
955     m_Status = ToBeContinued;
956     m_InternalStage = PAGEPARSE_STAGE_GETCONTENT;
957     m_CurrentOffset = 0;
958     CPDF_Object* pContent = pPage->m_pFormDict->GetElementValue(FX_BSTRC("Contents"));
959     if (pContent == NULL) {
960         m_Status = Done;
961         return;
962     }
963     if (pContent->GetType() == PDFOBJ_STREAM) {
964         m_nStreams = 0;
965         m_pSingleStream = FX_NEW CPDF_StreamAcc;
966         m_pSingleStream->LoadAllData((CPDF_Stream*)pContent, FALSE);
967     } else if (pContent->GetType() == PDFOBJ_ARRAY) {
968         CPDF_Array* pArray = (CPDF_Array*)pContent;
969         m_nStreams = pArray->GetCount();
970         if (m_nStreams == 0) {
971             m_Status = Done;
972             return;
973         }
974         m_pStreamArray = FX_Alloc(CPDF_StreamAcc*, m_nStreams);
975     } else {
976         m_Status = Done;
977         return;
978     }
979 }
980 void CPDF_ContentParser::Start(CPDF_Form* pForm, CPDF_AllStates* pGraphicStates,
981                                CFX_AffineMatrix* pParentMatrix, CPDF_Type3Char* pType3Char, CPDF_ParseOptions* pOptions, int level)
982 {
983     m_pType3Char = pType3Char;
984     m_pObjects = pForm;
985     m_bForm = TRUE;
986     CFX_AffineMatrix form_matrix = pForm->m_pFormDict->GetMatrix(FX_BSTRC("Matrix"));
987     if (pGraphicStates) {
988         form_matrix.Concat(pGraphicStates->m_CTM);
989     }
990     CPDF_Array* pBBox = pForm->m_pFormDict->GetArray(FX_BSTRC("BBox"));
991     CFX_FloatRect form_bbox;
992     CPDF_Path ClipPath;
993     if (pBBox) {
994         form_bbox = pBBox->GetRect();
995         ClipPath.New();
996         ClipPath.AppendRect(form_bbox.left, form_bbox.bottom, form_bbox.right, form_bbox.top);
997         ClipPath.Transform(&form_matrix);
998         if (pParentMatrix) {
999             ClipPath.Transform(pParentMatrix);
1000         }
1001         form_bbox.Transform(&form_matrix);
1002         if (pParentMatrix) {
1003             form_bbox.Transform(pParentMatrix);
1004         }
1005     }
1006     CPDF_Dictionary* pResources = pForm->m_pFormDict->GetDict(FX_BSTRC("Resources"));
1007     m_pParser = FX_NEW CPDF_StreamContentParser;
1008     m_pParser->Initialize();
1009     m_pParser->PrepareParse(pForm->m_pDocument, pForm->m_pPageResources, pForm->m_pResources, pParentMatrix, pForm,
1010                             pResources, &form_bbox, pOptions, pGraphicStates, level);
1011     m_pParser->m_pCurStates->m_CTM = form_matrix;
1012     m_pParser->m_pCurStates->m_ParentMatrix = form_matrix;
1013     if (ClipPath.NotNull()) {
1014         m_pParser->m_pCurStates->m_ClipPath.AppendPath(ClipPath, FXFILL_WINDING, TRUE);
1015     }
1016     if (pForm->m_Transparency & PDFTRANS_GROUP) {
1017         CPDF_GeneralStateData* pData = m_pParser->m_pCurStates->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 = FX_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 = (FX_LPBYTE)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(FX_BYTE, m_Size);
1054                     if (!m_pData) {
1055                         m_Status = Done;
1056                         return;
1057                     }
1058                     FX_DWORD pos = 0;
1059                     for (i = 0; i < m_nStreams; i ++) {
1060                         FXSYS_memcpy32(m_pData + pos, m_pStreamArray[i]->GetData(), m_pStreamArray[i]->GetSize());
1061                         pos += m_pStreamArray[i]->GetSize() + 1;
1062                         m_pData[pos - 1] = ' ';
1063                         delete m_pStreamArray[i];
1064                     }
1065                     FX_Free(m_pStreamArray);
1066                     m_pStreamArray = NULL;
1067                 } else {
1068                     m_pData = (FX_LPBYTE)m_pSingleStream->GetData();
1069                     m_Size = m_pSingleStream->GetSize();
1070                 }
1071                 m_InternalStage = PAGEPARSE_STAGE_PARSE;
1072                 m_CurrentOffset = 0;
1073             } else {
1074                 CPDF_Array* pContent = m_pObjects->m_pFormDict->GetArray(FX_BSTRC("Contents"));
1075                 m_pStreamArray[m_CurrentOffset] = FX_NEW CPDF_StreamAcc;
1076                 CPDF_Stream* pStreamObj = (CPDF_Stream*)(pContent ? pContent->GetElementValue(m_CurrentOffset) : NULL);
1077                 m_pStreamArray[m_CurrentOffset]->LoadAllData(pStreamObj, FALSE);
1078                 m_CurrentOffset ++;
1079             }
1080         }
1081         if (m_InternalStage == PAGEPARSE_STAGE_PARSE) {
1082             if (m_pParser == NULL) {
1083                 m_pParser = FX_NEW CPDF_StreamContentParser;
1084                 m_pParser->Initialize();
1085                 m_pParser->PrepareParse(m_pObjects->m_pDocument, m_pObjects->m_pPageResources, NULL, NULL, m_pObjects,
1086                                         m_pObjects->m_pResources, &m_pObjects->m_BBox, &m_Options, NULL, 0);
1087                 m_pParser->m_pCurStates->m_ColorState.GetModify()->Default();
1088             }
1089             if (m_CurrentOffset >= m_Size) {
1090                 m_InternalStage = PAGEPARSE_STAGE_CHECKCLIP;
1091             } else {
1092                 m_CurrentOffset += m_pParser->Parse(m_pData + m_CurrentOffset, m_Size - m_CurrentOffset, PARSE_STEP_LIMIT);
1093                 if (m_pParser->m_bAbort) {
1094                     m_InternalStage = PAGEPARSE_STAGE_CHECKCLIP;
1095                     continue;
1096                 }
1097             }
1098         }
1099         if (m_InternalStage == PAGEPARSE_STAGE_CHECKCLIP) {
1100             if (m_pType3Char) {
1101                 m_pType3Char->m_bColored = m_pParser->m_bColored;
1102                 m_pType3Char->m_Width = FXSYS_round(m_pParser->m_Type3Data[0] * 1000);
1103                 m_pType3Char->m_BBox.left = FXSYS_round(m_pParser->m_Type3Data[2] * 1000);
1104                 m_pType3Char->m_BBox.bottom = FXSYS_round(m_pParser->m_Type3Data[3] * 1000);
1105                 m_pType3Char->m_BBox.right = FXSYS_round(m_pParser->m_Type3Data[4] * 1000);
1106                 m_pType3Char->m_BBox.top = FXSYS_round(m_pParser->m_Type3Data[5] * 1000);
1107             }
1108             FX_POSITION pos = m_pObjects->m_ObjectList.GetHeadPosition();
1109             while (pos) {
1110                 CPDF_PageObject* pObj = (CPDF_PageObject*)m_pObjects->m_ObjectList.GetNext(pos);
1111                 if (pObj->m_ClipPath.IsNull()) {
1112                     continue;
1113                 }
1114                 if (pObj->m_ClipPath.GetPathCount() != 1) {
1115                     continue;
1116                 }
1117                 if (pObj->m_ClipPath.GetTextCount()) {
1118                     continue;
1119                 }
1120                 CPDF_Path ClipPath = pObj->m_ClipPath.GetPath(0);
1121                 if (!ClipPath.IsRect() || pObj->m_Type == PDFPAGE_SHADING) {
1122                     continue;
1123                 }
1124                 CFX_FloatRect old_rect(ClipPath.GetPointX(0), ClipPath.GetPointY(0),
1125                                        ClipPath.GetPointX(2), ClipPath.GetPointY(2));
1126                 CFX_FloatRect obj_rect(pObj->m_Left, pObj->m_Bottom, pObj->m_Right, pObj->m_Top);
1127                 if (old_rect.Contains(obj_rect)) {
1128                     pObj->m_ClipPath.SetNull();
1129                 }
1130             }
1131             m_Status = Done;
1132             return;
1133         }
1134         steps ++;
1135         if (pPause && pPause->NeedToPauseNow()) {
1136             break;
1137         }
1138     }
1139 }
1140 int CPDF_ContentParser::EstimateProgress()
1141 {
1142     if (m_Status == Ready) {
1143         return 0;
1144     }
1145     if (m_Status == Done) {
1146         return 100;
1147     }
1148     if (m_InternalStage == PAGEPARSE_STAGE_GETCONTENT) {
1149         return 10;
1150     }
1151     if (m_InternalStage == PAGEPARSE_STAGE_CHECKCLIP) {
1152         return 90;
1153     }
1154     return 10 + 80 * m_CurrentOffset / m_Size;
1155 }