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