| 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 |