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