OLD | NEW |
| (Empty) |
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 "core/fpdfapi/fpdf_page/pageint.h" | |
8 | |
9 #include <limits.h> | |
10 | |
11 #include "core/fpdfapi/cpdf_modulemgr.h" | |
12 #include "core/fpdfapi/font/cpdf_type3char.h" | |
13 #include "core/fpdfapi/fpdf_page/cpdf_allstates.h" | |
14 #include "core/fpdfapi/fpdf_page/cpdf_form.h" | |
15 #include "core/fpdfapi/fpdf_page/cpdf_page.h" | |
16 #include "core/fpdfapi/fpdf_page/cpdf_pageobject.h" | |
17 #include "core/fpdfapi/fpdf_page/cpdf_path.h" | |
18 #include "core/fpdfapi/fpdf_parser/cpdf_array.h" | |
19 #include "core/fpdfapi/fpdf_parser/cpdf_boolean.h" | |
20 #include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" | |
21 #include "core/fpdfapi/fpdf_parser/cpdf_document.h" | |
22 #include "core/fpdfapi/fpdf_parser/cpdf_name.h" | |
23 #include "core/fpdfapi/fpdf_parser/cpdf_null.h" | |
24 #include "core/fpdfapi/fpdf_parser/cpdf_number.h" | |
25 #include "core/fpdfapi/fpdf_parser/cpdf_stream.h" | |
26 #include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" | |
27 #include "core/fpdfapi/fpdf_parser/cpdf_string.h" | |
28 #include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h" | |
29 #include "core/fpdfapi/fpdf_parser/fpdf_parser_utility.h" | |
30 #include "core/fxcodec/fx_codec.h" | |
31 #include "core/fxcrt/fx_ext.h" | |
32 #include "core/fxcrt/fx_safe_types.h" | |
33 #include "core/fxge/cfx_fxgedevice.h" | |
34 #include "core/fxge/cfx_renderdevice.h" | |
35 | |
36 namespace { | |
37 | |
38 const uint32_t kMaxNestedArrayLevel = 512; | |
39 const uint32_t kMaxWordBuffer = 256; | |
40 const FX_STRSIZE kMaxStringLength = 32767; | |
41 | |
42 } // namespace | |
43 | |
44 CPDF_StreamParser::CPDF_StreamParser(const uint8_t* pData, uint32_t dwSize) | |
45 : m_pBuf(pData), | |
46 m_Size(dwSize), | |
47 m_Pos(0), | |
48 m_pLastObj(nullptr), | |
49 m_pPool(nullptr) {} | |
50 | |
51 CPDF_StreamParser::CPDF_StreamParser( | |
52 const uint8_t* pData, | |
53 uint32_t dwSize, | |
54 const CFX_WeakPtr<CFX_ByteStringPool>& pPool) | |
55 : m_pBuf(pData), | |
56 m_Size(dwSize), | |
57 m_Pos(0), | |
58 m_pLastObj(nullptr), | |
59 m_pPool(pPool) {} | |
60 | |
61 CPDF_StreamParser::~CPDF_StreamParser() { | |
62 if (m_pLastObj) { | |
63 m_pLastObj->Release(); | |
64 } | |
65 } | |
66 | |
67 uint32_t DecodeAllScanlines(CCodec_ScanlineDecoder* pDecoder, | |
68 uint8_t*& dest_buf, | |
69 uint32_t& dest_size) { | |
70 if (!pDecoder) { | |
71 return FX_INVALID_OFFSET; | |
72 } | |
73 int ncomps = pDecoder->CountComps(); | |
74 int bpc = pDecoder->GetBPC(); | |
75 int width = pDecoder->GetWidth(); | |
76 int height = pDecoder->GetHeight(); | |
77 int pitch = (width * ncomps * bpc + 7) / 8; | |
78 if (height == 0 || pitch > (1 << 30) / height) { | |
79 delete pDecoder; | |
80 return FX_INVALID_OFFSET; | |
81 } | |
82 dest_buf = FX_Alloc2D(uint8_t, pitch, height); | |
83 dest_size = pitch * height; // Safe since checked alloc returned. | |
84 for (int row = 0; row < height; row++) { | |
85 const uint8_t* pLine = pDecoder->GetScanline(row); | |
86 if (!pLine) | |
87 break; | |
88 | |
89 FXSYS_memcpy(dest_buf + row * pitch, pLine, pitch); | |
90 } | |
91 uint32_t srcoff = pDecoder->GetSrcOffset(); | |
92 delete pDecoder; | |
93 return srcoff; | |
94 } | |
95 | |
96 CCodec_ScanlineDecoder* FPDFAPI_CreateFaxDecoder( | |
97 const uint8_t* src_buf, | |
98 uint32_t src_size, | |
99 int width, | |
100 int height, | |
101 const CPDF_Dictionary* pParams); | |
102 | |
103 uint32_t PDF_DecodeInlineStream(const uint8_t* src_buf, | |
104 uint32_t limit, | |
105 int width, | |
106 int height, | |
107 CFX_ByteString& decoder, | |
108 CPDF_Dictionary* pParam, | |
109 uint8_t*& dest_buf, | |
110 uint32_t& dest_size) { | |
111 if (decoder == "CCITTFaxDecode" || decoder == "CCF") { | |
112 CCodec_ScanlineDecoder* pDecoder = | |
113 FPDFAPI_CreateFaxDecoder(src_buf, limit, width, height, pParam); | |
114 return DecodeAllScanlines(pDecoder, dest_buf, dest_size); | |
115 } | |
116 if (decoder == "ASCII85Decode" || decoder == "A85") { | |
117 return A85Decode(src_buf, limit, dest_buf, dest_size); | |
118 } | |
119 if (decoder == "ASCIIHexDecode" || decoder == "AHx") { | |
120 return HexDecode(src_buf, limit, dest_buf, dest_size); | |
121 } | |
122 if (decoder == "FlateDecode" || decoder == "Fl") { | |
123 return FPDFAPI_FlateOrLZWDecode(FALSE, src_buf, limit, pParam, dest_size, | |
124 dest_buf, dest_size); | |
125 } | |
126 if (decoder == "LZWDecode" || decoder == "LZW") { | |
127 return FPDFAPI_FlateOrLZWDecode(TRUE, src_buf, limit, pParam, 0, dest_buf, | |
128 dest_size); | |
129 } | |
130 if (decoder == "DCTDecode" || decoder == "DCT") { | |
131 CCodec_ScanlineDecoder* pDecoder = | |
132 CPDF_ModuleMgr::Get()->GetJpegModule()->CreateDecoder( | |
133 src_buf, limit, width, height, 0, | |
134 pParam ? pParam->GetIntegerFor("ColorTransform", 1) : 1); | |
135 return DecodeAllScanlines(pDecoder, dest_buf, dest_size); | |
136 } | |
137 if (decoder == "RunLengthDecode" || decoder == "RL") { | |
138 return RunLengthDecode(src_buf, limit, dest_buf, dest_size); | |
139 } | |
140 dest_size = 0; | |
141 dest_buf = 0; | |
142 return (uint32_t)-1; | |
143 } | |
144 | |
145 CPDF_Stream* CPDF_StreamParser::ReadInlineStream(CPDF_Document* pDoc, | |
146 CPDF_Dictionary* pDict, | |
147 CPDF_Object* pCSObj) { | |
148 if (m_Pos == m_Size) | |
149 return nullptr; | |
150 | |
151 if (PDFCharIsWhitespace(m_pBuf[m_Pos])) | |
152 m_Pos++; | |
153 | |
154 CFX_ByteString Decoder; | |
155 CPDF_Dictionary* pParam = nullptr; | |
156 CPDF_Object* pFilter = pDict->GetDirectObjectFor("Filter"); | |
157 if (pFilter) { | |
158 if (CPDF_Array* pArray = pFilter->AsArray()) { | |
159 Decoder = pArray->GetStringAt(0); | |
160 CPDF_Array* pParams = pDict->GetArrayFor("DecodeParms"); | |
161 if (pParams) | |
162 pParam = pParams->GetDictAt(0); | |
163 } else { | |
164 Decoder = pFilter->GetString(); | |
165 pParam = pDict->GetDictFor("DecodeParms"); | |
166 } | |
167 } | |
168 uint32_t width = pDict->GetIntegerFor("Width"); | |
169 uint32_t height = pDict->GetIntegerFor("Height"); | |
170 uint32_t OrigSize = 0; | |
171 if (pCSObj) { | |
172 uint32_t bpc = pDict->GetIntegerFor("BitsPerComponent"); | |
173 uint32_t nComponents = 1; | |
174 CPDF_ColorSpace* pCS = pDoc->LoadColorSpace(pCSObj); | |
175 if (pCS) { | |
176 nComponents = pCS->CountComponents(); | |
177 pDoc->GetPageData()->ReleaseColorSpace(pCSObj); | |
178 } else { | |
179 nComponents = 3; | |
180 } | |
181 uint32_t pitch = width; | |
182 if (bpc && pitch > INT_MAX / bpc) | |
183 return nullptr; | |
184 | |
185 pitch *= bpc; | |
186 if (nComponents && pitch > INT_MAX / nComponents) | |
187 return nullptr; | |
188 | |
189 pitch *= nComponents; | |
190 if (pitch > INT_MAX - 7) | |
191 return nullptr; | |
192 | |
193 pitch += 7; | |
194 pitch /= 8; | |
195 OrigSize = pitch; | |
196 } else { | |
197 if (width > INT_MAX - 7) | |
198 return nullptr; | |
199 | |
200 OrigSize = ((width + 7) / 8); | |
201 } | |
202 if (height && OrigSize > INT_MAX / height) | |
203 return nullptr; | |
204 | |
205 OrigSize *= height; | |
206 uint8_t* pData = nullptr; | |
207 uint32_t dwStreamSize; | |
208 if (Decoder.IsEmpty()) { | |
209 if (OrigSize > m_Size - m_Pos) { | |
210 OrigSize = m_Size - m_Pos; | |
211 } | |
212 pData = FX_Alloc(uint8_t, OrigSize); | |
213 FXSYS_memcpy(pData, m_pBuf + m_Pos, OrigSize); | |
214 dwStreamSize = OrigSize; | |
215 m_Pos += OrigSize; | |
216 } else { | |
217 uint32_t dwDestSize = OrigSize; | |
218 dwStreamSize = | |
219 PDF_DecodeInlineStream(m_pBuf + m_Pos, m_Size - m_Pos, width, height, | |
220 Decoder, pParam, pData, dwDestSize); | |
221 FX_Free(pData); | |
222 if ((int)dwStreamSize < 0) | |
223 return nullptr; | |
224 | |
225 uint32_t dwSavePos = m_Pos; | |
226 m_Pos += dwStreamSize; | |
227 while (1) { | |
228 uint32_t dwPrevPos = m_Pos; | |
229 CPDF_StreamParser::SyntaxType type = ParseNextElement(); | |
230 if (type == CPDF_StreamParser::EndOfData) | |
231 break; | |
232 | |
233 if (type != CPDF_StreamParser::Keyword) { | |
234 dwStreamSize += m_Pos - dwPrevPos; | |
235 continue; | |
236 } | |
237 if (GetWordSize() == 2 && GetWordBuf()[0] == 'E' && | |
238 GetWordBuf()[1] == 'I') { | |
239 m_Pos = dwPrevPos; | |
240 break; | |
241 } | |
242 dwStreamSize += m_Pos - dwPrevPos; | |
243 } | |
244 m_Pos = dwSavePos; | |
245 pData = FX_Alloc(uint8_t, dwStreamSize); | |
246 FXSYS_memcpy(pData, m_pBuf + m_Pos, dwStreamSize); | |
247 m_Pos += dwStreamSize; | |
248 } | |
249 pDict->SetIntegerFor("Length", (int)dwStreamSize); | |
250 return new CPDF_Stream(pData, dwStreamSize, pDict); | |
251 } | |
252 | |
253 CPDF_StreamParser::SyntaxType CPDF_StreamParser::ParseNextElement() { | |
254 if (m_pLastObj) { | |
255 m_pLastObj->Release(); | |
256 m_pLastObj = nullptr; | |
257 } | |
258 | |
259 m_WordSize = 0; | |
260 FX_BOOL bIsNumber = TRUE; | |
261 if (!PositionIsInBounds()) | |
262 return EndOfData; | |
263 | |
264 int ch = m_pBuf[m_Pos++]; | |
265 while (1) { | |
266 while (PDFCharIsWhitespace(ch)) { | |
267 if (!PositionIsInBounds()) | |
268 return EndOfData; | |
269 | |
270 ch = m_pBuf[m_Pos++]; | |
271 } | |
272 | |
273 if (ch != '%') | |
274 break; | |
275 | |
276 while (1) { | |
277 if (!PositionIsInBounds()) | |
278 return EndOfData; | |
279 | |
280 ch = m_pBuf[m_Pos++]; | |
281 if (PDFCharIsLineEnding(ch)) | |
282 break; | |
283 } | |
284 } | |
285 | |
286 if (PDFCharIsDelimiter(ch) && ch != '/') { | |
287 m_Pos--; | |
288 m_pLastObj = ReadNextObject(false, 0); | |
289 return Others; | |
290 } | |
291 | |
292 while (1) { | |
293 if (m_WordSize < kMaxWordBuffer) | |
294 m_WordBuffer[m_WordSize++] = ch; | |
295 | |
296 if (!PDFCharIsNumeric(ch)) | |
297 bIsNumber = FALSE; | |
298 | |
299 if (!PositionIsInBounds()) | |
300 break; | |
301 | |
302 ch = m_pBuf[m_Pos++]; | |
303 | |
304 if (PDFCharIsDelimiter(ch) || PDFCharIsWhitespace(ch)) { | |
305 m_Pos--; | |
306 break; | |
307 } | |
308 } | |
309 | |
310 m_WordBuffer[m_WordSize] = 0; | |
311 if (bIsNumber) | |
312 return Number; | |
313 | |
314 if (m_WordBuffer[0] == '/') | |
315 return Name; | |
316 | |
317 if (m_WordSize == 4) { | |
318 if (memcmp(m_WordBuffer, "true", 4) == 0) { | |
319 m_pLastObj = new CPDF_Boolean(TRUE); | |
320 return Others; | |
321 } | |
322 if (memcmp(m_WordBuffer, "null", 4) == 0) { | |
323 m_pLastObj = new CPDF_Null; | |
324 return Others; | |
325 } | |
326 } else if (m_WordSize == 5) { | |
327 if (memcmp(m_WordBuffer, "false", 5) == 0) { | |
328 m_pLastObj = new CPDF_Boolean(FALSE); | |
329 return Others; | |
330 } | |
331 } | |
332 return Keyword; | |
333 } | |
334 | |
335 CPDF_Object* CPDF_StreamParser::ReadNextObject(bool bAllowNestedArray, | |
336 uint32_t dwInArrayLevel) { | |
337 FX_BOOL bIsNumber; | |
338 GetNextWord(bIsNumber); | |
339 if (!m_WordSize) | |
340 return nullptr; | |
341 | |
342 if (bIsNumber) { | |
343 m_WordBuffer[m_WordSize] = 0; | |
344 return new CPDF_Number(CFX_ByteStringC(m_WordBuffer, m_WordSize)); | |
345 } | |
346 | |
347 int first_char = m_WordBuffer[0]; | |
348 if (first_char == '/') { | |
349 CFX_ByteString name = | |
350 PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1)); | |
351 return new CPDF_Name(m_pPool ? m_pPool->Intern(name) : name); | |
352 } | |
353 | |
354 if (first_char == '(') { | |
355 CFX_ByteString str = ReadString(); | |
356 return new CPDF_String(m_pPool ? m_pPool->Intern(str) : str, FALSE); | |
357 } | |
358 | |
359 if (first_char == '<') { | |
360 if (m_WordSize == 1) | |
361 return new CPDF_String(ReadHexString(), TRUE); | |
362 | |
363 CPDF_Dictionary* pDict = new CPDF_Dictionary(m_pPool); | |
364 while (1) { | |
365 GetNextWord(bIsNumber); | |
366 if (m_WordSize == 2 && m_WordBuffer[0] == '>') | |
367 break; | |
368 | |
369 if (!m_WordSize || m_WordBuffer[0] != '/') { | |
370 pDict->Release(); | |
371 return nullptr; | |
372 } | |
373 | |
374 CFX_ByteString key = | |
375 PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1)); | |
376 CPDF_Object* pObj = ReadNextObject(true, 0); | |
377 if (!pObj) { | |
378 pDict->Release(); | |
379 return nullptr; | |
380 } | |
381 | |
382 if (key.IsEmpty()) | |
383 pObj->Release(); | |
384 else | |
385 pDict->SetFor(key, pObj); | |
386 } | |
387 return pDict; | |
388 } | |
389 | |
390 if (first_char == '[') { | |
391 if ((!bAllowNestedArray && dwInArrayLevel) || | |
392 dwInArrayLevel > kMaxNestedArrayLevel) { | |
393 return nullptr; | |
394 } | |
395 | |
396 CPDF_Array* pArray = new CPDF_Array; | |
397 while (1) { | |
398 CPDF_Object* pObj = ReadNextObject(bAllowNestedArray, dwInArrayLevel + 1); | |
399 if (pObj) { | |
400 pArray->Add(pObj); | |
401 continue; | |
402 } | |
403 | |
404 if (!m_WordSize || m_WordBuffer[0] == ']') | |
405 break; | |
406 } | |
407 return pArray; | |
408 } | |
409 | |
410 if (m_WordSize == 5 && !memcmp(m_WordBuffer, "false", 5)) | |
411 return new CPDF_Boolean(FALSE); | |
412 | |
413 if (m_WordSize == 4) { | |
414 if (memcmp(m_WordBuffer, "true", 4) == 0) | |
415 return new CPDF_Boolean(TRUE); | |
416 | |
417 if (memcmp(m_WordBuffer, "null", 4) == 0) | |
418 return new CPDF_Null; | |
419 } | |
420 | |
421 return nullptr; | |
422 } | |
423 | |
424 void CPDF_StreamParser::GetNextWord(FX_BOOL& bIsNumber) { | |
425 m_WordSize = 0; | |
426 bIsNumber = TRUE; | |
427 if (!PositionIsInBounds()) | |
428 return; | |
429 | |
430 int ch = m_pBuf[m_Pos++]; | |
431 while (1) { | |
432 while (PDFCharIsWhitespace(ch)) { | |
433 if (!PositionIsInBounds()) { | |
434 return; | |
435 } | |
436 ch = m_pBuf[m_Pos++]; | |
437 } | |
438 | |
439 if (ch != '%') | |
440 break; | |
441 | |
442 while (1) { | |
443 if (!PositionIsInBounds()) | |
444 return; | |
445 ch = m_pBuf[m_Pos++]; | |
446 if (PDFCharIsLineEnding(ch)) | |
447 break; | |
448 } | |
449 } | |
450 | |
451 if (PDFCharIsDelimiter(ch)) { | |
452 bIsNumber = FALSE; | |
453 m_WordBuffer[m_WordSize++] = ch; | |
454 if (ch == '/') { | |
455 while (1) { | |
456 if (!PositionIsInBounds()) | |
457 return; | |
458 ch = m_pBuf[m_Pos++]; | |
459 if (!PDFCharIsOther(ch) && !PDFCharIsNumeric(ch)) { | |
460 m_Pos--; | |
461 return; | |
462 } | |
463 | |
464 if (m_WordSize < kMaxWordBuffer) | |
465 m_WordBuffer[m_WordSize++] = ch; | |
466 } | |
467 } else if (ch == '<') { | |
468 if (!PositionIsInBounds()) | |
469 return; | |
470 ch = m_pBuf[m_Pos++]; | |
471 if (ch == '<') | |
472 m_WordBuffer[m_WordSize++] = ch; | |
473 else | |
474 m_Pos--; | |
475 } else if (ch == '>') { | |
476 if (!PositionIsInBounds()) | |
477 return; | |
478 ch = m_pBuf[m_Pos++]; | |
479 if (ch == '>') | |
480 m_WordBuffer[m_WordSize++] = ch; | |
481 else | |
482 m_Pos--; | |
483 } | |
484 return; | |
485 } | |
486 | |
487 while (1) { | |
488 if (m_WordSize < kMaxWordBuffer) | |
489 m_WordBuffer[m_WordSize++] = ch; | |
490 if (!PDFCharIsNumeric(ch)) | |
491 bIsNumber = FALSE; | |
492 | |
493 if (!PositionIsInBounds()) | |
494 return; | |
495 ch = m_pBuf[m_Pos++]; | |
496 if (PDFCharIsDelimiter(ch) || PDFCharIsWhitespace(ch)) { | |
497 m_Pos--; | |
498 break; | |
499 } | |
500 } | |
501 } | |
502 | |
503 CFX_ByteString CPDF_StreamParser::ReadString() { | |
504 if (!PositionIsInBounds()) | |
505 return CFX_ByteString(); | |
506 | |
507 uint8_t ch = m_pBuf[m_Pos++]; | |
508 CFX_ByteTextBuf buf; | |
509 int parlevel = 0; | |
510 int status = 0; | |
511 int iEscCode = 0; | |
512 while (1) { | |
513 switch (status) { | |
514 case 0: | |
515 if (ch == ')') { | |
516 if (parlevel == 0) { | |
517 if (buf.GetLength() > kMaxStringLength) { | |
518 return CFX_ByteString(buf.GetBuffer(), kMaxStringLength); | |
519 } | |
520 return buf.MakeString(); | |
521 } | |
522 parlevel--; | |
523 buf.AppendChar(')'); | |
524 } else if (ch == '(') { | |
525 parlevel++; | |
526 buf.AppendChar('('); | |
527 } else if (ch == '\\') { | |
528 status = 1; | |
529 } else { | |
530 buf.AppendChar((char)ch); | |
531 } | |
532 break; | |
533 case 1: | |
534 if (ch >= '0' && ch <= '7') { | |
535 iEscCode = FXSYS_toDecimalDigit(static_cast<FX_WCHAR>(ch)); | |
536 status = 2; | |
537 break; | |
538 } | |
539 if (ch == 'n') { | |
540 buf.AppendChar('\n'); | |
541 } else if (ch == 'r') { | |
542 buf.AppendChar('\r'); | |
543 } else if (ch == 't') { | |
544 buf.AppendChar('\t'); | |
545 } else if (ch == 'b') { | |
546 buf.AppendChar('\b'); | |
547 } else if (ch == 'f') { | |
548 buf.AppendChar('\f'); | |
549 } else if (ch == '\r') { | |
550 status = 4; | |
551 break; | |
552 } else if (ch == '\n') { | |
553 } else { | |
554 buf.AppendChar(ch); | |
555 } | |
556 status = 0; | |
557 break; | |
558 case 2: | |
559 if (ch >= '0' && ch <= '7') { | |
560 iEscCode = | |
561 iEscCode * 8 + FXSYS_toDecimalDigit(static_cast<FX_WCHAR>(ch)); | |
562 status = 3; | |
563 } else { | |
564 buf.AppendChar(iEscCode); | |
565 status = 0; | |
566 continue; | |
567 } | |
568 break; | |
569 case 3: | |
570 if (ch >= '0' && ch <= '7') { | |
571 iEscCode = | |
572 iEscCode * 8 + FXSYS_toDecimalDigit(static_cast<FX_WCHAR>(ch)); | |
573 buf.AppendChar(iEscCode); | |
574 status = 0; | |
575 } else { | |
576 buf.AppendChar(iEscCode); | |
577 status = 0; | |
578 continue; | |
579 } | |
580 break; | |
581 case 4: | |
582 status = 0; | |
583 if (ch != '\n') { | |
584 continue; | |
585 } | |
586 break; | |
587 } | |
588 if (!PositionIsInBounds()) | |
589 break; | |
590 | |
591 ch = m_pBuf[m_Pos++]; | |
592 } | |
593 if (PositionIsInBounds()) | |
594 ++m_Pos; | |
595 | |
596 if (buf.GetLength() > kMaxStringLength) { | |
597 return CFX_ByteString(buf.GetBuffer(), kMaxStringLength); | |
598 } | |
599 return buf.MakeString(); | |
600 } | |
601 | |
602 CFX_ByteString CPDF_StreamParser::ReadHexString() { | |
603 if (!PositionIsInBounds()) | |
604 return CFX_ByteString(); | |
605 | |
606 CFX_ByteTextBuf buf; | |
607 bool bFirst = true; | |
608 int code = 0; | |
609 while (PositionIsInBounds()) { | |
610 int ch = m_pBuf[m_Pos++]; | |
611 | |
612 if (ch == '>') | |
613 break; | |
614 | |
615 if (!std::isxdigit(ch)) | |
616 continue; | |
617 | |
618 int val = FXSYS_toHexDigit(ch); | |
619 if (bFirst) { | |
620 code = val * 16; | |
621 } else { | |
622 code += val; | |
623 buf.AppendByte((uint8_t)code); | |
624 } | |
625 bFirst = !bFirst; | |
626 } | |
627 if (!bFirst) | |
628 buf.AppendChar((char)code); | |
629 | |
630 if (buf.GetLength() > kMaxStringLength) | |
631 return CFX_ByteString(buf.GetBuffer(), kMaxStringLength); | |
632 | |
633 return buf.MakeString(); | |
634 } | |
635 | |
636 bool CPDF_StreamParser::PositionIsInBounds() const { | |
637 return m_Pos < m_Size; | |
638 } | |
639 | |
640 CPDF_ContentParser::CPDF_ContentParser() | |
641 : m_Status(Ready), | |
642 m_InternalStage(STAGE_GETCONTENT), | |
643 m_pObjectHolder(nullptr), | |
644 m_bForm(false), | |
645 m_pType3Char(nullptr), | |
646 m_pData(nullptr), | |
647 m_Size(0), | |
648 m_CurrentOffset(0) {} | |
649 | |
650 CPDF_ContentParser::~CPDF_ContentParser() { | |
651 if (!m_pSingleStream) | |
652 FX_Free(m_pData); | |
653 } | |
654 | |
655 void CPDF_ContentParser::Start(CPDF_Page* pPage) { | |
656 if (m_Status != Ready || !pPage || !pPage->m_pDocument || | |
657 !pPage->m_pFormDict) { | |
658 m_Status = Done; | |
659 return; | |
660 } | |
661 m_pObjectHolder = pPage; | |
662 m_bForm = FALSE; | |
663 m_Status = ToBeContinued; | |
664 m_InternalStage = STAGE_GETCONTENT; | |
665 m_CurrentOffset = 0; | |
666 | |
667 CPDF_Object* pContent = pPage->m_pFormDict->GetDirectObjectFor("Contents"); | |
668 if (!pContent) { | |
669 m_Status = Done; | |
670 return; | |
671 } | |
672 if (CPDF_Stream* pStream = pContent->AsStream()) { | |
673 m_nStreams = 0; | |
674 m_pSingleStream.reset(new CPDF_StreamAcc); | |
675 m_pSingleStream->LoadAllData(pStream, FALSE); | |
676 } else if (CPDF_Array* pArray = pContent->AsArray()) { | |
677 m_nStreams = pArray->GetCount(); | |
678 if (m_nStreams) | |
679 m_StreamArray.resize(m_nStreams); | |
680 else | |
681 m_Status = Done; | |
682 } else { | |
683 m_Status = Done; | |
684 } | |
685 } | |
686 | |
687 void CPDF_ContentParser::Start(CPDF_Form* pForm, | |
688 CPDF_AllStates* pGraphicStates, | |
689 const CFX_Matrix* pParentMatrix, | |
690 CPDF_Type3Char* pType3Char, | |
691 int level) { | |
692 m_pType3Char = pType3Char; | |
693 m_pObjectHolder = pForm; | |
694 m_bForm = TRUE; | |
695 CFX_Matrix form_matrix = pForm->m_pFormDict->GetMatrixFor("Matrix"); | |
696 if (pGraphicStates) { | |
697 form_matrix.Concat(pGraphicStates->m_CTM); | |
698 } | |
699 CPDF_Array* pBBox = pForm->m_pFormDict->GetArrayFor("BBox"); | |
700 CFX_FloatRect form_bbox; | |
701 CPDF_Path ClipPath; | |
702 if (pBBox) { | |
703 form_bbox = pBBox->GetRect(); | |
704 ClipPath.Emplace(); | |
705 ClipPath.AppendRect(form_bbox.left, form_bbox.bottom, form_bbox.right, | |
706 form_bbox.top); | |
707 ClipPath.Transform(&form_matrix); | |
708 if (pParentMatrix) { | |
709 ClipPath.Transform(pParentMatrix); | |
710 } | |
711 form_bbox.Transform(&form_matrix); | |
712 if (pParentMatrix) { | |
713 form_bbox.Transform(pParentMatrix); | |
714 } | |
715 } | |
716 CPDF_Dictionary* pResources = pForm->m_pFormDict->GetDictFor("Resources"); | |
717 m_pParser.reset(new CPDF_StreamContentParser( | |
718 pForm->m_pDocument, pForm->m_pPageResources, pForm->m_pResources, | |
719 pParentMatrix, pForm, pResources, &form_bbox, pGraphicStates, level)); | |
720 m_pParser->GetCurStates()->m_CTM = form_matrix; | |
721 m_pParser->GetCurStates()->m_ParentMatrix = form_matrix; | |
722 if (ClipPath) { | |
723 m_pParser->GetCurStates()->m_ClipPath.AppendPath(ClipPath, FXFILL_WINDING, | |
724 TRUE); | |
725 } | |
726 if (pForm->m_Transparency & PDFTRANS_GROUP) { | |
727 CPDF_GeneralState* pState = &m_pParser->GetCurStates()->m_GeneralState; | |
728 pState->SetBlendType(FXDIB_BLEND_NORMAL); | |
729 pState->SetStrokeAlpha(1.0f); | |
730 pState->SetFillAlpha(1.0f); | |
731 pState->SetSoftMask(nullptr); | |
732 } | |
733 m_nStreams = 0; | |
734 m_pSingleStream.reset(new CPDF_StreamAcc); | |
735 m_pSingleStream->LoadAllData(pForm->m_pFormStream, FALSE); | |
736 m_pData = (uint8_t*)m_pSingleStream->GetData(); | |
737 m_Size = m_pSingleStream->GetSize(); | |
738 m_Status = ToBeContinued; | |
739 m_InternalStage = STAGE_PARSE; | |
740 m_CurrentOffset = 0; | |
741 } | |
742 | |
743 void CPDF_ContentParser::Continue(IFX_Pause* pPause) { | |
744 int steps = 0; | |
745 while (m_Status == ToBeContinued) { | |
746 if (m_InternalStage == STAGE_GETCONTENT) { | |
747 if (m_CurrentOffset == m_nStreams) { | |
748 if (!m_StreamArray.empty()) { | |
749 FX_SAFE_UINT32 safeSize = 0; | |
750 for (const auto& stream : m_StreamArray) { | |
751 safeSize += stream->GetSize(); | |
752 safeSize += 1; | |
753 } | |
754 if (!safeSize.IsValid()) { | |
755 m_Status = Done; | |
756 return; | |
757 } | |
758 m_Size = safeSize.ValueOrDie(); | |
759 m_pData = FX_Alloc(uint8_t, m_Size); | |
760 uint32_t pos = 0; | |
761 for (const auto& stream : m_StreamArray) { | |
762 FXSYS_memcpy(m_pData + pos, stream->GetData(), stream->GetSize()); | |
763 pos += stream->GetSize(); | |
764 m_pData[pos++] = ' '; | |
765 } | |
766 m_StreamArray.clear(); | |
767 } else { | |
768 m_pData = (uint8_t*)m_pSingleStream->GetData(); | |
769 m_Size = m_pSingleStream->GetSize(); | |
770 } | |
771 m_InternalStage = STAGE_PARSE; | |
772 m_CurrentOffset = 0; | |
773 } else { | |
774 CPDF_Array* pContent = | |
775 m_pObjectHolder->m_pFormDict->GetArrayFor("Contents"); | |
776 m_StreamArray[m_CurrentOffset].reset(new CPDF_StreamAcc); | |
777 CPDF_Stream* pStreamObj = ToStream( | |
778 pContent ? pContent->GetDirectObjectAt(m_CurrentOffset) : nullptr); | |
779 m_StreamArray[m_CurrentOffset]->LoadAllData(pStreamObj, FALSE); | |
780 m_CurrentOffset++; | |
781 } | |
782 } | |
783 if (m_InternalStage == STAGE_PARSE) { | |
784 if (!m_pParser) { | |
785 m_pParser.reset(new CPDF_StreamContentParser( | |
786 m_pObjectHolder->m_pDocument, m_pObjectHolder->m_pPageResources, | |
787 nullptr, nullptr, m_pObjectHolder, m_pObjectHolder->m_pResources, | |
788 &m_pObjectHolder->m_BBox, nullptr, 0)); | |
789 m_pParser->GetCurStates()->m_ColorState.SetDefault(); | |
790 } | |
791 if (m_CurrentOffset >= m_Size) { | |
792 m_InternalStage = STAGE_CHECKCLIP; | |
793 } else { | |
794 m_CurrentOffset += | |
795 m_pParser->Parse(m_pData + m_CurrentOffset, | |
796 m_Size - m_CurrentOffset, PARSE_STEP_LIMIT); | |
797 } | |
798 } | |
799 if (m_InternalStage == STAGE_CHECKCLIP) { | |
800 if (m_pType3Char) { | |
801 m_pType3Char->m_bColored = m_pParser->IsColored(); | |
802 m_pType3Char->m_Width = | |
803 FXSYS_round(m_pParser->GetType3Data()[0] * 1000); | |
804 m_pType3Char->m_BBox.left = | |
805 FXSYS_round(m_pParser->GetType3Data()[2] * 1000); | |
806 m_pType3Char->m_BBox.bottom = | |
807 FXSYS_round(m_pParser->GetType3Data()[3] * 1000); | |
808 m_pType3Char->m_BBox.right = | |
809 FXSYS_round(m_pParser->GetType3Data()[4] * 1000); | |
810 m_pType3Char->m_BBox.top = | |
811 FXSYS_round(m_pParser->GetType3Data()[5] * 1000); | |
812 } | |
813 for (auto& pObj : *m_pObjectHolder->GetPageObjectList()) { | |
814 if (!pObj->m_ClipPath) | |
815 continue; | |
816 if (pObj->m_ClipPath.GetPathCount() != 1) | |
817 continue; | |
818 if (pObj->m_ClipPath.GetTextCount()) | |
819 continue; | |
820 CPDF_Path ClipPath = pObj->m_ClipPath.GetPath(0); | |
821 if (!ClipPath.IsRect() || pObj->IsShading()) | |
822 continue; | |
823 CFX_FloatRect old_rect(ClipPath.GetPointX(0), ClipPath.GetPointY(0), | |
824 ClipPath.GetPointX(2), ClipPath.GetPointY(2)); | |
825 CFX_FloatRect obj_rect(pObj->m_Left, pObj->m_Bottom, pObj->m_Right, | |
826 pObj->m_Top); | |
827 if (old_rect.Contains(obj_rect)) { | |
828 pObj->m_ClipPath.SetNull(); | |
829 } | |
830 } | |
831 m_Status = Done; | |
832 return; | |
833 } | |
834 steps++; | |
835 if (pPause && pPause->NeedToPauseNow()) { | |
836 break; | |
837 } | |
838 } | |
839 } | |
OLD | NEW |