diff options
-rw-r--r-- | core/fpdfapi/parser/cpdf_hint_tables.cpp | 103 | ||||
-rw-r--r-- | core/fpdfapi/parser/cpdf_hint_tables.h | 48 | ||||
-rw-r--r-- | core/fpdfapi/parser/cpdf_hint_tables_unittest.cpp | 29 |
3 files changed, 118 insertions, 62 deletions
diff --git a/core/fpdfapi/parser/cpdf_hint_tables.cpp b/core/fpdfapi/parser/cpdf_hint_tables.cpp index 7d371909e9..fc9a46d68a 100644 --- a/core/fpdfapi/parser/cpdf_hint_tables.cpp +++ b/core/fpdfapi/parser/cpdf_hint_tables.cpp @@ -37,6 +37,9 @@ bool IsValidPageOffsetHintTableBitCount(uint32_t bits) { } // namespace +CPDF_HintTables::PageInfo::PageInfo() = default; +CPDF_HintTables::PageInfo::~PageInfo() = default; + CPDF_HintTables::CPDF_HintTables(CPDF_ReadValidator* pValidator, CPDF_LinearizedHeader* pLinearized) : m_pValidator(pValidator), @@ -59,6 +62,14 @@ uint32_t CPDF_HintTables::GetItemLength( } bool CPDF_HintTables::ReadPageHintTable(CFX_BitStream* hStream) { + const uint32_t nPages = m_pLinearized->GetPageCount(); + if (nPages < 1 || nPages >= CPDF_Document::kPageMaxNum) + return false; + + const uint32_t nFirstPageNum = m_pLinearized->GetFirstPageNo(); + if (nFirstPageNum >= nPages) + return false; + if (!hStream || hStream->IsEOF()) return false; @@ -122,83 +133,78 @@ bool CPDF_HintTables::ReadPageHintTable(CFX_BitStream* hStream) { // Item 13: Skip Item 13 which has 16 bits. hStream->SkipBits(16); - const uint32_t nPages = m_pLinearized->GetPageCount(); - if (nPages < 1 || nPages >= CPDF_Document::kPageMaxNum) - return false; - - const uint32_t dwPages = pdfium::base::checked_cast<uint32_t>(nPages); FX_SAFE_UINT32 required_bits = dwDeltaObjectsBits; - required_bits *= dwPages; + required_bits *= nPages; if (!CanReadFromBitStream(hStream, required_bits)) return false; + m_PageInfos = std::vector<PageInfo>(nPages); + m_PageInfos[nFirstPageNum].set_start_obj_num( + m_pLinearized->GetFirstPageObjNum()); + // The object number of remaining pages starts from 1. + uint32_t dwStartObjNum = 1; for (uint32_t i = 0; i < nPages; ++i) { FX_SAFE_UINT32 safeDeltaObj = hStream->GetBits(dwDeltaObjectsBits); safeDeltaObj += dwObjLeastNum; if (!safeDeltaObj.IsValid()) return false; - m_dwDeltaNObjsArray.push_back(safeDeltaObj.ValueOrDie()); + m_PageInfos[i].set_objects_count(safeDeltaObj.ValueOrDie()); + if (i == nFirstPageNum) + continue; + m_PageInfos[i].set_start_obj_num(dwStartObjNum); + dwStartObjNum += m_PageInfos[i].objects_count(); } hStream->ByteAlign(); required_bits = dwDeltaPageLenBits; - required_bits *= dwPages; + required_bits *= nPages; if (!CanReadFromBitStream(hStream, required_bits)) return false; - std::vector<uint32_t> dwPageLenArray; for (uint32_t i = 0; i < nPages; ++i) { FX_SAFE_UINT32 safePageLen = hStream->GetBits(dwDeltaPageLenBits); safePageLen += dwPageLeastLen; if (!safePageLen.IsValid()) return false; - - dwPageLenArray.push_back(safePageLen.ValueOrDie()); + m_PageInfos[i].set_page_length(safePageLen.ValueOrDie()); } - const uint32_t nFirstPageNum = m_pLinearized->GetFirstPageNo(); - if (nFirstPageNum >= nPages) - return false; - - m_szPageOffsetArray.resize(nPages, 0); ASSERT(m_szFirstPageObjOffset); - m_szPageOffsetArray[nFirstPageNum] = m_szFirstPageObjOffset; - FX_FILESIZE prev_page_offset = m_pLinearized->GetFirstPageEndOffset(); + m_PageInfos[nFirstPageNum].set_page_offset(m_szFirstPageObjOffset); + FX_FILESIZE prev_page_end = m_pLinearized->GetFirstPageEndOffset(); for (uint32_t i = 0; i < nPages; ++i) { if (i == nFirstPageNum) continue; - - m_szPageOffsetArray[i] = prev_page_offset; - prev_page_offset += dwPageLenArray[i]; + m_PageInfos[i].set_page_offset(prev_page_end); + prev_page_end += m_PageInfos[i].page_length(); } - m_szPageOffsetArray.push_back(m_szPageOffsetArray[nPages - 1] + - dwPageLenArray[nPages - 1]); hStream->ByteAlign(); // Number of shared objects. required_bits = dwSharedObjBits; - required_bits *= dwPages; + required_bits *= nPages; if (!CanReadFromBitStream(hStream, required_bits)) return false; + std::vector<uint32_t> dwNSharedObjsArray(nPages); for (uint32_t i = 0; i < nPages; i++) - m_dwNSharedObjsArray.push_back(hStream->GetBits(dwSharedObjBits)); + dwNSharedObjsArray[i] = hStream->GetBits(dwSharedObjBits); hStream->ByteAlign(); // Array of identifiers, size = nshared_objects. for (uint32_t i = 0; i < nPages; i++) { required_bits = dwSharedIdBits; - required_bits *= m_dwNSharedObjsArray[i]; + required_bits *= dwNSharedObjsArray[i]; if (!CanReadFromBitStream(hStream, required_bits)) return false; - for (uint32_t j = 0; j < m_dwNSharedObjsArray[i]; j++) - m_dwIdentifierArray.push_back(hStream->GetBits(dwSharedIdBits)); + for (uint32_t j = 0; j < dwNSharedObjsArray[i]; j++) + m_PageInfos[i].AddIdentifier(hStream->GetBits(dwSharedIdBits)); } hStream->ByteAlign(); for (uint32_t i = 0; i < nPages; i++) { - FX_SAFE_UINT32 safeSize = m_dwNSharedObjsArray[i]; + FX_SAFE_UINT32 safeSize = dwNSharedObjsArray[i]; safeSize *= dwSharedNumeratorBits; if (!CanReadFromBitStream(hStream, safeSize)) return false; @@ -207,7 +213,7 @@ bool CPDF_HintTables::ReadPageHintTable(CFX_BitStream* hStream) { } hStream->ByteAlign(); - FX_SAFE_UINT32 safeTotalPageLen = dwPages; + FX_SAFE_UINT32 safeTotalPageLen = nPages; safeTotalPageLen *= dwDeltaPageLenBits; if (!CanReadFromBitStream(hStream, safeTotalPageLen)) return false; @@ -343,24 +349,9 @@ bool CPDF_HintTables::GetPagePos(uint32_t index, if (index >= m_pLinearized->GetPageCount()) return false; - *szPageStartPos = m_szPageOffsetArray[index]; - *szPageLength = GetItemLength(index, m_szPageOffsetArray); - - const uint32_t nFirstPageObjNum = m_pLinearized->GetFirstPageObjNum(); - - const uint32_t dwFirstPageNum = m_pLinearized->GetFirstPageNo(); - if (index == dwFirstPageNum) { - *dwObjNum = nFirstPageObjNum; - return true; - } - - // The object number of remaining pages starts from 1. - *dwObjNum = 1; - for (uint32_t i = 0; i < index; ++i) { - if (i == dwFirstPageNum) - continue; - *dwObjNum += m_dwDeltaNObjsArray[i]; - } + *szPageStartPos = m_PageInfos[index].page_offset(); + *szPageLength = m_PageInfos[index].page_length(); + *dwObjNum = m_PageInfos[index].start_obj_num(); return true; } @@ -368,27 +359,23 @@ CPDF_DataAvail::DocAvailStatus CPDF_HintTables::CheckPage(uint32_t index) { if (index == m_pLinearized->GetFirstPageNo()) return CPDF_DataAvail::DataAvailable; - uint32_t dwLength = GetItemLength(index, m_szPageOffsetArray); - // If two pages have the same offset, it should be treated as an error. + if (index >= m_pLinearized->GetPageCount()) + return CPDF_DataAvail::DataError; + + uint32_t dwLength = m_PageInfos[index].page_length(); if (!dwLength) return CPDF_DataAvail::DataError; if (!m_pValidator->CheckDataRangeAndRequestIfUnavailable( - m_szPageOffsetArray[index], dwLength)) { + m_PageInfos[index].page_offset(), dwLength)) { return CPDF_DataAvail::DataNotAvailable; } // Download data of shared objects in the page. - uint32_t offset = 0; - for (uint32_t i = 0; i < index; ++i) - offset += m_dwNSharedObjsArray[i]; - const uint32_t nFirstPageObjNum = m_pLinearized->GetFirstPageObjNum(); - uint32_t dwIndex = 0; uint32_t dwObjNum = 0; - for (uint32_t j = 0; j < m_dwNSharedObjsArray[index]; ++j) { - dwIndex = m_dwIdentifierArray[offset + j]; + for (const uint32_t dwIndex : m_PageInfos[index].Identifiers()) { if (dwIndex >= m_dwSharedObjNumArray.size()) continue; diff --git a/core/fpdfapi/parser/cpdf_hint_tables.h b/core/fpdfapi/parser/cpdf_hint_tables.h index c51d95a255..0db190b189 100644 --- a/core/fpdfapi/parser/cpdf_hint_tables.h +++ b/core/fpdfapi/parser/cpdf_hint_tables.h @@ -20,6 +20,46 @@ class CPDF_ReadValidator; class CPDF_HintTables { public: + class PageInfo { + public: + PageInfo(); + ~PageInfo(); + + void set_objects_count(uint32_t objects_count) { + m_nObjectsCount = objects_count; + } + uint32_t objects_count() const { return m_nObjectsCount; } + + void set_page_offset(FX_FILESIZE offset) { m_szOffset = offset; } + FX_FILESIZE page_offset() const { return m_szOffset; } + + void set_page_length(uint32_t length) { m_dwLength = length; } + uint32_t page_length() const { return m_dwLength; } + + void set_start_obj_num(uint32_t start_obj_num) { + m_dwStartObjNum = start_obj_num; + } + uint32_t start_obj_num() const { return m_dwStartObjNum; } + + void AddIdentifier(uint32_t Identifier) { + m_dwIdentifierArray.push_back(Identifier); + } + + const std::vector<uint32_t>& Identifiers() const { + return m_dwIdentifierArray; + } + + private: + uint32_t m_nObjectsCount = 0; + FX_FILESIZE m_szOffset = 0; + uint32_t m_dwLength = 0; + uint32_t m_dwStartObjNum = 0; + std::vector<uint32_t> m_dwIdentifierArray; + + PageInfo(const PageInfo& other) = delete; + PageInfo& operator=(const PageInfo&) = delete; + }; + CPDF_HintTables(CPDF_ReadValidator* pValidator, CPDF_LinearizedHeader* pLinearized); virtual ~CPDF_HintTables(); @@ -33,6 +73,8 @@ class CPDF_HintTables { bool LoadHintStream(CPDF_Stream* pHintStream); + const std::vector<PageInfo>& PageInfos() const { return m_PageInfos; } + protected: bool ReadPageHintTable(CFX_BitStream* hStream); bool ReadSharedObjHintTable(CFX_BitStream* hStream, uint32_t offset); @@ -51,11 +93,9 @@ class CPDF_HintTables { uint32_t m_nFirstPageSharedObjs; FX_FILESIZE m_szFirstPageObjOffset; - std::vector<uint32_t> m_dwDeltaNObjsArray; - std::vector<uint32_t> m_dwNSharedObjsArray; + + std::vector<PageInfo> m_PageInfos; std::vector<uint32_t> m_dwSharedObjNumArray; - std::vector<uint32_t> m_dwIdentifierArray; - std::vector<FX_FILESIZE> m_szPageOffsetArray; std::vector<FX_FILESIZE> m_szSharedObjOffsetArray; }; diff --git a/core/fpdfapi/parser/cpdf_hint_tables_unittest.cpp b/core/fpdfapi/parser/cpdf_hint_tables_unittest.cpp index e45722950e..3d98196093 100644 --- a/core/fpdfapi/parser/cpdf_hint_tables_unittest.cpp +++ b/core/fpdfapi/parser/cpdf_hint_tables_unittest.cpp @@ -67,3 +67,32 @@ TEST_F(CPDF_HintTablesTest, Load) { ASSERT_FALSE( hint_tables->GetPagePos(2, &page_start, &page_length, &page_obj_num)); } + +TEST_F(CPDF_HintTablesTest, PageInfos) { + auto data_avail = MakeDataAvailFromFile("feature_linearized_loading.pdf"); + ASSERT_EQ(CPDF_DataAvail::DocAvailStatus::DataAvailable, + data_avail->IsDocAvail(nullptr)); + + const CPDF_HintTables* hint_tables = data_avail->GetHintTables(); + ASSERT_TRUE(hint_tables); + ASSERT_EQ(2u, hint_tables->PageInfos().size()); + + EXPECT_EQ(5u, hint_tables->PageInfos()[0].objects_count()); + EXPECT_EQ(777, hint_tables->PageInfos()[0].page_offset()); + EXPECT_EQ(4328u, hint_tables->PageInfos()[0].page_length()); + EXPECT_EQ(39u, hint_tables->PageInfos()[0].start_obj_num()); + ASSERT_EQ(2u, hint_tables->PageInfos()[0].Identifiers().size()); + + EXPECT_EQ(0u, hint_tables->PageInfos()[0].Identifiers()[0]); + EXPECT_EQ(0u, hint_tables->PageInfos()[0].Identifiers()[1]); + + EXPECT_EQ(3u, hint_tables->PageInfos()[1].objects_count()); + EXPECT_EQ(5105, hint_tables->PageInfos()[1].page_offset()); + EXPECT_EQ(767u, hint_tables->PageInfos()[1].page_length()); + EXPECT_EQ(1u, hint_tables->PageInfos()[1].start_obj_num()); + ASSERT_EQ(3u, hint_tables->PageInfos()[1].Identifiers().size()); + + EXPECT_EQ(2u, hint_tables->PageInfos()[1].Identifiers()[0]); + EXPECT_EQ(5u, hint_tables->PageInfos()[1].Identifiers()[1]); + EXPECT_EQ(3u, hint_tables->PageInfos()[1].Identifiers()[2]); +} |