Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(313)

Side by Side Diff: ui/base/resource/data_pack.cc

Issue 7604012: Remove the length field from the index entries in data pack files. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix write Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 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/memory/ref_counted_memory.h" 11 #include "base/memory/ref_counted_memory.h"
12 #include "base/metrics/histogram.h" 12 #include "base/metrics/histogram.h"
13 #include "base/string_piece.h" 13 #include "base/string_piece.h"
14 14
15 // For details of the file layout, see 15 // For details of the file layout, see
16 // http://dev.chromium.org/developers/design-documents/linuxresourcesandlocalize dstrings 16 // http://dev.chromium.org/developers/design-documents/linuxresourcesandlocalize dstrings
17 17
18 namespace { 18 namespace {
19 19
20 static const uint32 kFileFormatVersion = 2; 20 static const uint32 kFileFormatVersion = 3;
21 // Length of file header: version and entry count. 21 // Length of file header: version and entry count.
22 static const size_t kHeaderLength = 2 * sizeof(uint32); 22 static const size_t kHeaderLength = 2 * sizeof(uint32);
23 23
24 #pragma pack(push,2) 24 #pragma pack(push,2)
25 struct DataPackEntry { 25 struct DataPackEntry {
26 uint16 resource_id; 26 uint16 resource_id;
27 uint32 file_offset; 27 uint32 file_offset;
28 uint32 length;
29 28
30 static int CompareById(const void* void_key, const void* void_entry) { 29 static int CompareById(const void* void_key, const void* void_entry) {
31 uint16 key = *reinterpret_cast<const uint16*>(void_key); 30 uint16 key = *reinterpret_cast<const uint16*>(void_key);
32 const DataPackEntry* entry = 31 const DataPackEntry* entry =
33 reinterpret_cast<const DataPackEntry*>(void_entry); 32 reinterpret_cast<const DataPackEntry*>(void_entry);
34 if (key < entry->resource_id) { 33 if (key < entry->resource_id) {
35 return -1; 34 return -1;
36 } else if (key > entry->resource_id) { 35 } else if (key > entry->resource_id) {
37 return 1; 36 return 1;
38 } else { 37 } else {
39 return 0; 38 return 0;
40 } 39 }
41 } 40 }
42 }; 41 };
43 #pragma pack(pop) 42 #pragma pack(pop)
44 43
45 COMPILE_ASSERT(sizeof(DataPackEntry) == 10, size_of_header_must_be_ten); 44 COMPILE_ASSERT(sizeof(DataPackEntry) == 6, size_of_entry_must_be_six);
46 45
47 // We're crashing when trying to load a pak file on Windows. Add some error 46 // We're crashing when trying to load a pak file on Windows. Add some error
48 // codes for logging. 47 // codes for logging.
49 // http://crbug.com/58056 48 // http://crbug.com/58056
50 enum LoadErrors { 49 enum LoadErrors {
51 INIT_FAILED = 1, 50 INIT_FAILED = 1,
52 BAD_VERSION, 51 BAD_VERSION,
53 INDEX_TRUNCATED, 52 INDEX_TRUNCATED,
54 ENTRY_NOT_FOUND, 53 ENTRY_NOT_FOUND,
55 54
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 // 1) Check we have enough entries. 93 // 1) Check we have enough entries.
95 if (kHeaderLength + resource_count_ * sizeof(DataPackEntry) > 94 if (kHeaderLength + resource_count_ * sizeof(DataPackEntry) >
96 mmap_->length()) { 95 mmap_->length()) {
97 LOG(ERROR) << "Data pack file corruption: too short for number of " 96 LOG(ERROR) << "Data pack file corruption: too short for number of "
98 "entries specified."; 97 "entries specified.";
99 UMA_HISTOGRAM_ENUMERATION("DataPack.Load", INDEX_TRUNCATED, 98 UMA_HISTOGRAM_ENUMERATION("DataPack.Load", INDEX_TRUNCATED,
100 LOAD_ERRORS_COUNT); 99 LOAD_ERRORS_COUNT);
101 mmap_.reset(); 100 mmap_.reset();
102 return false; 101 return false;
103 } 102 }
104 // 2) Verify the entries are within the appropriate bounds. 103 // 2) Verify the entries are within the appropriate bounds. There's an extra
105 for (size_t i = 0; i < resource_count_; ++i) { 104 // entry after the last item which gives us the length of the last item.
105 for (size_t i = 0; i < resource_count_ + 1; ++i) {
106 const DataPackEntry* entry = reinterpret_cast<const DataPackEntry*>( 106 const DataPackEntry* entry = reinterpret_cast<const DataPackEntry*>(
107 mmap_->data() + kHeaderLength + (i * sizeof(DataPackEntry))); 107 mmap_->data() + kHeaderLength + (i * sizeof(DataPackEntry)));
108 if (entry->file_offset + entry->length > mmap_->length()) { 108 if (entry->file_offset > mmap_->length()) {
109 LOG(ERROR) << "Entry #" << i << " in data pack points off end of file. " 109 LOG(ERROR) << "Entry #" << i << " in data pack points off end of file. "
110 << "Was the file corrupted?"; 110 << "Was the file corrupted?";
111 UMA_HISTOGRAM_ENUMERATION("DataPack.Load", ENTRY_NOT_FOUND, 111 UMA_HISTOGRAM_ENUMERATION("DataPack.Load", ENTRY_NOT_FOUND,
112 LOAD_ERRORS_COUNT); 112 LOAD_ERRORS_COUNT);
113 mmap_.reset(); 113 mmap_.reset();
114 return false; 114 return false;
115 } 115 }
116 } 116 }
117 117
118 return true; 118 return true;
119 } 119 }
120 120
121 bool DataPack::GetStringPiece(uint16 resource_id, 121 bool DataPack::GetStringPiece(uint16 resource_id,
122 base::StringPiece* data) const { 122 base::StringPiece* data) const {
123 // It won't be hard to make this endian-agnostic, but it's not worth 123 // It won't be hard to make this endian-agnostic, but it's not worth
124 // bothering to do right now. 124 // bothering to do right now.
125 #if defined(__BYTE_ORDER) 125 #if defined(__BYTE_ORDER)
126 // Linux check 126 // Linux check
127 COMPILE_ASSERT(__BYTE_ORDER == __LITTLE_ENDIAN, 127 COMPILE_ASSERT(__BYTE_ORDER == __LITTLE_ENDIAN,
128 datapack_assumes_little_endian); 128 datapack_assumes_little_endian);
129 #elif defined(__BIG_ENDIAN__) 129 #elif defined(__BIG_ENDIAN__)
130 // Mac check 130 // Mac check
131 #error DataPack assumes little endian 131 #error DataPack assumes little endian
132 #endif 132 #endif
133 133
134 DataPackEntry* target = reinterpret_cast<DataPackEntry*>( 134 const DataPackEntry* target = reinterpret_cast<const DataPackEntry*>(
135 bsearch(&resource_id, mmap_->data() + kHeaderLength, resource_count_, 135 bsearch(&resource_id, mmap_->data() + kHeaderLength, resource_count_,
136 sizeof(DataPackEntry), DataPackEntry::CompareById)); 136 sizeof(DataPackEntry), DataPackEntry::CompareById));
137 if (!target) { 137 if (!target) {
138 return false; 138 return false;
139 } 139 }
140 140
141 data->set(mmap_->data() + target->file_offset, target->length); 141 const DataPackEntry* next_entry = target + 1;
142 size_t length = next_entry->file_offset - target->file_offset;
143
144 data->set(mmap_->data() + target->file_offset, length);
142 return true; 145 return true;
143 } 146 }
144 147
145 RefCountedStaticMemory* DataPack::GetStaticMemory(uint16 resource_id) const { 148 RefCountedStaticMemory* DataPack::GetStaticMemory(uint16 resource_id) const {
146 base::StringPiece piece; 149 base::StringPiece piece;
147 if (!GetStringPiece(resource_id, &piece)) 150 if (!GetStringPiece(resource_id, &piece))
148 return NULL; 151 return NULL;
149 152
150 return new RefCountedStaticMemory( 153 return new RefCountedStaticMemory(
151 reinterpret_cast<const unsigned char*>(piece.data()), piece.length()); 154 reinterpret_cast<const unsigned char*>(piece.data()), piece.length());
(...skipping 14 matching lines...) Expand all
166 169
167 // Note: the python version of this function explicitly sorted keys, but 170 // Note: the python version of this function explicitly sorted keys, but
168 // std::map is a sorted associative container, we shouldn't have to do that. 171 // std::map is a sorted associative container, we shouldn't have to do that.
169 uint32 entry_count = resources.size(); 172 uint32 entry_count = resources.size();
170 if (fwrite(&entry_count, sizeof(entry_count), 1, file) != 1) { 173 if (fwrite(&entry_count, sizeof(entry_count), 1, file) != 1) {
171 LOG(ERROR) << "Failed to write entry count"; 174 LOG(ERROR) << "Failed to write entry count";
172 file_util::CloseFile(file); 175 file_util::CloseFile(file);
173 return false; 176 return false;
174 } 177 }
175 178
176 // Each entry is 1 uint16 + 2 uint32s. 179 // Each entry is a uint16 + a uint32. We have an extra entry after the last
177 uint32 index_length = entry_count * sizeof(DataPackEntry); 180 // item so we can compute the size of the list item.
181 uint32 index_length = (entry_count + 1) * sizeof(DataPackEntry);
178 uint32 data_offset = kHeaderLength + index_length; 182 uint32 data_offset = kHeaderLength + index_length;
179 for (std::map<uint16, base::StringPiece>::const_iterator it = 183 for (std::map<uint16, base::StringPiece>::const_iterator it =
180 resources.begin(); 184 resources.begin();
181 it != resources.end(); ++it) { 185 it != resources.end(); ++it) {
182 uint16 resource_id = it->first; 186 uint16 resource_id = it->first;
183 if (fwrite(&resource_id, sizeof(resource_id), 1, file) != 1) { 187 if (fwrite(&resource_id, sizeof(resource_id), 1, file) != 1) {
184 LOG(ERROR) << "Failed to write id for " << resource_id; 188 LOG(ERROR) << "Failed to write id for " << resource_id;
185 file_util::CloseFile(file); 189 file_util::CloseFile(file);
186 return false; 190 return false;
187 } 191 }
188 192
189 if (fwrite(&data_offset, sizeof(data_offset), 1, file) != 1) { 193 if (fwrite(&data_offset, sizeof(data_offset), 1, file) != 1) {
190 LOG(ERROR) << "Failed to write offset for " << resource_id; 194 LOG(ERROR) << "Failed to write offset for " << resource_id;
191 file_util::CloseFile(file); 195 file_util::CloseFile(file);
192 return false; 196 return false;
193 } 197 }
194 198
195 uint32 len = it->second.length(); 199 data_offset += it->second.length();
196 if (fwrite(&len, sizeof(len), 1, file) != 1) { 200 }
197 LOG(ERROR) << "Failed to write length for " << resource_id;
198 file_util::CloseFile(file);
199 return false;
200 }
201 201
202 data_offset += len; 202 // We place an extra entry after the last item that allows us to read the
203 // size of the last item.
204 uint16 resource_id = 0;
205 if (fwrite(&resource_id, sizeof(resource_id), 1, file) != 1) {
206 LOG(ERROR) << "Failed to write extra resource id.";
207 file_util::CloseFile(file);
208 return false;
209 }
210
211 if (fwrite(&data_offset, sizeof(data_offset), 1, file) != 1) {
212 LOG(ERROR) << "Failed to write extra offset.";
213 file_util::CloseFile(file);
214 return false;
203 } 215 }
204 216
205 for (std::map<uint16, base::StringPiece>::const_iterator it = 217 for (std::map<uint16, base::StringPiece>::const_iterator it =
206 resources.begin(); 218 resources.begin();
207 it != resources.end(); ++it) { 219 it != resources.end(); ++it) {
208 if (fwrite(it->second.data(), it->second.length(), 1, file) != 1) { 220 if (fwrite(it->second.data(), it->second.length(), 1, file) != 1) {
209 LOG(ERROR) << "Failed to write data for " << it->first; 221 LOG(ERROR) << "Failed to write data for " << it->first;
210 file_util::CloseFile(file); 222 file_util::CloseFile(file);
211 return false; 223 return false;
212 } 224 }
213 } 225 }
214 226
215 file_util::CloseFile(file); 227 file_util::CloseFile(file);
216 228
217 return true; 229 return true;
218 } 230 }
219 231
220 } // namespace ui 232 } // namespace ui
OLDNEW
« no previous file with comments | « tools/grit/grit/format/data_pack_unittest.py ('k') | ui/base/test/data/data_pack_unittest/sample.pak » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698