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