| 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/include/fpdfapi/fpdf_parser.h" | |
| 8 | |
| 9 #include <algorithm> | |
| 10 #include <memory> | |
| 11 #include <set> | |
| 12 #include <utility> | |
| 13 #include <vector> | |
| 14 | |
| 15 #include "core/include/fpdfapi/cpdf_document.h" | |
| 16 #include "core/include/fpdfapi/cpdf_parser.h" | |
| 17 #include "core/include/fpdfapi/fpdf_module.h" | |
| 18 #include "core/include/fpdfapi/fpdf_page.h" | |
| 19 #include "core/include/fxcrt/fx_ext.h" | |
| 20 #include "core/include/fxcrt/fx_safe_types.h" | |
| 21 #include "core/src/fpdfapi/fpdf_page/pageint.h" | |
| 22 #include "core/src/fpdfapi/fpdf_parser/cpdf_syntax_parser.h" | |
| 23 #include "core/src/fpdfapi/fpdf_parser/fpdf_parser_utility.h" | |
| 24 #include "core/src/fpdfapi/fpdf_parser/parser_int.h" | |
| 25 #include "third_party/base/stl_util.h" | |
| 26 | |
| 27 namespace { | |
| 28 | |
| 29 bool CanReadFromBitStream(const CFX_BitStream* hStream, | |
| 30 const FX_SAFE_DWORD& num_bits) { | |
| 31 return num_bits.IsValid() && | |
| 32 hStream->BitsRemaining() >= num_bits.ValueOrDie(); | |
| 33 } | |
| 34 | |
| 35 } // namespace | |
| 36 | |
| 37 bool IsSignatureDict(const CPDF_Dictionary* pDict) { | |
| 38 CPDF_Object* pType = pDict->GetElementValue("Type"); | |
| 39 if (!pType) | |
| 40 pType = pDict->GetElementValue("FT"); | |
| 41 return pType && pType->GetString() == "Sig"; | |
| 42 } | |
| 43 | |
| 44 | |
| 45 class CPDF_DataAvail final : public IPDF_DataAvail { | |
| 46 public: | |
| 47 CPDF_DataAvail(IFX_FileAvail* pFileAvail, | |
| 48 IFX_FileRead* pFileRead, | |
| 49 FX_BOOL bSupportHintTable); | |
| 50 ~CPDF_DataAvail() override; | |
| 51 | |
| 52 // IPDF_DataAvail: | |
| 53 DocAvailStatus IsDocAvail(IFX_DownloadHints* pHints) override; | |
| 54 void SetDocument(CPDF_Document* pDoc) override; | |
| 55 DocAvailStatus IsPageAvail(int iPage, IFX_DownloadHints* pHints) override; | |
| 56 DocFormStatus IsFormAvail(IFX_DownloadHints* pHints) override; | |
| 57 DocLinearizationStatus IsLinearizedPDF() override; | |
| 58 FX_BOOL IsLinearized() override { return m_bLinearized; } | |
| 59 void GetLinearizedMainXRefInfo(FX_FILESIZE* pPos, FX_DWORD* pSize) override; | |
| 60 | |
| 61 int GetPageCount() const; | |
| 62 CPDF_Dictionary* GetPage(int index); | |
| 63 | |
| 64 friend class CPDF_HintTables; | |
| 65 | |
| 66 protected: | |
| 67 static const int kMaxDataAvailRecursionDepth = 64; | |
| 68 static int s_CurrentDataAvailRecursionDepth; | |
| 69 static const int kMaxPageRecursionDepth = 1024; | |
| 70 | |
| 71 FX_DWORD GetObjectSize(FX_DWORD objnum, FX_FILESIZE& offset); | |
| 72 FX_BOOL IsObjectsAvail(CFX_ArrayTemplate<CPDF_Object*>& obj_array, | |
| 73 FX_BOOL bParsePage, | |
| 74 IFX_DownloadHints* pHints, | |
| 75 CFX_ArrayTemplate<CPDF_Object*>& ret_array); | |
| 76 FX_BOOL CheckDocStatus(IFX_DownloadHints* pHints); | |
| 77 FX_BOOL CheckHeader(IFX_DownloadHints* pHints); | |
| 78 FX_BOOL CheckFirstPage(IFX_DownloadHints* pHints); | |
| 79 FX_BOOL CheckHintTables(IFX_DownloadHints* pHints); | |
| 80 FX_BOOL CheckEnd(IFX_DownloadHints* pHints); | |
| 81 FX_BOOL CheckCrossRef(IFX_DownloadHints* pHints); | |
| 82 FX_BOOL CheckCrossRefItem(IFX_DownloadHints* pHints); | |
| 83 FX_BOOL CheckTrailer(IFX_DownloadHints* pHints); | |
| 84 FX_BOOL CheckRoot(IFX_DownloadHints* pHints); | |
| 85 FX_BOOL CheckInfo(IFX_DownloadHints* pHints); | |
| 86 FX_BOOL CheckPages(IFX_DownloadHints* pHints); | |
| 87 FX_BOOL CheckPage(IFX_DownloadHints* pHints); | |
| 88 FX_BOOL CheckResources(IFX_DownloadHints* pHints); | |
| 89 FX_BOOL CheckAnnots(IFX_DownloadHints* pHints); | |
| 90 FX_BOOL CheckAcroForm(IFX_DownloadHints* pHints); | |
| 91 FX_BOOL CheckAcroFormSubObject(IFX_DownloadHints* pHints); | |
| 92 FX_BOOL CheckTrailerAppend(IFX_DownloadHints* pHints); | |
| 93 FX_BOOL CheckPageStatus(IFX_DownloadHints* pHints); | |
| 94 FX_BOOL CheckAllCrossRefStream(IFX_DownloadHints* pHints); | |
| 95 | |
| 96 int32_t CheckCrossRefStream(IFX_DownloadHints* pHints, | |
| 97 FX_FILESIZE& xref_offset); | |
| 98 FX_BOOL IsLinearizedFile(uint8_t* pData, FX_DWORD dwLen); | |
| 99 void SetStartOffset(FX_FILESIZE dwOffset); | |
| 100 FX_BOOL GetNextToken(CFX_ByteString& token); | |
| 101 FX_BOOL GetNextChar(uint8_t& ch); | |
| 102 CPDF_Object* ParseIndirectObjectAt( | |
| 103 FX_FILESIZE pos, | |
| 104 FX_DWORD objnum, | |
| 105 CPDF_IndirectObjectHolder* pObjList = nullptr); | |
| 106 CPDF_Object* GetObject(FX_DWORD objnum, | |
| 107 IFX_DownloadHints* pHints, | |
| 108 FX_BOOL* pExistInFile); | |
| 109 FX_BOOL GetPageKids(CPDF_Parser* pParser, CPDF_Object* pPages); | |
| 110 FX_BOOL PreparePageItem(); | |
| 111 FX_BOOL LoadPages(IFX_DownloadHints* pHints); | |
| 112 FX_BOOL LoadAllXref(IFX_DownloadHints* pHints); | |
| 113 FX_BOOL LoadAllFile(IFX_DownloadHints* pHints); | |
| 114 DocAvailStatus CheckLinearizedData(IFX_DownloadHints* pHints); | |
| 115 FX_BOOL CheckPageAnnots(int iPage, IFX_DownloadHints* pHints); | |
| 116 | |
| 117 DocAvailStatus CheckLinearizedFirstPage(int iPage, IFX_DownloadHints* pHints); | |
| 118 FX_BOOL HaveResourceAncestor(CPDF_Dictionary* pDict); | |
| 119 FX_BOOL CheckPage(int32_t iPage, IFX_DownloadHints* pHints); | |
| 120 FX_BOOL LoadDocPages(IFX_DownloadHints* pHints); | |
| 121 FX_BOOL LoadDocPage(int32_t iPage, IFX_DownloadHints* pHints); | |
| 122 FX_BOOL CheckPageNode(CPDF_PageNode& pageNodes, | |
| 123 int32_t iPage, | |
| 124 int32_t& iCount, | |
| 125 IFX_DownloadHints* pHints, | |
| 126 int level); | |
| 127 FX_BOOL CheckUnkownPageNode(FX_DWORD dwPageNo, | |
| 128 CPDF_PageNode* pPageNode, | |
| 129 IFX_DownloadHints* pHints); | |
| 130 FX_BOOL CheckArrayPageNode(FX_DWORD dwPageNo, | |
| 131 CPDF_PageNode* pPageNode, | |
| 132 IFX_DownloadHints* pHints); | |
| 133 FX_BOOL CheckPageCount(IFX_DownloadHints* pHints); | |
| 134 bool IsFirstCheck(int iPage); | |
| 135 void ResetFirstCheck(int iPage); | |
| 136 FX_BOOL IsDataAvail(FX_FILESIZE offset, | |
| 137 FX_DWORD size, | |
| 138 IFX_DownloadHints* pHints); | |
| 139 | |
| 140 CPDF_Parser m_parser; | |
| 141 CPDF_SyntaxParser m_syntaxParser; | |
| 142 CPDF_Object* m_pRoot; | |
| 143 FX_DWORD m_dwRootObjNum; | |
| 144 FX_DWORD m_dwInfoObjNum; | |
| 145 CPDF_Object* m_pLinearized; | |
| 146 CPDF_Object* m_pTrailer; | |
| 147 FX_BOOL m_bDocAvail; | |
| 148 FX_FILESIZE m_dwHeaderOffset; | |
| 149 FX_FILESIZE m_dwLastXRefOffset; | |
| 150 FX_FILESIZE m_dwXRefOffset; | |
| 151 FX_FILESIZE m_dwTrailerOffset; | |
| 152 FX_FILESIZE m_dwCurrentOffset; | |
| 153 PDF_DATAAVAIL_STATUS m_docStatus; | |
| 154 FX_FILESIZE m_dwFileLen; | |
| 155 CPDF_Document* m_pDocument; | |
| 156 std::set<FX_DWORD> m_ObjectSet; | |
| 157 CFX_ArrayTemplate<CPDF_Object*> m_objs_array; | |
| 158 FX_FILESIZE m_Pos; | |
| 159 FX_FILESIZE m_bufferOffset; | |
| 160 FX_DWORD m_bufferSize; | |
| 161 CFX_ByteString m_WordBuf; | |
| 162 uint8_t m_bufferData[512]; | |
| 163 CFX_DWordArray m_XRefStreamList; | |
| 164 CFX_DWordArray m_PageObjList; | |
| 165 FX_DWORD m_PagesObjNum; | |
| 166 FX_BOOL m_bLinearized; | |
| 167 FX_DWORD m_dwFirstPageNo; | |
| 168 FX_BOOL m_bLinearedDataOK; | |
| 169 FX_BOOL m_bMainXRefLoadTried; | |
| 170 FX_BOOL m_bMainXRefLoadedOK; | |
| 171 FX_BOOL m_bPagesTreeLoad; | |
| 172 FX_BOOL m_bPagesLoad; | |
| 173 CPDF_Parser* m_pCurrentParser; | |
| 174 FX_FILESIZE m_dwCurrentXRefSteam; | |
| 175 FX_BOOL m_bAnnotsLoad; | |
| 176 FX_BOOL m_bHaveAcroForm; | |
| 177 FX_DWORD m_dwAcroFormObjNum; | |
| 178 FX_BOOL m_bAcroFormLoad; | |
| 179 CPDF_Object* m_pAcroForm; | |
| 180 CFX_ArrayTemplate<CPDF_Object*> m_arrayAcroforms; | |
| 181 CPDF_Dictionary* m_pPageDict; | |
| 182 CPDF_Object* m_pPageResource; | |
| 183 FX_BOOL m_bNeedDownLoadResource; | |
| 184 FX_BOOL m_bPageLoadedOK; | |
| 185 FX_BOOL m_bLinearizedFormParamLoad; | |
| 186 CFX_ArrayTemplate<CPDF_Object*> m_PagesArray; | |
| 187 FX_DWORD m_dwEncryptObjNum; | |
| 188 FX_FILESIZE m_dwPrevXRefOffset; | |
| 189 FX_BOOL m_bTotalLoadPageTree; | |
| 190 FX_BOOL m_bCurPageDictLoadOK; | |
| 191 CPDF_PageNode m_pageNodes; | |
| 192 std::set<FX_DWORD> m_pageMapCheckState; | |
| 193 std::set<FX_DWORD> m_pagesLoadState; | |
| 194 std::unique_ptr<CPDF_HintTables> m_pHintTables; | |
| 195 FX_BOOL m_bSupportHintTable; | |
| 196 }; | |
| 197 | |
| 198 IPDF_DataAvail::IPDF_DataAvail(IFX_FileAvail* pFileAvail, | |
| 199 IFX_FileRead* pFileRead) | |
| 200 : m_pFileAvail(pFileAvail), m_pFileRead(pFileRead) {} | |
| 201 | |
| 202 // static | |
| 203 IPDF_DataAvail* IPDF_DataAvail::Create(IFX_FileAvail* pFileAvail, | |
| 204 IFX_FileRead* pFileRead) { | |
| 205 return new CPDF_DataAvail(pFileAvail, pFileRead, TRUE); | |
| 206 } | |
| 207 | |
| 208 // static | |
| 209 int CPDF_DataAvail::s_CurrentDataAvailRecursionDepth = 0; | |
| 210 | |
| 211 CPDF_DataAvail::CPDF_DataAvail(IFX_FileAvail* pFileAvail, | |
| 212 IFX_FileRead* pFileRead, | |
| 213 FX_BOOL bSupportHintTable) | |
| 214 : IPDF_DataAvail(pFileAvail, pFileRead) { | |
| 215 m_Pos = 0; | |
| 216 m_dwFileLen = 0; | |
| 217 if (m_pFileRead) { | |
| 218 m_dwFileLen = (FX_DWORD)m_pFileRead->GetSize(); | |
| 219 } | |
| 220 m_dwCurrentOffset = 0; | |
| 221 m_dwXRefOffset = 0; | |
| 222 m_bufferOffset = 0; | |
| 223 m_dwFirstPageNo = 0; | |
| 224 m_bufferSize = 0; | |
| 225 m_PagesObjNum = 0; | |
| 226 m_dwCurrentXRefSteam = 0; | |
| 227 m_dwAcroFormObjNum = 0; | |
| 228 m_dwInfoObjNum = 0; | |
| 229 m_pDocument = 0; | |
| 230 m_dwEncryptObjNum = 0; | |
| 231 m_dwPrevXRefOffset = 0; | |
| 232 m_dwLastXRefOffset = 0; | |
| 233 m_bDocAvail = FALSE; | |
| 234 m_bMainXRefLoadTried = FALSE; | |
| 235 m_bDocAvail = FALSE; | |
| 236 m_bLinearized = FALSE; | |
| 237 m_bPagesLoad = FALSE; | |
| 238 m_bPagesTreeLoad = FALSE; | |
| 239 m_bMainXRefLoadedOK = FALSE; | |
| 240 m_bAnnotsLoad = FALSE; | |
| 241 m_bHaveAcroForm = FALSE; | |
| 242 m_bAcroFormLoad = FALSE; | |
| 243 m_bPageLoadedOK = FALSE; | |
| 244 m_bNeedDownLoadResource = FALSE; | |
| 245 m_bLinearizedFormParamLoad = FALSE; | |
| 246 m_pLinearized = NULL; | |
| 247 m_pRoot = NULL; | |
| 248 m_pTrailer = NULL; | |
| 249 m_pCurrentParser = NULL; | |
| 250 m_pAcroForm = NULL; | |
| 251 m_pPageDict = NULL; | |
| 252 m_pPageResource = NULL; | |
| 253 m_docStatus = PDF_DATAAVAIL_HEADER; | |
| 254 m_parser.m_bOwnFileRead = false; | |
| 255 m_bTotalLoadPageTree = FALSE; | |
| 256 m_bCurPageDictLoadOK = FALSE; | |
| 257 m_bLinearedDataOK = FALSE; | |
| 258 m_bSupportHintTable = bSupportHintTable; | |
| 259 } | |
| 260 CPDF_DataAvail::~CPDF_DataAvail() { | |
| 261 if (m_pLinearized) | |
| 262 m_pLinearized->Release(); | |
| 263 | |
| 264 if (m_pRoot) | |
| 265 m_pRoot->Release(); | |
| 266 | |
| 267 if (m_pTrailer) | |
| 268 m_pTrailer->Release(); | |
| 269 | |
| 270 int iSize = m_arrayAcroforms.GetSize(); | |
| 271 for (int i = 0; i < iSize; ++i) | |
| 272 m_arrayAcroforms.GetAt(i)->Release(); | |
| 273 } | |
| 274 | |
| 275 void CPDF_DataAvail::SetDocument(CPDF_Document* pDoc) { | |
| 276 m_pDocument = pDoc; | |
| 277 } | |
| 278 | |
| 279 FX_DWORD CPDF_DataAvail::GetObjectSize(FX_DWORD objnum, FX_FILESIZE& offset) { | |
| 280 CPDF_Parser* pParser = m_pDocument->GetParser(); | |
| 281 if (!pParser || !pParser->IsValidObjectNumber(objnum)) | |
| 282 return 0; | |
| 283 | |
| 284 if (pParser->GetObjectType(objnum) == 2) | |
| 285 objnum = pParser->GetObjectPositionOrZero(objnum); | |
| 286 | |
| 287 if (pParser->GetObjectType(objnum) != 1 && | |
| 288 pParser->GetObjectType(objnum) != 255) { | |
| 289 return 0; | |
| 290 } | |
| 291 | |
| 292 offset = pParser->GetObjectPositionOrZero(objnum); | |
| 293 if (offset == 0) | |
| 294 return 0; | |
| 295 | |
| 296 auto it = pParser->m_SortedOffset.find(offset); | |
| 297 if (it == pParser->m_SortedOffset.end() || | |
| 298 ++it == pParser->m_SortedOffset.end()) { | |
| 299 return 0; | |
| 300 } | |
| 301 return *it - offset; | |
| 302 } | |
| 303 | |
| 304 FX_BOOL CPDF_DataAvail::IsObjectsAvail( | |
| 305 CFX_ArrayTemplate<CPDF_Object*>& obj_array, | |
| 306 FX_BOOL bParsePage, | |
| 307 IFX_DownloadHints* pHints, | |
| 308 CFX_ArrayTemplate<CPDF_Object*>& ret_array) { | |
| 309 if (!obj_array.GetSize()) | |
| 310 return TRUE; | |
| 311 | |
| 312 FX_DWORD count = 0; | |
| 313 CFX_ArrayTemplate<CPDF_Object*> new_obj_array; | |
| 314 int32_t i = 0; | |
| 315 for (i = 0; i < obj_array.GetSize(); i++) { | |
| 316 CPDF_Object* pObj = obj_array[i]; | |
| 317 if (!pObj) | |
| 318 continue; | |
| 319 | |
| 320 int32_t type = pObj->GetType(); | |
| 321 switch (type) { | |
| 322 case CPDF_Object::ARRAY: { | |
| 323 CPDF_Array* pArray = pObj->GetArray(); | |
| 324 for (FX_DWORD k = 0; k < pArray->GetCount(); ++k) | |
| 325 new_obj_array.Add(pArray->GetElement(k)); | |
| 326 } break; | |
| 327 case CPDF_Object::STREAM: | |
| 328 pObj = pObj->GetDict(); | |
| 329 case CPDF_Object::DICTIONARY: { | |
| 330 CPDF_Dictionary* pDict = pObj->GetDict(); | |
| 331 if (pDict && pDict->GetStringBy("Type") == "Page" && !bParsePage) | |
| 332 continue; | |
| 333 | |
| 334 for (const auto& it : *pDict) { | |
| 335 const CFX_ByteString& key = it.first; | |
| 336 CPDF_Object* value = it.second; | |
| 337 if (key != "Parent") | |
| 338 new_obj_array.Add(value); | |
| 339 } | |
| 340 } break; | |
| 341 case CPDF_Object::REFERENCE: { | |
| 342 CPDF_Reference* pRef = pObj->AsReference(); | |
| 343 FX_DWORD dwNum = pRef->GetRefObjNum(); | |
| 344 | |
| 345 FX_FILESIZE offset; | |
| 346 FX_DWORD size = GetObjectSize(dwNum, offset); | |
| 347 if (size == 0 || offset < 0 || offset >= m_dwFileLen) | |
| 348 break; | |
| 349 | |
| 350 if (!IsDataAvail(offset, size, pHints)) { | |
| 351 ret_array.Add(pObj); | |
| 352 count++; | |
| 353 } else if (!pdfium::ContainsKey(m_ObjectSet, dwNum)) { | |
| 354 m_ObjectSet.insert(dwNum); | |
| 355 CPDF_Object* pReferred = | |
| 356 m_pDocument->GetIndirectObject(pRef->GetRefObjNum()); | |
| 357 if (pReferred) | |
| 358 new_obj_array.Add(pReferred); | |
| 359 } | |
| 360 } break; | |
| 361 } | |
| 362 } | |
| 363 | |
| 364 if (count > 0) { | |
| 365 int32_t iSize = new_obj_array.GetSize(); | |
| 366 for (i = 0; i < iSize; ++i) { | |
| 367 CPDF_Object* pObj = new_obj_array[i]; | |
| 368 if (CPDF_Reference* pRef = pObj->AsReference()) { | |
| 369 FX_DWORD dwNum = pRef->GetRefObjNum(); | |
| 370 if (!pdfium::ContainsKey(m_ObjectSet, dwNum)) | |
| 371 ret_array.Add(pObj); | |
| 372 } else { | |
| 373 ret_array.Add(pObj); | |
| 374 } | |
| 375 } | |
| 376 return FALSE; | |
| 377 } | |
| 378 | |
| 379 obj_array.RemoveAll(); | |
| 380 obj_array.Append(new_obj_array); | |
| 381 return IsObjectsAvail(obj_array, FALSE, pHints, ret_array); | |
| 382 } | |
| 383 | |
| 384 IPDF_DataAvail::DocAvailStatus CPDF_DataAvail::IsDocAvail( | |
| 385 IFX_DownloadHints* pHints) { | |
| 386 if (!m_dwFileLen && m_pFileRead) { | |
| 387 m_dwFileLen = (FX_DWORD)m_pFileRead->GetSize(); | |
| 388 if (!m_dwFileLen) | |
| 389 return DataError; | |
| 390 } | |
| 391 | |
| 392 while (!m_bDocAvail) { | |
| 393 if (!CheckDocStatus(pHints)) | |
| 394 return DataNotAvailable; | |
| 395 } | |
| 396 | |
| 397 return DataAvailable; | |
| 398 } | |
| 399 | |
| 400 FX_BOOL CPDF_DataAvail::CheckAcroFormSubObject(IFX_DownloadHints* pHints) { | |
| 401 if (!m_objs_array.GetSize()) { | |
| 402 m_objs_array.RemoveAll(); | |
| 403 m_ObjectSet.clear(); | |
| 404 CFX_ArrayTemplate<CPDF_Object*> obj_array; | |
| 405 obj_array.Append(m_arrayAcroforms); | |
| 406 FX_BOOL bRet = IsObjectsAvail(obj_array, FALSE, pHints, m_objs_array); | |
| 407 if (bRet) | |
| 408 m_objs_array.RemoveAll(); | |
| 409 return bRet; | |
| 410 } | |
| 411 | |
| 412 CFX_ArrayTemplate<CPDF_Object*> new_objs_array; | |
| 413 FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
| 414 if (bRet) { | |
| 415 int32_t iSize = m_arrayAcroforms.GetSize(); | |
| 416 for (int32_t i = 0; i < iSize; ++i) { | |
| 417 m_arrayAcroforms.GetAt(i)->Release(); | |
| 418 } | |
| 419 m_arrayAcroforms.RemoveAll(); | |
| 420 } else { | |
| 421 m_objs_array.RemoveAll(); | |
| 422 m_objs_array.Append(new_objs_array); | |
| 423 } | |
| 424 return bRet; | |
| 425 } | |
| 426 | |
| 427 FX_BOOL CPDF_DataAvail::CheckAcroForm(IFX_DownloadHints* pHints) { | |
| 428 FX_BOOL bExist = FALSE; | |
| 429 m_pAcroForm = GetObject(m_dwAcroFormObjNum, pHints, &bExist); | |
| 430 if (!bExist) { | |
| 431 m_docStatus = PDF_DATAAVAIL_PAGETREE; | |
| 432 return TRUE; | |
| 433 } | |
| 434 | |
| 435 if (!m_pAcroForm) { | |
| 436 if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
| 437 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 438 return TRUE; | |
| 439 } | |
| 440 return FALSE; | |
| 441 } | |
| 442 | |
| 443 m_arrayAcroforms.Add(m_pAcroForm); | |
| 444 m_docStatus = PDF_DATAAVAIL_PAGETREE; | |
| 445 return TRUE; | |
| 446 } | |
| 447 | |
| 448 FX_BOOL CPDF_DataAvail::CheckDocStatus(IFX_DownloadHints* pHints) { | |
| 449 switch (m_docStatus) { | |
| 450 case PDF_DATAAVAIL_HEADER: | |
| 451 return CheckHeader(pHints); | |
| 452 case PDF_DATAAVAIL_FIRSTPAGE: | |
| 453 case PDF_DATAAVAIL_FIRSTPAGE_PREPARE: | |
| 454 return CheckFirstPage(pHints); | |
| 455 case PDF_DATAAVAIL_HINTTABLE: | |
| 456 return CheckHintTables(pHints); | |
| 457 case PDF_DATAAVAIL_END: | |
| 458 return CheckEnd(pHints); | |
| 459 case PDF_DATAAVAIL_CROSSREF: | |
| 460 return CheckCrossRef(pHints); | |
| 461 case PDF_DATAAVAIL_CROSSREF_ITEM: | |
| 462 return CheckCrossRefItem(pHints); | |
| 463 case PDF_DATAAVAIL_CROSSREF_STREAM: | |
| 464 return CheckAllCrossRefStream(pHints); | |
| 465 case PDF_DATAAVAIL_TRAILER: | |
| 466 return CheckTrailer(pHints); | |
| 467 case PDF_DATAAVAIL_TRAILER_APPEND: | |
| 468 return CheckTrailerAppend(pHints); | |
| 469 case PDF_DATAAVAIL_LOADALLCROSSREF: | |
| 470 return LoadAllXref(pHints); | |
| 471 case PDF_DATAAVAIL_LOADALLFILE: | |
| 472 return LoadAllFile(pHints); | |
| 473 case PDF_DATAAVAIL_ROOT: | |
| 474 return CheckRoot(pHints); | |
| 475 case PDF_DATAAVAIL_INFO: | |
| 476 return CheckInfo(pHints); | |
| 477 case PDF_DATAAVAIL_ACROFORM: | |
| 478 return CheckAcroForm(pHints); | |
| 479 case PDF_DATAAVAIL_PAGETREE: | |
| 480 if (m_bTotalLoadPageTree) | |
| 481 return CheckPages(pHints); | |
| 482 return LoadDocPages(pHints); | |
| 483 case PDF_DATAAVAIL_PAGE: | |
| 484 if (m_bTotalLoadPageTree) | |
| 485 return CheckPage(pHints); | |
| 486 m_docStatus = PDF_DATAAVAIL_PAGE_LATERLOAD; | |
| 487 return TRUE; | |
| 488 case PDF_DATAAVAIL_ERROR: | |
| 489 return LoadAllFile(pHints); | |
| 490 case PDF_DATAAVAIL_PAGE_LATERLOAD: | |
| 491 m_docStatus = PDF_DATAAVAIL_PAGE; | |
| 492 default: | |
| 493 m_bDocAvail = TRUE; | |
| 494 return TRUE; | |
| 495 } | |
| 496 } | |
| 497 | |
| 498 FX_BOOL CPDF_DataAvail::CheckPageStatus(IFX_DownloadHints* pHints) { | |
| 499 switch (m_docStatus) { | |
| 500 case PDF_DATAAVAIL_PAGETREE: | |
| 501 return CheckPages(pHints); | |
| 502 case PDF_DATAAVAIL_PAGE: | |
| 503 return CheckPage(pHints); | |
| 504 case PDF_DATAAVAIL_ERROR: | |
| 505 return LoadAllFile(pHints); | |
| 506 default: | |
| 507 m_bPagesTreeLoad = TRUE; | |
| 508 m_bPagesLoad = TRUE; | |
| 509 return TRUE; | |
| 510 } | |
| 511 } | |
| 512 | |
| 513 FX_BOOL CPDF_DataAvail::LoadAllFile(IFX_DownloadHints* pHints) { | |
| 514 if (m_pFileAvail->IsDataAvail(0, (FX_DWORD)m_dwFileLen)) { | |
| 515 m_docStatus = PDF_DATAAVAIL_DONE; | |
| 516 return TRUE; | |
| 517 } | |
| 518 | |
| 519 pHints->AddSegment(0, (FX_DWORD)m_dwFileLen); | |
| 520 return FALSE; | |
| 521 } | |
| 522 | |
| 523 FX_BOOL CPDF_DataAvail::LoadAllXref(IFX_DownloadHints* pHints) { | |
| 524 m_parser.m_pSyntax->InitParser(m_pFileRead, (FX_DWORD)m_dwHeaderOffset); | |
| 525 m_parser.m_bOwnFileRead = false; | |
| 526 if (!m_parser.LoadAllCrossRefV4(m_dwLastXRefOffset) && | |
| 527 !m_parser.LoadAllCrossRefV5(m_dwLastXRefOffset)) { | |
| 528 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 529 return FALSE; | |
| 530 } | |
| 531 | |
| 532 m_dwRootObjNum = m_parser.GetRootObjNum(); | |
| 533 m_dwInfoObjNum = m_parser.GetInfoObjNum(); | |
| 534 m_pCurrentParser = &m_parser; | |
| 535 m_docStatus = PDF_DATAAVAIL_ROOT; | |
| 536 return TRUE; | |
| 537 } | |
| 538 | |
| 539 CPDF_Object* CPDF_DataAvail::GetObject(FX_DWORD objnum, | |
| 540 IFX_DownloadHints* pHints, | |
| 541 FX_BOOL* pExistInFile) { | |
| 542 CPDF_Object* pRet = nullptr; | |
| 543 FX_DWORD size = 0; | |
| 544 FX_FILESIZE offset = 0; | |
| 545 CPDF_Parser* pParser = nullptr; | |
| 546 | |
| 547 if (pExistInFile) | |
| 548 *pExistInFile = TRUE; | |
| 549 | |
| 550 if (m_pDocument) { | |
| 551 size = GetObjectSize(objnum, offset); | |
| 552 pParser = m_pDocument->GetParser(); | |
| 553 } else { | |
| 554 size = (FX_DWORD)m_parser.GetObjectSize(objnum); | |
| 555 offset = m_parser.GetObjectOffset(objnum); | |
| 556 pParser = &m_parser; | |
| 557 } | |
| 558 | |
| 559 if (!IsDataAvail(offset, size, pHints)) | |
| 560 return nullptr; | |
| 561 | |
| 562 if (pParser) | |
| 563 pRet = pParser->ParseIndirectObject(nullptr, objnum); | |
| 564 | |
| 565 if (!pRet && pExistInFile) | |
| 566 *pExistInFile = FALSE; | |
| 567 | |
| 568 return pRet; | |
| 569 } | |
| 570 | |
| 571 FX_BOOL CPDF_DataAvail::CheckInfo(IFX_DownloadHints* pHints) { | |
| 572 FX_BOOL bExist = FALSE; | |
| 573 CPDF_Object* pInfo = GetObject(m_dwInfoObjNum, pHints, &bExist); | |
| 574 if (!bExist) { | |
| 575 m_docStatus = | |
| 576 (m_bHaveAcroForm ? PDF_DATAAVAIL_ACROFORM : PDF_DATAAVAIL_PAGETREE); | |
| 577 return TRUE; | |
| 578 } | |
| 579 | |
| 580 if (!pInfo) { | |
| 581 if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
| 582 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 583 return TRUE; | |
| 584 } | |
| 585 | |
| 586 if (m_Pos == m_dwFileLen) | |
| 587 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 588 return FALSE; | |
| 589 } | |
| 590 | |
| 591 if (pInfo) | |
| 592 pInfo->Release(); | |
| 593 | |
| 594 m_docStatus = | |
| 595 (m_bHaveAcroForm ? PDF_DATAAVAIL_ACROFORM : PDF_DATAAVAIL_PAGETREE); | |
| 596 | |
| 597 return TRUE; | |
| 598 } | |
| 599 | |
| 600 FX_BOOL CPDF_DataAvail::CheckRoot(IFX_DownloadHints* pHints) { | |
| 601 FX_BOOL bExist = FALSE; | |
| 602 m_pRoot = GetObject(m_dwRootObjNum, pHints, &bExist); | |
| 603 if (!bExist) { | |
| 604 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 605 return TRUE; | |
| 606 } | |
| 607 | |
| 608 if (!m_pRoot) { | |
| 609 if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
| 610 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 611 return TRUE; | |
| 612 } | |
| 613 return FALSE; | |
| 614 } | |
| 615 | |
| 616 CPDF_Dictionary* pDict = m_pRoot->GetDict(); | |
| 617 if (!pDict) { | |
| 618 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 619 return FALSE; | |
| 620 } | |
| 621 | |
| 622 CPDF_Reference* pRef = ToReference(pDict->GetElement("Pages")); | |
| 623 if (!pRef) { | |
| 624 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 625 return FALSE; | |
| 626 } | |
| 627 | |
| 628 m_PagesObjNum = pRef->GetRefObjNum(); | |
| 629 CPDF_Reference* pAcroFormRef = | |
| 630 ToReference(m_pRoot->GetDict()->GetElement("AcroForm")); | |
| 631 if (pAcroFormRef) { | |
| 632 m_bHaveAcroForm = TRUE; | |
| 633 m_dwAcroFormObjNum = pAcroFormRef->GetRefObjNum(); | |
| 634 } | |
| 635 | |
| 636 if (m_dwInfoObjNum) { | |
| 637 m_docStatus = PDF_DATAAVAIL_INFO; | |
| 638 } else { | |
| 639 m_docStatus = | |
| 640 m_bHaveAcroForm ? PDF_DATAAVAIL_ACROFORM : PDF_DATAAVAIL_PAGETREE; | |
| 641 } | |
| 642 return TRUE; | |
| 643 } | |
| 644 | |
| 645 FX_BOOL CPDF_DataAvail::PreparePageItem() { | |
| 646 CPDF_Dictionary* pRoot = m_pDocument->GetRoot(); | |
| 647 CPDF_Reference* pRef = | |
| 648 ToReference(pRoot ? pRoot->GetElement("Pages") : nullptr); | |
| 649 if (!pRef) { | |
| 650 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 651 return FALSE; | |
| 652 } | |
| 653 | |
| 654 m_PagesObjNum = pRef->GetRefObjNum(); | |
| 655 m_pCurrentParser = m_pDocument->GetParser(); | |
| 656 m_docStatus = PDF_DATAAVAIL_PAGETREE; | |
| 657 return TRUE; | |
| 658 } | |
| 659 | |
| 660 bool CPDF_DataAvail::IsFirstCheck(int iPage) { | |
| 661 return m_pageMapCheckState.insert(iPage).second; | |
| 662 } | |
| 663 | |
| 664 void CPDF_DataAvail::ResetFirstCheck(int iPage) { | |
| 665 m_pageMapCheckState.erase(iPage); | |
| 666 } | |
| 667 | |
| 668 FX_BOOL CPDF_DataAvail::CheckPage(IFX_DownloadHints* pHints) { | |
| 669 FX_DWORD iPageObjs = m_PageObjList.GetSize(); | |
| 670 CFX_DWordArray UnavailObjList; | |
| 671 for (FX_DWORD i = 0; i < iPageObjs; ++i) { | |
| 672 FX_DWORD dwPageObjNum = m_PageObjList.GetAt(i); | |
| 673 FX_BOOL bExist = FALSE; | |
| 674 CPDF_Object* pObj = GetObject(dwPageObjNum, pHints, &bExist); | |
| 675 if (!pObj) { | |
| 676 if (bExist) | |
| 677 UnavailObjList.Add(dwPageObjNum); | |
| 678 continue; | |
| 679 } | |
| 680 | |
| 681 if (pObj->IsArray()) { | |
| 682 CPDF_Array* pArray = pObj->GetArray(); | |
| 683 if (pArray) { | |
| 684 int32_t iSize = pArray->GetCount(); | |
| 685 for (int32_t j = 0; j < iSize; ++j) { | |
| 686 if (CPDF_Reference* pRef = ToReference(pArray->GetElement(j))) | |
| 687 UnavailObjList.Add(pRef->GetRefObjNum()); | |
| 688 } | |
| 689 } | |
| 690 } | |
| 691 | |
| 692 if (!pObj->IsDictionary()) { | |
| 693 pObj->Release(); | |
| 694 continue; | |
| 695 } | |
| 696 | |
| 697 CFX_ByteString type = pObj->GetDict()->GetStringBy("Type"); | |
| 698 if (type == "Pages") { | |
| 699 m_PagesArray.Add(pObj); | |
| 700 continue; | |
| 701 } | |
| 702 pObj->Release(); | |
| 703 } | |
| 704 | |
| 705 m_PageObjList.RemoveAll(); | |
| 706 if (UnavailObjList.GetSize()) { | |
| 707 m_PageObjList.Append(UnavailObjList); | |
| 708 return FALSE; | |
| 709 } | |
| 710 | |
| 711 FX_DWORD iPages = m_PagesArray.GetSize(); | |
| 712 for (FX_DWORD i = 0; i < iPages; i++) { | |
| 713 CPDF_Object* pPages = m_PagesArray.GetAt(i); | |
| 714 if (!pPages) | |
| 715 continue; | |
| 716 | |
| 717 if (!GetPageKids(m_pCurrentParser, pPages)) { | |
| 718 pPages->Release(); | |
| 719 while (++i < iPages) { | |
| 720 pPages = m_PagesArray.GetAt(i); | |
| 721 pPages->Release(); | |
| 722 } | |
| 723 m_PagesArray.RemoveAll(); | |
| 724 | |
| 725 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 726 return FALSE; | |
| 727 } | |
| 728 pPages->Release(); | |
| 729 } | |
| 730 | |
| 731 m_PagesArray.RemoveAll(); | |
| 732 if (!m_PageObjList.GetSize()) | |
| 733 m_docStatus = PDF_DATAAVAIL_DONE; | |
| 734 return TRUE; | |
| 735 } | |
| 736 | |
| 737 FX_BOOL CPDF_DataAvail::GetPageKids(CPDF_Parser* pParser, CPDF_Object* pPages) { | |
| 738 if (!pParser) { | |
| 739 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 740 return FALSE; | |
| 741 } | |
| 742 | |
| 743 CPDF_Dictionary* pDict = pPages->GetDict(); | |
| 744 CPDF_Object* pKids = pDict ? pDict->GetElement("Kids") : NULL; | |
| 745 if (!pKids) | |
| 746 return TRUE; | |
| 747 | |
| 748 switch (pKids->GetType()) { | |
| 749 case CPDF_Object::REFERENCE: | |
| 750 m_PageObjList.Add(pKids->AsReference()->GetRefObjNum()); | |
| 751 break; | |
| 752 case CPDF_Object::ARRAY: { | |
| 753 CPDF_Array* pKidsArray = pKids->AsArray(); | |
| 754 for (FX_DWORD i = 0; i < pKidsArray->GetCount(); ++i) { | |
| 755 if (CPDF_Reference* pRef = ToReference(pKidsArray->GetElement(i))) | |
| 756 m_PageObjList.Add(pRef->GetRefObjNum()); | |
| 757 } | |
| 758 } break; | |
| 759 default: | |
| 760 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 761 return FALSE; | |
| 762 } | |
| 763 return TRUE; | |
| 764 } | |
| 765 | |
| 766 FX_BOOL CPDF_DataAvail::CheckPages(IFX_DownloadHints* pHints) { | |
| 767 FX_BOOL bExist = FALSE; | |
| 768 CPDF_Object* pPages = GetObject(m_PagesObjNum, pHints, &bExist); | |
| 769 if (!bExist) { | |
| 770 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 771 return TRUE; | |
| 772 } | |
| 773 | |
| 774 if (!pPages) { | |
| 775 if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
| 776 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 777 return TRUE; | |
| 778 } | |
| 779 return FALSE; | |
| 780 } | |
| 781 | |
| 782 if (!GetPageKids(m_pCurrentParser, pPages)) { | |
| 783 pPages->Release(); | |
| 784 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 785 return FALSE; | |
| 786 } | |
| 787 | |
| 788 pPages->Release(); | |
| 789 m_docStatus = PDF_DATAAVAIL_PAGE; | |
| 790 return TRUE; | |
| 791 } | |
| 792 | |
| 793 FX_BOOL CPDF_DataAvail::CheckHeader(IFX_DownloadHints* pHints) { | |
| 794 FX_DWORD req_size = 1024; | |
| 795 if ((FX_FILESIZE)req_size > m_dwFileLen) | |
| 796 req_size = (FX_DWORD)m_dwFileLen; | |
| 797 | |
| 798 if (m_pFileAvail->IsDataAvail(0, req_size)) { | |
| 799 uint8_t buffer[1024]; | |
| 800 m_pFileRead->ReadBlock(buffer, 0, req_size); | |
| 801 | |
| 802 if (IsLinearizedFile(buffer, req_size)) { | |
| 803 m_docStatus = PDF_DATAAVAIL_FIRSTPAGE; | |
| 804 } else { | |
| 805 if (m_docStatus == PDF_DATAAVAIL_ERROR) | |
| 806 return FALSE; | |
| 807 m_docStatus = PDF_DATAAVAIL_END; | |
| 808 } | |
| 809 return TRUE; | |
| 810 } | |
| 811 | |
| 812 pHints->AddSegment(0, req_size); | |
| 813 return FALSE; | |
| 814 } | |
| 815 | |
| 816 FX_BOOL CPDF_DataAvail::CheckFirstPage(IFX_DownloadHints* pHints) { | |
| 817 CPDF_Dictionary* pDict = m_pLinearized->GetDict(); | |
| 818 CPDF_Object* pEndOffSet = pDict ? pDict->GetElement("E") : NULL; | |
| 819 if (!pEndOffSet) { | |
| 820 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 821 return FALSE; | |
| 822 } | |
| 823 | |
| 824 CPDF_Object* pXRefOffset = pDict ? pDict->GetElement("T") : NULL; | |
| 825 if (!pXRefOffset) { | |
| 826 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 827 return FALSE; | |
| 828 } | |
| 829 | |
| 830 CPDF_Object* pFileLen = pDict ? pDict->GetElement("L") : NULL; | |
| 831 if (!pFileLen) { | |
| 832 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 833 return FALSE; | |
| 834 } | |
| 835 | |
| 836 FX_BOOL bNeedDownLoad = FALSE; | |
| 837 if (pEndOffSet->IsNumber()) { | |
| 838 FX_DWORD dwEnd = pEndOffSet->GetInteger(); | |
| 839 dwEnd += 512; | |
| 840 if ((FX_FILESIZE)dwEnd > m_dwFileLen) | |
| 841 dwEnd = (FX_DWORD)m_dwFileLen; | |
| 842 | |
| 843 int32_t iStartPos = (int32_t)(m_dwFileLen > 1024 ? 1024 : m_dwFileLen); | |
| 844 int32_t iSize = dwEnd > 1024 ? dwEnd - 1024 : 0; | |
| 845 if (!m_pFileAvail->IsDataAvail(iStartPos, iSize)) { | |
| 846 pHints->AddSegment(iStartPos, iSize); | |
| 847 bNeedDownLoad = TRUE; | |
| 848 } | |
| 849 } | |
| 850 | |
| 851 m_dwLastXRefOffset = 0; | |
| 852 FX_FILESIZE dwFileLen = 0; | |
| 853 if (pXRefOffset->IsNumber()) | |
| 854 m_dwLastXRefOffset = pXRefOffset->GetInteger(); | |
| 855 | |
| 856 if (pFileLen->IsNumber()) | |
| 857 dwFileLen = pFileLen->GetInteger(); | |
| 858 | |
| 859 if (!m_pFileAvail->IsDataAvail(m_dwLastXRefOffset, | |
| 860 (FX_DWORD)(dwFileLen - m_dwLastXRefOffset))) { | |
| 861 if (m_docStatus == PDF_DATAAVAIL_FIRSTPAGE) { | |
| 862 FX_DWORD dwSize = (FX_DWORD)(dwFileLen - m_dwLastXRefOffset); | |
| 863 FX_FILESIZE offset = m_dwLastXRefOffset; | |
| 864 if (dwSize < 512 && dwFileLen > 512) { | |
| 865 dwSize = 512; | |
| 866 offset = dwFileLen - 512; | |
| 867 } | |
| 868 pHints->AddSegment(offset, dwSize); | |
| 869 } | |
| 870 } else { | |
| 871 m_docStatus = PDF_DATAAVAIL_FIRSTPAGE_PREPARE; | |
| 872 } | |
| 873 | |
| 874 if (bNeedDownLoad || m_docStatus != PDF_DATAAVAIL_FIRSTPAGE_PREPARE) { | |
| 875 m_docStatus = PDF_DATAAVAIL_FIRSTPAGE_PREPARE; | |
| 876 return FALSE; | |
| 877 } | |
| 878 | |
| 879 m_docStatus = | |
| 880 m_bSupportHintTable ? PDF_DATAAVAIL_HINTTABLE : PDF_DATAAVAIL_DONE; | |
| 881 return TRUE; | |
| 882 } | |
| 883 | |
| 884 FX_BOOL CPDF_DataAvail::IsDataAvail(FX_FILESIZE offset, | |
| 885 FX_DWORD size, | |
| 886 IFX_DownloadHints* pHints) { | |
| 887 if (offset > m_dwFileLen) | |
| 888 return TRUE; | |
| 889 | |
| 890 FX_SAFE_DWORD safeSize = pdfium::base::checked_cast<FX_DWORD>(offset); | |
| 891 safeSize += size; | |
| 892 safeSize += 512; | |
| 893 if (!safeSize.IsValid() || safeSize.ValueOrDie() > m_dwFileLen) | |
| 894 size = m_dwFileLen - offset; | |
| 895 else | |
| 896 size += 512; | |
| 897 | |
| 898 if (!m_pFileAvail->IsDataAvail(offset, size)) { | |
| 899 pHints->AddSegment(offset, size); | |
| 900 return FALSE; | |
| 901 } | |
| 902 return TRUE; | |
| 903 } | |
| 904 | |
| 905 FX_BOOL CPDF_DataAvail::CheckHintTables(IFX_DownloadHints* pHints) { | |
| 906 CPDF_Dictionary* pDict = m_pLinearized->GetDict(); | |
| 907 if (!pDict) { | |
| 908 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 909 return FALSE; | |
| 910 } | |
| 911 | |
| 912 if (!pDict->KeyExist("H") || !pDict->KeyExist("O") || !pDict->KeyExist("N")) { | |
| 913 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 914 return FALSE; | |
| 915 } | |
| 916 | |
| 917 int nPageCount = pDict->GetElementValue("N")->GetInteger(); | |
| 918 if (nPageCount <= 1) { | |
| 919 m_docStatus = PDF_DATAAVAIL_DONE; | |
| 920 return TRUE; | |
| 921 } | |
| 922 | |
| 923 CPDF_Array* pHintStreamRange = pDict->GetArrayBy("H"); | |
| 924 FX_FILESIZE szHSStart = | |
| 925 pHintStreamRange->GetElementValue(0) | |
| 926 ? pHintStreamRange->GetElementValue(0)->GetInteger() | |
| 927 : 0; | |
| 928 FX_FILESIZE szHSLength = | |
| 929 pHintStreamRange->GetElementValue(1) | |
| 930 ? pHintStreamRange->GetElementValue(1)->GetInteger() | |
| 931 : 0; | |
| 932 if (szHSStart < 0 || szHSLength <= 0) { | |
| 933 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 934 return FALSE; | |
| 935 } | |
| 936 | |
| 937 if (!IsDataAvail(szHSStart, szHSLength, pHints)) | |
| 938 return FALSE; | |
| 939 | |
| 940 m_syntaxParser.InitParser(m_pFileRead, m_dwHeaderOffset); | |
| 941 | |
| 942 std::unique_ptr<CPDF_HintTables> pHintTables( | |
| 943 new CPDF_HintTables(this, pDict)); | |
| 944 std::unique_ptr<CPDF_Object, ReleaseDeleter<CPDF_Object>> pHintStream( | |
| 945 ParseIndirectObjectAt(szHSStart, 0)); | |
| 946 CPDF_Stream* pStream = ToStream(pHintStream.get()); | |
| 947 if (pStream && pHintTables->LoadHintStream(pStream)) | |
| 948 m_pHintTables = std::move(pHintTables); | |
| 949 | |
| 950 m_docStatus = PDF_DATAAVAIL_DONE; | |
| 951 return TRUE; | |
| 952 } | |
| 953 | |
| 954 CPDF_Object* CPDF_DataAvail::ParseIndirectObjectAt( | |
| 955 FX_FILESIZE pos, | |
| 956 FX_DWORD objnum, | |
| 957 CPDF_IndirectObjectHolder* pObjList) { | |
| 958 FX_FILESIZE SavedPos = m_syntaxParser.SavePos(); | |
| 959 m_syntaxParser.RestorePos(pos); | |
| 960 | |
| 961 bool bIsNumber; | |
| 962 CFX_ByteString word = m_syntaxParser.GetNextWord(&bIsNumber); | |
| 963 if (!bIsNumber) | |
| 964 return nullptr; | |
| 965 | |
| 966 FX_DWORD parser_objnum = FXSYS_atoui(word); | |
| 967 if (objnum && parser_objnum != objnum) | |
| 968 return nullptr; | |
| 969 | |
| 970 word = m_syntaxParser.GetNextWord(&bIsNumber); | |
| 971 if (!bIsNumber) | |
| 972 return nullptr; | |
| 973 | |
| 974 FX_DWORD gennum = FXSYS_atoui(word); | |
| 975 if (m_syntaxParser.GetKeyword() != "obj") { | |
| 976 m_syntaxParser.RestorePos(SavedPos); | |
| 977 return nullptr; | |
| 978 } | |
| 979 | |
| 980 CPDF_Object* pObj = | |
| 981 m_syntaxParser.GetObject(pObjList, parser_objnum, gennum, true); | |
| 982 m_syntaxParser.RestorePos(SavedPos); | |
| 983 return pObj; | |
| 984 } | |
| 985 | |
| 986 IPDF_DataAvail::DocLinearizationStatus CPDF_DataAvail::IsLinearizedPDF() { | |
| 987 FX_DWORD req_size = 1024; | |
| 988 if (!m_pFileAvail->IsDataAvail(0, req_size)) | |
| 989 return LinearizationUnknown; | |
| 990 | |
| 991 if (!m_pFileRead) | |
| 992 return NotLinearized; | |
| 993 | |
| 994 FX_FILESIZE dwSize = m_pFileRead->GetSize(); | |
| 995 if (dwSize < (FX_FILESIZE)req_size) | |
| 996 return LinearizationUnknown; | |
| 997 | |
| 998 uint8_t buffer[1024]; | |
| 999 m_pFileRead->ReadBlock(buffer, 0, req_size); | |
| 1000 if (IsLinearizedFile(buffer, req_size)) | |
| 1001 return Linearized; | |
| 1002 | |
| 1003 return NotLinearized; | |
| 1004 } | |
| 1005 FX_BOOL CPDF_DataAvail::IsLinearizedFile(uint8_t* pData, FX_DWORD dwLen) { | |
| 1006 ScopedFileStream file(FX_CreateMemoryStream(pData, (size_t)dwLen, FALSE)); | |
| 1007 | |
| 1008 int32_t offset = GetHeaderOffset(file.get()); | |
| 1009 if (offset == -1) { | |
| 1010 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1011 return FALSE; | |
| 1012 } | |
| 1013 | |
| 1014 m_dwHeaderOffset = offset; | |
| 1015 m_syntaxParser.InitParser(file.get(), offset); | |
| 1016 m_syntaxParser.RestorePos(m_syntaxParser.m_HeaderOffset + 9); | |
| 1017 | |
| 1018 bool bNumber; | |
| 1019 CFX_ByteString wordObjNum = m_syntaxParser.GetNextWord(&bNumber); | |
| 1020 if (!bNumber) | |
| 1021 return FALSE; | |
| 1022 | |
| 1023 FX_DWORD objnum = FXSYS_atoui(wordObjNum); | |
| 1024 if (m_pLinearized) { | |
| 1025 m_pLinearized->Release(); | |
| 1026 m_pLinearized = nullptr; | |
| 1027 } | |
| 1028 | |
| 1029 m_pLinearized = | |
| 1030 ParseIndirectObjectAt(m_syntaxParser.m_HeaderOffset + 9, objnum); | |
| 1031 if (!m_pLinearized) | |
| 1032 return FALSE; | |
| 1033 | |
| 1034 CPDF_Dictionary* pDict = m_pLinearized->GetDict(); | |
| 1035 if (pDict && pDict->GetElement("Linearized")) { | |
| 1036 CPDF_Object* pLen = pDict->GetElement("L"); | |
| 1037 if (!pLen) | |
| 1038 return FALSE; | |
| 1039 | |
| 1040 if ((FX_FILESIZE)pLen->GetInteger() != m_pFileRead->GetSize()) | |
| 1041 return FALSE; | |
| 1042 | |
| 1043 m_bLinearized = TRUE; | |
| 1044 | |
| 1045 if (CPDF_Number* pNo = ToNumber(pDict->GetElement("P"))) | |
| 1046 m_dwFirstPageNo = pNo->GetInteger(); | |
| 1047 | |
| 1048 return TRUE; | |
| 1049 } | |
| 1050 return FALSE; | |
| 1051 } | |
| 1052 | |
| 1053 FX_BOOL CPDF_DataAvail::CheckEnd(IFX_DownloadHints* pHints) { | |
| 1054 FX_DWORD req_pos = (FX_DWORD)(m_dwFileLen > 1024 ? m_dwFileLen - 1024 : 0); | |
| 1055 FX_DWORD dwSize = (FX_DWORD)(m_dwFileLen - req_pos); | |
| 1056 | |
| 1057 if (m_pFileAvail->IsDataAvail(req_pos, dwSize)) { | |
| 1058 uint8_t buffer[1024]; | |
| 1059 m_pFileRead->ReadBlock(buffer, req_pos, dwSize); | |
| 1060 | |
| 1061 ScopedFileStream file(FX_CreateMemoryStream(buffer, (size_t)dwSize, FALSE)); | |
| 1062 m_syntaxParser.InitParser(file.get(), 0); | |
| 1063 m_syntaxParser.RestorePos(dwSize - 1); | |
| 1064 | |
| 1065 if (m_syntaxParser.SearchWord("startxref", TRUE, FALSE, dwSize)) { | |
| 1066 m_syntaxParser.GetNextWord(nullptr); | |
| 1067 | |
| 1068 bool bNumber; | |
| 1069 CFX_ByteString xrefpos_str = m_syntaxParser.GetNextWord(&bNumber); | |
| 1070 if (!bNumber) { | |
| 1071 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1072 return FALSE; | |
| 1073 } | |
| 1074 | |
| 1075 m_dwXRefOffset = (FX_FILESIZE)FXSYS_atoi64(xrefpos_str); | |
| 1076 if (!m_dwXRefOffset || m_dwXRefOffset > m_dwFileLen) { | |
| 1077 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 1078 return TRUE; | |
| 1079 } | |
| 1080 | |
| 1081 m_dwLastXRefOffset = m_dwXRefOffset; | |
| 1082 SetStartOffset(m_dwXRefOffset); | |
| 1083 m_docStatus = PDF_DATAAVAIL_CROSSREF; | |
| 1084 return TRUE; | |
| 1085 } | |
| 1086 | |
| 1087 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 1088 return TRUE; | |
| 1089 } | |
| 1090 | |
| 1091 pHints->AddSegment(req_pos, dwSize); | |
| 1092 return FALSE; | |
| 1093 } | |
| 1094 | |
| 1095 int32_t CPDF_DataAvail::CheckCrossRefStream(IFX_DownloadHints* pHints, | |
| 1096 FX_FILESIZE& xref_offset) { | |
| 1097 xref_offset = 0; | |
| 1098 FX_DWORD req_size = | |
| 1099 (FX_DWORD)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
| 1100 | |
| 1101 if (m_pFileAvail->IsDataAvail(m_Pos, req_size)) { | |
| 1102 int32_t iSize = (int32_t)(m_Pos + req_size - m_dwCurrentXRefSteam); | |
| 1103 CFX_BinaryBuf buf(iSize); | |
| 1104 uint8_t* pBuf = buf.GetBuffer(); | |
| 1105 | |
| 1106 m_pFileRead->ReadBlock(pBuf, m_dwCurrentXRefSteam, iSize); | |
| 1107 | |
| 1108 ScopedFileStream file(FX_CreateMemoryStream(pBuf, (size_t)iSize, FALSE)); | |
| 1109 m_parser.m_pSyntax->InitParser(file.get(), 0); | |
| 1110 | |
| 1111 bool bNumber; | |
| 1112 CFX_ByteString objnum = m_parser.m_pSyntax->GetNextWord(&bNumber); | |
| 1113 if (!bNumber) | |
| 1114 return -1; | |
| 1115 | |
| 1116 FX_DWORD objNum = FXSYS_atoui(objnum); | |
| 1117 CPDF_Object* pObj = m_parser.ParseIndirectObjectAt(nullptr, 0, objNum); | |
| 1118 if (!pObj) { | |
| 1119 m_Pos += m_parser.m_pSyntax->SavePos(); | |
| 1120 return 0; | |
| 1121 } | |
| 1122 | |
| 1123 CPDF_Dictionary* pDict = pObj->GetDict(); | |
| 1124 CPDF_Name* pName = ToName(pDict ? pDict->GetElement("Type") : nullptr); | |
| 1125 if (pName) { | |
| 1126 if (pName->GetString() == "XRef") { | |
| 1127 m_Pos += m_parser.m_pSyntax->SavePos(); | |
| 1128 xref_offset = pObj->GetDict()->GetIntegerBy("Prev"); | |
| 1129 pObj->Release(); | |
| 1130 return 1; | |
| 1131 } | |
| 1132 } | |
| 1133 pObj->Release(); | |
| 1134 return -1; | |
| 1135 } | |
| 1136 pHints->AddSegment(m_Pos, req_size); | |
| 1137 return 0; | |
| 1138 } | |
| 1139 | |
| 1140 inline void CPDF_DataAvail::SetStartOffset(FX_FILESIZE dwOffset) { | |
| 1141 m_Pos = dwOffset; | |
| 1142 } | |
| 1143 | |
| 1144 FX_BOOL CPDF_DataAvail::GetNextToken(CFX_ByteString& token) { | |
| 1145 uint8_t ch; | |
| 1146 if (!GetNextChar(ch)) | |
| 1147 return FALSE; | |
| 1148 | |
| 1149 while (1) { | |
| 1150 while (PDFCharIsWhitespace(ch)) { | |
| 1151 if (!GetNextChar(ch)) | |
| 1152 return FALSE; | |
| 1153 } | |
| 1154 | |
| 1155 if (ch != '%') | |
| 1156 break; | |
| 1157 | |
| 1158 while (1) { | |
| 1159 if (!GetNextChar(ch)) | |
| 1160 return FALSE; | |
| 1161 if (PDFCharIsLineEnding(ch)) | |
| 1162 break; | |
| 1163 } | |
| 1164 } | |
| 1165 | |
| 1166 uint8_t buffer[256]; | |
| 1167 FX_DWORD index = 0; | |
| 1168 if (PDFCharIsDelimiter(ch)) { | |
| 1169 buffer[index++] = ch; | |
| 1170 if (ch == '/') { | |
| 1171 while (1) { | |
| 1172 if (!GetNextChar(ch)) | |
| 1173 return FALSE; | |
| 1174 | |
| 1175 if (!PDFCharIsOther(ch) && !PDFCharIsNumeric(ch)) { | |
| 1176 m_Pos--; | |
| 1177 CFX_ByteString ret(buffer, index); | |
| 1178 token = ret; | |
| 1179 return TRUE; | |
| 1180 } | |
| 1181 | |
| 1182 if (index < sizeof(buffer)) | |
| 1183 buffer[index++] = ch; | |
| 1184 } | |
| 1185 } else if (ch == '<') { | |
| 1186 if (!GetNextChar(ch)) | |
| 1187 return FALSE; | |
| 1188 | |
| 1189 if (ch == '<') | |
| 1190 buffer[index++] = ch; | |
| 1191 else | |
| 1192 m_Pos--; | |
| 1193 } else if (ch == '>') { | |
| 1194 if (!GetNextChar(ch)) | |
| 1195 return FALSE; | |
| 1196 | |
| 1197 if (ch == '>') | |
| 1198 buffer[index++] = ch; | |
| 1199 else | |
| 1200 m_Pos--; | |
| 1201 } | |
| 1202 | |
| 1203 CFX_ByteString ret(buffer, index); | |
| 1204 token = ret; | |
| 1205 return TRUE; | |
| 1206 } | |
| 1207 | |
| 1208 while (1) { | |
| 1209 if (index < sizeof(buffer)) | |
| 1210 buffer[index++] = ch; | |
| 1211 | |
| 1212 if (!GetNextChar(ch)) | |
| 1213 return FALSE; | |
| 1214 | |
| 1215 if (PDFCharIsDelimiter(ch) || PDFCharIsWhitespace(ch)) { | |
| 1216 m_Pos--; | |
| 1217 break; | |
| 1218 } | |
| 1219 } | |
| 1220 | |
| 1221 token = CFX_ByteString(buffer, index); | |
| 1222 return TRUE; | |
| 1223 } | |
| 1224 | |
| 1225 FX_BOOL CPDF_DataAvail::GetNextChar(uint8_t& ch) { | |
| 1226 FX_FILESIZE pos = m_Pos; | |
| 1227 if (pos >= m_dwFileLen) | |
| 1228 return FALSE; | |
| 1229 | |
| 1230 if (m_bufferOffset >= pos || | |
| 1231 (FX_FILESIZE)(m_bufferOffset + m_bufferSize) <= pos) { | |
| 1232 FX_FILESIZE read_pos = pos; | |
| 1233 FX_DWORD read_size = 512; | |
| 1234 if ((FX_FILESIZE)read_size > m_dwFileLen) | |
| 1235 read_size = (FX_DWORD)m_dwFileLen; | |
| 1236 | |
| 1237 if ((FX_FILESIZE)(read_pos + read_size) > m_dwFileLen) | |
| 1238 read_pos = m_dwFileLen - read_size; | |
| 1239 | |
| 1240 if (!m_pFileRead->ReadBlock(m_bufferData, read_pos, read_size)) | |
| 1241 return FALSE; | |
| 1242 | |
| 1243 m_bufferOffset = read_pos; | |
| 1244 m_bufferSize = read_size; | |
| 1245 } | |
| 1246 ch = m_bufferData[pos - m_bufferOffset]; | |
| 1247 m_Pos++; | |
| 1248 return TRUE; | |
| 1249 } | |
| 1250 | |
| 1251 FX_BOOL CPDF_DataAvail::CheckCrossRefItem(IFX_DownloadHints* pHints) { | |
| 1252 int32_t iSize = 0; | |
| 1253 CFX_ByteString token; | |
| 1254 while (1) { | |
| 1255 if (!GetNextToken(token)) { | |
| 1256 iSize = (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
| 1257 pHints->AddSegment(m_Pos, iSize); | |
| 1258 return FALSE; | |
| 1259 } | |
| 1260 | |
| 1261 if (token == "trailer") { | |
| 1262 m_dwTrailerOffset = m_Pos; | |
| 1263 m_docStatus = PDF_DATAAVAIL_TRAILER; | |
| 1264 return TRUE; | |
| 1265 } | |
| 1266 } | |
| 1267 } | |
| 1268 | |
| 1269 FX_BOOL CPDF_DataAvail::CheckAllCrossRefStream(IFX_DownloadHints* pHints) { | |
| 1270 FX_FILESIZE xref_offset = 0; | |
| 1271 | |
| 1272 int32_t nRet = CheckCrossRefStream(pHints, xref_offset); | |
| 1273 if (nRet == 1) { | |
| 1274 if (!xref_offset) { | |
| 1275 m_docStatus = PDF_DATAAVAIL_LOADALLCROSSREF; | |
| 1276 } else { | |
| 1277 m_dwCurrentXRefSteam = xref_offset; | |
| 1278 m_Pos = xref_offset; | |
| 1279 } | |
| 1280 return TRUE; | |
| 1281 } | |
| 1282 | |
| 1283 if (nRet == -1) | |
| 1284 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1285 return FALSE; | |
| 1286 } | |
| 1287 | |
| 1288 FX_BOOL CPDF_DataAvail::CheckCrossRef(IFX_DownloadHints* pHints) { | |
| 1289 int32_t iSize = 0; | |
| 1290 CFX_ByteString token; | |
| 1291 if (!GetNextToken(token)) { | |
| 1292 iSize = (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
| 1293 pHints->AddSegment(m_Pos, iSize); | |
| 1294 return FALSE; | |
| 1295 } | |
| 1296 | |
| 1297 if (token == "xref") { | |
| 1298 while (1) { | |
| 1299 if (!GetNextToken(token)) { | |
| 1300 iSize = | |
| 1301 (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
| 1302 pHints->AddSegment(m_Pos, iSize); | |
| 1303 m_docStatus = PDF_DATAAVAIL_CROSSREF_ITEM; | |
| 1304 return FALSE; | |
| 1305 } | |
| 1306 | |
| 1307 if (token == "trailer") { | |
| 1308 m_dwTrailerOffset = m_Pos; | |
| 1309 m_docStatus = PDF_DATAAVAIL_TRAILER; | |
| 1310 return TRUE; | |
| 1311 } | |
| 1312 } | |
| 1313 } else { | |
| 1314 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 1315 return TRUE; | |
| 1316 } | |
| 1317 return FALSE; | |
| 1318 } | |
| 1319 | |
| 1320 FX_BOOL CPDF_DataAvail::CheckTrailerAppend(IFX_DownloadHints* pHints) { | |
| 1321 if (m_Pos < m_dwFileLen) { | |
| 1322 FX_FILESIZE dwAppendPos = m_Pos + m_syntaxParser.SavePos(); | |
| 1323 int32_t iSize = (int32_t)( | |
| 1324 dwAppendPos + 512 > m_dwFileLen ? m_dwFileLen - dwAppendPos : 512); | |
| 1325 | |
| 1326 if (!m_pFileAvail->IsDataAvail(dwAppendPos, iSize)) { | |
| 1327 pHints->AddSegment(dwAppendPos, iSize); | |
| 1328 return FALSE; | |
| 1329 } | |
| 1330 } | |
| 1331 | |
| 1332 if (m_dwPrevXRefOffset) { | |
| 1333 SetStartOffset(m_dwPrevXRefOffset); | |
| 1334 m_docStatus = PDF_DATAAVAIL_CROSSREF; | |
| 1335 } else { | |
| 1336 m_docStatus = PDF_DATAAVAIL_LOADALLCROSSREF; | |
| 1337 } | |
| 1338 return TRUE; | |
| 1339 } | |
| 1340 | |
| 1341 FX_BOOL CPDF_DataAvail::CheckTrailer(IFX_DownloadHints* pHints) { | |
| 1342 int32_t iTrailerSize = | |
| 1343 (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
| 1344 if (m_pFileAvail->IsDataAvail(m_Pos, iTrailerSize)) { | |
| 1345 int32_t iSize = (int32_t)(m_Pos + iTrailerSize - m_dwTrailerOffset); | |
| 1346 CFX_BinaryBuf buf(iSize); | |
| 1347 uint8_t* pBuf = buf.GetBuffer(); | |
| 1348 if (!pBuf) { | |
| 1349 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1350 return FALSE; | |
| 1351 } | |
| 1352 | |
| 1353 if (!m_pFileRead->ReadBlock(pBuf, m_dwTrailerOffset, iSize)) | |
| 1354 return FALSE; | |
| 1355 | |
| 1356 ScopedFileStream file(FX_CreateMemoryStream(pBuf, (size_t)iSize, FALSE)); | |
| 1357 m_syntaxParser.InitParser(file.get(), 0); | |
| 1358 | |
| 1359 std::unique_ptr<CPDF_Object, ReleaseDeleter<CPDF_Object>> pTrailer( | |
| 1360 m_syntaxParser.GetObject(nullptr, 0, 0, true)); | |
| 1361 if (!pTrailer) { | |
| 1362 m_Pos += m_syntaxParser.SavePos(); | |
| 1363 pHints->AddSegment(m_Pos, iTrailerSize); | |
| 1364 return FALSE; | |
| 1365 } | |
| 1366 | |
| 1367 if (!pTrailer->IsDictionary()) | |
| 1368 return FALSE; | |
| 1369 | |
| 1370 CPDF_Dictionary* pTrailerDict = pTrailer->GetDict(); | |
| 1371 CPDF_Object* pEncrypt = pTrailerDict->GetElement("Encrypt"); | |
| 1372 if (ToReference(pEncrypt)) { | |
| 1373 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 1374 return TRUE; | |
| 1375 } | |
| 1376 | |
| 1377 FX_DWORD xrefpos = GetDirectInteger(pTrailerDict, "Prev"); | |
| 1378 if (xrefpos) { | |
| 1379 m_dwPrevXRefOffset = GetDirectInteger(pTrailerDict, "XRefStm"); | |
| 1380 if (m_dwPrevXRefOffset) { | |
| 1381 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 1382 } else { | |
| 1383 m_dwPrevXRefOffset = xrefpos; | |
| 1384 if (m_dwPrevXRefOffset >= m_dwFileLen) { | |
| 1385 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| 1386 } else { | |
| 1387 SetStartOffset(m_dwPrevXRefOffset); | |
| 1388 m_docStatus = PDF_DATAAVAIL_TRAILER_APPEND; | |
| 1389 } | |
| 1390 } | |
| 1391 return TRUE; | |
| 1392 } | |
| 1393 m_dwPrevXRefOffset = 0; | |
| 1394 m_docStatus = PDF_DATAAVAIL_TRAILER_APPEND; | |
| 1395 return TRUE; | |
| 1396 } | |
| 1397 pHints->AddSegment(m_Pos, iTrailerSize); | |
| 1398 return FALSE; | |
| 1399 } | |
| 1400 | |
| 1401 FX_BOOL CPDF_DataAvail::CheckPage(int32_t iPage, IFX_DownloadHints* pHints) { | |
| 1402 while (TRUE) { | |
| 1403 switch (m_docStatus) { | |
| 1404 case PDF_DATAAVAIL_PAGETREE: | |
| 1405 if (!LoadDocPages(pHints)) | |
| 1406 return FALSE; | |
| 1407 break; | |
| 1408 case PDF_DATAAVAIL_PAGE: | |
| 1409 if (!LoadDocPage(iPage, pHints)) | |
| 1410 return FALSE; | |
| 1411 break; | |
| 1412 case PDF_DATAAVAIL_ERROR: | |
| 1413 return LoadAllFile(pHints); | |
| 1414 default: | |
| 1415 m_bPagesTreeLoad = TRUE; | |
| 1416 m_bPagesLoad = TRUE; | |
| 1417 m_bCurPageDictLoadOK = TRUE; | |
| 1418 m_docStatus = PDF_DATAAVAIL_PAGE; | |
| 1419 return TRUE; | |
| 1420 } | |
| 1421 } | |
| 1422 } | |
| 1423 | |
| 1424 FX_BOOL CPDF_DataAvail::CheckArrayPageNode(FX_DWORD dwPageNo, | |
| 1425 CPDF_PageNode* pPageNode, | |
| 1426 IFX_DownloadHints* pHints) { | |
| 1427 FX_BOOL bExist = FALSE; | |
| 1428 CPDF_Object* pPages = GetObject(dwPageNo, pHints, &bExist); | |
| 1429 if (!bExist) { | |
| 1430 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1431 return FALSE; | |
| 1432 } | |
| 1433 | |
| 1434 if (!pPages) { | |
| 1435 if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
| 1436 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1437 return FALSE; | |
| 1438 } | |
| 1439 return FALSE; | |
| 1440 } | |
| 1441 | |
| 1442 CPDF_Array* pArray = pPages->AsArray(); | |
| 1443 if (!pArray) { | |
| 1444 pPages->Release(); | |
| 1445 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1446 return FALSE; | |
| 1447 } | |
| 1448 | |
| 1449 pPageNode->m_type = PDF_PAGENODE_PAGES; | |
| 1450 for (FX_DWORD i = 0; i < pArray->GetCount(); ++i) { | |
| 1451 CPDF_Reference* pKid = ToReference(pArray->GetElement(i)); | |
| 1452 if (!pKid) | |
| 1453 continue; | |
| 1454 | |
| 1455 CPDF_PageNode* pNode = new CPDF_PageNode(); | |
| 1456 pPageNode->m_childNode.Add(pNode); | |
| 1457 pNode->m_dwPageNo = pKid->GetRefObjNum(); | |
| 1458 } | |
| 1459 pPages->Release(); | |
| 1460 return TRUE; | |
| 1461 } | |
| 1462 | |
| 1463 FX_BOOL CPDF_DataAvail::CheckUnkownPageNode(FX_DWORD dwPageNo, | |
| 1464 CPDF_PageNode* pPageNode, | |
| 1465 IFX_DownloadHints* pHints) { | |
| 1466 FX_BOOL bExist = FALSE; | |
| 1467 CPDF_Object* pPage = GetObject(dwPageNo, pHints, &bExist); | |
| 1468 if (!bExist) { | |
| 1469 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1470 return FALSE; | |
| 1471 } | |
| 1472 | |
| 1473 if (!pPage) { | |
| 1474 if (m_docStatus == PDF_DATAAVAIL_ERROR) | |
| 1475 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1476 return FALSE; | |
| 1477 } | |
| 1478 | |
| 1479 if (pPage->IsArray()) { | |
| 1480 pPageNode->m_dwPageNo = dwPageNo; | |
| 1481 pPageNode->m_type = PDF_PAGENODE_ARRAY; | |
| 1482 pPage->Release(); | |
| 1483 return TRUE; | |
| 1484 } | |
| 1485 | |
| 1486 if (!pPage->IsDictionary()) { | |
| 1487 pPage->Release(); | |
| 1488 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1489 return FALSE; | |
| 1490 } | |
| 1491 | |
| 1492 pPageNode->m_dwPageNo = dwPageNo; | |
| 1493 CPDF_Dictionary* pDict = pPage->GetDict(); | |
| 1494 CFX_ByteString type = pDict->GetStringBy("Type"); | |
| 1495 if (type == "Pages") { | |
| 1496 pPageNode->m_type = PDF_PAGENODE_PAGES; | |
| 1497 CPDF_Object* pKids = pDict->GetElement("Kids"); | |
| 1498 if (!pKids) { | |
| 1499 m_docStatus = PDF_DATAAVAIL_PAGE; | |
| 1500 return TRUE; | |
| 1501 } | |
| 1502 | |
| 1503 switch (pKids->GetType()) { | |
| 1504 case CPDF_Object::REFERENCE: { | |
| 1505 CPDF_Reference* pKid = pKids->AsReference(); | |
| 1506 CPDF_PageNode* pNode = new CPDF_PageNode(); | |
| 1507 pPageNode->m_childNode.Add(pNode); | |
| 1508 pNode->m_dwPageNo = pKid->GetRefObjNum(); | |
| 1509 } break; | |
| 1510 case CPDF_Object::ARRAY: { | |
| 1511 CPDF_Array* pKidsArray = pKids->AsArray(); | |
| 1512 for (FX_DWORD i = 0; i < pKidsArray->GetCount(); ++i) { | |
| 1513 CPDF_Reference* pKid = ToReference(pKidsArray->GetElement(i)); | |
| 1514 if (!pKid) | |
| 1515 continue; | |
| 1516 | |
| 1517 CPDF_PageNode* pNode = new CPDF_PageNode(); | |
| 1518 pPageNode->m_childNode.Add(pNode); | |
| 1519 pNode->m_dwPageNo = pKid->GetRefObjNum(); | |
| 1520 } | |
| 1521 } break; | |
| 1522 default: | |
| 1523 break; | |
| 1524 } | |
| 1525 } else if (type == "Page") { | |
| 1526 pPageNode->m_type = PDF_PAGENODE_PAGE; | |
| 1527 } else { | |
| 1528 pPage->Release(); | |
| 1529 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1530 return FALSE; | |
| 1531 } | |
| 1532 pPage->Release(); | |
| 1533 return TRUE; | |
| 1534 } | |
| 1535 | |
| 1536 FX_BOOL CPDF_DataAvail::CheckPageNode(CPDF_PageNode& pageNodes, | |
| 1537 int32_t iPage, | |
| 1538 int32_t& iCount, | |
| 1539 IFX_DownloadHints* pHints, | |
| 1540 int level) { | |
| 1541 if (level >= kMaxPageRecursionDepth) | |
| 1542 return FALSE; | |
| 1543 | |
| 1544 int32_t iSize = pageNodes.m_childNode.GetSize(); | |
| 1545 if (iSize <= 0 || iPage >= iSize) { | |
| 1546 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1547 return FALSE; | |
| 1548 } | |
| 1549 | |
| 1550 for (int32_t i = 0; i < iSize; ++i) { | |
| 1551 CPDF_PageNode* pNode = pageNodes.m_childNode.GetAt(i); | |
| 1552 if (!pNode) | |
| 1553 continue; | |
| 1554 | |
| 1555 switch (pNode->m_type) { | |
| 1556 case PDF_PAGENODE_UNKNOWN: | |
| 1557 if (!CheckUnkownPageNode(pNode->m_dwPageNo, pNode, pHints)) { | |
| 1558 return FALSE; | |
| 1559 } | |
| 1560 --i; | |
| 1561 break; | |
| 1562 case PDF_PAGENODE_PAGE: | |
| 1563 iCount++; | |
| 1564 if (iPage == iCount && m_pDocument) | |
| 1565 m_pDocument->m_PageList.SetAt(iPage, pNode->m_dwPageNo); | |
| 1566 break; | |
| 1567 case PDF_PAGENODE_PAGES: | |
| 1568 if (!CheckPageNode(*pNode, iPage, iCount, pHints, level + 1)) | |
| 1569 return FALSE; | |
| 1570 break; | |
| 1571 case PDF_PAGENODE_ARRAY: | |
| 1572 if (!CheckArrayPageNode(pNode->m_dwPageNo, pNode, pHints)) | |
| 1573 return FALSE; | |
| 1574 --i; | |
| 1575 break; | |
| 1576 } | |
| 1577 | |
| 1578 if (iPage == iCount) { | |
| 1579 m_docStatus = PDF_DATAAVAIL_DONE; | |
| 1580 return TRUE; | |
| 1581 } | |
| 1582 } | |
| 1583 return TRUE; | |
| 1584 } | |
| 1585 | |
| 1586 FX_BOOL CPDF_DataAvail::LoadDocPage(int32_t iPage, IFX_DownloadHints* pHints) { | |
| 1587 if (m_pDocument->GetPageCount() <= iPage || | |
| 1588 m_pDocument->m_PageList.GetAt(iPage)) { | |
| 1589 m_docStatus = PDF_DATAAVAIL_DONE; | |
| 1590 return TRUE; | |
| 1591 } | |
| 1592 | |
| 1593 if (m_pageNodes.m_type == PDF_PAGENODE_PAGE) { | |
| 1594 if (iPage == 0) { | |
| 1595 m_docStatus = PDF_DATAAVAIL_DONE; | |
| 1596 return TRUE; | |
| 1597 } | |
| 1598 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1599 return TRUE; | |
| 1600 } | |
| 1601 int32_t iCount = -1; | |
| 1602 return CheckPageNode(m_pageNodes, iPage, iCount, pHints, 0); | |
| 1603 } | |
| 1604 | |
| 1605 FX_BOOL CPDF_DataAvail::CheckPageCount(IFX_DownloadHints* pHints) { | |
| 1606 FX_BOOL bExist = FALSE; | |
| 1607 CPDF_Object* pPages = GetObject(m_PagesObjNum, pHints, &bExist); | |
| 1608 if (!bExist) { | |
| 1609 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1610 return FALSE; | |
| 1611 } | |
| 1612 | |
| 1613 if (!pPages) | |
| 1614 return FALSE; | |
| 1615 | |
| 1616 CPDF_Dictionary* pPagesDict = pPages->GetDict(); | |
| 1617 if (!pPagesDict) { | |
| 1618 pPages->Release(); | |
| 1619 m_docStatus = PDF_DATAAVAIL_ERROR; | |
| 1620 return FALSE; | |
| 1621 } | |
| 1622 | |
| 1623 if (!pPagesDict->KeyExist("Kids")) { | |
| 1624 pPages->Release(); | |
| 1625 return TRUE; | |
| 1626 } | |
| 1627 | |
| 1628 int count = pPagesDict->GetIntegerBy("Count"); | |
| 1629 if (count > 0) { | |
| 1630 pPages->Release(); | |
| 1631 return TRUE; | |
| 1632 } | |
| 1633 | |
| 1634 pPages->Release(); | |
| 1635 return FALSE; | |
| 1636 } | |
| 1637 | |
| 1638 FX_BOOL CPDF_DataAvail::LoadDocPages(IFX_DownloadHints* pHints) { | |
| 1639 if (!CheckUnkownPageNode(m_PagesObjNum, &m_pageNodes, pHints)) | |
| 1640 return FALSE; | |
| 1641 | |
| 1642 if (CheckPageCount(pHints)) { | |
| 1643 m_docStatus = PDF_DATAAVAIL_PAGE; | |
| 1644 return TRUE; | |
| 1645 } | |
| 1646 | |
| 1647 m_bTotalLoadPageTree = TRUE; | |
| 1648 return FALSE; | |
| 1649 } | |
| 1650 | |
| 1651 FX_BOOL CPDF_DataAvail::LoadPages(IFX_DownloadHints* pHints) { | |
| 1652 while (!m_bPagesTreeLoad) { | |
| 1653 if (!CheckPageStatus(pHints)) | |
| 1654 return FALSE; | |
| 1655 } | |
| 1656 | |
| 1657 if (m_bPagesLoad) | |
| 1658 return TRUE; | |
| 1659 | |
| 1660 m_pDocument->LoadPages(); | |
| 1661 return FALSE; | |
| 1662 } | |
| 1663 | |
| 1664 IPDF_DataAvail::DocAvailStatus CPDF_DataAvail::CheckLinearizedData( | |
| 1665 IFX_DownloadHints* pHints) { | |
| 1666 if (m_bLinearedDataOK) | |
| 1667 return DataAvailable; | |
| 1668 | |
| 1669 if (!m_bMainXRefLoadTried) { | |
| 1670 FX_SAFE_DWORD data_size = m_dwFileLen; | |
| 1671 data_size -= m_dwLastXRefOffset; | |
| 1672 if (!data_size.IsValid()) | |
| 1673 return DataError; | |
| 1674 | |
| 1675 if (!m_pFileAvail->IsDataAvail(m_dwLastXRefOffset, | |
| 1676 data_size.ValueOrDie())) { | |
| 1677 pHints->AddSegment(m_dwLastXRefOffset, data_size.ValueOrDie()); | |
| 1678 return DataNotAvailable; | |
| 1679 } | |
| 1680 | |
| 1681 CPDF_Parser::Error eRet = | |
| 1682 m_pDocument->GetParser()->LoadLinearizedMainXRefTable(); | |
| 1683 m_bMainXRefLoadTried = TRUE; | |
| 1684 if (eRet != CPDF_Parser::SUCCESS) | |
| 1685 return DataError; | |
| 1686 | |
| 1687 if (!PreparePageItem()) | |
| 1688 return DataNotAvailable; | |
| 1689 | |
| 1690 m_bMainXRefLoadedOK = TRUE; | |
| 1691 m_bLinearedDataOK = TRUE; | |
| 1692 } | |
| 1693 | |
| 1694 return m_bLinearedDataOK ? DataAvailable : DataNotAvailable; | |
| 1695 } | |
| 1696 | |
| 1697 FX_BOOL CPDF_DataAvail::CheckPageAnnots(int32_t iPage, | |
| 1698 IFX_DownloadHints* pHints) { | |
| 1699 if (!m_objs_array.GetSize()) { | |
| 1700 m_objs_array.RemoveAll(); | |
| 1701 m_ObjectSet.clear(); | |
| 1702 | |
| 1703 CPDF_Dictionary* pPageDict = m_pDocument->GetPage(iPage); | |
| 1704 if (!pPageDict) | |
| 1705 return TRUE; | |
| 1706 | |
| 1707 CPDF_Object* pAnnots = pPageDict->GetElement("Annots"); | |
| 1708 if (!pAnnots) | |
| 1709 return TRUE; | |
| 1710 | |
| 1711 CFX_ArrayTemplate<CPDF_Object*> obj_array; | |
| 1712 obj_array.Add(pAnnots); | |
| 1713 | |
| 1714 FX_BOOL bRet = IsObjectsAvail(obj_array, FALSE, pHints, m_objs_array); | |
| 1715 if (bRet) | |
| 1716 m_objs_array.RemoveAll(); | |
| 1717 | |
| 1718 return bRet; | |
| 1719 } | |
| 1720 | |
| 1721 CFX_ArrayTemplate<CPDF_Object*> new_objs_array; | |
| 1722 FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
| 1723 m_objs_array.RemoveAll(); | |
| 1724 if (!bRet) | |
| 1725 m_objs_array.Append(new_objs_array); | |
| 1726 | |
| 1727 return bRet; | |
| 1728 } | |
| 1729 | |
| 1730 IPDF_DataAvail::DocAvailStatus CPDF_DataAvail::CheckLinearizedFirstPage( | |
| 1731 int32_t iPage, | |
| 1732 IFX_DownloadHints* pHints) { | |
| 1733 if (!m_bAnnotsLoad) { | |
| 1734 if (!CheckPageAnnots(iPage, pHints)) | |
| 1735 return DataNotAvailable; | |
| 1736 m_bAnnotsLoad = TRUE; | |
| 1737 } | |
| 1738 | |
| 1739 DocAvailStatus nRet = CheckLinearizedData(pHints); | |
| 1740 if (nRet == DataAvailable) | |
| 1741 m_bPageLoadedOK = FALSE; | |
| 1742 return nRet; | |
| 1743 } | |
| 1744 | |
| 1745 FX_BOOL CPDF_DataAvail::HaveResourceAncestor(CPDF_Dictionary* pDict) { | |
| 1746 CFX_AutoRestorer<int> restorer(&s_CurrentDataAvailRecursionDepth); | |
| 1747 if (++s_CurrentDataAvailRecursionDepth > kMaxDataAvailRecursionDepth) | |
| 1748 return FALSE; | |
| 1749 | |
| 1750 CPDF_Object* pParent = pDict->GetElement("Parent"); | |
| 1751 if (!pParent) | |
| 1752 return FALSE; | |
| 1753 | |
| 1754 CPDF_Dictionary* pParentDict = pParent->GetDict(); | |
| 1755 if (!pParentDict) | |
| 1756 return FALSE; | |
| 1757 | |
| 1758 CPDF_Object* pRet = pParentDict->GetElement("Resources"); | |
| 1759 if (pRet) { | |
| 1760 m_pPageResource = pRet; | |
| 1761 return TRUE; | |
| 1762 } | |
| 1763 | |
| 1764 return HaveResourceAncestor(pParentDict); | |
| 1765 } | |
| 1766 | |
| 1767 IPDF_DataAvail::DocAvailStatus CPDF_DataAvail::IsPageAvail( | |
| 1768 int32_t iPage, | |
| 1769 IFX_DownloadHints* pHints) { | |
| 1770 if (!m_pDocument) | |
| 1771 return DataError; | |
| 1772 | |
| 1773 if (IsFirstCheck(iPage)) { | |
| 1774 m_bCurPageDictLoadOK = FALSE; | |
| 1775 m_bPageLoadedOK = FALSE; | |
| 1776 m_bAnnotsLoad = FALSE; | |
| 1777 m_bNeedDownLoadResource = FALSE; | |
| 1778 m_objs_array.RemoveAll(); | |
| 1779 m_ObjectSet.clear(); | |
| 1780 } | |
| 1781 | |
| 1782 if (pdfium::ContainsKey(m_pagesLoadState, iPage)) | |
| 1783 return DataAvailable; | |
| 1784 | |
| 1785 if (m_bLinearized) { | |
| 1786 if ((FX_DWORD)iPage == m_dwFirstPageNo) { | |
| 1787 DocAvailStatus nRet = CheckLinearizedFirstPage(iPage, pHints); | |
| 1788 if (nRet == DataAvailable) | |
| 1789 m_pagesLoadState.insert(iPage); | |
| 1790 return nRet; | |
| 1791 } | |
| 1792 | |
| 1793 DocAvailStatus nResult = CheckLinearizedData(pHints); | |
| 1794 if (nResult != DataAvailable) | |
| 1795 return nResult; | |
| 1796 | |
| 1797 if (m_pHintTables) { | |
| 1798 nResult = m_pHintTables->CheckPage(iPage, pHints); | |
| 1799 if (nResult != DataAvailable) | |
| 1800 return nResult; | |
| 1801 m_pagesLoadState.insert(iPage); | |
| 1802 return DataAvailable; | |
| 1803 } | |
| 1804 | |
| 1805 if (m_bMainXRefLoadedOK) { | |
| 1806 if (m_bTotalLoadPageTree) { | |
| 1807 if (!LoadPages(pHints)) | |
| 1808 return DataNotAvailable; | |
| 1809 } else { | |
| 1810 if (!m_bCurPageDictLoadOK && !CheckPage(iPage, pHints)) | |
| 1811 return DataNotAvailable; | |
| 1812 } | |
| 1813 } else { | |
| 1814 if (!LoadAllFile(pHints)) | |
| 1815 return DataNotAvailable; | |
| 1816 m_pDocument->GetParser()->RebuildCrossRef(); | |
| 1817 ResetFirstCheck(iPage); | |
| 1818 return DataAvailable; | |
| 1819 } | |
| 1820 } else { | |
| 1821 if (!m_bTotalLoadPageTree && !m_bCurPageDictLoadOK && | |
| 1822 !CheckPage(iPage, pHints)) { | |
| 1823 return DataNotAvailable; | |
| 1824 } | |
| 1825 } | |
| 1826 | |
| 1827 if (m_bHaveAcroForm && !m_bAcroFormLoad) { | |
| 1828 if (!CheckAcroFormSubObject(pHints)) | |
| 1829 return DataNotAvailable; | |
| 1830 m_bAcroFormLoad = TRUE; | |
| 1831 } | |
| 1832 | |
| 1833 if (!m_bPageLoadedOK) { | |
| 1834 if (!m_objs_array.GetSize()) { | |
| 1835 m_objs_array.RemoveAll(); | |
| 1836 m_ObjectSet.clear(); | |
| 1837 | |
| 1838 m_pPageDict = m_pDocument->GetPage(iPage); | |
| 1839 if (!m_pPageDict) { | |
| 1840 ResetFirstCheck(iPage); | |
| 1841 return DataAvailable; | |
| 1842 } | |
| 1843 | |
| 1844 CFX_ArrayTemplate<CPDF_Object*> obj_array; | |
| 1845 obj_array.Add(m_pPageDict); | |
| 1846 FX_BOOL bRet = IsObjectsAvail(obj_array, TRUE, pHints, m_objs_array); | |
| 1847 if (!bRet) | |
| 1848 return DataNotAvailable; | |
| 1849 | |
| 1850 m_objs_array.RemoveAll(); | |
| 1851 } else { | |
| 1852 CFX_ArrayTemplate<CPDF_Object*> new_objs_array; | |
| 1853 FX_BOOL bRet = | |
| 1854 IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
| 1855 | |
| 1856 m_objs_array.RemoveAll(); | |
| 1857 if (!bRet) { | |
| 1858 m_objs_array.Append(new_objs_array); | |
| 1859 return DataNotAvailable; | |
| 1860 } | |
| 1861 } | |
| 1862 m_bPageLoadedOK = TRUE; | |
| 1863 } | |
| 1864 | |
| 1865 if (!m_bAnnotsLoad) { | |
| 1866 if (!CheckPageAnnots(iPage, pHints)) | |
| 1867 return DataNotAvailable; | |
| 1868 m_bAnnotsLoad = TRUE; | |
| 1869 } | |
| 1870 | |
| 1871 if (m_pPageDict && !m_bNeedDownLoadResource) { | |
| 1872 m_pPageResource = m_pPageDict->GetElement("Resources"); | |
| 1873 if (!m_pPageResource) | |
| 1874 m_bNeedDownLoadResource = HaveResourceAncestor(m_pPageDict); | |
| 1875 else | |
| 1876 m_bNeedDownLoadResource = TRUE; | |
| 1877 } | |
| 1878 | |
| 1879 if (m_bNeedDownLoadResource) { | |
| 1880 FX_BOOL bRet = CheckResources(pHints); | |
| 1881 if (!bRet) | |
| 1882 return DataNotAvailable; | |
| 1883 m_bNeedDownLoadResource = FALSE; | |
| 1884 } | |
| 1885 | |
| 1886 m_bPageLoadedOK = FALSE; | |
| 1887 m_bAnnotsLoad = FALSE; | |
| 1888 m_bCurPageDictLoadOK = FALSE; | |
| 1889 | |
| 1890 ResetFirstCheck(iPage); | |
| 1891 m_pagesLoadState.insert(iPage); | |
| 1892 return DataAvailable; | |
| 1893 } | |
| 1894 | |
| 1895 FX_BOOL CPDF_DataAvail::CheckResources(IFX_DownloadHints* pHints) { | |
| 1896 if (!m_objs_array.GetSize()) { | |
| 1897 m_objs_array.RemoveAll(); | |
| 1898 CFX_ArrayTemplate<CPDF_Object*> obj_array; | |
| 1899 obj_array.Add(m_pPageResource); | |
| 1900 | |
| 1901 FX_BOOL bRet = IsObjectsAvail(obj_array, TRUE, pHints, m_objs_array); | |
| 1902 if (bRet) | |
| 1903 m_objs_array.RemoveAll(); | |
| 1904 return bRet; | |
| 1905 } | |
| 1906 | |
| 1907 CFX_ArrayTemplate<CPDF_Object*> new_objs_array; | |
| 1908 FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
| 1909 m_objs_array.RemoveAll(); | |
| 1910 if (!bRet) | |
| 1911 m_objs_array.Append(new_objs_array); | |
| 1912 return bRet; | |
| 1913 } | |
| 1914 | |
| 1915 void CPDF_DataAvail::GetLinearizedMainXRefInfo(FX_FILESIZE* pPos, | |
| 1916 FX_DWORD* pSize) { | |
| 1917 if (pPos) | |
| 1918 *pPos = m_dwLastXRefOffset; | |
| 1919 if (pSize) | |
| 1920 *pSize = (FX_DWORD)(m_dwFileLen - m_dwLastXRefOffset); | |
| 1921 } | |
| 1922 | |
| 1923 int CPDF_DataAvail::GetPageCount() const { | |
| 1924 if (m_pLinearized) { | |
| 1925 CPDF_Dictionary* pDict = m_pLinearized->GetDict(); | |
| 1926 CPDF_Object* pObj = pDict ? pDict->GetElementValue("N") : nullptr; | |
| 1927 return pObj ? pObj->GetInteger() : 0; | |
| 1928 } | |
| 1929 return m_pDocument ? m_pDocument->GetPageCount() : 0; | |
| 1930 } | |
| 1931 | |
| 1932 CPDF_Dictionary* CPDF_DataAvail::GetPage(int index) { | |
| 1933 if (!m_pDocument || index < 0 || index >= GetPageCount()) | |
| 1934 return nullptr; | |
| 1935 | |
| 1936 if (m_pLinearized) { | |
| 1937 CPDF_Dictionary* pDict = m_pLinearized->GetDict(); | |
| 1938 CPDF_Object* pObj = pDict ? pDict->GetElementValue("P") : nullptr; | |
| 1939 | |
| 1940 int pageNum = pObj ? pObj->GetInteger() : 0; | |
| 1941 if (m_pHintTables && index != pageNum) { | |
| 1942 FX_FILESIZE szPageStartPos = 0; | |
| 1943 FX_FILESIZE szPageLength = 0; | |
| 1944 FX_DWORD dwObjNum = 0; | |
| 1945 FX_BOOL bPagePosGot = m_pHintTables->GetPagePos(index, szPageStartPos, | |
| 1946 szPageLength, dwObjNum); | |
| 1947 if (!bPagePosGot) | |
| 1948 return nullptr; | |
| 1949 | |
| 1950 m_syntaxParser.InitParser(m_pFileRead, (FX_DWORD)szPageStartPos); | |
| 1951 CPDF_Object* pPageDict = ParseIndirectObjectAt(0, dwObjNum, m_pDocument); | |
| 1952 if (!pPageDict) | |
| 1953 return nullptr; | |
| 1954 | |
| 1955 if (!m_pDocument->InsertIndirectObject(dwObjNum, pPageDict)) | |
| 1956 return nullptr; | |
| 1957 return pPageDict->GetDict(); | |
| 1958 } | |
| 1959 } | |
| 1960 return m_pDocument->GetPage(index); | |
| 1961 } | |
| 1962 | |
| 1963 IPDF_DataAvail::DocFormStatus CPDF_DataAvail::IsFormAvail( | |
| 1964 IFX_DownloadHints* pHints) { | |
| 1965 if (!m_pDocument) | |
| 1966 return FormAvailable; | |
| 1967 | |
| 1968 if (!m_bLinearizedFormParamLoad) { | |
| 1969 CPDF_Dictionary* pRoot = m_pDocument->GetRoot(); | |
| 1970 if (!pRoot) | |
| 1971 return FormAvailable; | |
| 1972 | |
| 1973 CPDF_Object* pAcroForm = pRoot->GetElement("AcroForm"); | |
| 1974 if (!pAcroForm) | |
| 1975 return FormNotExist; | |
| 1976 | |
| 1977 DocAvailStatus nDocStatus = CheckLinearizedData(pHints); | |
| 1978 if (nDocStatus == DataError) | |
| 1979 return FormError; | |
| 1980 if (nDocStatus == DataNotAvailable) | |
| 1981 return FormNotAvailable; | |
| 1982 | |
| 1983 if (!m_objs_array.GetSize()) | |
| 1984 m_objs_array.Add(pAcroForm->GetDict()); | |
| 1985 m_bLinearizedFormParamLoad = TRUE; | |
| 1986 } | |
| 1987 | |
| 1988 CFX_ArrayTemplate<CPDF_Object*> new_objs_array; | |
| 1989 FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
| 1990 m_objs_array.RemoveAll(); | |
| 1991 if (!bRet) { | |
| 1992 m_objs_array.Append(new_objs_array); | |
| 1993 return FormNotAvailable; | |
| 1994 } | |
| 1995 return FormAvailable; | |
| 1996 } | |
| 1997 | |
| 1998 CPDF_PageNode::CPDF_PageNode() : m_type(PDF_PAGENODE_UNKNOWN) {} | |
| 1999 | |
| 2000 CPDF_PageNode::~CPDF_PageNode() { | |
| 2001 for (int32_t i = 0; i < m_childNode.GetSize(); ++i) | |
| 2002 delete m_childNode[i]; | |
| 2003 m_childNode.RemoveAll(); | |
| 2004 } | |
| 2005 | |
| 2006 CPDF_HintTables::~CPDF_HintTables() { | |
| 2007 m_dwDeltaNObjsArray.RemoveAll(); | |
| 2008 m_dwNSharedObjsArray.RemoveAll(); | |
| 2009 m_dwSharedObjNumArray.RemoveAll(); | |
| 2010 m_dwIdentifierArray.RemoveAll(); | |
| 2011 } | |
| 2012 | |
| 2013 FX_DWORD CPDF_HintTables::GetItemLength( | |
| 2014 int index, | |
| 2015 const std::vector<FX_FILESIZE>& szArray) { | |
| 2016 if (index < 0 || szArray.size() < 2 || | |
| 2017 static_cast<size_t>(index) > szArray.size() - 2 || | |
| 2018 szArray[index] > szArray[index + 1]) { | |
| 2019 return 0; | |
| 2020 } | |
| 2021 return szArray[index + 1] - szArray[index]; | |
| 2022 } | |
| 2023 | |
| 2024 FX_BOOL CPDF_HintTables::ReadPageHintTable(CFX_BitStream* hStream) { | |
| 2025 if (!hStream || hStream->IsEOF()) | |
| 2026 return FALSE; | |
| 2027 | |
| 2028 int nStreamOffset = ReadPrimaryHintStreamOffset(); | |
| 2029 int nStreamLen = ReadPrimaryHintStreamLength(); | |
| 2030 if (nStreamOffset < 0 || nStreamLen < 1) | |
| 2031 return FALSE; | |
| 2032 | |
| 2033 const FX_DWORD kHeaderSize = 288; | |
| 2034 if (hStream->BitsRemaining() < kHeaderSize) | |
| 2035 return FALSE; | |
| 2036 | |
| 2037 // Item 1: The least number of objects in a page. | |
| 2038 FX_DWORD dwObjLeastNum = hStream->GetBits(32); | |
| 2039 | |
| 2040 // Item 2: The location of the first page's page object. | |
| 2041 FX_DWORD dwFirstObjLoc = hStream->GetBits(32); | |
| 2042 if (dwFirstObjLoc > nStreamOffset) { | |
| 2043 FX_SAFE_DWORD safeLoc = pdfium::base::checked_cast<FX_DWORD>(nStreamLen); | |
| 2044 safeLoc += dwFirstObjLoc; | |
| 2045 if (!safeLoc.IsValid()) | |
| 2046 return FALSE; | |
| 2047 m_szFirstPageObjOffset = | |
| 2048 pdfium::base::checked_cast<FX_FILESIZE>(safeLoc.ValueOrDie()); | |
| 2049 } else { | |
| 2050 m_szFirstPageObjOffset = | |
| 2051 pdfium::base::checked_cast<FX_FILESIZE>(dwFirstObjLoc); | |
| 2052 } | |
| 2053 | |
| 2054 // Item 3: The number of bits needed to represent the difference | |
| 2055 // between the greatest and least number of objects in a page. | |
| 2056 FX_DWORD dwDeltaObjectsBits = hStream->GetBits(16); | |
| 2057 | |
| 2058 // Item 4: The least length of a page in bytes. | |
| 2059 FX_DWORD dwPageLeastLen = hStream->GetBits(32); | |
| 2060 | |
| 2061 // Item 5: The number of bits needed to represent the difference | |
| 2062 // between the greatest and least length of a page, in bytes. | |
| 2063 FX_DWORD dwDeltaPageLenBits = hStream->GetBits(16); | |
| 2064 | |
| 2065 // Skip Item 6, 7, 8, 9 total 96 bits. | |
| 2066 hStream->SkipBits(96); | |
| 2067 | |
| 2068 // Item 10: The number of bits needed to represent the greatest | |
| 2069 // number of shared object references. | |
| 2070 FX_DWORD dwSharedObjBits = hStream->GetBits(16); | |
| 2071 | |
| 2072 // Item 11: The number of bits needed to represent the numerically | |
| 2073 // greatest shared object identifier used by the pages. | |
| 2074 FX_DWORD dwSharedIdBits = hStream->GetBits(16); | |
| 2075 | |
| 2076 // Item 12: The number of bits needed to represent the numerator of | |
| 2077 // the fractional position for each shared object reference. For each | |
| 2078 // shared object referenced from a page, there is an indication of | |
| 2079 // where in the page's content stream the object is first referenced. | |
| 2080 FX_DWORD dwSharedNumeratorBits = hStream->GetBits(16); | |
| 2081 | |
| 2082 // Item 13: Skip Item 13 which has 16 bits. | |
| 2083 hStream->SkipBits(16); | |
| 2084 | |
| 2085 CPDF_Object* pPageNum = m_pLinearizedDict->GetElementValue("N"); | |
| 2086 int nPages = pPageNum ? pPageNum->GetInteger() : 0; | |
| 2087 if (nPages < 1) | |
| 2088 return FALSE; | |
| 2089 | |
| 2090 FX_SAFE_DWORD required_bits = dwDeltaObjectsBits; | |
| 2091 required_bits *= pdfium::base::checked_cast<FX_DWORD>(nPages); | |
| 2092 if (!CanReadFromBitStream(hStream, required_bits)) | |
| 2093 return FALSE; | |
| 2094 | |
| 2095 for (int i = 0; i < nPages; ++i) { | |
| 2096 FX_SAFE_DWORD safeDeltaObj = hStream->GetBits(dwDeltaObjectsBits); | |
| 2097 safeDeltaObj += dwObjLeastNum; | |
| 2098 if (!safeDeltaObj.IsValid()) | |
| 2099 return FALSE; | |
| 2100 m_dwDeltaNObjsArray.Add(safeDeltaObj.ValueOrDie()); | |
| 2101 } | |
| 2102 hStream->ByteAlign(); | |
| 2103 | |
| 2104 required_bits = dwDeltaPageLenBits; | |
| 2105 required_bits *= pdfium::base::checked_cast<FX_DWORD>(nPages); | |
| 2106 if (!CanReadFromBitStream(hStream, required_bits)) | |
| 2107 return FALSE; | |
| 2108 | |
| 2109 CFX_DWordArray dwPageLenArray; | |
| 2110 for (int i = 0; i < nPages; ++i) { | |
| 2111 FX_SAFE_DWORD safePageLen = hStream->GetBits(dwDeltaPageLenBits); | |
| 2112 safePageLen += dwPageLeastLen; | |
| 2113 if (!safePageLen.IsValid()) | |
| 2114 return FALSE; | |
| 2115 dwPageLenArray.Add(safePageLen.ValueOrDie()); | |
| 2116 } | |
| 2117 | |
| 2118 CPDF_Object* pOffsetE = m_pLinearizedDict->GetElementValue("E"); | |
| 2119 int nOffsetE = pOffsetE ? pOffsetE->GetInteger() : -1; | |
| 2120 if (nOffsetE < 0) | |
| 2121 return FALSE; | |
| 2122 | |
| 2123 CPDF_Object* pFirstPageNum = m_pLinearizedDict->GetElementValue("P"); | |
| 2124 int nFirstPageNum = pFirstPageNum ? pFirstPageNum->GetInteger() : 0; | |
| 2125 for (int i = 0; i < nPages; ++i) { | |
| 2126 if (i == nFirstPageNum) { | |
| 2127 m_szPageOffsetArray.push_back(m_szFirstPageObjOffset); | |
| 2128 } else if (i == nFirstPageNum + 1) { | |
| 2129 if (i == 1) { | |
| 2130 m_szPageOffsetArray.push_back(nOffsetE); | |
| 2131 } else { | |
| 2132 m_szPageOffsetArray.push_back(m_szPageOffsetArray[i - 2] + | |
| 2133 dwPageLenArray[i - 2]); | |
| 2134 } | |
| 2135 } else { | |
| 2136 if (i == 0) { | |
| 2137 m_szPageOffsetArray.push_back(nOffsetE); | |
| 2138 } else { | |
| 2139 m_szPageOffsetArray.push_back(m_szPageOffsetArray[i - 1] + | |
| 2140 dwPageLenArray[i - 1]); | |
| 2141 } | |
| 2142 } | |
| 2143 } | |
| 2144 | |
| 2145 if (nPages > 0) { | |
| 2146 m_szPageOffsetArray.push_back(m_szPageOffsetArray[nPages - 1] + | |
| 2147 dwPageLenArray[nPages - 1]); | |
| 2148 } | |
| 2149 hStream->ByteAlign(); | |
| 2150 | |
| 2151 // Number of shared objects. | |
| 2152 required_bits = dwSharedObjBits; | |
| 2153 required_bits *= pdfium::base::checked_cast<FX_DWORD>(nPages); | |
| 2154 if (!CanReadFromBitStream(hStream, required_bits)) | |
| 2155 return FALSE; | |
| 2156 | |
| 2157 for (int i = 0; i < nPages; i++) | |
| 2158 m_dwNSharedObjsArray.Add(hStream->GetBits(dwSharedObjBits)); | |
| 2159 hStream->ByteAlign(); | |
| 2160 | |
| 2161 // Array of identifiers, size = nshared_objects. | |
| 2162 for (int i = 0; i < nPages; i++) { | |
| 2163 required_bits = dwSharedIdBits; | |
| 2164 required_bits *= m_dwNSharedObjsArray[i]; | |
| 2165 if (!CanReadFromBitStream(hStream, required_bits)) | |
| 2166 return FALSE; | |
| 2167 | |
| 2168 for (int j = 0; j < m_dwNSharedObjsArray[i]; j++) | |
| 2169 m_dwIdentifierArray.Add(hStream->GetBits(dwSharedIdBits)); | |
| 2170 } | |
| 2171 hStream->ByteAlign(); | |
| 2172 | |
| 2173 for (int i = 0; i < nPages; i++) { | |
| 2174 FX_SAFE_DWORD safeSize = m_dwNSharedObjsArray[i]; | |
| 2175 safeSize *= dwSharedNumeratorBits; | |
| 2176 if (!CanReadFromBitStream(hStream, safeSize)) | |
| 2177 return FALSE; | |
| 2178 | |
| 2179 hStream->SkipBits(safeSize.ValueOrDie()); | |
| 2180 } | |
| 2181 hStream->ByteAlign(); | |
| 2182 | |
| 2183 FX_SAFE_DWORD safeTotalPageLen = pdfium::base::checked_cast<FX_DWORD>(nPages); | |
| 2184 safeTotalPageLen *= dwDeltaPageLenBits; | |
| 2185 if (!CanReadFromBitStream(hStream, safeTotalPageLen)) | |
| 2186 return FALSE; | |
| 2187 | |
| 2188 hStream->SkipBits(safeTotalPageLen.ValueOrDie()); | |
| 2189 hStream->ByteAlign(); | |
| 2190 return TRUE; | |
| 2191 } | |
| 2192 | |
| 2193 FX_BOOL CPDF_HintTables::ReadSharedObjHintTable(CFX_BitStream* hStream, | |
| 2194 FX_DWORD offset) { | |
| 2195 if (!hStream || hStream->IsEOF()) | |
| 2196 return FALSE; | |
| 2197 | |
| 2198 int nStreamOffset = ReadPrimaryHintStreamOffset(); | |
| 2199 int nStreamLen = ReadPrimaryHintStreamLength(); | |
| 2200 if (nStreamOffset < 0 || nStreamLen < 1) | |
| 2201 return FALSE; | |
| 2202 | |
| 2203 FX_SAFE_DWORD bit_offset = offset; | |
| 2204 bit_offset *= 8; | |
| 2205 if (!bit_offset.IsValid() || hStream->GetPos() > bit_offset.ValueOrDie()) | |
| 2206 return FALSE; | |
| 2207 hStream->SkipBits(bit_offset.ValueOrDie() - hStream->GetPos()); | |
| 2208 | |
| 2209 const FX_DWORD kHeaderSize = 192; | |
| 2210 if (hStream->BitsRemaining() < kHeaderSize) | |
| 2211 return FALSE; | |
| 2212 | |
| 2213 // Item 1: The object number of the first object in the shared objects | |
| 2214 // section. | |
| 2215 FX_DWORD dwFirstSharedObjNum = hStream->GetBits(32); | |
| 2216 | |
| 2217 // Item 2: The location of the first object in the shared objects section. | |
| 2218 FX_DWORD dwFirstSharedObjLoc = hStream->GetBits(32); | |
| 2219 if (dwFirstSharedObjLoc > nStreamOffset) | |
| 2220 dwFirstSharedObjLoc += nStreamLen; | |
| 2221 | |
| 2222 // Item 3: The number of shared object entries for the first page. | |
| 2223 m_nFirstPageSharedObjs = hStream->GetBits(32); | |
| 2224 | |
| 2225 // Item 4: The number of shared object entries for the shared objects | |
| 2226 // section, including the number of shared object entries for the first page. | |
| 2227 FX_DWORD dwSharedObjTotal = hStream->GetBits(32); | |
| 2228 | |
| 2229 // Item 5: The number of bits needed to represent the greatest number of | |
| 2230 // objects in a shared object group. Skipped. | |
| 2231 hStream->SkipBits(16); | |
| 2232 | |
| 2233 // Item 6: The least length of a shared object group in bytes. | |
| 2234 FX_DWORD dwGroupLeastLen = hStream->GetBits(32); | |
| 2235 | |
| 2236 // Item 7: The number of bits needed to represent the difference between the | |
| 2237 // greatest and least length of a shared object group, in bytes. | |
| 2238 FX_DWORD dwDeltaGroupLen = hStream->GetBits(16); | |
| 2239 CPDF_Object* pFirstPageObj = m_pLinearizedDict->GetElementValue("O"); | |
| 2240 int nFirstPageObjNum = pFirstPageObj ? pFirstPageObj->GetInteger() : -1; | |
| 2241 if (nFirstPageObjNum < 0) | |
| 2242 return FALSE; | |
| 2243 | |
| 2244 FX_DWORD dwPrevObjLen = 0; | |
| 2245 FX_DWORD dwCurObjLen = 0; | |
| 2246 FX_SAFE_DWORD required_bits = dwSharedObjTotal; | |
| 2247 required_bits *= dwDeltaGroupLen; | |
| 2248 if (!CanReadFromBitStream(hStream, required_bits)) | |
| 2249 return FALSE; | |
| 2250 | |
| 2251 for (int i = 0; i < dwSharedObjTotal; ++i) { | |
| 2252 dwPrevObjLen = dwCurObjLen; | |
| 2253 FX_SAFE_DWORD safeObjLen = hStream->GetBits(dwDeltaGroupLen); | |
| 2254 safeObjLen += dwGroupLeastLen; | |
| 2255 if (!safeObjLen.IsValid()) | |
| 2256 return FALSE; | |
| 2257 | |
| 2258 dwCurObjLen = safeObjLen.ValueOrDie(); | |
| 2259 if (i < m_nFirstPageSharedObjs) { | |
| 2260 m_dwSharedObjNumArray.Add(nFirstPageObjNum + i); | |
| 2261 if (i == 0) | |
| 2262 m_szSharedObjOffsetArray.push_back(m_szFirstPageObjOffset); | |
| 2263 } else { | |
| 2264 FX_SAFE_DWORD safeObjNum = dwFirstSharedObjNum; | |
| 2265 safeObjNum += i - m_nFirstPageSharedObjs; | |
| 2266 if (!safeObjNum.IsValid()) | |
| 2267 return FALSE; | |
| 2268 | |
| 2269 m_dwSharedObjNumArray.Add(safeObjNum.ValueOrDie()); | |
| 2270 if (i == m_nFirstPageSharedObjs) { | |
| 2271 m_szSharedObjOffsetArray.push_back( | |
| 2272 pdfium::base::checked_cast<int32_t>(dwFirstSharedObjLoc)); | |
| 2273 } | |
| 2274 } | |
| 2275 | |
| 2276 if (i != 0 && i != m_nFirstPageSharedObjs) { | |
| 2277 FX_SAFE_INT32 safeLoc = pdfium::base::checked_cast<int32_t>(dwPrevObjLen); | |
| 2278 safeLoc += m_szSharedObjOffsetArray[i - 1]; | |
| 2279 if (!safeLoc.IsValid()) | |
| 2280 return FALSE; | |
| 2281 | |
| 2282 m_szSharedObjOffsetArray.push_back(safeLoc.ValueOrDie()); | |
| 2283 } | |
| 2284 } | |
| 2285 | |
| 2286 if (dwSharedObjTotal > 0) { | |
| 2287 FX_SAFE_INT32 safeLoc = pdfium::base::checked_cast<int32_t>(dwCurObjLen); | |
| 2288 safeLoc += m_szSharedObjOffsetArray[dwSharedObjTotal - 1]; | |
| 2289 if (!safeLoc.IsValid()) | |
| 2290 return FALSE; | |
| 2291 | |
| 2292 m_szSharedObjOffsetArray.push_back(safeLoc.ValueOrDie()); | |
| 2293 } | |
| 2294 | |
| 2295 hStream->ByteAlign(); | |
| 2296 if (hStream->BitsRemaining() < dwSharedObjTotal) | |
| 2297 return FALSE; | |
| 2298 | |
| 2299 hStream->SkipBits(dwSharedObjTotal); | |
| 2300 hStream->ByteAlign(); | |
| 2301 return TRUE; | |
| 2302 } | |
| 2303 | |
| 2304 FX_BOOL CPDF_HintTables::GetPagePos(int index, | |
| 2305 FX_FILESIZE& szPageStartPos, | |
| 2306 FX_FILESIZE& szPageLength, | |
| 2307 FX_DWORD& dwObjNum) { | |
| 2308 if (!m_pLinearizedDict) | |
| 2309 return FALSE; | |
| 2310 | |
| 2311 szPageStartPos = m_szPageOffsetArray[index]; | |
| 2312 szPageLength = GetItemLength(index, m_szPageOffsetArray); | |
| 2313 | |
| 2314 CPDF_Object* pFirstPageNum = m_pLinearizedDict->GetElementValue("P"); | |
| 2315 int nFirstPageNum = pFirstPageNum ? pFirstPageNum->GetInteger() : 0; | |
| 2316 | |
| 2317 CPDF_Object* pFirstPageObjNum = m_pLinearizedDict->GetElementValue("O"); | |
| 2318 if (!pFirstPageObjNum) | |
| 2319 return FALSE; | |
| 2320 | |
| 2321 int nFirstPageObjNum = pFirstPageObjNum->GetInteger(); | |
| 2322 if (index == nFirstPageNum) { | |
| 2323 dwObjNum = nFirstPageObjNum; | |
| 2324 return TRUE; | |
| 2325 } | |
| 2326 | |
| 2327 // The object number of remaining pages starts from 1. | |
| 2328 dwObjNum = 1; | |
| 2329 for (int i = 0; i < index; ++i) { | |
| 2330 if (i == nFirstPageNum) | |
| 2331 continue; | |
| 2332 dwObjNum += m_dwDeltaNObjsArray[i]; | |
| 2333 } | |
| 2334 return TRUE; | |
| 2335 } | |
| 2336 | |
| 2337 IPDF_DataAvail::DocAvailStatus CPDF_HintTables::CheckPage( | |
| 2338 int index, | |
| 2339 IFX_DownloadHints* pHints) { | |
| 2340 if (!m_pLinearizedDict || !pHints) | |
| 2341 return IPDF_DataAvail::DataError; | |
| 2342 | |
| 2343 CPDF_Object* pFirstAvailPage = m_pLinearizedDict->GetElementValue("P"); | |
| 2344 int nFirstAvailPage = pFirstAvailPage ? pFirstAvailPage->GetInteger() : 0; | |
| 2345 if (index == nFirstAvailPage) | |
| 2346 return IPDF_DataAvail::DataAvailable; | |
| 2347 | |
| 2348 FX_DWORD dwLength = GetItemLength(index, m_szPageOffsetArray); | |
| 2349 // If two pages have the same offset, it should be treated as an error. | |
| 2350 if (!dwLength) | |
| 2351 return IPDF_DataAvail::DataError; | |
| 2352 | |
| 2353 if (!m_pDataAvail->IsDataAvail(m_szPageOffsetArray[index], dwLength, pHints)) | |
| 2354 return IPDF_DataAvail::DataNotAvailable; | |
| 2355 | |
| 2356 // Download data of shared objects in the page. | |
| 2357 FX_DWORD offset = 0; | |
| 2358 for (int i = 0; i < index; ++i) | |
| 2359 offset += m_dwNSharedObjsArray[i]; | |
| 2360 | |
| 2361 CPDF_Object* pFirstPageObj = m_pLinearizedDict->GetElementValue("O"); | |
| 2362 int nFirstPageObjNum = pFirstPageObj ? pFirstPageObj->GetInteger() : -1; | |
| 2363 if (nFirstPageObjNum < 0) | |
| 2364 return IPDF_DataAvail::DataError; | |
| 2365 | |
| 2366 FX_DWORD dwIndex = 0; | |
| 2367 FX_DWORD dwObjNum = 0; | |
| 2368 for (int j = 0; j < m_dwNSharedObjsArray[index]; ++j) { | |
| 2369 dwIndex = m_dwIdentifierArray[offset + j]; | |
| 2370 if (dwIndex >= m_dwSharedObjNumArray.GetSize()) | |
| 2371 return IPDF_DataAvail::DataNotAvailable; | |
| 2372 | |
| 2373 dwObjNum = m_dwSharedObjNumArray[dwIndex]; | |
| 2374 if (dwObjNum >= nFirstPageObjNum && | |
| 2375 dwObjNum < nFirstPageObjNum + m_nFirstPageSharedObjs) { | |
| 2376 continue; | |
| 2377 } | |
| 2378 | |
| 2379 dwLength = GetItemLength(dwIndex, m_szSharedObjOffsetArray); | |
| 2380 // If two objects have the same offset, it should be treated as an error. | |
| 2381 if (!dwLength) | |
| 2382 return IPDF_DataAvail::DataError; | |
| 2383 | |
| 2384 if (!m_pDataAvail->IsDataAvail(m_szSharedObjOffsetArray[dwIndex], dwLength, | |
| 2385 pHints)) { | |
| 2386 return IPDF_DataAvail::DataNotAvailable; | |
| 2387 } | |
| 2388 } | |
| 2389 return IPDF_DataAvail::DataAvailable; | |
| 2390 } | |
| 2391 | |
| 2392 FX_BOOL CPDF_HintTables::LoadHintStream(CPDF_Stream* pHintStream) { | |
| 2393 if (!pHintStream || !m_pLinearizedDict) | |
| 2394 return FALSE; | |
| 2395 | |
| 2396 CPDF_Dictionary* pDict = pHintStream->GetDict(); | |
| 2397 CPDF_Object* pOffset = pDict ? pDict->GetElement("S") : nullptr; | |
| 2398 if (!pOffset || !pOffset->IsNumber()) | |
| 2399 return FALSE; | |
| 2400 | |
| 2401 int shared_hint_table_offset = pOffset->GetInteger(); | |
| 2402 CPDF_StreamAcc acc; | |
| 2403 acc.LoadAllData(pHintStream); | |
| 2404 | |
| 2405 FX_DWORD size = acc.GetSize(); | |
| 2406 // The header section of page offset hint table is 36 bytes. | |
| 2407 // The header section of shared object hint table is 24 bytes. | |
| 2408 // Hint table has at least 60 bytes. | |
| 2409 const FX_DWORD MIN_STREAM_LEN = 60; | |
| 2410 if (size < MIN_STREAM_LEN || shared_hint_table_offset <= 0 || | |
| 2411 size < shared_hint_table_offset) { | |
| 2412 return FALSE; | |
| 2413 } | |
| 2414 | |
| 2415 CFX_BitStream bs; | |
| 2416 bs.Init(acc.GetData(), size); | |
| 2417 return ReadPageHintTable(&bs) && | |
| 2418 ReadSharedObjHintTable(&bs, pdfium::base::checked_cast<FX_DWORD>( | |
| 2419 shared_hint_table_offset)); | |
| 2420 } | |
| 2421 | |
| 2422 int CPDF_HintTables::ReadPrimaryHintStreamOffset() const { | |
| 2423 if (!m_pLinearizedDict) | |
| 2424 return -1; | |
| 2425 | |
| 2426 CPDF_Array* pRange = m_pLinearizedDict->GetArrayBy("H"); | |
| 2427 if (!pRange) | |
| 2428 return -1; | |
| 2429 | |
| 2430 CPDF_Object* pStreamOffset = pRange->GetElementValue(0); | |
| 2431 if (!pStreamOffset) | |
| 2432 return -1; | |
| 2433 | |
| 2434 return pStreamOffset->GetInteger(); | |
| 2435 } | |
| 2436 | |
| 2437 int CPDF_HintTables::ReadPrimaryHintStreamLength() const { | |
| 2438 if (!m_pLinearizedDict) | |
| 2439 return -1; | |
| 2440 | |
| 2441 CPDF_Array* pRange = m_pLinearizedDict->GetArrayBy("H"); | |
| 2442 if (!pRange) | |
| 2443 return -1; | |
| 2444 | |
| 2445 CPDF_Object* pStreamLen = pRange->GetElementValue(1); | |
| 2446 if (!pStreamLen) | |
| 2447 return -1; | |
| 2448 | |
| 2449 return pStreamLen->GetInteger(); | |
| 2450 } | |
| OLD | NEW |