OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium 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 "ui/base/resource/data_pack.h" | 5 #include "ui/base/resource/data_pack.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
53 BAD_VERSION, | 53 BAD_VERSION, |
54 INDEX_TRUNCATED, | 54 INDEX_TRUNCATED, |
55 ENTRY_NOT_FOUND, | 55 ENTRY_NOT_FOUND, |
56 HEADER_TRUNCATED, | 56 HEADER_TRUNCATED, |
57 WRONG_ENCODING, | 57 WRONG_ENCODING, |
58 INIT_FAILED_FROM_FILE, | 58 INIT_FAILED_FROM_FILE, |
59 | 59 |
60 LOAD_ERRORS_COUNT, | 60 LOAD_ERRORS_COUNT, |
61 }; | 61 }; |
62 | 62 |
| 63 class MemoryMappedDataSource : public ui::DataSource { |
| 64 public: |
| 65 MemoryMappedDataSource(std::unique_ptr<base::MemoryMappedFile> mmap) |
| 66 : mmap_(std::move(mmap)) {} |
| 67 |
| 68 ~MemoryMappedDataSource() override {}; |
| 69 |
| 70 size_t Length() const override { return mmap_->length(); } |
| 71 |
| 72 const uint8_t* Data() const override { return mmap_->data(); } |
| 73 |
| 74 private: |
| 75 std::unique_ptr<base::MemoryMappedFile> mmap_; |
| 76 |
| 77 DISALLOW_COPY_AND_ASSIGN(MemoryMappedDataSource); |
| 78 }; |
| 79 |
| 80 class BufferDataSource : public ui::DataSource { |
| 81 public: |
| 82 BufferDataSource(base::StringPiece buffer) : buffer_(buffer) {} |
| 83 |
| 84 ~BufferDataSource() override {}; |
| 85 |
| 86 size_t Length() const override { return buffer_.length(); } |
| 87 |
| 88 const uint8_t* Data() const override { |
| 89 return reinterpret_cast<const uint8_t*>(buffer_.data()); |
| 90 } |
| 91 |
| 92 private: |
| 93 base::StringPiece buffer_; |
| 94 |
| 95 DISALLOW_COPY_AND_ASSIGN(BufferDataSource); |
| 96 }; |
| 97 |
63 } // namespace | 98 } // namespace |
64 | 99 |
65 namespace ui { | 100 namespace ui { |
66 | 101 |
67 DataPack::DataPack(ui::ScaleFactor scale_factor) | 102 DataPack::DataPack(ui::ScaleFactor scale_factor) |
68 : resource_count_(0), | 103 : resource_count_(0), |
69 text_encoding_type_(BINARY), | 104 text_encoding_type_(BINARY), |
70 scale_factor_(scale_factor), | 105 scale_factor_(scale_factor), |
71 has_only_material_design_assets_(false) { | 106 has_only_material_design_assets_(false) { |
72 } | 107 } |
73 | 108 |
74 DataPack::~DataPack() { | 109 DataPack::~DataPack() { |
75 } | 110 } |
76 | 111 |
77 bool DataPack::LoadFromPath(const base::FilePath& path) { | 112 bool DataPack::LoadFromPath(const base::FilePath& path) { |
78 mmap_.reset(new base::MemoryMappedFile); | 113 std::unique_ptr<base::MemoryMappedFile> mmap(new base::MemoryMappedFile); |
79 if (!mmap_->Initialize(path)) { | 114 if (!mmap->Initialize(path)) { |
80 DLOG(ERROR) << "Failed to mmap datapack"; | 115 DLOG(ERROR) << "Failed to mmap datapack"; |
81 UMA_HISTOGRAM_ENUMERATION("DataPack.Load", INIT_FAILED, | 116 UMA_HISTOGRAM_ENUMERATION("DataPack.Load", INIT_FAILED, |
82 LOAD_ERRORS_COUNT); | 117 LOAD_ERRORS_COUNT); |
83 mmap_.reset(); | |
84 return false; | 118 return false; |
85 } | 119 } |
| 120 data_source_.reset(new MemoryMappedDataSource(std::move(mmap))); |
86 return LoadImpl(); | 121 return LoadImpl(); |
87 } | 122 } |
88 | 123 |
89 bool DataPack::LoadFromFile(base::File file) { | 124 bool DataPack::LoadFromFile(base::File file) { |
90 return LoadFromFileRegion(std::move(file), | 125 return LoadFromFileRegion(std::move(file), |
91 base::MemoryMappedFile::Region::kWholeFile); | 126 base::MemoryMappedFile::Region::kWholeFile); |
92 } | 127 } |
93 | 128 |
94 bool DataPack::LoadFromFileRegion( | 129 bool DataPack::LoadFromFileRegion( |
95 base::File file, | 130 base::File file, |
96 const base::MemoryMappedFile::Region& region) { | 131 const base::MemoryMappedFile::Region& region) { |
97 mmap_.reset(new base::MemoryMappedFile); | 132 std::unique_ptr<base::MemoryMappedFile> mmap(new base::MemoryMappedFile); |
98 if (!mmap_->Initialize(std::move(file), region)) { | 133 if (!mmap->Initialize(std::move(file), region)) { |
99 DLOG(ERROR) << "Failed to mmap datapack"; | 134 DLOG(ERROR) << "Failed to mmap datapack"; |
100 UMA_HISTOGRAM_ENUMERATION("DataPack.Load", INIT_FAILED_FROM_FILE, | 135 UMA_HISTOGRAM_ENUMERATION("DataPack.Load", INIT_FAILED_FROM_FILE, |
101 LOAD_ERRORS_COUNT); | 136 LOAD_ERRORS_COUNT); |
102 mmap_.reset(); | |
103 return false; | 137 return false; |
104 } | 138 } |
| 139 data_source_.reset(new MemoryMappedDataSource(std::move(mmap))); |
| 140 return LoadImpl(); |
| 141 } |
| 142 |
| 143 bool DataPack::LoadFromBuffer(base::StringPiece buffer) { |
| 144 data_source_.reset(new BufferDataSource(buffer)); |
105 return LoadImpl(); | 145 return LoadImpl(); |
106 } | 146 } |
107 | 147 |
108 bool DataPack::LoadImpl() { | 148 bool DataPack::LoadImpl() { |
109 // Sanity check the header of the file. | 149 // Sanity check the header of the file. |
110 if (kHeaderLength > mmap_->length()) { | 150 if (kHeaderLength > data_source_->Length()) { |
111 DLOG(ERROR) << "Data pack file corruption: incomplete file header."; | 151 DLOG(ERROR) << "Data pack file corruption: incomplete file header."; |
112 UMA_HISTOGRAM_ENUMERATION("DataPack.Load", HEADER_TRUNCATED, | 152 UMA_HISTOGRAM_ENUMERATION("DataPack.Load", HEADER_TRUNCATED, |
113 LOAD_ERRORS_COUNT); | 153 LOAD_ERRORS_COUNT); |
114 mmap_.reset(); | 154 data_source_.reset(); |
115 return false; | 155 return false; |
116 } | 156 } |
117 | 157 |
118 // Parse the header of the file. | 158 // Parse the header of the file. |
119 // First uint32_t: version; second: resource count; | 159 // First uint32_t: version; second: resource count; |
120 const uint32_t* ptr = reinterpret_cast<const uint32_t*>(mmap_->data()); | 160 const uint32_t* ptr = reinterpret_cast<const uint32_t*>(data_source_->Data()); |
121 uint32_t version = ptr[0]; | 161 uint32_t version = ptr[0]; |
122 if (version != kFileFormatVersion) { | 162 if (version != kFileFormatVersion) { |
123 LOG(ERROR) << "Bad data pack version: got " << version << ", expected " | 163 LOG(ERROR) << "Bad data pack version: got " << version << ", expected " |
124 << kFileFormatVersion; | 164 << kFileFormatVersion; |
125 UMA_HISTOGRAM_ENUMERATION("DataPack.Load", BAD_VERSION, | 165 UMA_HISTOGRAM_ENUMERATION("DataPack.Load", BAD_VERSION, |
126 LOAD_ERRORS_COUNT); | 166 LOAD_ERRORS_COUNT); |
127 mmap_.reset(); | 167 data_source_.reset(); |
128 return false; | 168 return false; |
129 } | 169 } |
130 resource_count_ = ptr[1]; | 170 resource_count_ = ptr[1]; |
131 | 171 |
132 // third: text encoding. | 172 // third: text encoding. |
133 const uint8_t* ptr_encoding = reinterpret_cast<const uint8_t*>(ptr + 2); | 173 const uint8_t* ptr_encoding = reinterpret_cast<const uint8_t*>(ptr + 2); |
134 text_encoding_type_ = static_cast<TextEncodingType>(*ptr_encoding); | 174 text_encoding_type_ = static_cast<TextEncodingType>(*ptr_encoding); |
135 if (text_encoding_type_ != UTF8 && text_encoding_type_ != UTF16 && | 175 if (text_encoding_type_ != UTF8 && text_encoding_type_ != UTF16 && |
136 text_encoding_type_ != BINARY) { | 176 text_encoding_type_ != BINARY) { |
137 LOG(ERROR) << "Bad data pack text encoding: got " << text_encoding_type_ | 177 LOG(ERROR) << "Bad data pack text encoding: got " << text_encoding_type_ |
138 << ", expected between " << BINARY << " and " << UTF16; | 178 << ", expected between " << BINARY << " and " << UTF16; |
139 UMA_HISTOGRAM_ENUMERATION("DataPack.Load", WRONG_ENCODING, | 179 UMA_HISTOGRAM_ENUMERATION("DataPack.Load", WRONG_ENCODING, |
140 LOAD_ERRORS_COUNT); | 180 LOAD_ERRORS_COUNT); |
141 mmap_.reset(); | 181 data_source_.reset(); |
142 return false; | 182 return false; |
143 } | 183 } |
144 | 184 |
145 // Sanity check the file. | 185 // Sanity check the file. |
146 // 1) Check we have enough entries. There's an extra entry after the last item | 186 // 1) Check we have enough entries. There's an extra entry after the last item |
147 // which gives the length of the last item. | 187 // which gives the length of the last item. |
148 if (kHeaderLength + (resource_count_ + 1) * sizeof(DataPackEntry) > | 188 if (kHeaderLength + (resource_count_ + 1) * sizeof(DataPackEntry) > |
149 mmap_->length()) { | 189 data_source_->Length()) { |
150 LOG(ERROR) << "Data pack file corruption: too short for number of " | 190 LOG(ERROR) << "Data pack file corruption: too short for number of " |
151 "entries specified."; | 191 "entries specified."; |
152 UMA_HISTOGRAM_ENUMERATION("DataPack.Load", INDEX_TRUNCATED, | 192 UMA_HISTOGRAM_ENUMERATION("DataPack.Load", INDEX_TRUNCATED, |
153 LOAD_ERRORS_COUNT); | 193 LOAD_ERRORS_COUNT); |
154 mmap_.reset(); | 194 data_source_.reset(); |
155 return false; | 195 return false; |
156 } | 196 } |
157 // 2) Verify the entries are within the appropriate bounds. There's an extra | 197 // 2) Verify the entries are within the appropriate bounds. There's an extra |
158 // entry after the last item which gives us the length of the last item. | 198 // entry after the last item which gives us the length of the last item. |
159 for (size_t i = 0; i < resource_count_ + 1; ++i) { | 199 for (size_t i = 0; i < resource_count_ + 1; ++i) { |
160 const DataPackEntry* entry = reinterpret_cast<const DataPackEntry*>( | 200 const DataPackEntry* entry = reinterpret_cast<const DataPackEntry*>( |
161 mmap_->data() + kHeaderLength + (i * sizeof(DataPackEntry))); | 201 data_source_->Data() + kHeaderLength + (i * sizeof(DataPackEntry))); |
162 if (entry->file_offset > mmap_->length()) { | 202 if (entry->file_offset > data_source_->Length()) { |
163 LOG(ERROR) << "Entry #" << i << " in data pack points off end of file. " | 203 LOG(ERROR) << "Entry #" << i << " in data pack points off end of file. " |
164 << "Was the file corrupted?"; | 204 << "Was the file corrupted?"; |
165 UMA_HISTOGRAM_ENUMERATION("DataPack.Load", ENTRY_NOT_FOUND, | 205 UMA_HISTOGRAM_ENUMERATION("DataPack.Load", ENTRY_NOT_FOUND, |
166 LOAD_ERRORS_COUNT); | 206 LOAD_ERRORS_COUNT); |
167 mmap_.reset(); | 207 data_source_.reset(); |
168 return false; | 208 return false; |
169 } | 209 } |
170 } | 210 } |
171 | 211 |
172 return true; | 212 return true; |
173 } | 213 } |
174 | 214 |
175 bool DataPack::HasResource(uint16_t resource_id) const { | 215 bool DataPack::HasResource(uint16_t resource_id) const { |
176 return !!bsearch(&resource_id, mmap_->data() + kHeaderLength, resource_count_, | 216 return !!bsearch(&resource_id, data_source_->Data() + kHeaderLength, |
177 sizeof(DataPackEntry), DataPackEntry::CompareById); | 217 resource_count_, sizeof(DataPackEntry), |
| 218 DataPackEntry::CompareById); |
178 } | 219 } |
179 | 220 |
180 bool DataPack::GetStringPiece(uint16_t resource_id, | 221 bool DataPack::GetStringPiece(uint16_t resource_id, |
181 base::StringPiece* data) const { | 222 base::StringPiece* data) const { |
182 // It won't be hard to make this endian-agnostic, but it's not worth | 223 // It won't be hard to make this endian-agnostic, but it's not worth |
183 // bothering to do right now. | 224 // bothering to do right now. |
184 #if defined(__BYTE_ORDER) | 225 #if defined(__BYTE_ORDER) |
185 // Linux check | 226 // Linux check |
186 static_assert(__BYTE_ORDER == __LITTLE_ENDIAN, | 227 static_assert(__BYTE_ORDER == __LITTLE_ENDIAN, |
187 "datapack assumes little endian"); | 228 "datapack assumes little endian"); |
188 #elif defined(__BIG_ENDIAN__) | 229 #elif defined(__BIG_ENDIAN__) |
189 // Mac check | 230 // Mac check |
190 #error DataPack assumes little endian | 231 #error DataPack assumes little endian |
191 #endif | 232 #endif |
192 | 233 |
193 const DataPackEntry* target = reinterpret_cast<const DataPackEntry*>( | 234 const DataPackEntry* target = reinterpret_cast<const DataPackEntry*>(bsearch( |
194 bsearch(&resource_id, mmap_->data() + kHeaderLength, resource_count_, | 235 &resource_id, data_source_->Data() + kHeaderLength, resource_count_, |
195 sizeof(DataPackEntry), DataPackEntry::CompareById)); | 236 sizeof(DataPackEntry), DataPackEntry::CompareById)); |
196 if (!target) { | 237 if (!target) { |
197 return false; | 238 return false; |
198 } | 239 } |
199 | 240 |
200 const DataPackEntry* next_entry = target + 1; | 241 const DataPackEntry* next_entry = target + 1; |
201 // If the next entry points beyond the end of the file this data pack's entry | 242 // If the next entry points beyond the end of the file this data pack's entry |
202 // table is corrupt. Log an error and return false. See | 243 // table is corrupt. Log an error and return false. See |
203 // http://crbug.com/371301. | 244 // http://crbug.com/371301. |
204 if (next_entry->file_offset > mmap_->length()) { | 245 if (next_entry->file_offset > data_source_->Length()) { |
205 size_t entry_index = target - | 246 size_t entry_index = target - reinterpret_cast<const DataPackEntry*>( |
206 reinterpret_cast<const DataPackEntry*>(mmap_->data() + kHeaderLength); | 247 data_source_->Data() + kHeaderLength); |
207 LOG(ERROR) << "Entry #" << entry_index << " in data pack points off end " | 248 LOG(ERROR) << "Entry #" << entry_index << " in data pack points off end " |
208 << "of file. This should have been caught when loading. Was the " | 249 << "of file. This should have been caught when loading. Was the " |
209 << "file modified?"; | 250 << "file modified?"; |
210 return false; | 251 return false; |
211 } | 252 } |
212 | 253 |
213 size_t length = next_entry->file_offset - target->file_offset; | 254 size_t length = next_entry->file_offset - target->file_offset; |
214 data->set(reinterpret_cast<const char*>(mmap_->data() + target->file_offset), | 255 data->set( |
215 length); | 256 reinterpret_cast<const char*>(data_source_->Data() + target->file_offset), |
| 257 length); |
216 return true; | 258 return true; |
217 } | 259 } |
218 | 260 |
219 base::RefCountedStaticMemory* DataPack::GetStaticMemory( | 261 base::RefCountedStaticMemory* DataPack::GetStaticMemory( |
220 uint16_t resource_id) const { | 262 uint16_t resource_id) const { |
221 base::StringPiece piece; | 263 base::StringPiece piece; |
222 if (!GetStringPiece(resource_id, &piece)) | 264 if (!GetStringPiece(resource_id, &piece)) |
223 return NULL; | 265 return NULL; |
224 | 266 |
225 return new base::RefCountedStaticMemory(piece.data(), piece.length()); | 267 return new base::RefCountedStaticMemory(piece.data(), piece.length()); |
226 } | 268 } |
227 | 269 |
228 ResourceHandle::TextEncodingType DataPack::GetTextEncodingType() const { | 270 ResourceHandle::TextEncodingType DataPack::GetTextEncodingType() const { |
229 return text_encoding_type_; | 271 return text_encoding_type_; |
230 } | 272 } |
231 | 273 |
232 ui::ScaleFactor DataPack::GetScaleFactor() const { | 274 ui::ScaleFactor DataPack::GetScaleFactor() const { |
233 return scale_factor_; | 275 return scale_factor_; |
234 } | 276 } |
235 | 277 |
236 bool DataPack::HasOnlyMaterialDesignAssets() const { | 278 bool DataPack::HasOnlyMaterialDesignAssets() const { |
237 return has_only_material_design_assets_; | 279 return has_only_material_design_assets_; |
238 } | 280 } |
239 | 281 |
240 #if DCHECK_IS_ON() | 282 #if DCHECK_IS_ON() |
241 void DataPack::CheckForDuplicateResources( | 283 void DataPack::CheckForDuplicateResources( |
242 const ScopedVector<ResourceHandle>& packs) { | 284 const ScopedVector<ResourceHandle>& packs) { |
243 for (size_t i = 0; i < resource_count_ + 1; ++i) { | 285 for (size_t i = 0; i < resource_count_ + 1; ++i) { |
244 const DataPackEntry* entry = reinterpret_cast<const DataPackEntry*>( | 286 const DataPackEntry* entry = reinterpret_cast<const DataPackEntry*>( |
245 mmap_->data() + kHeaderLength + (i * sizeof(DataPackEntry))); | 287 data_source_->Data() + kHeaderLength + (i * sizeof(DataPackEntry))); |
246 const uint16_t resource_id = entry->resource_id; | 288 const uint16_t resource_id = entry->resource_id; |
247 const float resource_scale = GetScaleForScaleFactor(scale_factor_); | 289 const float resource_scale = GetScaleForScaleFactor(scale_factor_); |
248 for (const ResourceHandle* handle : packs) { | 290 for (const ResourceHandle* handle : packs) { |
249 if (HasOnlyMaterialDesignAssets() != | 291 if (HasOnlyMaterialDesignAssets() != |
250 handle->HasOnlyMaterialDesignAssets()) { | 292 handle->HasOnlyMaterialDesignAssets()) { |
251 continue; | 293 continue; |
252 } | 294 } |
253 if (GetScaleForScaleFactor(handle->GetScaleFactor()) != resource_scale) | 295 if (GetScaleForScaleFactor(handle->GetScaleFactor()) != resource_scale) |
254 continue; | 296 continue; |
255 DCHECK(!handle->HasResource(resource_id)) << "Duplicate resource " | 297 DCHECK(!handle->HasResource(resource_id)) << "Duplicate resource " |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
345 return false; | 387 return false; |
346 } | 388 } |
347 } | 389 } |
348 | 390 |
349 base::CloseFile(file); | 391 base::CloseFile(file); |
350 | 392 |
351 return true; | 393 return true; |
352 } | 394 } |
353 | 395 |
354 } // namespace ui | 396 } // namespace ui |
OLD | NEW |