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