| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 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/include/fpdfapi/cpdf_array.h" | |
| 8 #include "core/include/fpdfapi/cpdf_dictionary.h" | |
| 9 #include "core/include/fpdfapi/cpdf_document.h" | |
| 10 #include "core/include/fpdfapi/cpdf_name.h" | |
| 11 #include "core/include/fpdfapi/cpdf_number.h" | |
| 12 #include "core/include/fpdfapi/cpdf_reference.h" | |
| 13 #include "core/include/fpdfapi/cpdf_stream.h" | |
| 14 #include "core/include/fxcrt/fx_ext.h" | |
| 15 #include "core/include/fxcrt/fx_safe_types.h" | |
| 16 #include "core/src/fpdfapi/fpdf_parser/cpdf_data_avail.h" | |
| 17 #include "core/src/fpdfapi/fpdf_parser/fpdf_parser_utility.h" | |
| 18 #include "third_party/base/stl_util.h" | |
| 19 | |
| 20 IPDF_DataAvail::IPDF_DataAvail(IPDF_DataAvail::FileAvail* pFileAvail, | |
| 21 IFX_FileRead* pFileRead) | |
| 22 : m_pFileAvail(pFileAvail), m_pFileRead(pFileRead) {} | |
| 23 | |
| 24 IPDF_DataAvail::~IPDF_DataAvail() {} | |
| 25 | |
| 26 IPDF_DataAvail::FileAvail::~FileAvail() {} | |
| 27 | |
| 28 IPDF_DataAvail::DownloadHints::~DownloadHints() {} | |
| 29 | |
| 30 // static | |
| 31 IPDF_DataAvail* IPDF_DataAvail::Create(IPDF_DataAvail::FileAvail* pFileAvail, | |
| 32 IFX_FileRead* pFileRead) { | |
| 33 return new CPDF_DataAvail(pFileAvail, pFileRead, TRUE); | |
| 34 } | |
| 35 | |
| 36 // static | |
| 37 int CPDF_DataAvail::s_CurrentDataAvailRecursionDepth = 0; | |
| 38 | |
| 39 CPDF_DataAvail::CPDF_DataAvail(IPDF_DataAvail::FileAvail* pFileAvail, | |
| 40 IFX_FileRead* pFileRead, | |
| 41 FX_BOOL bSupportHintTable) | |
| 42 : IPDF_DataAvail(pFileAvail, pFileRead) { | |
| 43 m_Pos = 0; | |
| 44 m_dwFileLen = 0; | |
| 45 if (m_pFileRead) { | |
| 46 m_dwFileLen = (FX_DWORD)m_pFileRead->GetSize(); | |
| 47 } | |
| 48 m_dwCurrentOffset = 0; | |
| 49 m_dwXRefOffset = 0; | |
| 50 m_bufferOffset = 0; | |
| 51 m_dwFirstPageNo = 0; | |
| 52 m_bufferSize = 0; | |
| 53 m_PagesObjNum = 0; | |
| 54 m_dwCurrentXRefSteam = 0; | |
| 55 m_dwAcroFormObjNum = 0; | |
| 56 m_dwInfoObjNum = 0; | |
| 57 m_pDocument = 0; | |
| 58 m_dwEncryptObjNum = 0; | |
| 59 m_dwPrevXRefOffset = 0; | |
| 60 m_dwLastXRefOffset = 0; | |
| 61 m_bDocAvail = FALSE; | |
| 62 m_bMainXRefLoadTried = FALSE; | |
| 63 m_bDocAvail = FALSE; | |
| 64 m_bLinearized = FALSE; | |
| 65 m_bPagesLoad = FALSE; | |
| 66 m_bPagesTreeLoad = FALSE; | |
| 67 m_bMainXRefLoadedOK = FALSE; | |
| 68 m_bAnnotsLoad = FALSE; | |
| 69 m_bHaveAcroForm = FALSE; | |
| 70 m_bAcroFormLoad = FALSE; | |
| 71 m_bPageLoadedOK = FALSE; | |
| 72 m_bNeedDownLoadResource = FALSE; | |
| 73 m_bLinearizedFormParamLoad = FALSE; | |
| 74 m_pLinearized = NULL; | |
| 75 m_pRoot = NULL; | |
| 76 m_pTrailer = NULL; | |
| 77 m_pCurrentParser = NULL; | |
| 78 m_pAcroForm = NULL; | |
| 79 m_pPageDict = NULL; | |
| 80 m_pPageResource = NULL; | |
| 81 m_docStatus = PDF_DATAAVAIL_HEADER; | |
| 82 m_parser.m_bOwnFileRead = false; | |
| 83 m_bTotalLoadPageTree = FALSE; | |
| 84 m_bCurPageDictLoadOK = FALSE; | |
| 85 m_bLinearedDataOK = FALSE; | |
| 86 m_bSupportHintTable = bSupportHintTable; | |
| 87 } | |
| 88 CPDF_DataAvail::~CPDF_DataAvail() { | |
| 89 if (m_pLinearized) | |
| 90 m_pLinearized->Release(); | |
| 91 | |
| 92 if (m_pRoot) | |
| 93 m_pRoot->Release(); | |
| 94 | |
| 95 if (m_pTrailer) | |
| 96 m_pTrailer->Release(); | |
| 97 | |
| 98 int iSize = m_arrayAcroforms.GetSize(); | |
| 99 for (int i = 0; i < iSize; ++i) | |
| 100 m_arrayAcroforms.GetAt(i)->Release(); | |
| 101 } | |
| 102 | |
| 103 void CPDF_DataAvail::SetDocument(CPDF_Document* pDoc) { | |
| 104 m_pDocument = pDoc; | |
| 105 } | |
| 106 | |
| 107 FX_DWORD CPDF_DataAvail::GetObjectSize(FX_DWORD objnum, FX_FILESIZE& offset) { | |
| 108 CPDF_Parser* pParser = m_pDocument->GetParser(); | |
| 109 if (!pParser || !pParser->IsValidObjectNumber(objnum)) | |
| 110 return 0; | |
| 111 | |
| 112 if (pParser->GetObjectType(objnum) == 2) | |
| 113 objnum = pParser->GetObjectPositionOrZero(objnum); | |
| 114 | |
| 115 if (pParser->GetObjectType(objnum) != 1 && | |
| 116 pParser->GetObjectType(objnum) != 255) { | |
| 117 return 0; | |
| 118 } | |
| 119 | |
| 120 offset = pParser->GetObjectPositionOrZero(objnum); | |
| 121 if (offset == 0) | |
| 122 return 0; | |
| 123 | |
| 124 auto it = pParser->m_SortedOffset.find(offset); | |
| 125 if (it == pParser->m_SortedOffset.end() || | |
| 126 ++it == pParser->m_SortedOffset.end()) { | |
| 127 return 0; | |
| 128 } | |
| 129 return *it - offset; | |
| 130 } | |
| 131 | |
| 132 FX_BOOL CPDF_DataAvail::IsObjectsAvail( | |
| 133 CFX_ArrayTemplate<CPDF_Object*>& obj_array, | |
| 134 FX_BOOL bParsePage, | |
| 135 IPDF_DataAvail::DownloadHints* pHints, | |
| 136 CFX_ArrayTemplate<CPDF_Object*>& ret_array) { | |
| 137 if (!obj_array.GetSize()) | |
| 138 return TRUE; | |
| 139 | |
| 140 FX_DWORD count = 0; | |
| 141 CFX_ArrayTemplate<CPDF_Object*> new_obj_array; | |
| 142 int32_t i = 0; | |
| 143 for (i = 0; i < obj_array.GetSize(); i++) { | |
| 144 CPDF_Object* pObj = obj_array[i]; | |
| 145 if (!pObj) | |
| 146 continue; | |
| 147 | |
| 148 int32_t type = pObj->GetType(); | |
| 149 switch (type) { | |
| 150 case CPDF_Object::ARRAY: { | |
| 151 CPDF_Array* pArray = pObj->GetArray(); | |
| 152 for (FX_DWORD k = 0; k < pArray->GetCount(); ++k) | |
| 153 new_obj_array.Add(pArray->GetElement(k)); | |
| 154 } break; | |
| 155 case CPDF_Object::STREAM: | |
| 156 pObj = pObj->GetDict(); | |
| 157 case CPDF_Object::DICTIONARY: { | |
| 158 CPDF_Dictionary* pDict = pObj->GetDict(); | |
| 159 if (pDict && pDict->GetStringBy("Type") == "Page" && !bParsePage) | |
| 160 continue; | |
| 161 | |
| 162 for (const auto& it : *pDict) { | |
| 163 const CFX_ByteString& key = it.first; | |
| 164 CPDF_Object* value = it.second; | |
| 165 if (key != "Parent") | |
| 166 new_obj_array.Add(value); | |
| 167 } | |
| 168 } break; | |
| 169 case CPDF_Object::REFERENCE: { | |
| 170 CPDF_Reference* pRef = pObj->AsReference(); | |
| 171 FX_DWORD dwNum = pRef->GetRefObjNum(); | |
| 172 | |
| 173 FX_FILESIZE offset; | |
| 174 FX_DWORD size = GetObjectSize(dwNum, offset); | |
| 175 if (size == 0 || offset < 0 || offset >= m_dwFileLen) | |
| 176 break; | |
| 177 | |
| 178 if (!IsDataAvail(offset, size, pHints)) { | |
| 179 ret_array.Add(pObj); | |
| 180 count++; | |
| 181 } else if (!pdfium::ContainsKey(m_ObjectSet, dwNum)) { | |
| 182 m_ObjectSet.insert(dwNum); | |
| 183 CPDF_Object* pReferred = | |
| 184 m_pDocument->GetIndirectObject(pRef->GetRefObjNum()); | |
| 185 if (pReferred) | |
| 186 new_obj_array.Add(pReferred); | |
| 187 } | |
| 188 } break; | |
| 189 } | |
| 190 } | |
| 191 | |
| 192 if (count > 0) { | |
| 193 int32_t iSize = new_obj_array.GetSize(); | |
| 194 for (i = 0; i < iSize; ++i) { | |
| 195 CPDF_Object* pObj = new_obj_array[i]; | |
| 196 if (CPDF_Reference* pRef = pObj->AsReference()) { | |
| 197 FX_DWORD dwNum = pRef->GetRefObjNum(); | |
| 198 if (!pdfium::ContainsKey(m_ObjectSet, dwNum)) | |
| 199 ret_array.Add(pObj); | |
| 200 } else { | |
| 201 ret_array.Add(pObj); | |
| 202 } | |
| 203 } | |
| 204 return FALSE; | |
| 205 } | |
| 206 | |
| 207 obj_array.RemoveAll(); | |
| 208 obj_array.Append(new_obj_array); | |
| 209 return IsObjectsAvail(obj_array, FALSE, pHints, ret_array); | |
| 210 } | |
| 211 | |
| 212 IPDF_DataAvail::DocAvailStatus CPDF_DataAvail::IsDocAvail( | |
| 213 IPDF_DataAvail::DownloadHints* pHints) { | |
| 214 if (!m_dwFileLen && m_pFileRead) { | |
| 215 m_dwFileLen = (FX_DWORD)m_pFileRead->GetSize(); | |
| 216 if (!m_dwFileLen) | |
| 217 return DataError; | |
| 218 } | |
| 219 | |
| 220 while (!m_bDocAvail) { | |
| 221 if (!CheckDocStatus(pHints)) | |
| 222 return DataNotAvailable; | |
| 223 } | |
| 224 | |
| 225 return DataAvailable; | |
| 226 } | |
| 227 | |
| 228 FX_BOOL CPDF_DataAvail::CheckAcroFormSubObject( | |
| 229 IPDF_DataAvail::DownloadHints* pHints) { | |
| 230 if (!m_objs_array.GetSize()) { | |
| 231 m_objs_array.RemoveAll(); | |
| 232 m_ObjectSet.clear(); | |
| 233 CFX_ArrayTemplate<CPDF_Object*> obj_array; | |
| 234 obj_array.Append(m_arrayAcroforms); | |
| 235 FX_BOOL bRet = IsObjectsAvail(obj_array, FALSE, pHints, m_objs_array); | |
| 236 if (bRet) | |
| 237 m_objs_array.RemoveAll(); | |
| 238 return bRet; | |
| 239 } | |
| 240 | |
| 241 CFX_ArrayTemplate<CPDF_Object*> new_objs_array; | |
| 242 FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
| 243 if (bRet) { | |
| 244 int32_t iSize = m_arrayAcroforms.GetSize(); | |
| 245 for (int32_t i = 0; i < iSize; ++i) { | |
| 246 m_arrayAcroforms.GetAt(i)->Release(); | |
| 247 } | |
| 248 m_arrayAcroforms.RemoveAll(); | |
| 249 } else { | |
| 250 m_objs_array.RemoveAll(); | |
| 251 m_objs_array.Append(new_objs_array); | |
| 252 } | |
| 253 return bRet; | |
| 254 } | |
| 255 | |
| 256 FX_BOOL CPDF_DataAvail::CheckAcroForm(IPDF_DataAvail::DownloadHints* pHints) { | |
| 257 FX_BOOL bExist = FALSE; | |
| 258 m_pAcroForm = GetObject(m_dwAcroFormObjNum, pHints, &bExist); | |
| 259 if (!bExist) { | |
| 260 m_docStatus = PDF_DATAAVAIL_PAGETREE; | |
| 261 return TRUE; | |
| 262 } | |
| 263 | |
| 264 if (!m_pAcroForm) { | |
| 265 if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
| 266 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 267 return TRUE; | |
| 268 } | |
| 269 return FALSE; | |
| 270 } | |
| 271 | |
| 272 m_arrayAcroforms.Add(m_pAcroForm); | |
| 273 m_docStatus = PDF_DATAAVAIL_PAGETREE; | |
| 274 return TRUE; | |
| 275 } | |
| 276 | |
| 277 FX_BOOL CPDF_DataAvail::CheckDocStatus(IPDF_DataAvail::DownloadHints* pHints) { | |
| 278 switch (m_docStatus) { | |
| 279 case PDF_DATAAVAIL_HEADER: | |
| 280 return CheckHeader(pHints); | |
| 281 case PDF_DATAAVAIL_FIRSTPAGE: | |
| 282 case PDF_DATAAVAIL_FIRSTPAGE_PREPARE: | |
| 283 return CheckFirstPage(pHints); | |
| 284 case PDF_DATAAVAIL_HINTTABLE: | |
| 285 return CheckHintTables(pHints); | |
| 286 case PDF_DATAAVAIL_END: | |
| 287 return CheckEnd(pHints); | |
| 288 case PDF_DATAAVAIL_CROSSREF: | |
| 289 return CheckCrossRef(pHints); | |
| 290 case PDF_DATAAVAIL_CROSSREF_ITEM: | |
| 291 return CheckCrossRefItem(pHints); | |
| 292 case PDF_DATAAVAIL_CROSSREF_STREAM: | |
| 293 return CheckAllCrossRefStream(pHints); | |
| 294 case PDF_DATAAVAIL_TRAILER: | |
| 295 return CheckTrailer(pHints); | |
| 296 case PDF_DATAAVAIL_TRAILER_APPEND: | |
| 297 return CheckTrailerAppend(pHints); | |
| 298 case PDF_DATAAVAIL_LOADALLCROSSREF: | |
| 299 return LoadAllXref(pHints); | |
| 300 case PDF_DATAAVAIL_LOADALLFILE: | |
| 301 return LoadAllFile(pHints); | |
| 302 case PDF_DATAAVAIL_ROOT: | |
| 303 return CheckRoot(pHints); | |
| 304 case PDF_DATAAVAIL_INFO: | |
| 305 return CheckInfo(pHints); | |
| 306 case PDF_DATAAVAIL_ACROFORM: | |
| 307 return CheckAcroForm(pHints); | |
| 308 case PDF_DATAAVAIL_PAGETREE: | |
| 309 if (m_bTotalLoadPageTree) | |
| 310 return CheckPages(pHints); | |
| 311 return LoadDocPages(pHints); | |
| 312 case PDF_DATAAVAIL_PAGE: | |
| 313 if (m_bTotalLoadPageTree) | |
| 314 return CheckPage(pHints); | |
| 315 m_docStatus = PDF_DATAAVAIL_PAGE_LATERLOAD; | |
| 316 return TRUE; | |
| 317 case PDF_DATAAVAIL_ERROR: | |
| 318 return LoadAllFile(pHints); | |
| 319 case PDF_DATAAVAIL_PAGE_LATERLOAD: | |
| 320 m_docStatus = PDF_DATAAVAIL_PAGE; | |
| 321 default: | |
| 322 m_bDocAvail = TRUE; | |
| 323 return TRUE; | |
| 324 } | |
| 325 } | |
| 326 | |
| 327 FX_BOOL CPDF_DataAvail::CheckPageStatus(IPDF_DataAvail::DownloadHints* pHints) { | |
| 328 switch (m_docStatus) { | |
| 329 case PDF_DATAAVAIL_PAGETREE: | |
| 330 return CheckPages(pHints); | |
| 331 case PDF_DATAAVAIL_PAGE: | |
| 332 return CheckPage(pHints); | |
| 333 case PDF_DATAAVAIL_ERROR: | |
| 334 return LoadAllFile(pHints); | |
| 335 default: | |
| 336 m_bPagesTreeLoad = TRUE; | |
| 337 m_bPagesLoad = TRUE; | |
| 338 return TRUE; | |
| 339 } | |
| 340 } | |
| 341 | |
| 342 FX_BOOL CPDF_DataAvail::LoadAllFile(IPDF_DataAvail::DownloadHints* pHints) { | |
| 343 if (m_pFileAvail->IsDataAvail(0, (FX_DWORD)m_dwFileLen)) { | |
| 344 m_docStatus = PDF_DATAAVAIL_DONE; | |
| 345 return TRUE; | |
| 346 } | |
| 347 | |
| 348 pHints->AddSegment(0, (FX_DWORD)m_dwFileLen); | |
| 349 return FALSE; | |
| 350 } | |
| 351 | |
| 352 FX_BOOL CPDF_DataAvail::LoadAllXref(IPDF_DataAvail::DownloadHints* pHints) { | |
| 353 m_parser.m_pSyntax->InitParser(m_pFileRead, (FX_DWORD)m_dwHeaderOffset); | |
| 354 m_parser.m_bOwnFileRead = false; | |
| 355 if (!m_parser.LoadAllCrossRefV4(m_dwLastXRefOffset) && | |
| 356 !m_parser.LoadAllCrossRefV5(m_dwLastXRefOffset)) { | |
| 357 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 358 return FALSE; | |
| 359 } | |
| 360 | |
| 361 m_dwRootObjNum = m_parser.GetRootObjNum(); | |
| 362 m_dwInfoObjNum = m_parser.GetInfoObjNum(); | |
| 363 m_pCurrentParser = &m_parser; | |
| 364 m_docStatus = PDF_DATAAVAIL_ROOT; | |
| 365 return TRUE; | |
| 366 } | |
| 367 | |
| 368 CPDF_Object* CPDF_DataAvail::GetObject(FX_DWORD objnum, | |
| 369 IPDF_DataAvail::DownloadHints* pHints, | |
| 370 FX_BOOL* pExistInFile) { | |
| 371 CPDF_Object* pRet = nullptr; | |
| 372 FX_DWORD size = 0; | |
| 373 FX_FILESIZE offset = 0; | |
| 374 CPDF_Parser* pParser = nullptr; | |
| 375 | |
| 376 if (pExistInFile) | |
| 377 *pExistInFile = TRUE; | |
| 378 | |
| 379 if (m_pDocument) { | |
| 380 size = GetObjectSize(objnum, offset); | |
| 381 pParser = m_pDocument->GetParser(); | |
| 382 } else { | |
| 383 size = (FX_DWORD)m_parser.GetObjectSize(objnum); | |
| 384 offset = m_parser.GetObjectOffset(objnum); | |
| 385 pParser = &m_parser; | |
| 386 } | |
| 387 | |
| 388 if (!IsDataAvail(offset, size, pHints)) | |
| 389 return nullptr; | |
| 390 | |
| 391 if (pParser) | |
| 392 pRet = pParser->ParseIndirectObject(nullptr, objnum); | |
| 393 | |
| 394 if (!pRet && pExistInFile) | |
| 395 *pExistInFile = FALSE; | |
| 396 | |
| 397 return pRet; | |
| 398 } | |
| 399 | |
| 400 FX_BOOL CPDF_DataAvail::CheckInfo(IPDF_DataAvail::DownloadHints* pHints) { | |
| 401 FX_BOOL bExist = FALSE; | |
| 402 CPDF_Object* pInfo = GetObject(m_dwInfoObjNum, pHints, &bExist); | |
| 403 if (!bExist) { | |
| 404 m_docStatus = | |
| 405 (m_bHaveAcroForm ? PDF_DATAAVAIL_ACROFORM : PDF_DATAAVAIL_PAGETREE); | |
| 406 return TRUE; | |
| 407 } | |
| 408 | |
| 409 if (!pInfo) { | |
| 410 if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
| 411 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 412 return TRUE; | |
| 413 } | |
| 414 | |
| 415 if (m_Pos == m_dwFileLen) | |
| 416 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 417 return FALSE; | |
| 418 } | |
| 419 | |
| 420 if (pInfo) | |
| 421 pInfo->Release(); | |
| 422 | |
| 423 m_docStatus = | |
| 424 (m_bHaveAcroForm ? PDF_DATAAVAIL_ACROFORM : PDF_DATAAVAIL_PAGETREE); | |
| 425 | |
| 426 return TRUE; | |
| 427 } | |
| 428 | |
| 429 FX_BOOL CPDF_DataAvail::CheckRoot(IPDF_DataAvail::DownloadHints* pHints) { | |
| 430 FX_BOOL bExist = FALSE; | |
| 431 m_pRoot = GetObject(m_dwRootObjNum, pHints, &bExist); | |
| 432 if (!bExist) { | |
| 433 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 434 return TRUE; | |
| 435 } | |
| 436 | |
| 437 if (!m_pRoot) { | |
| 438 if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
| 439 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 440 return TRUE; | |
| 441 } | |
| 442 return FALSE; | |
| 443 } | |
| 444 | |
| 445 CPDF_Dictionary* pDict = m_pRoot->GetDict(); | |
| 446 if (!pDict) { | |
| 447 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 448 return FALSE; | |
| 449 } | |
| 450 | |
| 451 CPDF_Reference* pRef = ToReference(pDict->GetElement("Pages")); | |
| 452 if (!pRef) { | |
| 453 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 454 return FALSE; | |
| 455 } | |
| 456 | |
| 457 m_PagesObjNum = pRef->GetRefObjNum(); | |
| 458 CPDF_Reference* pAcroFormRef = | |
| 459 ToReference(m_pRoot->GetDict()->GetElement("AcroForm")); | |
| 460 if (pAcroFormRef) { | |
| 461 m_bHaveAcroForm = TRUE; | |
| 462 m_dwAcroFormObjNum = pAcroFormRef->GetRefObjNum(); | |
| 463 } | |
| 464 | |
| 465 if (m_dwInfoObjNum) { | |
| 466 m_docStatus = PDF_DATAAVAIL_INFO; | |
| 467 } else { | |
| 468 m_docStatus = | |
| 469 m_bHaveAcroForm ? PDF_DATAAVAIL_ACROFORM : PDF_DATAAVAIL_PAGETREE; | |
| 470 } | |
| 471 return TRUE; | |
| 472 } | |
| 473 | |
| 474 FX_BOOL CPDF_DataAvail::PreparePageItem() { | |
| 475 CPDF_Dictionary* pRoot = m_pDocument->GetRoot(); | |
| 476 CPDF_Reference* pRef = | |
| 477 ToReference(pRoot ? pRoot->GetElement("Pages") : nullptr); | |
| 478 if (!pRef) { | |
| 479 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 480 return FALSE; | |
| 481 } | |
| 482 | |
| 483 m_PagesObjNum = pRef->GetRefObjNum(); | |
| 484 m_pCurrentParser = m_pDocument->GetParser(); | |
| 485 m_docStatus = PDF_DATAAVAIL_PAGETREE; | |
| 486 return TRUE; | |
| 487 } | |
| 488 | |
| 489 bool CPDF_DataAvail::IsFirstCheck(int iPage) { | |
| 490 return m_pageMapCheckState.insert(iPage).second; | |
| 491 } | |
| 492 | |
| 493 void CPDF_DataAvail::ResetFirstCheck(int iPage) { | |
| 494 m_pageMapCheckState.erase(iPage); | |
| 495 } | |
| 496 | |
| 497 FX_BOOL CPDF_DataAvail::CheckPage(IPDF_DataAvail::DownloadHints* pHints) { | |
| 498 FX_DWORD iPageObjs = m_PageObjList.GetSize(); | |
| 499 CFX_DWordArray UnavailObjList; | |
| 500 for (FX_DWORD i = 0; i < iPageObjs; ++i) { | |
| 501 FX_DWORD dwPageObjNum = m_PageObjList.GetAt(i); | |
| 502 FX_BOOL bExist = FALSE; | |
| 503 CPDF_Object* pObj = GetObject(dwPageObjNum, pHints, &bExist); | |
| 504 if (!pObj) { | |
| 505 if (bExist) | |
| 506 UnavailObjList.Add(dwPageObjNum); | |
| 507 continue; | |
| 508 } | |
| 509 | |
| 510 if (pObj->IsArray()) { | |
| 511 CPDF_Array* pArray = pObj->GetArray(); | |
| 512 if (pArray) { | |
| 513 int32_t iSize = pArray->GetCount(); | |
| 514 for (int32_t j = 0; j < iSize; ++j) { | |
| 515 if (CPDF_Reference* pRef = ToReference(pArray->GetElement(j))) | |
| 516 UnavailObjList.Add(pRef->GetRefObjNum()); | |
| 517 } | |
| 518 } | |
| 519 } | |
| 520 | |
| 521 if (!pObj->IsDictionary()) { | |
| 522 pObj->Release(); | |
| 523 continue; | |
| 524 } | |
| 525 | |
| 526 CFX_ByteString type = pObj->GetDict()->GetStringBy("Type"); | |
| 527 if (type == "Pages") { | |
| 528 m_PagesArray.Add(pObj); | |
| 529 continue; | |
| 530 } | |
| 531 pObj->Release(); | |
| 532 } | |
| 533 | |
| 534 m_PageObjList.RemoveAll(); | |
| 535 if (UnavailObjList.GetSize()) { | |
| 536 m_PageObjList.Append(UnavailObjList); | |
| 537 return FALSE; | |
| 538 } | |
| 539 | |
| 540 FX_DWORD iPages = m_PagesArray.GetSize(); | |
| 541 for (FX_DWORD i = 0; i < iPages; i++) { | |
| 542 CPDF_Object* pPages = m_PagesArray.GetAt(i); | |
| 543 if (!pPages) | |
| 544 continue; | |
| 545 | |
| 546 if (!GetPageKids(m_pCurrentParser, pPages)) { | |
| 547 pPages->Release(); | |
| 548 while (++i < iPages) { | |
| 549 pPages = m_PagesArray.GetAt(i); | |
| 550 pPages->Release(); | |
| 551 } | |
| 552 m_PagesArray.RemoveAll(); | |
| 553 | |
| 554 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 555 return FALSE; | |
| 556 } | |
| 557 pPages->Release(); | |
| 558 } | |
| 559 | |
| 560 m_PagesArray.RemoveAll(); | |
| 561 if (!m_PageObjList.GetSize()) | |
| 562 m_docStatus = PDF_DATAAVAIL_DONE; | |
| 563 return TRUE; | |
| 564 } | |
| 565 | |
| 566 FX_BOOL CPDF_DataAvail::GetPageKids(CPDF_Parser* pParser, CPDF_Object* pPages) { | |
| 567 if (!pParser) { | |
| 568 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 569 return FALSE; | |
| 570 } | |
| 571 | |
| 572 CPDF_Dictionary* pDict = pPages->GetDict(); | |
| 573 CPDF_Object* pKids = pDict ? pDict->GetElement("Kids") : NULL; | |
| 574 if (!pKids) | |
| 575 return TRUE; | |
| 576 | |
| 577 switch (pKids->GetType()) { | |
| 578 case CPDF_Object::REFERENCE: | |
| 579 m_PageObjList.Add(pKids->AsReference()->GetRefObjNum()); | |
| 580 break; | |
| 581 case CPDF_Object::ARRAY: { | |
| 582 CPDF_Array* pKidsArray = pKids->AsArray(); | |
| 583 for (FX_DWORD i = 0; i < pKidsArray->GetCount(); ++i) { | |
| 584 if (CPDF_Reference* pRef = ToReference(pKidsArray->GetElement(i))) | |
| 585 m_PageObjList.Add(pRef->GetRefObjNum()); | |
| 586 } | |
| 587 } break; | |
| 588 default: | |
| 589 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 590 return FALSE; | |
| 591 } | |
| 592 return TRUE; | |
| 593 } | |
| 594 | |
| 595 FX_BOOL CPDF_DataAvail::CheckPages(IPDF_DataAvail::DownloadHints* pHints) { | |
| 596 FX_BOOL bExist = FALSE; | |
| 597 CPDF_Object* pPages = GetObject(m_PagesObjNum, pHints, &bExist); | |
| 598 if (!bExist) { | |
| 599 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 600 return TRUE; | |
| 601 } | |
| 602 | |
| 603 if (!pPages) { | |
| 604 if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
| 605 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 606 return TRUE; | |
| 607 } | |
| 608 return FALSE; | |
| 609 } | |
| 610 | |
| 611 if (!GetPageKids(m_pCurrentParser, pPages)) { | |
| 612 pPages->Release(); | |
| 613 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 614 return FALSE; | |
| 615 } | |
| 616 | |
| 617 pPages->Release(); | |
| 618 m_docStatus = PDF_DATAAVAIL_PAGE; | |
| 619 return TRUE; | |
| 620 } | |
| 621 | |
| 622 FX_BOOL CPDF_DataAvail::CheckHeader(IPDF_DataAvail::DownloadHints* pHints) { | |
| 623 FX_DWORD req_size = 1024; | |
| 624 if ((FX_FILESIZE)req_size > m_dwFileLen) | |
| 625 req_size = (FX_DWORD)m_dwFileLen; | |
| 626 | |
| 627 if (m_pFileAvail->IsDataAvail(0, req_size)) { | |
| 628 uint8_t buffer[1024]; | |
| 629 m_pFileRead->ReadBlock(buffer, 0, req_size); | |
| 630 | |
| 631 if (IsLinearizedFile(buffer, req_size)) { | |
| 632 m_docStatus = PDF_DATAAVAIL_FIRSTPAGE; | |
| 633 } else { | |
| 634 if (m_docStatus == PDF_DATAAVAIL_ERROR) | |
| 635 return FALSE; | |
| 636 m_docStatus = PDF_DATAAVAIL_END; | |
| 637 } | |
| 638 return TRUE; | |
| 639 } | |
| 640 | |
| 641 pHints->AddSegment(0, req_size); | |
| 642 return FALSE; | |
| 643 } | |
| 644 | |
| 645 FX_BOOL CPDF_DataAvail::CheckFirstPage(IPDF_DataAvail::DownloadHints* pHints) { | |
| 646 CPDF_Dictionary* pDict = m_pLinearized->GetDict(); | |
| 647 CPDF_Object* pEndOffSet = pDict ? pDict->GetElement("E") : NULL; | |
| 648 if (!pEndOffSet) { | |
| 649 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 650 return FALSE; | |
| 651 } | |
| 652 | |
| 653 CPDF_Object* pXRefOffset = pDict ? pDict->GetElement("T") : NULL; | |
| 654 if (!pXRefOffset) { | |
| 655 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 656 return FALSE; | |
| 657 } | |
| 658 | |
| 659 CPDF_Object* pFileLen = pDict ? pDict->GetElement("L") : NULL; | |
| 660 if (!pFileLen) { | |
| 661 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 662 return FALSE; | |
| 663 } | |
| 664 | |
| 665 FX_BOOL bNeedDownLoad = FALSE; | |
| 666 if (pEndOffSet->IsNumber()) { | |
| 667 FX_DWORD dwEnd = pEndOffSet->GetInteger(); | |
| 668 dwEnd += 512; | |
| 669 if ((FX_FILESIZE)dwEnd > m_dwFileLen) | |
| 670 dwEnd = (FX_DWORD)m_dwFileLen; | |
| 671 | |
| 672 int32_t iStartPos = (int32_t)(m_dwFileLen > 1024 ? 1024 : m_dwFileLen); | |
| 673 int32_t iSize = dwEnd > 1024 ? dwEnd - 1024 : 0; | |
| 674 if (!m_pFileAvail->IsDataAvail(iStartPos, iSize)) { | |
| 675 pHints->AddSegment(iStartPos, iSize); | |
| 676 bNeedDownLoad = TRUE; | |
| 677 } | |
| 678 } | |
| 679 | |
| 680 m_dwLastXRefOffset = 0; | |
| 681 FX_FILESIZE dwFileLen = 0; | |
| 682 if (pXRefOffset->IsNumber()) | |
| 683 m_dwLastXRefOffset = pXRefOffset->GetInteger(); | |
| 684 | |
| 685 if (pFileLen->IsNumber()) | |
| 686 dwFileLen = pFileLen->GetInteger(); | |
| 687 | |
| 688 if (!m_pFileAvail->IsDataAvail(m_dwLastXRefOffset, | |
| 689 (FX_DWORD)(dwFileLen - m_dwLastXRefOffset))) { | |
| 690 if (m_docStatus == PDF_DATAAVAIL_FIRSTPAGE) { | |
| 691 FX_DWORD dwSize = (FX_DWORD)(dwFileLen - m_dwLastXRefOffset); | |
| 692 FX_FILESIZE offset = m_dwLastXRefOffset; | |
| 693 if (dwSize < 512 && dwFileLen > 512) { | |
| 694 dwSize = 512; | |
| 695 offset = dwFileLen - 512; | |
| 696 } | |
| 697 pHints->AddSegment(offset, dwSize); | |
| 698 } | |
| 699 } else { | |
| 700 m_docStatus = PDF_DATAAVAIL_FIRSTPAGE_PREPARE; | |
| 701 } | |
| 702 | |
| 703 if (bNeedDownLoad || m_docStatus != PDF_DATAAVAIL_FIRSTPAGE_PREPARE) { | |
| 704 m_docStatus = PDF_DATAAVAIL_FIRSTPAGE_PREPARE; | |
| 705 return FALSE; | |
| 706 } | |
| 707 | |
| 708 m_docStatus = | |
| 709 m_bSupportHintTable ? PDF_DATAAVAIL_HINTTABLE : PDF_DATAAVAIL_DONE; | |
| 710 return TRUE; | |
| 711 } | |
| 712 | |
| 713 FX_BOOL CPDF_DataAvail::IsDataAvail(FX_FILESIZE offset, | |
| 714 FX_DWORD size, | |
| 715 IPDF_DataAvail::DownloadHints* pHints) { | |
| 716 if (offset > m_dwFileLen) | |
| 717 return TRUE; | |
| 718 | |
| 719 FX_SAFE_DWORD safeSize = pdfium::base::checked_cast<FX_DWORD>(offset); | |
| 720 safeSize += size; | |
| 721 safeSize += 512; | |
| 722 if (!safeSize.IsValid() || safeSize.ValueOrDie() > m_dwFileLen) | |
| 723 size = m_dwFileLen - offset; | |
| 724 else | |
| 725 size += 512; | |
| 726 | |
| 727 if (!m_pFileAvail->IsDataAvail(offset, size)) { | |
| 728 pHints->AddSegment(offset, size); | |
| 729 return FALSE; | |
| 730 } | |
| 731 return TRUE; | |
| 732 } | |
| 733 | |
| 734 FX_BOOL CPDF_DataAvail::CheckHintTables(IPDF_DataAvail::DownloadHints* pHints) { | |
| 735 CPDF_Dictionary* pDict = m_pLinearized->GetDict(); | |
| 736 if (!pDict) { | |
| 737 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 738 return FALSE; | |
| 739 } | |
| 740 | |
| 741 if (!pDict->KeyExist("H") || !pDict->KeyExist("O") || !pDict->KeyExist("N")) { | |
| 742 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 743 return FALSE; | |
| 744 } | |
| 745 | |
| 746 int nPageCount = pDict->GetElementValue("N")->GetInteger(); | |
| 747 if (nPageCount <= 1) { | |
| 748 m_docStatus = PDF_DATAAVAIL_DONE; | |
| 749 return TRUE; | |
| 750 } | |
| 751 | |
| 752 CPDF_Array* pHintStreamRange = pDict->GetArrayBy("H"); | |
| 753 FX_FILESIZE szHSStart = | |
| 754 pHintStreamRange->GetElementValue(0) | |
| 755 ? pHintStreamRange->GetElementValue(0)->GetInteger() | |
| 756 : 0; | |
| 757 FX_FILESIZE szHSLength = | |
| 758 pHintStreamRange->GetElementValue(1) | |
| 759 ? pHintStreamRange->GetElementValue(1)->GetInteger() | |
| 760 : 0; | |
| 761 if (szHSStart < 0 || szHSLength <= 0) { | |
| 762 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 763 return FALSE; | |
| 764 } | |
| 765 | |
| 766 if (!IsDataAvail(szHSStart, szHSLength, pHints)) | |
| 767 return FALSE; | |
| 768 | |
| 769 m_syntaxParser.InitParser(m_pFileRead, m_dwHeaderOffset); | |
| 770 | |
| 771 std::unique_ptr<CPDF_HintTables> pHintTables( | |
| 772 new CPDF_HintTables(this, pDict)); | |
| 773 std::unique_ptr<CPDF_Object, ReleaseDeleter<CPDF_Object>> pHintStream( | |
| 774 ParseIndirectObjectAt(szHSStart, 0)); | |
| 775 CPDF_Stream* pStream = ToStream(pHintStream.get()); | |
| 776 if (pStream && pHintTables->LoadHintStream(pStream)) | |
| 777 m_pHintTables = std::move(pHintTables); | |
| 778 | |
| 779 m_docStatus = PDF_DATAAVAIL_DONE; | |
| 780 return TRUE; | |
| 781 } | |
| 782 | |
| 783 CPDF_Object* CPDF_DataAvail::ParseIndirectObjectAt( | |
| 784 FX_FILESIZE pos, | |
| 785 FX_DWORD objnum, | |
| 786 CPDF_IndirectObjectHolder* pObjList) { | |
| 787 FX_FILESIZE SavedPos = m_syntaxParser.SavePos(); | |
| 788 m_syntaxParser.RestorePos(pos); | |
| 789 | |
| 790 bool bIsNumber; | |
| 791 CFX_ByteString word = m_syntaxParser.GetNextWord(&bIsNumber); | |
| 792 if (!bIsNumber) | |
| 793 return nullptr; | |
| 794 | |
| 795 FX_DWORD parser_objnum = FXSYS_atoui(word); | |
| 796 if (objnum && parser_objnum != objnum) | |
| 797 return nullptr; | |
| 798 | |
| 799 word = m_syntaxParser.GetNextWord(&bIsNumber); | |
| 800 if (!bIsNumber) | |
| 801 return nullptr; | |
| 802 | |
| 803 FX_DWORD gennum = FXSYS_atoui(word); | |
| 804 if (m_syntaxParser.GetKeyword() != "obj") { | |
| 805 m_syntaxParser.RestorePos(SavedPos); | |
| 806 return nullptr; | |
| 807 } | |
| 808 | |
| 809 CPDF_Object* pObj = | |
| 810 m_syntaxParser.GetObject(pObjList, parser_objnum, gennum, true); | |
| 811 m_syntaxParser.RestorePos(SavedPos); | |
| 812 return pObj; | |
| 813 } | |
| 814 | |
| 815 IPDF_DataAvail::DocLinearizationStatus CPDF_DataAvail::IsLinearizedPDF() { | |
| 816 FX_DWORD req_size = 1024; | |
| 817 if (!m_pFileAvail->IsDataAvail(0, req_size)) | |
| 818 return LinearizationUnknown; | |
| 819 | |
| 820 if (!m_pFileRead) | |
| 821 return NotLinearized; | |
| 822 | |
| 823 FX_FILESIZE dwSize = m_pFileRead->GetSize(); | |
| 824 if (dwSize < (FX_FILESIZE)req_size) | |
| 825 return LinearizationUnknown; | |
| 826 | |
| 827 uint8_t buffer[1024]; | |
| 828 m_pFileRead->ReadBlock(buffer, 0, req_size); | |
| 829 if (IsLinearizedFile(buffer, req_size)) | |
| 830 return Linearized; | |
| 831 | |
| 832 return NotLinearized; | |
| 833 } | |
| 834 FX_BOOL CPDF_DataAvail::IsLinearizedFile(uint8_t* pData, FX_DWORD dwLen) { | |
| 835 ScopedFileStream file(FX_CreateMemoryStream(pData, (size_t)dwLen, FALSE)); | |
| 836 | |
| 837 int32_t offset = GetHeaderOffset(file.get()); | |
| 838 if (offset == -1) { | |
| 839 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 840 return FALSE; | |
| 841 } | |
| 842 | |
| 843 m_dwHeaderOffset = offset; | |
| 844 m_syntaxParser.InitParser(file.get(), offset); | |
| 845 m_syntaxParser.RestorePos(m_syntaxParser.m_HeaderOffset + 9); | |
| 846 | |
| 847 bool bNumber; | |
| 848 CFX_ByteString wordObjNum = m_syntaxParser.GetNextWord(&bNumber); | |
| 849 if (!bNumber) | |
| 850 return FALSE; | |
| 851 | |
| 852 FX_DWORD objnum = FXSYS_atoui(wordObjNum); | |
| 853 if (m_pLinearized) { | |
| 854 m_pLinearized->Release(); | |
| 855 m_pLinearized = nullptr; | |
| 856 } | |
| 857 | |
| 858 m_pLinearized = | |
| 859 ParseIndirectObjectAt(m_syntaxParser.m_HeaderOffset + 9, objnum); | |
| 860 if (!m_pLinearized) | |
| 861 return FALSE; | |
| 862 | |
| 863 CPDF_Dictionary* pDict = m_pLinearized->GetDict(); | |
| 864 if (pDict && pDict->GetElement("Linearized")) { | |
| 865 CPDF_Object* pLen = pDict->GetElement("L"); | |
| 866 if (!pLen) | |
| 867 return FALSE; | |
| 868 | |
| 869 if ((FX_FILESIZE)pLen->GetInteger() != m_pFileRead->GetSize()) | |
| 870 return FALSE; | |
| 871 | |
| 872 m_bLinearized = TRUE; | |
| 873 | |
| 874 if (CPDF_Number* pNo = ToNumber(pDict->GetElement("P"))) | |
| 875 m_dwFirstPageNo = pNo->GetInteger(); | |
| 876 | |
| 877 return TRUE; | |
| 878 } | |
| 879 return FALSE; | |
| 880 } | |
| 881 | |
| 882 FX_BOOL CPDF_DataAvail::CheckEnd(IPDF_DataAvail::DownloadHints* pHints) { | |
| 883 FX_DWORD req_pos = (FX_DWORD)(m_dwFileLen > 1024 ? m_dwFileLen - 1024 : 0); | |
| 884 FX_DWORD dwSize = (FX_DWORD)(m_dwFileLen - req_pos); | |
| 885 | |
| 886 if (m_pFileAvail->IsDataAvail(req_pos, dwSize)) { | |
| 887 uint8_t buffer[1024]; | |
| 888 m_pFileRead->ReadBlock(buffer, req_pos, dwSize); | |
| 889 | |
| 890 ScopedFileStream file(FX_CreateMemoryStream(buffer, (size_t)dwSize, FALSE)); | |
| 891 m_syntaxParser.InitParser(file.get(), 0); | |
| 892 m_syntaxParser.RestorePos(dwSize - 1); | |
| 893 | |
| 894 if (m_syntaxParser.SearchWord("startxref", TRUE, FALSE, dwSize)) { | |
| 895 m_syntaxParser.GetNextWord(nullptr); | |
| 896 | |
| 897 bool bNumber; | |
| 898 CFX_ByteString xrefpos_str = m_syntaxParser.GetNextWord(&bNumber); | |
| 899 if (!bNumber) { | |
| 900 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 901 return FALSE; | |
| 902 } | |
| 903 | |
| 904 m_dwXRefOffset = (FX_FILESIZE)FXSYS_atoi64(xrefpos_str); | |
| 905 if (!m_dwXRefOffset || m_dwXRefOffset > m_dwFileLen) { | |
| 906 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 907 return TRUE; | |
| 908 } | |
| 909 | |
| 910 m_dwLastXRefOffset = m_dwXRefOffset; | |
| 911 SetStartOffset(m_dwXRefOffset); | |
| 912 m_docStatus = PDF_DATAAVAIL_CROSSREF; | |
| 913 return TRUE; | |
| 914 } | |
| 915 | |
| 916 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 917 return TRUE; | |
| 918 } | |
| 919 | |
| 920 pHints->AddSegment(req_pos, dwSize); | |
| 921 return FALSE; | |
| 922 } | |
| 923 | |
| 924 int32_t CPDF_DataAvail::CheckCrossRefStream( | |
| 925 IPDF_DataAvail::DownloadHints* pHints, | |
| 926 FX_FILESIZE& xref_offset) { | |
| 927 xref_offset = 0; | |
| 928 FX_DWORD req_size = | |
| 929 (FX_DWORD)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
| 930 | |
| 931 if (m_pFileAvail->IsDataAvail(m_Pos, req_size)) { | |
| 932 int32_t iSize = (int32_t)(m_Pos + req_size - m_dwCurrentXRefSteam); | |
| 933 CFX_BinaryBuf buf(iSize); | |
| 934 uint8_t* pBuf = buf.GetBuffer(); | |
| 935 | |
| 936 m_pFileRead->ReadBlock(pBuf, m_dwCurrentXRefSteam, iSize); | |
| 937 | |
| 938 ScopedFileStream file(FX_CreateMemoryStream(pBuf, (size_t)iSize, FALSE)); | |
| 939 m_parser.m_pSyntax->InitParser(file.get(), 0); | |
| 940 | |
| 941 bool bNumber; | |
| 942 CFX_ByteString objnum = m_parser.m_pSyntax->GetNextWord(&bNumber); | |
| 943 if (!bNumber) | |
| 944 return -1; | |
| 945 | |
| 946 FX_DWORD objNum = FXSYS_atoui(objnum); | |
| 947 CPDF_Object* pObj = m_parser.ParseIndirectObjectAt(nullptr, 0, objNum); | |
| 948 if (!pObj) { | |
| 949 m_Pos += m_parser.m_pSyntax->SavePos(); | |
| 950 return 0; | |
| 951 } | |
| 952 | |
| 953 CPDF_Dictionary* pDict = pObj->GetDict(); | |
| 954 CPDF_Name* pName = ToName(pDict ? pDict->GetElement("Type") : nullptr); | |
| 955 if (pName) { | |
| 956 if (pName->GetString() == "XRef") { | |
| 957 m_Pos += m_parser.m_pSyntax->SavePos(); | |
| 958 xref_offset = pObj->GetDict()->GetIntegerBy("Prev"); | |
| 959 pObj->Release(); | |
| 960 return 1; | |
| 961 } | |
| 962 } | |
| 963 pObj->Release(); | |
| 964 return -1; | |
| 965 } | |
| 966 pHints->AddSegment(m_Pos, req_size); | |
| 967 return 0; | |
| 968 } | |
| 969 | |
| 970 inline void CPDF_DataAvail::SetStartOffset(FX_FILESIZE dwOffset) { | |
| 971 m_Pos = dwOffset; | |
| 972 } | |
| 973 | |
| 974 FX_BOOL CPDF_DataAvail::GetNextToken(CFX_ByteString& token) { | |
| 975 uint8_t ch; | |
| 976 if (!GetNextChar(ch)) | |
| 977 return FALSE; | |
| 978 | |
| 979 while (1) { | |
| 980 while (PDFCharIsWhitespace(ch)) { | |
| 981 if (!GetNextChar(ch)) | |
| 982 return FALSE; | |
| 983 } | |
| 984 | |
| 985 if (ch != '%') | |
| 986 break; | |
| 987 | |
| 988 while (1) { | |
| 989 if (!GetNextChar(ch)) | |
| 990 return FALSE; | |
| 991 if (PDFCharIsLineEnding(ch)) | |
| 992 break; | |
| 993 } | |
| 994 } | |
| 995 | |
| 996 uint8_t buffer[256]; | |
| 997 FX_DWORD index = 0; | |
| 998 if (PDFCharIsDelimiter(ch)) { | |
| 999 buffer[index++] = ch; | |
| 1000 if (ch == '/') { | |
| 1001 while (1) { | |
| 1002 if (!GetNextChar(ch)) | |
| 1003 return FALSE; | |
| 1004 | |
| 1005 if (!PDFCharIsOther(ch) && !PDFCharIsNumeric(ch)) { | |
| 1006 m_Pos--; | |
| 1007 CFX_ByteString ret(buffer, index); | |
| 1008 token = ret; | |
| 1009 return TRUE; | |
| 1010 } | |
| 1011 | |
| 1012 if (index < sizeof(buffer)) | |
| 1013 buffer[index++] = ch; | |
| 1014 } | |
| 1015 } else if (ch == '<') { | |
| 1016 if (!GetNextChar(ch)) | |
| 1017 return FALSE; | |
| 1018 | |
| 1019 if (ch == '<') | |
| 1020 buffer[index++] = ch; | |
| 1021 else | |
| 1022 m_Pos--; | |
| 1023 } else if (ch == '>') { | |
| 1024 if (!GetNextChar(ch)) | |
| 1025 return FALSE; | |
| 1026 | |
| 1027 if (ch == '>') | |
| 1028 buffer[index++] = ch; | |
| 1029 else | |
| 1030 m_Pos--; | |
| 1031 } | |
| 1032 | |
| 1033 CFX_ByteString ret(buffer, index); | |
| 1034 token = ret; | |
| 1035 return TRUE; | |
| 1036 } | |
| 1037 | |
| 1038 while (1) { | |
| 1039 if (index < sizeof(buffer)) | |
| 1040 buffer[index++] = ch; | |
| 1041 | |
| 1042 if (!GetNextChar(ch)) | |
| 1043 return FALSE; | |
| 1044 | |
| 1045 if (PDFCharIsDelimiter(ch) || PDFCharIsWhitespace(ch)) { | |
| 1046 m_Pos--; | |
| 1047 break; | |
| 1048 } | |
| 1049 } | |
| 1050 | |
| 1051 token = CFX_ByteString(buffer, index); | |
| 1052 return TRUE; | |
| 1053 } | |
| 1054 | |
| 1055 FX_BOOL CPDF_DataAvail::GetNextChar(uint8_t& ch) { | |
| 1056 FX_FILESIZE pos = m_Pos; | |
| 1057 if (pos >= m_dwFileLen) | |
| 1058 return FALSE; | |
| 1059 | |
| 1060 if (m_bufferOffset >= pos || | |
| 1061 (FX_FILESIZE)(m_bufferOffset + m_bufferSize) <= pos) { | |
| 1062 FX_FILESIZE read_pos = pos; | |
| 1063 FX_DWORD read_size = 512; | |
| 1064 if ((FX_FILESIZE)read_size > m_dwFileLen) | |
| 1065 read_size = (FX_DWORD)m_dwFileLen; | |
| 1066 | |
| 1067 if ((FX_FILESIZE)(read_pos + read_size) > m_dwFileLen) | |
| 1068 read_pos = m_dwFileLen - read_size; | |
| 1069 | |
| 1070 if (!m_pFileRead->ReadBlock(m_bufferData, read_pos, read_size)) | |
| 1071 return FALSE; | |
| 1072 | |
| 1073 m_bufferOffset = read_pos; | |
| 1074 m_bufferSize = read_size; | |
| 1075 } | |
| 1076 ch = m_bufferData[pos - m_bufferOffset]; | |
| 1077 m_Pos++; | |
| 1078 return TRUE; | |
| 1079 } | |
| 1080 | |
| 1081 FX_BOOL CPDF_DataAvail::CheckCrossRefItem( | |
| 1082 IPDF_DataAvail::DownloadHints* pHints) { | |
| 1083 int32_t iSize = 0; | |
| 1084 CFX_ByteString token; | |
| 1085 while (1) { | |
| 1086 if (!GetNextToken(token)) { | |
| 1087 iSize = (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
| 1088 pHints->AddSegment(m_Pos, iSize); | |
| 1089 return FALSE; | |
| 1090 } | |
| 1091 | |
| 1092 if (token == "trailer") { | |
| 1093 m_dwTrailerOffset = m_Pos; | |
| 1094 m_docStatus = PDF_DATAAVAIL_TRAILER; | |
| 1095 return TRUE; | |
| 1096 } | |
| 1097 } | |
| 1098 } | |
| 1099 | |
| 1100 FX_BOOL CPDF_DataAvail::CheckAllCrossRefStream( | |
| 1101 IPDF_DataAvail::DownloadHints* pHints) { | |
| 1102 FX_FILESIZE xref_offset = 0; | |
| 1103 | |
| 1104 int32_t nRet = CheckCrossRefStream(pHints, xref_offset); | |
| 1105 if (nRet == 1) { | |
| 1106 if (!xref_offset) { | |
| 1107 m_docStatus = PDF_DATAAVAIL_LOADALLCROSSREF; | |
| 1108 } else { | |
| 1109 m_dwCurrentXRefSteam = xref_offset; | |
| 1110 m_Pos = xref_offset; | |
| 1111 } | |
| 1112 return TRUE; | |
| 1113 } | |
| 1114 | |
| 1115 if (nRet == -1) | |
| 1116 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1117 return FALSE; | |
| 1118 } | |
| 1119 | |
| 1120 FX_BOOL CPDF_DataAvail::CheckCrossRef(IPDF_DataAvail::DownloadHints* pHints) { | |
| 1121 int32_t iSize = 0; | |
| 1122 CFX_ByteString token; | |
| 1123 if (!GetNextToken(token)) { | |
| 1124 iSize = (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
| 1125 pHints->AddSegment(m_Pos, iSize); | |
| 1126 return FALSE; | |
| 1127 } | |
| 1128 | |
| 1129 if (token == "xref") { | |
| 1130 while (1) { | |
| 1131 if (!GetNextToken(token)) { | |
| 1132 iSize = | |
| 1133 (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
| 1134 pHints->AddSegment(m_Pos, iSize); | |
| 1135 m_docStatus = PDF_DATAAVAIL_CROSSREF_ITEM; | |
| 1136 return FALSE; | |
| 1137 } | |
| 1138 | |
| 1139 if (token == "trailer") { | |
| 1140 m_dwTrailerOffset = m_Pos; | |
| 1141 m_docStatus = PDF_DATAAVAIL_TRAILER; | |
| 1142 return TRUE; | |
| 1143 } | |
| 1144 } | |
| 1145 } else { | |
| 1146 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 1147 return TRUE; | |
| 1148 } | |
| 1149 return FALSE; | |
| 1150 } | |
| 1151 | |
| 1152 FX_BOOL CPDF_DataAvail::CheckTrailerAppend( | |
| 1153 IPDF_DataAvail::DownloadHints* pHints) { | |
| 1154 if (m_Pos < m_dwFileLen) { | |
| 1155 FX_FILESIZE dwAppendPos = m_Pos + m_syntaxParser.SavePos(); | |
| 1156 int32_t iSize = (int32_t)( | |
| 1157 dwAppendPos + 512 > m_dwFileLen ? m_dwFileLen - dwAppendPos : 512); | |
| 1158 | |
| 1159 if (!m_pFileAvail->IsDataAvail(dwAppendPos, iSize)) { | |
| 1160 pHints->AddSegment(dwAppendPos, iSize); | |
| 1161 return FALSE; | |
| 1162 } | |
| 1163 } | |
| 1164 | |
| 1165 if (m_dwPrevXRefOffset) { | |
| 1166 SetStartOffset(m_dwPrevXRefOffset); | |
| 1167 m_docStatus = PDF_DATAAVAIL_CROSSREF; | |
| 1168 } else { | |
| 1169 m_docStatus = PDF_DATAAVAIL_LOADALLCROSSREF; | |
| 1170 } | |
| 1171 return TRUE; | |
| 1172 } | |
| 1173 | |
| 1174 FX_BOOL CPDF_DataAvail::CheckTrailer(IPDF_DataAvail::DownloadHints* pHints) { | |
| 1175 int32_t iTrailerSize = | |
| 1176 (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
| 1177 if (m_pFileAvail->IsDataAvail(m_Pos, iTrailerSize)) { | |
| 1178 int32_t iSize = (int32_t)(m_Pos + iTrailerSize - m_dwTrailerOffset); | |
| 1179 CFX_BinaryBuf buf(iSize); | |
| 1180 uint8_t* pBuf = buf.GetBuffer(); | |
| 1181 if (!pBuf) { | |
| 1182 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1183 return FALSE; | |
| 1184 } | |
| 1185 | |
| 1186 if (!m_pFileRead->ReadBlock(pBuf, m_dwTrailerOffset, iSize)) | |
| 1187 return FALSE; | |
| 1188 | |
| 1189 ScopedFileStream file(FX_CreateMemoryStream(pBuf, (size_t)iSize, FALSE)); | |
| 1190 m_syntaxParser.InitParser(file.get(), 0); | |
| 1191 | |
| 1192 std::unique_ptr<CPDF_Object, ReleaseDeleter<CPDF_Object>> pTrailer( | |
| 1193 m_syntaxParser.GetObject(nullptr, 0, 0, true)); | |
| 1194 if (!pTrailer) { | |
| 1195 m_Pos += m_syntaxParser.SavePos(); | |
| 1196 pHints->AddSegment(m_Pos, iTrailerSize); | |
| 1197 return FALSE; | |
| 1198 } | |
| 1199 | |
| 1200 if (!pTrailer->IsDictionary()) | |
| 1201 return FALSE; | |
| 1202 | |
| 1203 CPDF_Dictionary* pTrailerDict = pTrailer->GetDict(); | |
| 1204 CPDF_Object* pEncrypt = pTrailerDict->GetElement("Encrypt"); | |
| 1205 if (ToReference(pEncrypt)) { | |
| 1206 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 1207 return TRUE; | |
| 1208 } | |
| 1209 | |
| 1210 FX_DWORD xrefpos = GetDirectInteger(pTrailerDict, "Prev"); | |
| 1211 if (xrefpos) { | |
| 1212 m_dwPrevXRefOffset = GetDirectInteger(pTrailerDict, "XRefStm"); | |
| 1213 if (m_dwPrevXRefOffset) { | |
| 1214 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 1215 } else { | |
| 1216 m_dwPrevXRefOffset = xrefpos; | |
| 1217 if (m_dwPrevXRefOffset >= m_dwFileLen) { | |
| 1218 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 1219 } else { | |
| 1220 SetStartOffset(m_dwPrevXRefOffset); | |
| 1221 m_docStatus = PDF_DATAAVAIL_TRAILER_APPEND; | |
| 1222 } | |
| 1223 } | |
| 1224 return TRUE; | |
| 1225 } | |
| 1226 m_dwPrevXRefOffset = 0; | |
| 1227 m_docStatus = PDF_DATAAVAIL_TRAILER_APPEND; | |
| 1228 return TRUE; | |
| 1229 } | |
| 1230 pHints->AddSegment(m_Pos, iTrailerSize); | |
| 1231 return FALSE; | |
| 1232 } | |
| 1233 | |
| 1234 FX_BOOL CPDF_DataAvail::CheckPage(int32_t iPage, | |
| 1235 IPDF_DataAvail::DownloadHints* pHints) { | |
| 1236 while (TRUE) { | |
| 1237 switch (m_docStatus) { | |
| 1238 case PDF_DATAAVAIL_PAGETREE: | |
| 1239 if (!LoadDocPages(pHints)) | |
| 1240 return FALSE; | |
| 1241 break; | |
| 1242 case PDF_DATAAVAIL_PAGE: | |
| 1243 if (!LoadDocPage(iPage, pHints)) | |
| 1244 return FALSE; | |
| 1245 break; | |
| 1246 case PDF_DATAAVAIL_ERROR: | |
| 1247 return LoadAllFile(pHints); | |
| 1248 default: | |
| 1249 m_bPagesTreeLoad = TRUE; | |
| 1250 m_bPagesLoad = TRUE; | |
| 1251 m_bCurPageDictLoadOK = TRUE; | |
| 1252 m_docStatus = PDF_DATAAVAIL_PAGE; | |
| 1253 return TRUE; | |
| 1254 } | |
| 1255 } | |
| 1256 } | |
| 1257 | |
| 1258 FX_BOOL CPDF_DataAvail::CheckArrayPageNode( | |
| 1259 FX_DWORD dwPageNo, | |
| 1260 CPDF_DataAvail::PageNode* pPageNode, | |
| 1261 IPDF_DataAvail::DownloadHints* pHints) { | |
| 1262 FX_BOOL bExist = FALSE; | |
| 1263 CPDF_Object* pPages = GetObject(dwPageNo, pHints, &bExist); | |
| 1264 if (!bExist) { | |
| 1265 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1266 return FALSE; | |
| 1267 } | |
| 1268 | |
| 1269 if (!pPages) { | |
| 1270 if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
| 1271 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1272 return FALSE; | |
| 1273 } | |
| 1274 return FALSE; | |
| 1275 } | |
| 1276 | |
| 1277 CPDF_Array* pArray = pPages->AsArray(); | |
| 1278 if (!pArray) { | |
| 1279 pPages->Release(); | |
| 1280 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1281 return FALSE; | |
| 1282 } | |
| 1283 | |
| 1284 pPageNode->m_type = PDF_PAGENODE_PAGES; | |
| 1285 for (FX_DWORD i = 0; i < pArray->GetCount(); ++i) { | |
| 1286 CPDF_Reference* pKid = ToReference(pArray->GetElement(i)); | |
| 1287 if (!pKid) | |
| 1288 continue; | |
| 1289 | |
| 1290 PageNode* pNode = new PageNode(); | |
| 1291 pPageNode->m_childNode.Add(pNode); | |
| 1292 pNode->m_dwPageNo = pKid->GetRefObjNum(); | |
| 1293 } | |
| 1294 pPages->Release(); | |
| 1295 return TRUE; | |
| 1296 } | |
| 1297 | |
| 1298 FX_BOOL CPDF_DataAvail::CheckUnkownPageNode( | |
| 1299 FX_DWORD dwPageNo, | |
| 1300 CPDF_DataAvail::PageNode* pPageNode, | |
| 1301 IPDF_DataAvail::DownloadHints* pHints) { | |
| 1302 FX_BOOL bExist = FALSE; | |
| 1303 CPDF_Object* pPage = GetObject(dwPageNo, pHints, &bExist); | |
| 1304 if (!bExist) { | |
| 1305 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1306 return FALSE; | |
| 1307 } | |
| 1308 | |
| 1309 if (!pPage) { | |
| 1310 if (m_docStatus == PDF_DATAAVAIL_ERROR) | |
| 1311 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1312 return FALSE; | |
| 1313 } | |
| 1314 | |
| 1315 if (pPage->IsArray()) { | |
| 1316 pPageNode->m_dwPageNo = dwPageNo; | |
| 1317 pPageNode->m_type = PDF_PAGENODE_ARRAY; | |
| 1318 pPage->Release(); | |
| 1319 return TRUE; | |
| 1320 } | |
| 1321 | |
| 1322 if (!pPage->IsDictionary()) { | |
| 1323 pPage->Release(); | |
| 1324 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1325 return FALSE; | |
| 1326 } | |
| 1327 | |
| 1328 pPageNode->m_dwPageNo = dwPageNo; | |
| 1329 CPDF_Dictionary* pDict = pPage->GetDict(); | |
| 1330 CFX_ByteString type = pDict->GetStringBy("Type"); | |
| 1331 if (type == "Pages") { | |
| 1332 pPageNode->m_type = PDF_PAGENODE_PAGES; | |
| 1333 CPDF_Object* pKids = pDict->GetElement("Kids"); | |
| 1334 if (!pKids) { | |
| 1335 m_docStatus = PDF_DATAAVAIL_PAGE; | |
| 1336 return TRUE; | |
| 1337 } | |
| 1338 | |
| 1339 switch (pKids->GetType()) { | |
| 1340 case CPDF_Object::REFERENCE: { | |
| 1341 CPDF_Reference* pKid = pKids->AsReference(); | |
| 1342 PageNode* pNode = new PageNode(); | |
| 1343 pPageNode->m_childNode.Add(pNode); | |
| 1344 pNode->m_dwPageNo = pKid->GetRefObjNum(); | |
| 1345 } break; | |
| 1346 case CPDF_Object::ARRAY: { | |
| 1347 CPDF_Array* pKidsArray = pKids->AsArray(); | |
| 1348 for (FX_DWORD i = 0; i < pKidsArray->GetCount(); ++i) { | |
| 1349 CPDF_Reference* pKid = ToReference(pKidsArray->GetElement(i)); | |
| 1350 if (!pKid) | |
| 1351 continue; | |
| 1352 | |
| 1353 PageNode* pNode = new PageNode(); | |
| 1354 pPageNode->m_childNode.Add(pNode); | |
| 1355 pNode->m_dwPageNo = pKid->GetRefObjNum(); | |
| 1356 } | |
| 1357 } break; | |
| 1358 default: | |
| 1359 break; | |
| 1360 } | |
| 1361 } else if (type == "Page") { | |
| 1362 pPageNode->m_type = PDF_PAGENODE_PAGE; | |
| 1363 } else { | |
| 1364 pPage->Release(); | |
| 1365 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1366 return FALSE; | |
| 1367 } | |
| 1368 pPage->Release(); | |
| 1369 return TRUE; | |
| 1370 } | |
| 1371 | |
| 1372 FX_BOOL CPDF_DataAvail::CheckPageNode(CPDF_DataAvail::PageNode& pageNodes, | |
| 1373 int32_t iPage, | |
| 1374 int32_t& iCount, | |
| 1375 IPDF_DataAvail::DownloadHints* pHints, | |
| 1376 int level) { | |
| 1377 if (level >= kMaxPageRecursionDepth) | |
| 1378 return FALSE; | |
| 1379 | |
| 1380 int32_t iSize = pageNodes.m_childNode.GetSize(); | |
| 1381 if (iSize <= 0 || iPage >= iSize) { | |
| 1382 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1383 return FALSE; | |
| 1384 } | |
| 1385 | |
| 1386 for (int32_t i = 0; i < iSize; ++i) { | |
| 1387 PageNode* pNode = pageNodes.m_childNode.GetAt(i); | |
| 1388 if (!pNode) | |
| 1389 continue; | |
| 1390 | |
| 1391 switch (pNode->m_type) { | |
| 1392 case PDF_PAGENODE_UNKNOWN: | |
| 1393 if (!CheckUnkownPageNode(pNode->m_dwPageNo, pNode, pHints)) { | |
| 1394 return FALSE; | |
| 1395 } | |
| 1396 --i; | |
| 1397 break; | |
| 1398 case PDF_PAGENODE_PAGE: | |
| 1399 iCount++; | |
| 1400 if (iPage == iCount && m_pDocument) | |
| 1401 m_pDocument->m_PageList.SetAt(iPage, pNode->m_dwPageNo); | |
| 1402 break; | |
| 1403 case PDF_PAGENODE_PAGES: | |
| 1404 if (!CheckPageNode(*pNode, iPage, iCount, pHints, level + 1)) | |
| 1405 return FALSE; | |
| 1406 break; | |
| 1407 case PDF_PAGENODE_ARRAY: | |
| 1408 if (!CheckArrayPageNode(pNode->m_dwPageNo, pNode, pHints)) | |
| 1409 return FALSE; | |
| 1410 --i; | |
| 1411 break; | |
| 1412 } | |
| 1413 | |
| 1414 if (iPage == iCount) { | |
| 1415 m_docStatus = PDF_DATAAVAIL_DONE; | |
| 1416 return TRUE; | |
| 1417 } | |
| 1418 } | |
| 1419 return TRUE; | |
| 1420 } | |
| 1421 | |
| 1422 FX_BOOL CPDF_DataAvail::LoadDocPage(int32_t iPage, | |
| 1423 IPDF_DataAvail::DownloadHints* pHints) { | |
| 1424 if (m_pDocument->GetPageCount() <= iPage || | |
| 1425 m_pDocument->m_PageList.GetAt(iPage)) { | |
| 1426 m_docStatus = PDF_DATAAVAIL_DONE; | |
| 1427 return TRUE; | |
| 1428 } | |
| 1429 | |
| 1430 if (m_pageNodes.m_type == PDF_PAGENODE_PAGE) { | |
| 1431 if (iPage == 0) { | |
| 1432 m_docStatus = PDF_DATAAVAIL_DONE; | |
| 1433 return TRUE; | |
| 1434 } | |
| 1435 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1436 return TRUE; | |
| 1437 } | |
| 1438 int32_t iCount = -1; | |
| 1439 return CheckPageNode(m_pageNodes, iPage, iCount, pHints, 0); | |
| 1440 } | |
| 1441 | |
| 1442 FX_BOOL CPDF_DataAvail::CheckPageCount(IPDF_DataAvail::DownloadHints* pHints) { | |
| 1443 FX_BOOL bExist = FALSE; | |
| 1444 CPDF_Object* pPages = GetObject(m_PagesObjNum, pHints, &bExist); | |
| 1445 if (!bExist) { | |
| 1446 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1447 return FALSE; | |
| 1448 } | |
| 1449 | |
| 1450 if (!pPages) | |
| 1451 return FALSE; | |
| 1452 | |
| 1453 CPDF_Dictionary* pPagesDict = pPages->GetDict(); | |
| 1454 if (!pPagesDict) { | |
| 1455 pPages->Release(); | |
| 1456 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1457 return FALSE; | |
| 1458 } | |
| 1459 | |
| 1460 if (!pPagesDict->KeyExist("Kids")) { | |
| 1461 pPages->Release(); | |
| 1462 return TRUE; | |
| 1463 } | |
| 1464 | |
| 1465 int count = pPagesDict->GetIntegerBy("Count"); | |
| 1466 if (count > 0) { | |
| 1467 pPages->Release(); | |
| 1468 return TRUE; | |
| 1469 } | |
| 1470 | |
| 1471 pPages->Release(); | |
| 1472 return FALSE; | |
| 1473 } | |
| 1474 | |
| 1475 FX_BOOL CPDF_DataAvail::LoadDocPages(IPDF_DataAvail::DownloadHints* pHints) { | |
| 1476 if (!CheckUnkownPageNode(m_PagesObjNum, &m_pageNodes, pHints)) | |
| 1477 return FALSE; | |
| 1478 | |
| 1479 if (CheckPageCount(pHints)) { | |
| 1480 m_docStatus = PDF_DATAAVAIL_PAGE; | |
| 1481 return TRUE; | |
| 1482 } | |
| 1483 | |
| 1484 m_bTotalLoadPageTree = TRUE; | |
| 1485 return FALSE; | |
| 1486 } | |
| 1487 | |
| 1488 FX_BOOL CPDF_DataAvail::LoadPages(IPDF_DataAvail::DownloadHints* pHints) { | |
| 1489 while (!m_bPagesTreeLoad) { | |
| 1490 if (!CheckPageStatus(pHints)) | |
| 1491 return FALSE; | |
| 1492 } | |
| 1493 | |
| 1494 if (m_bPagesLoad) | |
| 1495 return TRUE; | |
| 1496 | |
| 1497 m_pDocument->LoadPages(); | |
| 1498 return FALSE; | |
| 1499 } | |
| 1500 | |
| 1501 IPDF_DataAvail::DocAvailStatus CPDF_DataAvail::CheckLinearizedData( | |
| 1502 IPDF_DataAvail::DownloadHints* pHints) { | |
| 1503 if (m_bLinearedDataOK) | |
| 1504 return DataAvailable; | |
| 1505 | |
| 1506 if (!m_bMainXRefLoadTried) { | |
| 1507 FX_SAFE_DWORD data_size = m_dwFileLen; | |
| 1508 data_size -= m_dwLastXRefOffset; | |
| 1509 if (!data_size.IsValid()) | |
| 1510 return DataError; | |
| 1511 | |
| 1512 if (!m_pFileAvail->IsDataAvail(m_dwLastXRefOffset, | |
| 1513 data_size.ValueOrDie())) { | |
| 1514 pHints->AddSegment(m_dwLastXRefOffset, data_size.ValueOrDie()); | |
| 1515 return DataNotAvailable; | |
| 1516 } | |
| 1517 | |
| 1518 CPDF_Parser::Error eRet = | |
| 1519 m_pDocument->GetParser()->LoadLinearizedMainXRefTable(); | |
| 1520 m_bMainXRefLoadTried = TRUE; | |
| 1521 if (eRet != CPDF_Parser::SUCCESS) | |
| 1522 return DataError; | |
| 1523 | |
| 1524 if (!PreparePageItem()) | |
| 1525 return DataNotAvailable; | |
| 1526 | |
| 1527 m_bMainXRefLoadedOK = TRUE; | |
| 1528 m_bLinearedDataOK = TRUE; | |
| 1529 } | |
| 1530 | |
| 1531 return m_bLinearedDataOK ? DataAvailable : DataNotAvailable; | |
| 1532 } | |
| 1533 | |
| 1534 FX_BOOL CPDF_DataAvail::CheckPageAnnots(int32_t iPage, | |
| 1535 IPDF_DataAvail::DownloadHints* pHints) { | |
| 1536 if (!m_objs_array.GetSize()) { | |
| 1537 m_objs_array.RemoveAll(); | |
| 1538 m_ObjectSet.clear(); | |
| 1539 | |
| 1540 CPDF_Dictionary* pPageDict = m_pDocument->GetPage(iPage); | |
| 1541 if (!pPageDict) | |
| 1542 return TRUE; | |
| 1543 | |
| 1544 CPDF_Object* pAnnots = pPageDict->GetElement("Annots"); | |
| 1545 if (!pAnnots) | |
| 1546 return TRUE; | |
| 1547 | |
| 1548 CFX_ArrayTemplate<CPDF_Object*> obj_array; | |
| 1549 obj_array.Add(pAnnots); | |
| 1550 | |
| 1551 FX_BOOL bRet = IsObjectsAvail(obj_array, FALSE, pHints, m_objs_array); | |
| 1552 if (bRet) | |
| 1553 m_objs_array.RemoveAll(); | |
| 1554 | |
| 1555 return bRet; | |
| 1556 } | |
| 1557 | |
| 1558 CFX_ArrayTemplate<CPDF_Object*> new_objs_array; | |
| 1559 FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
| 1560 m_objs_array.RemoveAll(); | |
| 1561 if (!bRet) | |
| 1562 m_objs_array.Append(new_objs_array); | |
| 1563 | |
| 1564 return bRet; | |
| 1565 } | |
| 1566 | |
| 1567 IPDF_DataAvail::DocAvailStatus CPDF_DataAvail::CheckLinearizedFirstPage( | |
| 1568 int32_t iPage, | |
| 1569 IPDF_DataAvail::DownloadHints* pHints) { | |
| 1570 if (!m_bAnnotsLoad) { | |
| 1571 if (!CheckPageAnnots(iPage, pHints)) | |
| 1572 return DataNotAvailable; | |
| 1573 m_bAnnotsLoad = TRUE; | |
| 1574 } | |
| 1575 | |
| 1576 DocAvailStatus nRet = CheckLinearizedData(pHints); | |
| 1577 if (nRet == DataAvailable) | |
| 1578 m_bPageLoadedOK = FALSE; | |
| 1579 return nRet; | |
| 1580 } | |
| 1581 | |
| 1582 FX_BOOL CPDF_DataAvail::HaveResourceAncestor(CPDF_Dictionary* pDict) { | |
| 1583 CFX_AutoRestorer<int> restorer(&s_CurrentDataAvailRecursionDepth); | |
| 1584 if (++s_CurrentDataAvailRecursionDepth > kMaxDataAvailRecursionDepth) | |
| 1585 return FALSE; | |
| 1586 | |
| 1587 CPDF_Object* pParent = pDict->GetElement("Parent"); | |
| 1588 if (!pParent) | |
| 1589 return FALSE; | |
| 1590 | |
| 1591 CPDF_Dictionary* pParentDict = pParent->GetDict(); | |
| 1592 if (!pParentDict) | |
| 1593 return FALSE; | |
| 1594 | |
| 1595 CPDF_Object* pRet = pParentDict->GetElement("Resources"); | |
| 1596 if (pRet) { | |
| 1597 m_pPageResource = pRet; | |
| 1598 return TRUE; | |
| 1599 } | |
| 1600 | |
| 1601 return HaveResourceAncestor(pParentDict); | |
| 1602 } | |
| 1603 | |
| 1604 IPDF_DataAvail::DocAvailStatus CPDF_DataAvail::IsPageAvail( | |
| 1605 int32_t iPage, | |
| 1606 IPDF_DataAvail::DownloadHints* pHints) { | |
| 1607 if (!m_pDocument) | |
| 1608 return DataError; | |
| 1609 | |
| 1610 if (IsFirstCheck(iPage)) { | |
| 1611 m_bCurPageDictLoadOK = FALSE; | |
| 1612 m_bPageLoadedOK = FALSE; | |
| 1613 m_bAnnotsLoad = FALSE; | |
| 1614 m_bNeedDownLoadResource = FALSE; | |
| 1615 m_objs_array.RemoveAll(); | |
| 1616 m_ObjectSet.clear(); | |
| 1617 } | |
| 1618 | |
| 1619 if (pdfium::ContainsKey(m_pagesLoadState, iPage)) | |
| 1620 return DataAvailable; | |
| 1621 | |
| 1622 if (m_bLinearized) { | |
| 1623 if ((FX_DWORD)iPage == m_dwFirstPageNo) { | |
| 1624 DocAvailStatus nRet = CheckLinearizedFirstPage(iPage, pHints); | |
| 1625 if (nRet == DataAvailable) | |
| 1626 m_pagesLoadState.insert(iPage); | |
| 1627 return nRet; | |
| 1628 } | |
| 1629 | |
| 1630 DocAvailStatus nResult = CheckLinearizedData(pHints); | |
| 1631 if (nResult != DataAvailable) | |
| 1632 return nResult; | |
| 1633 | |
| 1634 if (m_pHintTables) { | |
| 1635 nResult = m_pHintTables->CheckPage(iPage, pHints); | |
| 1636 if (nResult != DataAvailable) | |
| 1637 return nResult; | |
| 1638 m_pagesLoadState.insert(iPage); | |
| 1639 return DataAvailable; | |
| 1640 } | |
| 1641 | |
| 1642 if (m_bMainXRefLoadedOK) { | |
| 1643 if (m_bTotalLoadPageTree) { | |
| 1644 if (!LoadPages(pHints)) | |
| 1645 return DataNotAvailable; | |
| 1646 } else { | |
| 1647 if (!m_bCurPageDictLoadOK && !CheckPage(iPage, pHints)) | |
| 1648 return DataNotAvailable; | |
| 1649 } | |
| 1650 } else { | |
| 1651 if (!LoadAllFile(pHints)) | |
| 1652 return DataNotAvailable; | |
| 1653 m_pDocument->GetParser()->RebuildCrossRef(); | |
| 1654 ResetFirstCheck(iPage); | |
| 1655 return DataAvailable; | |
| 1656 } | |
| 1657 } else { | |
| 1658 if (!m_bTotalLoadPageTree && !m_bCurPageDictLoadOK && | |
| 1659 !CheckPage(iPage, pHints)) { | |
| 1660 return DataNotAvailable; | |
| 1661 } | |
| 1662 } | |
| 1663 | |
| 1664 if (m_bHaveAcroForm && !m_bAcroFormLoad) { | |
| 1665 if (!CheckAcroFormSubObject(pHints)) | |
| 1666 return DataNotAvailable; | |
| 1667 m_bAcroFormLoad = TRUE; | |
| 1668 } | |
| 1669 | |
| 1670 if (!m_bPageLoadedOK) { | |
| 1671 if (!m_objs_array.GetSize()) { | |
| 1672 m_objs_array.RemoveAll(); | |
| 1673 m_ObjectSet.clear(); | |
| 1674 | |
| 1675 m_pPageDict = m_pDocument->GetPage(iPage); | |
| 1676 if (!m_pPageDict) { | |
| 1677 ResetFirstCheck(iPage); | |
| 1678 return DataAvailable; | |
| 1679 } | |
| 1680 | |
| 1681 CFX_ArrayTemplate<CPDF_Object*> obj_array; | |
| 1682 obj_array.Add(m_pPageDict); | |
| 1683 FX_BOOL bRet = IsObjectsAvail(obj_array, TRUE, pHints, m_objs_array); | |
| 1684 if (!bRet) | |
| 1685 return DataNotAvailable; | |
| 1686 | |
| 1687 m_objs_array.RemoveAll(); | |
| 1688 } else { | |
| 1689 CFX_ArrayTemplate<CPDF_Object*> new_objs_array; | |
| 1690 FX_BOOL bRet = | |
| 1691 IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
| 1692 | |
| 1693 m_objs_array.RemoveAll(); | |
| 1694 if (!bRet) { | |
| 1695 m_objs_array.Append(new_objs_array); | |
| 1696 return DataNotAvailable; | |
| 1697 } | |
| 1698 } | |
| 1699 m_bPageLoadedOK = TRUE; | |
| 1700 } | |
| 1701 | |
| 1702 if (!m_bAnnotsLoad) { | |
| 1703 if (!CheckPageAnnots(iPage, pHints)) | |
| 1704 return DataNotAvailable; | |
| 1705 m_bAnnotsLoad = TRUE; | |
| 1706 } | |
| 1707 | |
| 1708 if (m_pPageDict && !m_bNeedDownLoadResource) { | |
| 1709 m_pPageResource = m_pPageDict->GetElement("Resources"); | |
| 1710 if (!m_pPageResource) | |
| 1711 m_bNeedDownLoadResource = HaveResourceAncestor(m_pPageDict); | |
| 1712 else | |
| 1713 m_bNeedDownLoadResource = TRUE; | |
| 1714 } | |
| 1715 | |
| 1716 if (m_bNeedDownLoadResource) { | |
| 1717 FX_BOOL bRet = CheckResources(pHints); | |
| 1718 if (!bRet) | |
| 1719 return DataNotAvailable; | |
| 1720 m_bNeedDownLoadResource = FALSE; | |
| 1721 } | |
| 1722 | |
| 1723 m_bPageLoadedOK = FALSE; | |
| 1724 m_bAnnotsLoad = FALSE; | |
| 1725 m_bCurPageDictLoadOK = FALSE; | |
| 1726 | |
| 1727 ResetFirstCheck(iPage); | |
| 1728 m_pagesLoadState.insert(iPage); | |
| 1729 return DataAvailable; | |
| 1730 } | |
| 1731 | |
| 1732 FX_BOOL CPDF_DataAvail::CheckResources(IPDF_DataAvail::DownloadHints* pHints) { | |
| 1733 if (!m_objs_array.GetSize()) { | |
| 1734 m_objs_array.RemoveAll(); | |
| 1735 CFX_ArrayTemplate<CPDF_Object*> obj_array; | |
| 1736 obj_array.Add(m_pPageResource); | |
| 1737 | |
| 1738 FX_BOOL bRet = IsObjectsAvail(obj_array, TRUE, pHints, m_objs_array); | |
| 1739 if (bRet) | |
| 1740 m_objs_array.RemoveAll(); | |
| 1741 return bRet; | |
| 1742 } | |
| 1743 | |
| 1744 CFX_ArrayTemplate<CPDF_Object*> new_objs_array; | |
| 1745 FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
| 1746 m_objs_array.RemoveAll(); | |
| 1747 if (!bRet) | |
| 1748 m_objs_array.Append(new_objs_array); | |
| 1749 return bRet; | |
| 1750 } | |
| 1751 | |
| 1752 void CPDF_DataAvail::GetLinearizedMainXRefInfo(FX_FILESIZE* pPos, | |
| 1753 FX_DWORD* pSize) { | |
| 1754 if (pPos) | |
| 1755 *pPos = m_dwLastXRefOffset; | |
| 1756 if (pSize) | |
| 1757 *pSize = (FX_DWORD)(m_dwFileLen - m_dwLastXRefOffset); | |
| 1758 } | |
| 1759 | |
| 1760 int CPDF_DataAvail::GetPageCount() const { | |
| 1761 if (m_pLinearized) { | |
| 1762 CPDF_Dictionary* pDict = m_pLinearized->GetDict(); | |
| 1763 CPDF_Object* pObj = pDict ? pDict->GetElementValue("N") : nullptr; | |
| 1764 return pObj ? pObj->GetInteger() : 0; | |
| 1765 } | |
| 1766 return m_pDocument ? m_pDocument->GetPageCount() : 0; | |
| 1767 } | |
| 1768 | |
| 1769 CPDF_Dictionary* CPDF_DataAvail::GetPage(int index) { | |
| 1770 if (!m_pDocument || index < 0 || index >= GetPageCount()) | |
| 1771 return nullptr; | |
| 1772 | |
| 1773 if (m_pLinearized) { | |
| 1774 CPDF_Dictionary* pDict = m_pLinearized->GetDict(); | |
| 1775 CPDF_Object* pObj = pDict ? pDict->GetElementValue("P") : nullptr; | |
| 1776 | |
| 1777 int pageNum = pObj ? pObj->GetInteger() : 0; | |
| 1778 if (m_pHintTables && index != pageNum) { | |
| 1779 FX_FILESIZE szPageStartPos = 0; | |
| 1780 FX_FILESIZE szPageLength = 0; | |
| 1781 FX_DWORD dwObjNum = 0; | |
| 1782 FX_BOOL bPagePosGot = m_pHintTables->GetPagePos(index, szPageStartPos, | |
| 1783 szPageLength, dwObjNum); | |
| 1784 if (!bPagePosGot) | |
| 1785 return nullptr; | |
| 1786 | |
| 1787 m_syntaxParser.InitParser(m_pFileRead, (FX_DWORD)szPageStartPos); | |
| 1788 CPDF_Object* pPageDict = ParseIndirectObjectAt(0, dwObjNum, m_pDocument); | |
| 1789 if (!pPageDict) | |
| 1790 return nullptr; | |
| 1791 | |
| 1792 if (!m_pDocument->InsertIndirectObject(dwObjNum, pPageDict)) | |
| 1793 return nullptr; | |
| 1794 return pPageDict->GetDict(); | |
| 1795 } | |
| 1796 } | |
| 1797 return m_pDocument->GetPage(index); | |
| 1798 } | |
| 1799 | |
| 1800 IPDF_DataAvail::DocFormStatus CPDF_DataAvail::IsFormAvail( | |
| 1801 IPDF_DataAvail::DownloadHints* pHints) { | |
| 1802 if (!m_pDocument) | |
| 1803 return FormAvailable; | |
| 1804 | |
| 1805 if (!m_bLinearizedFormParamLoad) { | |
| 1806 CPDF_Dictionary* pRoot = m_pDocument->GetRoot(); | |
| 1807 if (!pRoot) | |
| 1808 return FormAvailable; | |
| 1809 | |
| 1810 CPDF_Object* pAcroForm = pRoot->GetElement("AcroForm"); | |
| 1811 if (!pAcroForm) | |
| 1812 return FormNotExist; | |
| 1813 | |
| 1814 DocAvailStatus nDocStatus = CheckLinearizedData(pHints); | |
| 1815 if (nDocStatus == DataError) | |
| 1816 return FormError; | |
| 1817 if (nDocStatus == DataNotAvailable) | |
| 1818 return FormNotAvailable; | |
| 1819 | |
| 1820 if (!m_objs_array.GetSize()) | |
| 1821 m_objs_array.Add(pAcroForm->GetDict()); | |
| 1822 m_bLinearizedFormParamLoad = TRUE; | |
| 1823 } | |
| 1824 | |
| 1825 CFX_ArrayTemplate<CPDF_Object*> new_objs_array; | |
| 1826 FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
| 1827 m_objs_array.RemoveAll(); | |
| 1828 if (!bRet) { | |
| 1829 m_objs_array.Append(new_objs_array); | |
| 1830 return FormNotAvailable; | |
| 1831 } | |
| 1832 return FormAvailable; | |
| 1833 } | |
| 1834 | |
| 1835 CPDF_DataAvail::PageNode::PageNode() : m_type(PDF_PAGENODE_UNKNOWN) {} | |
| 1836 | |
| 1837 CPDF_DataAvail::PageNode::~PageNode() { | |
| 1838 for (int32_t i = 0; i < m_childNode.GetSize(); ++i) | |
| 1839 delete m_childNode[i]; | |
| 1840 m_childNode.RemoveAll(); | |
| 1841 } | |
| OLD | NEW |