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