| OLD | NEW |
| 1 // Copyright 2015 PDFium Authors. All rights reserved. | 1 // Copyright 2015 PDFium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <algorithm> | 5 #include <algorithm> |
| 6 #include <memory> | 6 #include <memory> |
| 7 #include <string> | 7 #include <string> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "public/fpdfview.h" | 10 #include "public/fpdfview.h" |
| (...skipping 27 matching lines...) Expand all Loading... |
| 38 bool IsOpened() const { return !!file_contents_; } | 38 bool IsOpened() const { return !!file_contents_; } |
| 39 | 39 |
| 40 FPDF_FILEACCESS* file_access() { return &file_access_; } | 40 FPDF_FILEACCESS* file_access() { return &file_access_; } |
| 41 FX_DOWNLOADHINTS* hints() { return this; } | 41 FX_DOWNLOADHINTS* hints() { return this; } |
| 42 FX_FILEAVAIL* file_avail() { return this; } | 42 FX_FILEAVAIL* file_avail() { return this; } |
| 43 | 43 |
| 44 const std::vector<std::pair<size_t, size_t>>& requested_segments() const { | 44 const std::vector<std::pair<size_t, size_t>>& requested_segments() const { |
| 45 return requested_segments_; | 45 return requested_segments_; |
| 46 } | 46 } |
| 47 | 47 |
| 48 void ClearRequestedSegments() { requested_segments_.clear(); } | 48 size_t max_requested_bound() const { return max_requested_bound_; } |
| 49 |
| 50 void ClearRequestedSegments() { |
| 51 requested_segments_.clear(); |
| 52 max_requested_bound_ = 0; |
| 53 } |
| 49 | 54 |
| 50 bool is_new_data_available() const { return is_new_data_available_; } | 55 bool is_new_data_available() const { return is_new_data_available_; } |
| 51 void set_is_new_data_available(bool is_new_data_available) { | 56 void set_is_new_data_available(bool is_new_data_available) { |
| 52 is_new_data_available_ = is_new_data_available; | 57 is_new_data_available_ = is_new_data_available; |
| 53 } | 58 } |
| 54 | 59 |
| 60 size_t max_already_available_bound() const { |
| 61 return available_ranges_.empty() ? 0 : available_ranges_.rbegin()->second; |
| 62 } |
| 63 |
| 55 private: | 64 private: |
| 56 void SetDataAvailable(size_t start, size_t size) { | 65 void SetDataAvailable(size_t start, size_t size) { |
| 57 if (size == 0) | 66 if (size == 0) |
| 58 return; | 67 return; |
| 59 const auto range = std::make_pair(start, start + size); | 68 const auto range = std::make_pair(start, start + size); |
| 60 if (available_ranges_.empty()) { | 69 if (available_ranges_.empty()) { |
| 61 available_ranges_.insert(range); | 70 available_ranges_.insert(range); |
| 62 return; | 71 return; |
| 63 } | 72 } |
| 64 auto start_it = available_ranges_.upper_bound(range); | 73 auto start_it = available_ranges_.upper_bound(range); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 102 std::min(static_cast<unsigned long>(file_length_), pos + size); | 111 std::min(static_cast<unsigned long>(file_length_), pos + size); |
| 103 if (end <= pos) | 112 if (end <= pos) |
| 104 return 0; | 113 return 0; |
| 105 memcpy(pBuf, file_contents_.get() + pos, end - pos); | 114 memcpy(pBuf, file_contents_.get() + pos, end - pos); |
| 106 SetDataAvailable(pos, end - pos); | 115 SetDataAvailable(pos, end - pos); |
| 107 return static_cast<int>(end - pos); | 116 return static_cast<int>(end - pos); |
| 108 } | 117 } |
| 109 | 118 |
| 110 void AddSegmentImpl(size_t offset, size_t size) { | 119 void AddSegmentImpl(size_t offset, size_t size) { |
| 111 requested_segments_.push_back(std::make_pair(offset, size)); | 120 requested_segments_.push_back(std::make_pair(offset, size)); |
| 121 max_requested_bound_ = std::max(max_requested_bound_, offset + size); |
| 112 } | 122 } |
| 113 | 123 |
| 114 bool IsDataAvailImpl(size_t offset, size_t size) { | 124 bool IsDataAvailImpl(size_t offset, size_t size) { |
| 115 if (offset + size > file_length_) | 125 if (offset + size > file_length_) |
| 116 return false; | 126 return false; |
| 117 if (is_new_data_available_) { | 127 if (is_new_data_available_) { |
| 118 SetDataAvailable(offset, size); | 128 SetDataAvailable(offset, size); |
| 119 return true; | 129 return true; |
| 120 } | 130 } |
| 121 return CheckDataAlreadyAvailable(offset, size); | 131 return CheckDataAlreadyAvailable(offset, size); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 136 size_t offset, | 146 size_t offset, |
| 137 size_t size) { | 147 size_t size) { |
| 138 return static_cast<TestAsyncLoader*>(pThis)->IsDataAvailImpl(offset, size); | 148 return static_cast<TestAsyncLoader*>(pThis)->IsDataAvailImpl(offset, size); |
| 139 } | 149 } |
| 140 | 150 |
| 141 FPDF_FILEACCESS file_access_; | 151 FPDF_FILEACCESS file_access_; |
| 142 | 152 |
| 143 std::unique_ptr<char, pdfium::FreeDeleter> file_contents_; | 153 std::unique_ptr<char, pdfium::FreeDeleter> file_contents_; |
| 144 size_t file_length_; | 154 size_t file_length_; |
| 145 std::vector<std::pair<size_t, size_t>> requested_segments_; | 155 std::vector<std::pair<size_t, size_t>> requested_segments_; |
| 156 size_t max_requested_bound_ = 0; |
| 146 bool is_new_data_available_ = true; | 157 bool is_new_data_available_ = true; |
| 147 | 158 |
| 148 using Range = std::pair<size_t, size_t>; | 159 using Range = std::pair<size_t, size_t>; |
| 149 struct range_compare { | 160 struct range_compare { |
| 150 bool operator()(const Range& lval, const Range& rval) const { | 161 bool operator()(const Range& lval, const Range& rval) const { |
| 151 return lval.first < rval.first; | 162 return lval.first < rval.first; |
| 152 } | 163 } |
| 153 }; | 164 }; |
| 154 using RangesContainer = std::set<Range, range_compare>; | 165 using RangesContainer = std::set<Range, range_compare>; |
| 155 RangesContainer available_ranges_; | 166 RangesContainer available_ranges_; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 178 document_ = FPDFAvail_GetDocument(avail_, nullptr); | 189 document_ = FPDFAvail_GetDocument(avail_, nullptr); |
| 179 ASSERT_TRUE(document_); | 190 ASSERT_TRUE(document_); |
| 180 ASSERT_EQ(PDF_DATA_AVAIL, FPDFAvail_IsPageAvail(avail_, 1, loader.hints())); | 191 ASSERT_EQ(PDF_DATA_AVAIL, FPDFAvail_IsPageAvail(avail_, 1, loader.hints())); |
| 181 | 192 |
| 182 // No new data available, to prevent load "Pages" node. | 193 // No new data available, to prevent load "Pages" node. |
| 183 loader.set_is_new_data_available(false); | 194 loader.set_is_new_data_available(false); |
| 184 FPDF_PAGE page = LoadPage(1); | 195 FPDF_PAGE page = LoadPage(1); |
| 185 EXPECT_TRUE(page); | 196 EXPECT_TRUE(page); |
| 186 UnloadPage(page); | 197 UnloadPage(page); |
| 187 } | 198 } |
| 199 |
| 200 TEST_F(FPDFDataAvailEmbeddertest, |
| 201 DoNotLoadMainCrossRefForFirstPageIfLinearized) { |
| 202 TestAsyncLoader loader("feature_linearized_loading.pdf"); |
| 203 avail_ = FPDFAvail_Create(loader.file_avail(), loader.file_access()); |
| 204 ASSERT_EQ(PDF_DATA_AVAIL, FPDFAvail_IsDocAvail(avail_, loader.hints())); |
| 205 document_ = FPDFAvail_GetDocument(avail_, nullptr); |
| 206 ASSERT_TRUE(document_); |
| 207 const int first_page_num = FPDFAvail_GetFirstPageNum(document_); |
| 208 |
| 209 // The main cross ref table should not be processed. |
| 210 // (It is always at file end) |
| 211 EXPECT_GT(loader.file_access()->m_FileLen, |
| 212 loader.max_already_available_bound()); |
| 213 |
| 214 // Prevent access to non requested data to coerce the parser to send new |
| 215 // request for non available (non requested before) data. |
| 216 loader.set_is_new_data_available(false); |
| 217 FPDFAvail_IsPageAvail(avail_, first_page_num, loader.hints()); |
| 218 |
| 219 // The main cross ref table should not be requested. |
| 220 // (It is always at file end) |
| 221 EXPECT_GT(loader.file_access()->m_FileLen, loader.max_requested_bound()); |
| 222 |
| 223 // Allow parse page. |
| 224 loader.set_is_new_data_available(true); |
| 225 ASSERT_EQ(PDF_DATA_AVAIL, |
| 226 FPDFAvail_IsPageAvail(avail_, first_page_num, loader.hints())); |
| 227 |
| 228 // The main cross ref table should not be processed. |
| 229 // (It is always at file end) |
| 230 EXPECT_GT(loader.file_access()->m_FileLen, |
| 231 loader.max_already_available_bound()); |
| 232 |
| 233 // Prevent loading data, while page loading. |
| 234 loader.set_is_new_data_available(false); |
| 235 FPDF_PAGE page = LoadPage(first_page_num); |
| 236 EXPECT_TRUE(page); |
| 237 UnloadPage(page); |
| 238 } |
| OLD | NEW |