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 <set> | 8 #include <set> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
12 #include "base/files/file_util.h" | 12 #include "base/files/file_util.h" |
13 #include "base/files/memory_mapped_file.h" | 13 #include "base/files/memory_mapped_file.h" |
14 #include "base/logging.h" | 14 #include "base/logging.h" |
15 #include "base/memory/ptr_util.h" | 15 #include "base/memory/ptr_util.h" |
16 #include "base/memory/ref_counted_memory.h" | 16 #include "base/memory/ref_counted_memory.h" |
17 #include "base/metrics/histogram_macros.h" | 17 #include "base/metrics/histogram_macros.h" |
18 #include "base/stl_util.h" | 18 #include "base/stl_util.h" |
19 #include "base/strings/string_piece.h" | 19 #include "base/strings/string_piece.h" |
20 #include "base/synchronization/lock.h" | 20 #include "base/synchronization/lock.h" |
21 | 21 |
22 // For details of the file layout, see | 22 // For details of the file layout, see |
23 // http://dev.chromium.org/developers/design-documents/linuxresourcesandlocalize
dstrings | 23 // http://dev.chromium.org/developers/design-documents/linuxresourcesandlocalize
dstrings |
24 | 24 |
25 namespace { | 25 namespace { |
26 | 26 |
27 static const uint32_t kFileFormatV4 = 4; | 27 static const uint32_t kFileFormatVersion = 4; |
28 static const uint32_t kFileFormatV5 = 5; | 28 // Length of file header: version, entry count and text encoding type. |
29 // int32(version), int32(resource_count), int8(encoding) | 29 static const size_t kHeaderLength = 2 * sizeof(uint32_t) + sizeof(uint8_t); |
30 static const size_t kHeaderLengthV4 = 2 * sizeof(uint32_t) + sizeof(uint8_t); | 30 |
31 // int32(version), int8(encoding), 3 bytes padding, | 31 #pragma pack(push, 2) |
32 // int16(resource_count), int16(alias_count) | 32 struct DataPackEntry { |
33 static const size_t kHeaderLengthV5 = | 33 uint16_t resource_id; |
34 sizeof(uint32_t) + sizeof(uint8_t) * 4 + sizeof(uint16_t) * 2; | 34 uint32_t file_offset; |
| 35 |
| 36 static int CompareById(const void* void_key, const void* void_entry) { |
| 37 uint16_t key = *reinterpret_cast<const uint16_t*>(void_key); |
| 38 const DataPackEntry* entry = |
| 39 reinterpret_cast<const DataPackEntry*>(void_entry); |
| 40 if (key < entry->resource_id) { |
| 41 return -1; |
| 42 } else if (key > entry->resource_id) { |
| 43 return 1; |
| 44 } else { |
| 45 return 0; |
| 46 } |
| 47 } |
| 48 }; |
| 49 #pragma pack(pop) |
| 50 |
| 51 static_assert(sizeof(DataPackEntry) == 6, "size of entry must be six"); |
35 | 52 |
36 // We're crashing when trying to load a pak file on Windows. Add some error | 53 // We're crashing when trying to load a pak file on Windows. Add some error |
37 // codes for logging. | 54 // codes for logging. |
38 // http://crbug.com/58056 | 55 // http://crbug.com/58056 |
39 enum LoadErrors { | 56 enum LoadErrors { |
40 INIT_FAILED = 1, | 57 INIT_FAILED = 1, |
41 BAD_VERSION, | 58 BAD_VERSION, |
42 INDEX_TRUNCATED, | 59 INDEX_TRUNCATED, |
43 ENTRY_NOT_FOUND, | 60 ENTRY_NOT_FOUND, |
44 HEADER_TRUNCATED, | 61 HEADER_TRUNCATED, |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 if (!base::ContainsKey(*resource_ids_logged, resource_id)) { | 95 if (!base::ContainsKey(*resource_ids_logged, resource_id)) { |
79 printf("Resource=%d\n", resource_id); | 96 printf("Resource=%d\n", resource_id); |
80 resource_ids_logged->insert(resource_id); | 97 resource_ids_logged->insert(resource_id); |
81 } | 98 } |
82 } | 99 } |
83 | 100 |
84 } // namespace | 101 } // namespace |
85 | 102 |
86 namespace ui { | 103 namespace ui { |
87 | 104 |
88 #pragma pack(push, 2) | |
89 struct DataPack::Entry { | |
90 uint16_t resource_id; | |
91 uint32_t file_offset; | |
92 | |
93 static int CompareById(const void* void_key, const void* void_entry) { | |
94 uint16_t key = *reinterpret_cast<const uint16_t*>(void_key); | |
95 const Entry* entry = reinterpret_cast<const Entry*>(void_entry); | |
96 return key - entry->resource_id; | |
97 } | |
98 }; | |
99 | |
100 struct DataPack::Alias { | |
101 uint16_t resource_id; | |
102 uint16_t entry_index; | |
103 | |
104 static int CompareById(const void* void_key, const void* void_entry) { | |
105 uint16_t key = *reinterpret_cast<const uint16_t*>(void_key); | |
106 const Alias* entry = reinterpret_cast<const Alias*>(void_entry); | |
107 return key - entry->resource_id; | |
108 } | |
109 }; | |
110 #pragma pack(pop) | |
111 | |
112 // Abstraction of a data source (memory mapped file or in-memory buffer). | 105 // Abstraction of a data source (memory mapped file or in-memory buffer). |
113 class DataPack::DataSource { | 106 class DataPack::DataSource { |
114 public: | 107 public: |
115 virtual ~DataSource() {} | 108 virtual ~DataSource() {} |
116 | 109 |
117 virtual size_t GetLength() const = 0; | 110 virtual size_t GetLength() const = 0; |
118 virtual const uint8_t* GetData() const = 0; | 111 virtual const uint8_t* GetData() const = 0; |
119 }; | 112 }; |
120 | 113 |
121 class DataPack::MemoryMappedDataSource : public DataPack::DataSource { | 114 class DataPack::MemoryMappedDataSource : public DataPack::DataSource { |
(...skipping 27 matching lines...) Expand all Loading... |
149 return reinterpret_cast<const uint8_t*>(buffer_.data()); | 142 return reinterpret_cast<const uint8_t*>(buffer_.data()); |
150 } | 143 } |
151 | 144 |
152 private: | 145 private: |
153 base::StringPiece buffer_; | 146 base::StringPiece buffer_; |
154 | 147 |
155 DISALLOW_COPY_AND_ASSIGN(BufferDataSource); | 148 DISALLOW_COPY_AND_ASSIGN(BufferDataSource); |
156 }; | 149 }; |
157 | 150 |
158 DataPack::DataPack(ui::ScaleFactor scale_factor) | 151 DataPack::DataPack(ui::ScaleFactor scale_factor) |
159 : resource_table_(nullptr), | 152 : resource_count_(0), |
160 resource_count_(0), | |
161 alias_table_(nullptr), | |
162 alias_count_(0), | |
163 text_encoding_type_(BINARY), | 153 text_encoding_type_(BINARY), |
164 scale_factor_(scale_factor) { | 154 scale_factor_(scale_factor) { |
165 // Static assert must be within a DataPack member to appease visiblity rules. | |
166 static_assert(sizeof(Entry) == 6, "size of Entry must be 6"); | |
167 static_assert(sizeof(Alias) == 4, "size of Alias must be 4"); | |
168 } | 155 } |
169 | 156 |
170 DataPack::~DataPack() { | 157 DataPack::~DataPack() { |
171 } | 158 } |
172 | 159 |
173 bool DataPack::LoadFromPath(const base::FilePath& path) { | 160 bool DataPack::LoadFromPath(const base::FilePath& path) { |
174 std::unique_ptr<base::MemoryMappedFile> mmap = | 161 std::unique_ptr<base::MemoryMappedFile> mmap = |
175 base::MakeUnique<base::MemoryMappedFile>(); | 162 base::MakeUnique<base::MemoryMappedFile>(); |
176 if (!mmap->Initialize(path)) { | 163 if (!mmap->Initialize(path)) { |
177 DLOG(ERROR) << "Failed to mmap datapack"; | 164 DLOG(ERROR) << "Failed to mmap datapack"; |
(...skipping 21 matching lines...) Expand all Loading... |
199 return false; | 186 return false; |
200 } | 187 } |
201 return LoadImpl(base::MakeUnique<MemoryMappedDataSource>(std::move(mmap))); | 188 return LoadImpl(base::MakeUnique<MemoryMappedDataSource>(std::move(mmap))); |
202 } | 189 } |
203 | 190 |
204 bool DataPack::LoadFromBuffer(base::StringPiece buffer) { | 191 bool DataPack::LoadFromBuffer(base::StringPiece buffer) { |
205 return LoadImpl(base::MakeUnique<BufferDataSource>(buffer)); | 192 return LoadImpl(base::MakeUnique<BufferDataSource>(buffer)); |
206 } | 193 } |
207 | 194 |
208 bool DataPack::LoadImpl(std::unique_ptr<DataPack::DataSource> data_source) { | 195 bool DataPack::LoadImpl(std::unique_ptr<DataPack::DataSource> data_source) { |
209 const uint8_t* data = data_source->GetData(); | 196 // Sanity check the header of the file. |
210 size_t data_length = data_source->GetLength(); | 197 if (kHeaderLength > data_source->GetLength()) { |
211 // Parse the version and check for truncated header. | |
212 uint32_t version = 0; | |
213 if (data_length > sizeof(version)) | |
214 version = reinterpret_cast<const uint32_t*>(data)[0]; | |
215 size_t header_length = | |
216 version == kFileFormatV4 ? kHeaderLengthV4 : kHeaderLengthV5; | |
217 if (version == 0 || data_length < header_length) { | |
218 DLOG(ERROR) << "Data pack file corruption: incomplete file header."; | 198 DLOG(ERROR) << "Data pack file corruption: incomplete file header."; |
219 LogDataPackError(HEADER_TRUNCATED); | 199 LogDataPackError(HEADER_TRUNCATED); |
220 return false; | 200 return false; |
221 } | 201 } |
222 | 202 |
223 // Parse the header of the file. | 203 // Parse the header of the file. |
224 if (version == kFileFormatV4) { | 204 // First uint32_t: version; second: resource count; |
225 resource_count_ = reinterpret_cast<const uint32_t*>(data)[1]; | 205 const uint32_t* ptr = |
226 alias_count_ = 0; | 206 reinterpret_cast<const uint32_t*>(data_source->GetData()); |
227 text_encoding_type_ = static_cast<TextEncodingType>(data[8]); | 207 uint32_t version = ptr[0]; |
228 } else if (version == kFileFormatV5) { | 208 if (version != kFileFormatVersion) { |
229 // Version 5 added the alias table and changed the header format. | |
230 text_encoding_type_ = static_cast<TextEncodingType>(data[4]); | |
231 resource_count_ = reinterpret_cast<const uint16_t*>(data)[4]; | |
232 alias_count_ = reinterpret_cast<const uint16_t*>(data)[5]; | |
233 } else { | |
234 LOG(ERROR) << "Bad data pack version: got " << version << ", expected " | 209 LOG(ERROR) << "Bad data pack version: got " << version << ", expected " |
235 << kFileFormatV4 << " or " << kFileFormatV5; | 210 << kFileFormatVersion; |
236 LogDataPackError(BAD_VERSION); | 211 LogDataPackError(BAD_VERSION); |
237 return false; | 212 return false; |
238 } | 213 } |
| 214 resource_count_ = ptr[1]; |
239 | 215 |
| 216 // third: text encoding. |
| 217 const uint8_t* ptr_encoding = reinterpret_cast<const uint8_t*>(ptr + 2); |
| 218 text_encoding_type_ = static_cast<TextEncodingType>(*ptr_encoding); |
240 if (text_encoding_type_ != UTF8 && text_encoding_type_ != UTF16 && | 219 if (text_encoding_type_ != UTF8 && text_encoding_type_ != UTF16 && |
241 text_encoding_type_ != BINARY) { | 220 text_encoding_type_ != BINARY) { |
242 LOG(ERROR) << "Bad data pack text encoding: got " << text_encoding_type_ | 221 LOG(ERROR) << "Bad data pack text encoding: got " << text_encoding_type_ |
243 << ", expected between " << BINARY << " and " << UTF16; | 222 << ", expected between " << BINARY << " and " << UTF16; |
244 LogDataPackError(WRONG_ENCODING); | 223 LogDataPackError(WRONG_ENCODING); |
245 return false; | 224 return false; |
246 } | 225 } |
247 | 226 |
248 // Sanity check the file. | 227 // Sanity check the file. |
249 // 1) Check we have enough entries. There's an extra entry after the last item | 228 // 1) Check we have enough entries. There's an extra entry after the last item |
250 // which gives the length of the last item. | 229 // which gives the length of the last item. |
251 size_t resource_table_size = (resource_count_ + 1) * sizeof(Entry); | 230 if (kHeaderLength + (resource_count_ + 1) * sizeof(DataPackEntry) > |
252 size_t alias_table_size = alias_count_ * sizeof(Alias); | 231 data_source->GetLength()) { |
253 if (header_length + resource_table_size + alias_table_size > data_length) { | 232 LOG(ERROR) << "Data pack file corruption: too short for number of " |
254 LOG(ERROR) << "Data pack file corruption: " | 233 "entries specified."; |
255 << "too short for number of entries."; | |
256 LogDataPackError(INDEX_TRUNCATED); | 234 LogDataPackError(INDEX_TRUNCATED); |
257 return false; | 235 return false; |
258 } | 236 } |
259 | |
260 resource_table_ = reinterpret_cast<const Entry*>(&data[header_length]); | |
261 alias_table_ = reinterpret_cast<const Alias*>( | |
262 &data[header_length + resource_table_size]); | |
263 | |
264 // 2) Verify the entries are within the appropriate bounds. There's an extra | 237 // 2) Verify the entries are within the appropriate bounds. There's an extra |
265 // entry after the last item which gives us the length of the last item. | 238 // entry after the last item which gives us the length of the last item. |
266 for (size_t i = 0; i < resource_count_ + 1; ++i) { | 239 for (size_t i = 0; i < resource_count_ + 1; ++i) { |
267 if (resource_table_[i].file_offset > data_length) { | 240 const DataPackEntry* entry = reinterpret_cast<const DataPackEntry*>( |
268 LOG(ERROR) << "Data pack file corruption: " | 241 data_source->GetData() + kHeaderLength + (i * sizeof(DataPackEntry))); |
269 << "Entry #" << i << " past end."; | 242 if (entry->file_offset > data_source->GetLength()) { |
270 LogDataPackError(ENTRY_NOT_FOUND); | 243 LOG(ERROR) << "Entry #" << i << " in data pack points off end of file. " |
271 return false; | 244 << "Was the file corrupted?"; |
272 } | |
273 } | |
274 | |
275 // 3) Verify the aliases are within the appropriate bounds. | |
276 for (size_t i = 0; i < alias_count_; ++i) { | |
277 if (alias_table_[i].entry_index >= resource_count_) { | |
278 LOG(ERROR) << "Data pack file corruption: " | |
279 << "Alias #" << i << " past end."; | |
280 LogDataPackError(ENTRY_NOT_FOUND); | 245 LogDataPackError(ENTRY_NOT_FOUND); |
281 return false; | 246 return false; |
282 } | 247 } |
283 } | 248 } |
284 | 249 |
285 data_source_ = std::move(data_source); | 250 data_source_ = std::move(data_source); |
| 251 |
286 return true; | 252 return true; |
287 } | 253 } |
288 | 254 |
289 const DataPack::Entry* DataPack::LookupEntryById(uint16_t resource_id) const { | |
290 // Search the resource table first as most resources will be in there. | |
291 const Entry* ret = reinterpret_cast<const Entry*>( | |
292 bsearch(&resource_id, resource_table_, resource_count_, sizeof(Entry), | |
293 Entry::CompareById)); | |
294 if (ret == nullptr) { | |
295 // Search the alias table for the ~10% of entries which are aliases. | |
296 const Alias* alias = reinterpret_cast<const Alias*>( | |
297 bsearch(&resource_id, alias_table_, alias_count_, sizeof(Alias), | |
298 Alias::CompareById)); | |
299 if (alias != nullptr) { | |
300 ret = &resource_table_[alias->entry_index]; | |
301 } | |
302 } | |
303 return ret; | |
304 } | |
305 | |
306 bool DataPack::HasResource(uint16_t resource_id) const { | 255 bool DataPack::HasResource(uint16_t resource_id) const { |
307 return !!LookupEntryById(resource_id); | 256 return !!bsearch(&resource_id, data_source_->GetData() + kHeaderLength, |
| 257 resource_count_, sizeof(DataPackEntry), |
| 258 DataPackEntry::CompareById); |
308 } | 259 } |
309 | 260 |
310 bool DataPack::GetStringPiece(uint16_t resource_id, | 261 bool DataPack::GetStringPiece(uint16_t resource_id, |
311 base::StringPiece* data) const { | 262 base::StringPiece* data) const { |
312 // It won't be hard to make this endian-agnostic, but it's not worth | 263 // It won't be hard to make this endian-agnostic, but it's not worth |
313 // bothering to do right now. | 264 // bothering to do right now. |
314 #if defined(__BYTE_ORDER) | 265 #if defined(__BYTE_ORDER) |
315 // Linux check | 266 // Linux check |
316 static_assert(__BYTE_ORDER == __LITTLE_ENDIAN, | 267 static_assert(__BYTE_ORDER == __LITTLE_ENDIAN, |
317 "datapack assumes little endian"); | 268 "datapack assumes little endian"); |
318 #elif defined(__BIG_ENDIAN__) | 269 #elif defined(__BIG_ENDIAN__) |
319 // Mac check | 270 // Mac check |
320 #error DataPack assumes little endian | 271 #error DataPack assumes little endian |
321 #endif | 272 #endif |
322 | 273 |
323 const Entry* target = LookupEntryById(resource_id); | 274 const DataPackEntry* target = reinterpret_cast<const DataPackEntry*>(bsearch( |
324 if (!target) | 275 &resource_id, data_source_->GetData() + kHeaderLength, resource_count_, |
| 276 sizeof(DataPackEntry), DataPackEntry::CompareById)); |
| 277 if (!target) { |
325 return false; | 278 return false; |
| 279 } |
326 | 280 |
327 const Entry* next_entry = target + 1; | 281 const DataPackEntry* next_entry = target + 1; |
328 // If the next entry points beyond the end of the file this data pack's entry | 282 // If the next entry points beyond the end of the file this data pack's entry |
329 // table is corrupt. Log an error and return false. See | 283 // table is corrupt. Log an error and return false. See |
330 // http://crbug.com/371301. | 284 // http://crbug.com/371301. |
331 size_t entry_offset = | 285 if (next_entry->file_offset > data_source_->GetLength()) { |
332 reinterpret_cast<const uint8_t*>(next_entry) - data_source_->GetData(); | 286 size_t entry_index = target - reinterpret_cast<const DataPackEntry*>( |
333 size_t pak_size = data_source_->GetLength(); | 287 data_source_->GetData() + kHeaderLength); |
334 if (entry_offset > pak_size || next_entry->file_offset > pak_size) { | |
335 size_t entry_index = target - resource_table_; | |
336 LOG(ERROR) << "Entry #" << entry_index << " in data pack points off end " | 288 LOG(ERROR) << "Entry #" << entry_index << " in data pack points off end " |
337 << "of file. This should have been caught when loading. Was the " | 289 << "of file. This should have been caught when loading. Was the " |
338 << "file modified?"; | 290 << "file modified?"; |
339 return false; | 291 return false; |
340 } | 292 } |
341 | 293 |
342 MaybePrintResourceId(resource_id); | 294 MaybePrintResourceId(resource_id); |
343 size_t length = next_entry->file_offset - target->file_offset; | 295 size_t length = next_entry->file_offset - target->file_offset; |
344 data->set(reinterpret_cast<const char*>(data_source_->GetData() + | 296 data->set(reinterpret_cast<const char*>(data_source_->GetData() + |
345 target->file_offset), | 297 target->file_offset), |
(...skipping 15 matching lines...) Expand all Loading... |
361 } | 313 } |
362 | 314 |
363 ui::ScaleFactor DataPack::GetScaleFactor() const { | 315 ui::ScaleFactor DataPack::GetScaleFactor() const { |
364 return scale_factor_; | 316 return scale_factor_; |
365 } | 317 } |
366 | 318 |
367 #if DCHECK_IS_ON() | 319 #if DCHECK_IS_ON() |
368 void DataPack::CheckForDuplicateResources( | 320 void DataPack::CheckForDuplicateResources( |
369 const std::vector<std::unique_ptr<ResourceHandle>>& packs) { | 321 const std::vector<std::unique_ptr<ResourceHandle>>& packs) { |
370 for (size_t i = 0; i < resource_count_ + 1; ++i) { | 322 for (size_t i = 0; i < resource_count_ + 1; ++i) { |
371 const uint16_t resource_id = resource_table_[i].resource_id; | 323 const DataPackEntry* entry = reinterpret_cast<const DataPackEntry*>( |
| 324 data_source_->GetData() + kHeaderLength + (i * sizeof(DataPackEntry))); |
| 325 const uint16_t resource_id = entry->resource_id; |
372 const float resource_scale = GetScaleForScaleFactor(scale_factor_); | 326 const float resource_scale = GetScaleForScaleFactor(scale_factor_); |
373 for (const auto& handle : packs) { | 327 for (const auto& handle : packs) { |
374 if (GetScaleForScaleFactor(handle->GetScaleFactor()) != resource_scale) | 328 if (GetScaleForScaleFactor(handle->GetScaleFactor()) != resource_scale) |
375 continue; | 329 continue; |
376 DCHECK(!handle->HasResource(resource_id)) << "Duplicate resource " | 330 DCHECK(!handle->HasResource(resource_id)) << "Duplicate resource " |
377 << resource_id << " with scale " | 331 << resource_id << " with scale " |
378 << resource_scale; | 332 << resource_scale; |
379 } | 333 } |
380 } | 334 } |
381 } | 335 } |
382 #endif // DCHECK_IS_ON() | 336 #endif // DCHECK_IS_ON() |
383 | 337 |
384 // static | 338 // static |
385 bool DataPack::WritePack(const base::FilePath& path, | 339 bool DataPack::WritePack(const base::FilePath& path, |
386 const std::map<uint16_t, base::StringPiece>& resources, | 340 const std::map<uint16_t, base::StringPiece>& resources, |
387 TextEncodingType textEncodingType) { | 341 TextEncodingType textEncodingType) { |
| 342 FILE* file = base::OpenFile(path, "wb"); |
| 343 if (!file) |
| 344 return false; |
| 345 |
| 346 if (fwrite(&kFileFormatVersion, sizeof(kFileFormatVersion), 1, file) != 1) { |
| 347 LOG(ERROR) << "Failed to write file version"; |
| 348 base::CloseFile(file); |
| 349 return false; |
| 350 } |
| 351 |
| 352 // Note: the python version of this function explicitly sorted keys, but |
| 353 // std::map is a sorted associative container, we shouldn't have to do that. |
| 354 uint32_t entry_count = resources.size(); |
| 355 if (fwrite(&entry_count, sizeof(entry_count), 1, file) != 1) { |
| 356 LOG(ERROR) << "Failed to write entry count"; |
| 357 base::CloseFile(file); |
| 358 return false; |
| 359 } |
| 360 |
388 if (textEncodingType != UTF8 && textEncodingType != UTF16 && | 361 if (textEncodingType != UTF8 && textEncodingType != UTF16 && |
389 textEncodingType != BINARY) { | 362 textEncodingType != BINARY) { |
390 LOG(ERROR) << "Invalid text encoding type, got " << textEncodingType | 363 LOG(ERROR) << "Invalid text encoding type, got " << textEncodingType |
391 << ", expected between " << BINARY << " and " << UTF16; | 364 << ", expected between " << BINARY << " and " << UTF16; |
| 365 base::CloseFile(file); |
392 return false; | 366 return false; |
393 } | 367 } |
394 | 368 |
395 FILE* file = base::OpenFile(path, "wb"); | 369 uint8_t write_buffer = static_cast<uint8_t>(textEncodingType); |
396 if (!file) | 370 if (fwrite(&write_buffer, sizeof(uint8_t), 1, file) != 1) { |
397 return false; | 371 LOG(ERROR) << "Failed to write file text resources encoding"; |
398 | |
399 uint32_t encoding = static_cast<uint32_t>(textEncodingType); | |
400 // Note: the python version of this function explicitly sorted keys, but | |
401 // std::map is a sorted associative container, we shouldn't have to do that. | |
402 uint16_t entry_count = resources.size(); | |
403 // Don't bother computing aliases (revisit if it becomes worth it). | |
404 uint16_t alias_count = 0; | |
405 | |
406 if (fwrite(&kFileFormatV5, sizeof(kFileFormatV5), 1, file) != 1 || | |
407 fwrite(&encoding, sizeof(uint32_t), 1, file) != 1 || | |
408 fwrite(&entry_count, sizeof(entry_count), 1, file) != 1 || | |
409 fwrite(&alias_count, sizeof(alias_count), 1, file) != 1) { | |
410 LOG(ERROR) << "Failed to write header"; | |
411 base::CloseFile(file); | 372 base::CloseFile(file); |
412 return false; | 373 return false; |
413 } | 374 } |
414 | 375 |
415 // Each entry is a uint16_t + a uint32_t. We have an extra entry after the | 376 // Each entry is a uint16_t + a uint32_t. We have an extra entry after the |
416 // last item so we can compute the size of the list item. | 377 // last item so we can compute the size of the list item. |
417 uint32_t index_length = (entry_count + 1) * sizeof(Entry); | 378 uint32_t index_length = (entry_count + 1) * sizeof(DataPackEntry); |
418 uint32_t data_offset = kHeaderLengthV5 + index_length; | 379 uint32_t data_offset = kHeaderLength + index_length; |
419 for (std::map<uint16_t, base::StringPiece>::const_iterator it = | 380 for (std::map<uint16_t, base::StringPiece>::const_iterator it = |
420 resources.begin(); | 381 resources.begin(); |
421 it != resources.end(); ++it) { | 382 it != resources.end(); ++it) { |
422 uint16_t resource_id = it->first; | 383 uint16_t resource_id = it->first; |
423 if (fwrite(&resource_id, sizeof(resource_id), 1, file) != 1 || | 384 if (fwrite(&resource_id, sizeof(resource_id), 1, file) != 1) { |
424 fwrite(&data_offset, sizeof(data_offset), 1, file) != 1) { | 385 LOG(ERROR) << "Failed to write id for " << resource_id; |
425 LOG(ERROR) << "Failed to write entry for " << resource_id; | |
426 base::CloseFile(file); | 386 base::CloseFile(file); |
427 return false; | 387 return false; |
428 } | 388 } |
| 389 |
| 390 if (fwrite(&data_offset, sizeof(data_offset), 1, file) != 1) { |
| 391 LOG(ERROR) << "Failed to write offset for " << resource_id; |
| 392 base::CloseFile(file); |
| 393 return false; |
| 394 } |
429 | 395 |
430 data_offset += it->second.length(); | 396 data_offset += it->second.length(); |
431 } | 397 } |
432 | 398 |
433 // We place an extra entry after the last item that allows us to read the | 399 // We place an extra entry after the last item that allows us to read the |
434 // size of the last item. | 400 // size of the last item. |
435 uint16_t resource_id = 0; | 401 uint16_t resource_id = 0; |
436 if (fwrite(&resource_id, sizeof(resource_id), 1, file) != 1) { | 402 if (fwrite(&resource_id, sizeof(resource_id), 1, file) != 1) { |
437 LOG(ERROR) << "Failed to write extra resource id."; | 403 LOG(ERROR) << "Failed to write extra resource id."; |
438 base::CloseFile(file); | 404 base::CloseFile(file); |
(...skipping 15 matching lines...) Expand all Loading... |
454 return false; | 420 return false; |
455 } | 421 } |
456 } | 422 } |
457 | 423 |
458 base::CloseFile(file); | 424 base::CloseFile(file); |
459 | 425 |
460 return true; | 426 return true; |
461 } | 427 } |
462 | 428 |
463 } // namespace ui | 429 } // namespace ui |
OLD | NEW |