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