summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/fpdfapi/parser/cpdf_data_avail.cpp25
-rw-r--r--core/fpdfapi/parser/cpdf_data_avail.h1
-rw-r--r--core/fpdfapi/parser/cpdf_hint_tables.cpp12
-rw-r--r--core/fpdfapi/parser/cpdf_hint_tables.h7
-rw-r--r--core/fpdfapi/parser/cpdf_read_validator.cpp28
-rw-r--r--core/fpdfapi/parser/cpdf_read_validator_unittest.cpp48
6 files changed, 87 insertions, 34 deletions
diff --git a/core/fpdfapi/parser/cpdf_data_avail.cpp b/core/fpdfapi/parser/cpdf_data_avail.cpp
index b2415915c4..aaec4c7708 100644
--- a/core/fpdfapi/parser/cpdf_data_avail.cpp
+++ b/core/fpdfapi/parser/cpdf_data_avail.cpp
@@ -599,24 +599,6 @@ bool CPDF_DataAvail::CheckFirstPage() {
return true;
}
-bool CPDF_DataAvail::IsDataAvail(FX_FILESIZE offset, size_t size) {
- if (offset < 0 || offset > m_dwFileLen)
- return true;
-
- FX_SAFE_FILESIZE safeSize = offset;
- safeSize += size;
- safeSize += 512;
- if (!safeSize.IsValid() || safeSize.ValueOrDie() > m_dwFileLen)
- size = m_dwFileLen - offset;
- else
- size += 512;
-
- if (!GetValidator()->CheckDataRangeAndRequestIfUnavailable(offset, size))
- return false;
-
- return true;
-}
-
bool CPDF_DataAvail::CheckHintTables() {
if (m_pLinearized->GetPageCount() <= 1) {
m_docStatus = PDF_DATAAVAIL_DONE;
@@ -630,13 +612,14 @@ bool CPDF_DataAvail::CheckHintTables() {
const FX_FILESIZE szHintStart = m_pLinearized->GetHintStart();
const uint32_t szHintLength = m_pLinearized->GetHintLength();
- if (!IsDataAvail(szHintStart, szHintLength))
+ if (!GetValidator()->CheckDataRangeAndRequestIfUnavailable(szHintStart,
+ szHintLength))
return false;
m_syntaxParser.InitParser(m_pFileRead, m_dwHeaderOffset);
- auto pHintTables =
- pdfium::MakeUnique<CPDF_HintTables>(this, m_pLinearized.get());
+ auto pHintTables = pdfium::MakeUnique<CPDF_HintTables>(GetValidator().Get(),
+ m_pLinearized.get());
std::unique_ptr<CPDF_Object> pHintStream =
ParseIndirectObjectAt(szHintStart, 0);
CPDF_Stream* pStream = ToStream(pHintStream.get());
diff --git a/core/fpdfapi/parser/cpdf_data_avail.h b/core/fpdfapi/parser/cpdf_data_avail.h
index 24b5b7f357..1ebee8768a 100644
--- a/core/fpdfapi/parser/cpdf_data_avail.h
+++ b/core/fpdfapi/parser/cpdf_data_avail.h
@@ -98,7 +98,6 @@ class CPDF_DataAvail final {
bool bSupportHintTable);
~CPDF_DataAvail();
- bool IsDataAvail(FX_FILESIZE offset, size_t size);
DocAvailStatus IsDocAvail(DownloadHints* pHints);
void SetDocument(CPDF_Document* pDoc);
DocAvailStatus IsPageAvail(uint32_t dwPage, DownloadHints* pHints);
diff --git a/core/fpdfapi/parser/cpdf_hint_tables.cpp b/core/fpdfapi/parser/cpdf_hint_tables.cpp
index 7a5eb2397b..e88da2eea8 100644
--- a/core/fpdfapi/parser/cpdf_hint_tables.cpp
+++ b/core/fpdfapi/parser/cpdf_hint_tables.cpp
@@ -13,6 +13,7 @@
#include "core/fpdfapi/parser/cpdf_dictionary.h"
#include "core/fpdfapi/parser/cpdf_document.h"
#include "core/fpdfapi/parser/cpdf_linearized_header.h"
+#include "core/fpdfapi/parser/cpdf_read_validator.h"
#include "core/fpdfapi/parser/cpdf_stream.h"
#include "core/fpdfapi/parser/cpdf_stream_acc.h"
#include "core/fxcrt/cfx_bitstream.h"
@@ -35,9 +36,9 @@ bool IsValidPageOffsetHintTableBitCount(uint32_t bits) {
} // namespace
-CPDF_HintTables::CPDF_HintTables(CPDF_DataAvail* pDataAvail,
+CPDF_HintTables::CPDF_HintTables(CPDF_ReadValidator* pValidator,
CPDF_LinearizedHeader* pLinearized)
- : m_pDataAvail(pDataAvail),
+ : m_pValidator(pValidator),
m_pLinearized(pLinearized),
m_nFirstPageSharedObjs(0),
m_szFirstPageObjOffset(0) {
@@ -413,7 +414,8 @@ CPDF_DataAvail::DocAvailStatus CPDF_HintTables::CheckPage(uint32_t index) {
if (!dwLength)
return CPDF_DataAvail::DataError;
- if (!m_pDataAvail->IsDataAvail(m_szPageOffsetArray[index], dwLength))
+ if (!m_pValidator->CheckDataRangeAndRequestIfUnavailable(
+ m_szPageOffsetArray[index], dwLength))
return CPDF_DataAvail::DataNotAvailable;
// Download data of shared objects in the page.
@@ -444,8 +446,8 @@ CPDF_DataAvail::DocAvailStatus CPDF_HintTables::CheckPage(uint32_t index) {
if (!dwLength)
return CPDF_DataAvail::DataError;
- if (!m_pDataAvail->IsDataAvail(m_szSharedObjOffsetArray[dwIndex],
- dwLength)) {
+ if (!m_pValidator->CheckDataRangeAndRequestIfUnavailable(
+ m_szSharedObjOffsetArray[dwIndex], dwLength)) {
return CPDF_DataAvail::DataNotAvailable;
}
}
diff --git a/core/fpdfapi/parser/cpdf_hint_tables.h b/core/fpdfapi/parser/cpdf_hint_tables.h
index 9658be5462..a9aa5d42d9 100644
--- a/core/fpdfapi/parser/cpdf_hint_tables.h
+++ b/core/fpdfapi/parser/cpdf_hint_tables.h
@@ -16,10 +16,11 @@
class CFX_BitStream;
class CPDF_LinearizedHeader;
class CPDF_Stream;
+class CPDF_ReadValidator;
class CPDF_HintTables {
public:
- CPDF_HintTables(CPDF_DataAvail* pDataAvail,
+ CPDF_HintTables(CPDF_ReadValidator* pValidator,
CPDF_LinearizedHeader* pLinearized);
virtual ~CPDF_HintTables();
@@ -48,8 +49,8 @@ class CPDF_HintTables {
uint32_t GetItemLength(uint32_t index,
const std::vector<FX_FILESIZE>& szArray);
- // Owner, outlives this object.
- UnownedPtr<CPDF_DataAvail> const m_pDataAvail;
+ // Owned by |m_pDataAvail|.
+ UnownedPtr<CPDF_ReadValidator> m_pValidator;
// Owned by |m_pDataAvail|.
UnownedPtr<CPDF_LinearizedHeader> const m_pLinearized;
diff --git a/core/fpdfapi/parser/cpdf_read_validator.cpp b/core/fpdfapi/parser/cpdf_read_validator.cpp
index 6c311f7571..2363f851ec 100644
--- a/core/fpdfapi/parser/cpdf_read_validator.cpp
+++ b/core/fpdfapi/parser/cpdf_read_validator.cpp
@@ -6,11 +6,12 @@
#include <algorithm>
+#include "core/fpdfapi/cpdf_modulemgr.h"
#include "third_party/base/logging.h"
namespace {
-constexpr FX_FILESIZE kAlignBlockValue = 512;
+constexpr FX_FILESIZE kAlignBlockValue = CPDF_ModuleMgr::kFileBufSize;
FX_FILESIZE AlignDown(FX_FILESIZE offset) {
return offset > 0 ? (offset - offset % kAlignBlockValue) : 0;
@@ -64,8 +65,10 @@ bool CPDF_ReadValidator::ReadBlock(void* buffer,
if (!end_offset.IsValid() || end_offset.ValueOrDie() > file_size_)
return false;
- if (!CheckDataRangeAndRequestIfUnavailable(offset, size))
+ if (!IsDataRangeAvailable(offset, size)) {
+ ScheduleDownload(offset, size);
return false;
+ }
if (file_read_->ReadBlock(buffer, offset, size))
return true;
@@ -122,10 +125,27 @@ bool CPDF_ReadValidator::IsWholeFileAvailable() {
bool CPDF_ReadValidator::CheckDataRangeAndRequestIfUnavailable(
FX_FILESIZE offset,
size_t size) {
- if (IsDataRangeAvailable(offset, size))
+ FX_SAFE_FILESIZE end_segment_offset = offset;
+ end_segment_offset += size;
+ // Increase checked range to allow CPDF_SyntaxParser read whole buffer.
+ end_segment_offset += CPDF_ModuleMgr::kFileBufSize;
+ if (!end_segment_offset.IsValid()) {
+ NOTREACHED();
+ return false;
+ }
+ end_segment_offset = std::min(
+ file_size_, static_cast<FX_FILESIZE>(end_segment_offset.ValueOrDie()));
+ FX_SAFE_SIZE_T segment_size = end_segment_offset;
+ segment_size -= offset;
+ if (!segment_size.IsValid()) {
+ NOTREACHED();
+ return false;
+ }
+
+ if (IsDataRangeAvailable(offset, segment_size.ValueOrDie()))
return true;
- ScheduleDownload(offset, size);
+ ScheduleDownload(offset, segment_size.ValueOrDie());
return false;
}
diff --git a/core/fpdfapi/parser/cpdf_read_validator_unittest.cpp b/core/fpdfapi/parser/cpdf_read_validator_unittest.cpp
index 13ace078d3..89b7e6b4de 100644
--- a/core/fpdfapi/parser/cpdf_read_validator_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_read_validator_unittest.cpp
@@ -243,3 +243,51 @@ TEST(CPDF_ReadValidatorTest, SessionReset) {
EXPECT_TRUE(validator->has_unavailable_data());
EXPECT_FALSE(validator->read_error());
}
+
+TEST(CPDF_ReadValidatorTest, CheckDataRangeAndRequestIfUnavailable) {
+ std::vector<uint8_t> test_data(kTestDataSize);
+ auto file = pdfium::MakeRetain<CFX_MemoryStream>(test_data.data(),
+ test_data.size(), false);
+ MockFileAvail file_avail;
+ auto validator = pdfium::MakeRetain<CPDF_ReadValidator>(file, &file_avail);
+
+ MockDownloadHints hints;
+ validator->SetDownloadHints(&hints);
+
+ EXPECT_FALSE(validator->CheckDataRangeAndRequestIfUnavailable(5000, 100));
+ EXPECT_FALSE(validator->read_error());
+ EXPECT_TRUE(validator->has_unavailable_data());
+
+ // Requested range should be enlarged and aligned.
+ EXPECT_EQ(MakeRange(4608, 5632), hints.GetLastRequstedRange());
+
+ file_avail.SetAvailableRange(hints.GetLastRequstedRange());
+ hints.Reset();
+
+ validator->ResetErrors();
+ EXPECT_TRUE(validator->CheckDataRangeAndRequestIfUnavailable(5000, 100));
+ // No new request on already available data.
+ EXPECT_EQ(MakeRange(0, 0), hints.GetLastRequstedRange());
+ EXPECT_FALSE(validator->read_error());
+ EXPECT_FALSE(validator->has_unavailable_data());
+
+ std::vector<uint8_t> read_buffer(100);
+ EXPECT_TRUE(
+ validator->ReadBlock(read_buffer.data(), 5000, read_buffer.size()));
+ // No new request on already available data.
+ EXPECT_EQ(MakeRange(0, 0), hints.GetLastRequstedRange());
+ EXPECT_FALSE(validator->read_error());
+ EXPECT_FALSE(validator->has_unavailable_data());
+
+ validator->ResetErrors();
+ // Try request unavailable data at file end.
+ EXPECT_FALSE(validator->CheckDataRangeAndRequestIfUnavailable(
+ validator->GetSize() - 100, 100));
+
+ // Should not enlarge request at file end.
+ EXPECT_EQ(validator->GetSize(), hints.GetLastRequstedRange().second);
+ EXPECT_FALSE(validator->read_error());
+ EXPECT_TRUE(validator->has_unavailable_data());
+
+ validator->SetDownloadHints(nullptr);
+}