OLD | NEW |
1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2008 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 "base/data_pack.h" | 5 #include "base/data_pack.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 | 8 |
9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/string_piece.h" | 11 #include "base/string_piece.h" |
12 | 12 |
13 // For details of the file layout, see | 13 // For details of the file layout, see |
14 // http://dev.chromium.org/developers/design-documents/linuxresourcesandlocalize
dstrings | 14 // http://dev.chromium.org/developers/design-documents/linuxresourcesandlocalize
dstrings |
15 | 15 |
16 namespace { | 16 namespace { |
17 static const uint32_t kFileFormatVersion = 1; | 17 |
| 18 // A word is four bytes. |
| 19 static const size_t kWord = 4; |
| 20 |
| 21 static const uint32 kFileFormatVersion = 1; |
18 // Length of file header: version and entry count. | 22 // Length of file header: version and entry count. |
19 static const size_t kHeaderLength = 2 * sizeof(uint32_t); | 23 static const size_t kHeaderLength = 2 * sizeof(uint32); |
20 | 24 |
| 25 #pragma pack(push,1) |
21 struct DataPackEntry { | 26 struct DataPackEntry { |
22 uint32_t resource_id; | 27 uint32 resource_id; |
23 uint32_t file_offset; | 28 uint32 file_offset; |
24 uint32_t length; | 29 uint32 length; |
25 | 30 |
26 static int CompareById(const void* void_key, const void* void_entry) { | 31 static int CompareById(const void* void_key, const void* void_entry) { |
27 uint32_t key = *reinterpret_cast<const uint32_t*>(void_key); | 32 uint32 key = *reinterpret_cast<const uint32*>(void_key); |
28 const DataPackEntry* entry = | 33 const DataPackEntry* entry = |
29 reinterpret_cast<const DataPackEntry*>(void_entry); | 34 reinterpret_cast<const DataPackEntry*>(void_entry); |
30 if (key < entry->resource_id) { | 35 if (key < entry->resource_id) { |
31 return -1; | 36 return -1; |
32 } else if (key > entry->resource_id) { | 37 } else if (key > entry->resource_id) { |
33 return 1; | 38 return 1; |
34 } else { | 39 } else { |
35 return 0; | 40 return 0; |
36 } | 41 } |
37 } | 42 } |
38 } __attribute((packed)); | 43 }; |
| 44 #pragma pack(pop) |
| 45 |
| 46 COMPILE_ASSERT(sizeof(DataPackEntry) == 12, size_of_header_must_be_twelve); |
39 | 47 |
40 } // anonymous namespace | 48 } // anonymous namespace |
41 | 49 |
42 namespace base { | 50 namespace base { |
43 | 51 |
44 // In .cc for MemoryMappedFile dtor. | 52 // In .cc for MemoryMappedFile dtor. |
45 DataPack::DataPack() : resource_count_(0) { | 53 DataPack::DataPack() : resource_count_(0) { |
46 } | 54 } |
47 DataPack::~DataPack() { | 55 DataPack::~DataPack() { |
48 } | 56 } |
49 | 57 |
50 bool DataPack::Load(const FilePath& path) { | 58 bool DataPack::Load(const FilePath& path) { |
51 mmap_.reset(new file_util::MemoryMappedFile); | 59 mmap_.reset(new file_util::MemoryMappedFile); |
52 if (!mmap_->Initialize(path)) { | 60 if (!mmap_->Initialize(path)) { |
53 PCHECK(false) << "Failed to mmap " << path.value(); | 61 DLOG(ERROR) << "Failed to mmap datapack"; |
| 62 return false; |
54 } | 63 } |
55 | 64 |
56 // Parse the header of the file. | 65 // Parse the header of the file. |
57 // First uint32_t: version; second: resource count. | 66 // First uint32: version; second: resource count. |
58 const uint32* ptr = reinterpret_cast<const uint32_t*>(mmap_->data()); | 67 const uint32* ptr = reinterpret_cast<const uint32*>(mmap_->data()); |
59 uint32 version = ptr[0]; | 68 uint32 version = ptr[0]; |
60 if (version != kFileFormatVersion) { | 69 if (version != kFileFormatVersion) { |
61 LOG(ERROR) << "Bad data pack version: got " << version << ", expected " | 70 LOG(ERROR) << "Bad data pack version: got " << version << ", expected " |
62 << kFileFormatVersion; | 71 << kFileFormatVersion; |
63 mmap_.reset(); | 72 mmap_.reset(); |
64 return false; | 73 return false; |
65 } | 74 } |
66 resource_count_ = ptr[1]; | 75 resource_count_ = ptr[1]; |
67 | 76 |
68 // Sanity check the file. | 77 // Sanity check the file. |
(...skipping 13 matching lines...) Expand all Loading... |
82 LOG(ERROR) << "Entry #" << i << " in data pack points off end of file. " | 91 LOG(ERROR) << "Entry #" << i << " in data pack points off end of file. " |
83 << "Was the file corrupted?"; | 92 << "Was the file corrupted?"; |
84 mmap_.reset(); | 93 mmap_.reset(); |
85 return false; | 94 return false; |
86 } | 95 } |
87 } | 96 } |
88 | 97 |
89 return true; | 98 return true; |
90 } | 99 } |
91 | 100 |
92 bool DataPack::GetStringPiece(uint32_t resource_id, StringPiece* data) { | 101 bool DataPack::GetStringPiece(uint32 resource_id, StringPiece* data) { |
93 // It won't be hard to make this endian-agnostic, but it's not worth | 102 // It won't be hard to make this endian-agnostic, but it's not worth |
94 // bothering to do right now. | 103 // bothering to do right now. |
95 #if defined(__BYTE_ORDER) | 104 #if defined(__BYTE_ORDER) |
96 // Linux check | 105 // Linux check |
97 COMPILE_ASSERT(__BYTE_ORDER == __LITTLE_ENDIAN, | 106 COMPILE_ASSERT(__BYTE_ORDER == __LITTLE_ENDIAN, |
98 datapack_assumes_little_endian); | 107 datapack_assumes_little_endian); |
99 #elif defined(__BIG_ENDIAN__) | 108 #elif defined(__BIG_ENDIAN__) |
100 // Mac check | 109 // Mac check |
101 #error DataPack assumes little endian | 110 #error DataPack assumes little endian |
102 #endif | 111 #endif |
103 | 112 |
104 DataPackEntry* target = reinterpret_cast<DataPackEntry*>( | 113 DataPackEntry* target = reinterpret_cast<DataPackEntry*>( |
105 bsearch(&resource_id, mmap_->data() + kHeaderLength, resource_count_, | 114 bsearch(&resource_id, mmap_->data() + kHeaderLength, resource_count_, |
106 sizeof(DataPackEntry), DataPackEntry::CompareById)); | 115 sizeof(DataPackEntry), DataPackEntry::CompareById)); |
107 if (!target) { | 116 if (!target) { |
108 LOG(ERROR) << "No resource found with id: " << resource_id; | |
109 return false; | 117 return false; |
110 } | 118 } |
111 | 119 |
112 data->set(mmap_->data() + target->file_offset, target->length); | 120 data->set(mmap_->data() + target->file_offset, target->length); |
113 return true; | 121 return true; |
114 } | 122 } |
115 | 123 |
116 RefCountedStaticMemory* DataPack::GetStaticMemory(uint32_t resource_id) { | 124 RefCountedStaticMemory* DataPack::GetStaticMemory(uint32 resource_id) { |
117 base::StringPiece piece; | 125 base::StringPiece piece; |
118 if (!GetStringPiece(resource_id, &piece)) | 126 if (!GetStringPiece(resource_id, &piece)) |
119 return NULL; | 127 return NULL; |
120 | 128 |
121 return new RefCountedStaticMemory( | 129 return new RefCountedStaticMemory( |
122 reinterpret_cast<const unsigned char*>(piece.data()), piece.length()); | 130 reinterpret_cast<const unsigned char*>(piece.data()), piece.length()); |
123 } | 131 } |
124 | 132 |
| 133 // static |
| 134 bool DataPack::WritePack(const FilePath& path, |
| 135 const std::map<uint32, StringPiece>& resources) { |
| 136 FILE* file = file_util::OpenFile(path, "wb"); |
| 137 if (!file) |
| 138 return false; |
| 139 |
| 140 if (fwrite(&kFileFormatVersion, 1, kWord, file) != kWord) { |
| 141 LOG(ERROR) << "Failed to write file version"; |
| 142 file_util::CloseFile(file); |
| 143 return false; |
| 144 } |
| 145 |
| 146 // Note: the python version of this function explicitly sorted keys, but |
| 147 // std::map is a sorted associative container, we shouldn't have to do that. |
| 148 uint32 entry_count = resources.size(); |
| 149 if (fwrite(&entry_count, 1, kWord, file) != kWord) { |
| 150 LOG(ERROR) << "Failed to write entry count"; |
| 151 file_util::CloseFile(file); |
| 152 return false; |
| 153 } |
| 154 |
| 155 // Each entry is 3 uint32s. |
| 156 uint32 index_length = entry_count * 3 * kWord; |
| 157 uint32 data_offset = kHeaderLength + index_length; |
| 158 for (std::map<uint32, StringPiece>::const_iterator it = resources.begin(); |
| 159 it != resources.end(); ++it) { |
| 160 if (fwrite(&it->first, 1, kWord, file) != kWord) { |
| 161 LOG(ERROR) << "Failed to write id for " << it->first; |
| 162 file_util::CloseFile(file); |
| 163 return false; |
| 164 } |
| 165 |
| 166 if (fwrite(&data_offset, 1, kWord, file) != kWord) { |
| 167 LOG(ERROR) << "Failed to write offset for " << it->first; |
| 168 file_util::CloseFile(file); |
| 169 return false; |
| 170 } |
| 171 |
| 172 uint32 len = it->second.length(); |
| 173 if (fwrite(&len, 1, kWord, file) != kWord) { |
| 174 LOG(ERROR) << "Failed to write length for " << it->first; |
| 175 file_util::CloseFile(file); |
| 176 return false; |
| 177 } |
| 178 |
| 179 data_offset += len; |
| 180 } |
| 181 |
| 182 for (std::map<uint32, StringPiece>::const_iterator it = resources.begin(); |
| 183 it != resources.end(); ++it) { |
| 184 if (fwrite(it->second.data(), it->second.length(), 1, file) != 1) { |
| 185 LOG(ERROR) << "Failed to write data for " << it->first; |
| 186 file_util::CloseFile(file); |
| 187 return false; |
| 188 } |
| 189 } |
| 190 |
| 191 file_util::CloseFile(file); |
| 192 |
| 193 return true; |
| 194 } |
| 195 |
125 } // namespace base | 196 } // namespace base |
OLD | NEW |