blob: 29a921c497c969783d503a3477d5c313bc8d6023 [file] [log] [blame]
Adam Lesinski1ab598f2015-08-14 14:26:04 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Adam Lesinskib54ef102016-10-21 13:38:42 -070017#include "unflatten/BinaryResourceParser.h"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070018
19#include <algorithm>
20#include <map>
21#include <string>
22
23#include "android-base/logging.h"
24#include "android-base/macros.h"
25#include "androidfw/ResourceTypes.h"
26#include "androidfw/TypeWrappers.h"
27
Adam Lesinski1ab598f2015-08-14 14:26:04 -070028#include "ResourceTable.h"
29#include "ResourceUtils.h"
30#include "ResourceValues.h"
31#include "Source.h"
32#include "ValueVisitor.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070033#include "unflatten/ResChunkPullParser.h"
34#include "util/Util.h"
35
Adam Lesinski1ab598f2015-08-14 14:26:04 -070036namespace aapt {
37
38using namespace android;
39
Adam Lesinski59e04c62016-02-04 15:59:23 -080040namespace {
41
Adam Lesinski1ab598f2015-08-14 14:26:04 -070042/*
43 * Visitor that converts a reference's resource ID to a resource name,
44 * given a mapping from resource ID to resource name.
45 */
46class ReferenceIdToNameVisitor : public ValueVisitor {
Adam Lesinskib54ef102016-10-21 13:38:42 -070047 public:
Adam Lesinskice5e56e2016-10-21 17:56:45 -070048 using ValueVisitor::Visit;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070049
Adam Lesinskib54ef102016-10-21 13:38:42 -070050 explicit ReferenceIdToNameVisitor(
51 const std::map<ResourceId, ResourceName>* mapping)
Adam Lesinskice5e56e2016-10-21 17:56:45 -070052 : mapping_(mapping) {
53 CHECK(mapping_ != nullptr);
Adam Lesinskib54ef102016-10-21 13:38:42 -070054 }
55
Adam Lesinskice5e56e2016-10-21 17:56:45 -070056 void Visit(Reference* reference) override {
57 if (!reference->id || !reference->id.value().is_valid()) {
Adam Lesinskib54ef102016-10-21 13:38:42 -070058 return;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070059 }
60
Adam Lesinskib54ef102016-10-21 13:38:42 -070061 ResourceId id = reference->id.value();
Adam Lesinskice5e56e2016-10-21 17:56:45 -070062 auto cache_iter = mapping_->find(id);
63 if (cache_iter != mapping_->end()) {
64 reference->name = cache_iter->second;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070065 }
Adam Lesinskib54ef102016-10-21 13:38:42 -070066 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -070067
68 private:
69 DISALLOW_COPY_AND_ASSIGN(ReferenceIdToNameVisitor);
70
71 const std::map<ResourceId, ResourceName>* mapping_;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070072};
73
Adam Lesinskib54ef102016-10-21 13:38:42 -070074} // namespace
Adam Lesinski59e04c62016-02-04 15:59:23 -080075
Adam Lesinskib54ef102016-10-21 13:38:42 -070076BinaryResourceParser::BinaryResourceParser(IAaptContext* context,
77 ResourceTable* table,
78 const Source& source,
79 const void* data, size_t len)
Adam Lesinskice5e56e2016-10-21 17:56:45 -070080 : context_(context),
81 table_(table),
82 source_(source),
83 data_(data),
84 data_len_(len) {}
Adam Lesinski1ab598f2015-08-14 14:26:04 -070085
Adam Lesinskice5e56e2016-10-21 17:56:45 -070086bool BinaryResourceParser::Parse() {
87 ResChunkPullParser parser(data_, data_len_);
Adam Lesinski1ab598f2015-08-14 14:26:04 -070088
Adam Lesinskib54ef102016-10-21 13:38:42 -070089 bool error = false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -070090 while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
91 if (parser.chunk()->type != android::RES_TABLE_TYPE) {
92 context_->GetDiagnostics()->Warn(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -070093 << "unknown chunk of type '"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070094 << (int)parser.chunk()->type << "'");
Adam Lesinskib54ef102016-10-21 13:38:42 -070095 continue;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070096 }
97
Adam Lesinskice5e56e2016-10-21 17:56:45 -070098 if (!ParseTable(parser.chunk())) {
Adam Lesinskib54ef102016-10-21 13:38:42 -070099 error = true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700100 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700101 }
102
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700103 if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
104 context_->GetDiagnostics()->Error(
105 DiagMessage(source_) << "corrupt resource table: " << parser.error());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700106 return false;
107 }
108 return !error;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700109}
110
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700111/**
Adam Lesinskib54ef102016-10-21 13:38:42 -0700112 * Parses the resource table, which contains all the packages, types, and
113 * entries.
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700114 */
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700115bool BinaryResourceParser::ParseTable(const ResChunk_header* chunk) {
116 const ResTable_header* table_header = ConvertTo<ResTable_header>(chunk);
117 if (!table_header) {
118 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700119 << "corrupt ResTable_header chunk");
120 return false;
121 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700122
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700123 ResChunkPullParser parser(GetChunkData(&table_header->header),
124 GetChunkDataLen(&table_header->header));
125 while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
126 switch (util::DeviceToHost16(parser.chunk()->type)) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700127 case android::RES_STRING_POOL_TYPE:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700128 if (value_pool_.getError() == NO_INIT) {
129 status_t err = value_pool_.setTo(
130 parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700131 if (err != NO_ERROR) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700132 context_->GetDiagnostics()->Error(
133 DiagMessage(source_) << "corrupt string pool in ResTable: "
134 << value_pool_.getError());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700135 return false;
136 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700137
Adam Lesinskib54ef102016-10-21 13:38:42 -0700138 // Reserve some space for the strings we are going to add.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700139 table_->string_pool.HintWillAdd(value_pool_.size(),
140 value_pool_.styleCount());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700141 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700142 context_->GetDiagnostics()->Warn(
143 DiagMessage(source_) << "unexpected string pool in ResTable");
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700144 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700145 break;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700146
Adam Lesinskib54ef102016-10-21 13:38:42 -0700147 case android::RES_TABLE_PACKAGE_TYPE:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700148 if (!ParsePackage(parser.chunk())) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700149 return false;
150 }
151 break;
152
153 default:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700154 context_->GetDiagnostics()->Warn(
155 DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700156 << "unexpected chunk type "
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700157 << (int)util::DeviceToHost16(parser.chunk()->type));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700158 break;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700159 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700160 }
161
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700162 if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
163 context_->GetDiagnostics()->Error(
164 DiagMessage(source_) << "corrupt resource table: " << parser.error());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700165 return false;
166 }
167 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700168}
169
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700170bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) {
171 const ResTable_package* package_header = ConvertTo<ResTable_package>(chunk);
172 if (!package_header) {
173 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700174 << "corrupt ResTable_package chunk");
175 return false;
176 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700177
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700178 uint32_t package_id = util::DeviceToHost32(package_header->id);
179 if (package_id > std::numeric_limits<uint8_t>::max()) {
180 context_->GetDiagnostics()->Error(
181 DiagMessage(source_) << "package ID is too big (" << package_id << ")");
Adam Lesinskib54ef102016-10-21 13:38:42 -0700182 return false;
183 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700184
Adam Lesinskib54ef102016-10-21 13:38:42 -0700185 // Extract the package name.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700186 size_t len = strnlen16((const char16_t*)package_header->name,
187 arraysize(package_header->name));
188 std::u16string package_name;
189 package_name.resize(len);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700190 for (size_t i = 0; i < len; i++) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700191 package_name[i] = util::DeviceToHost16(package_header->name[i]);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700192 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700193
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700194 ResourceTablePackage* package = table_->CreatePackage(
195 util::Utf16ToUtf8(package_name), static_cast<uint8_t>(package_id));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700196 if (!package) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700197 context_->GetDiagnostics()->Error(
198 DiagMessage(source_) << "incompatible package '" << package_name
199 << "' with ID " << package_id);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700200 return false;
201 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700202
Adam Lesinskib54ef102016-10-21 13:38:42 -0700203 // There can be multiple packages in a table, so
204 // clear the type and key pool in case they were set from a previous package.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700205 type_pool_.uninit();
206 key_pool_.uninit();
Adam Lesinskie352b992015-11-16 11:59:14 -0800207
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700208 ResChunkPullParser parser(GetChunkData(&package_header->header),
209 GetChunkDataLen(&package_header->header));
210 while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
211 switch (util::DeviceToHost16(parser.chunk()->type)) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700212 case android::RES_STRING_POOL_TYPE:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700213 if (type_pool_.getError() == NO_INIT) {
214 status_t err = type_pool_.setTo(
215 parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700216 if (err != NO_ERROR) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700217 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700218 << "corrupt type string pool in "
219 << "ResTable_package: "
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700220 << type_pool_.getError());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700221 return false;
222 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700223 } else if (key_pool_.getError() == NO_INIT) {
224 status_t err = key_pool_.setTo(
225 parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700226 if (err != NO_ERROR) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700227 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700228 << "corrupt key string pool in "
229 << "ResTable_package: "
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700230 << key_pool_.getError());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700231 return false;
232 }
233 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700234 context_->GetDiagnostics()->Warn(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700235 << "unexpected string pool");
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700236 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700237 break;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700238
Adam Lesinskib54ef102016-10-21 13:38:42 -0700239 case android::RES_TABLE_TYPE_SPEC_TYPE:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700240 if (!ParseTypeSpec(parser.chunk())) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700241 return false;
242 }
243 break;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700244
Adam Lesinskib54ef102016-10-21 13:38:42 -0700245 case android::RES_TABLE_TYPE_TYPE:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700246 if (!ParseType(package, parser.chunk())) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700247 return false;
248 }
249 break;
250
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800251 case android::RES_TABLE_LIBRARY_TYPE:
252 if (!ParseLibrary(parser.chunk())) {
253 return false;
254 }
255 break;
256
Adam Lesinskib54ef102016-10-21 13:38:42 -0700257 default:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700258 context_->GetDiagnostics()->Warn(
259 DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700260 << "unexpected chunk type "
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700261 << (int)util::DeviceToHost16(parser.chunk()->type));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700262 break;
263 }
264 }
265
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700266 if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
267 context_->GetDiagnostics()->Error(
268 DiagMessage(source_) << "corrupt ResTable_package: " << parser.error());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700269 return false;
270 }
271
272 // Now go through the table and change local resource ID references to
273 // symbolic references.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700274 ReferenceIdToNameVisitor visitor(&id_index_);
275 VisitAllValuesInTable(table_, &visitor);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700276 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700277}
278
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700279bool BinaryResourceParser::ParseTypeSpec(const ResChunk_header* chunk) {
280 if (type_pool_.getError() != NO_ERROR) {
281 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700282 << "missing type string pool");
283 return false;
284 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700285
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700286 const ResTable_typeSpec* type_spec = ConvertTo<ResTable_typeSpec>(chunk);
287 if (!type_spec) {
288 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700289 << "corrupt ResTable_typeSpec chunk");
290 return false;
291 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700292
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700293 if (type_spec->id == 0) {
294 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700295 << "ResTable_typeSpec has invalid id: "
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700296 << type_spec->id);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700297 return false;
298 }
299 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700300}
301
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700302bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700303 const ResChunk_header* chunk) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700304 if (type_pool_.getError() != NO_ERROR) {
305 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700306 << "missing type string pool");
307 return false;
308 }
309
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700310 if (key_pool_.getError() != NO_ERROR) {
311 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700312 << "missing key string pool");
313 return false;
314 }
315
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700316 const ResTable_type* type = ConvertTo<ResTable_type>(chunk);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700317 if (!type) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700318 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700319 << "corrupt ResTable_type chunk");
320 return false;
321 }
322
323 if (type->id == 0) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700324 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700325 << "ResTable_type has invalid id: "
326 << (int)type->id);
327 return false;
328 }
329
330 ConfigDescription config;
331 config.copyFromDtoH(type->config);
332
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700333 const std::string type_str = util::GetString(type_pool_, type->id - 1);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700334
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700335 const ResourceType* parsed_type = ParseResourceType(type_str);
336 if (!parsed_type) {
337 context_->GetDiagnostics()->Error(
338 DiagMessage(source_) << "invalid type name '" << type_str
Adam Lesinskib54ef102016-10-21 13:38:42 -0700339 << "' for type with ID " << (int)type->id);
340 return false;
341 }
342
343 TypeVariant tv(type);
344 for (auto it = tv.beginEntries(); it != tv.endEntries(); ++it) {
345 const ResTable_entry* entry = *it;
346 if (!entry) {
347 continue;
348 }
349
350 const ResourceName name(
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700351 package->name, *parsed_type,
352 util::GetString(key_pool_, util::DeviceToHost32(entry->key.index)));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700353
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700354 const ResourceId res_id(package->id.value(), type->id,
355 static_cast<uint16_t>(it.index()));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700356
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700357 std::unique_ptr<Value> resource_value;
Adam Lesinskib54ef102016-10-21 13:38:42 -0700358 if (entry->flags & ResTable_entry::FLAG_COMPLEX) {
359 const ResTable_map_entry* mapEntry =
360 static_cast<const ResTable_map_entry*>(entry);
361
362 // TODO(adamlesinski): Check that the entry count is valid.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700363 resource_value = ParseMapEntry(name, config, mapEntry);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700364 } else {
365 const Res_value* value =
366 (const Res_value*)((const uint8_t*)entry +
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700367 util::DeviceToHost32(entry->size));
368 resource_value = ParseValue(name, config, value, entry->flags);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700369 }
370
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700371 if (!resource_value) {
372 context_->GetDiagnostics()->Error(
373 DiagMessage(source_) << "failed to parse value for resource " << name
374 << " (" << res_id << ") with configuration '"
Adam Lesinskib54ef102016-10-21 13:38:42 -0700375 << config << "'");
376 return false;
377 }
378
Pierre Lecesne2599aa42017-02-01 22:47:03 +0000379 if (!table_->AddResourceAllowMangled(name, res_id, config, {}, std::move(resource_value),
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700380 context_->GetDiagnostics())) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700381 return false;
382 }
383
384 if ((entry->flags & ResTable_entry::FLAG_PUBLIC) != 0) {
385 Symbol symbol;
386 symbol.state = SymbolState::kPublic;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700387 symbol.source = source_.WithLine(0);
388 if (!table_->SetSymbolStateAllowMangled(name, res_id, symbol,
389 context_->GetDiagnostics())) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700390 return false;
Adam Lesinskib54ef102016-10-21 13:38:42 -0700391 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700392 }
393
Adam Lesinskib54ef102016-10-21 13:38:42 -0700394 // Add this resource name->id mapping to the index so
395 // that we can resolve all ID references to name references.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700396 auto cache_iter = id_index_.find(res_id);
397 if (cache_iter == id_index_.end()) {
398 id_index_.insert({res_id, name});
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700399 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700400 }
401 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700402}
403
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800404bool BinaryResourceParser::ParseLibrary(const ResChunk_header* chunk) {
405 DynamicRefTable dynamic_ref_table;
406 if (dynamic_ref_table.load(reinterpret_cast<const ResTable_lib_header*>(chunk)) != NO_ERROR) {
407 return false;
408 }
409
410 const KeyedVector<String16, uint8_t>& entries = dynamic_ref_table.entries();
411 const size_t count = entries.size();
412 for (size_t i = 0; i < count; i++) {
413 table_->included_packages_[entries.valueAt(i)] =
414 util::Utf16ToUtf8(StringPiece16(entries.keyAt(i).string()));
415 }
416 return true;
417}
418
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700419std::unique_ptr<Item> BinaryResourceParser::ParseValue(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700420 const ResourceNameRef& name, const ConfigDescription& config,
421 const Res_value* value, uint16_t flags) {
422 if (name.type == ResourceType::kId) {
423 return util::make_unique<Id>();
424 }
425
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700426 const uint32_t data = util::DeviceToHost32(value->data);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700427
428 if (value->dataType == Res_value::TYPE_STRING) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700429 const std::string str = util::GetString(value_pool_, data);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700430
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700431 const ResStringPool_span* spans = value_pool_.styleAt(data);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700432
433 // Check if the string has a valid style associated with it.
434 if (spans != nullptr && spans->name.index != ResStringPool_span::END) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700435 StyleString style_str = {str};
Adam Lesinskib54ef102016-10-21 13:38:42 -0700436 while (spans->name.index != ResStringPool_span::END) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700437 style_str.spans.push_back(
438 Span{util::GetString(value_pool_, spans->name.index),
Adam Lesinskib54ef102016-10-21 13:38:42 -0700439 spans->firstChar, spans->lastChar});
440 spans++;
441 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700442 return util::make_unique<StyledString>(table_->string_pool.MakeRef(
443 style_str,
Adam Lesinskib54ef102016-10-21 13:38:42 -0700444 StringPool::Context(StringPool::Context::kStylePriority, config)));
445 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700446 if (name.type != ResourceType::kString && util::StartsWith(str, "res/")) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700447 // This must be a FileReference.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700448 return util::make_unique<FileReference>(table_->string_pool.MakeRef(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700449 str,
450 StringPool::Context(StringPool::Context::kHighPriority, config)));
451 }
452
453 // There are no styles associated with this string, so treat it as
454 // a simple string.
455 return util::make_unique<String>(
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700456 table_->string_pool.MakeRef(str, StringPool::Context(config)));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700457 }
458 }
459
460 if (value->dataType == Res_value::TYPE_REFERENCE ||
461 value->dataType == Res_value::TYPE_ATTRIBUTE) {
462 const Reference::Type type = (value->dataType == Res_value::TYPE_REFERENCE)
463 ? Reference::Type::kResource
464 : Reference::Type::kAttribute;
465
466 if (data == 0) {
467 // A reference of 0, must be the magic @null reference.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700468 Res_value null_type = {};
469 null_type.dataType = Res_value::TYPE_REFERENCE;
470 return util::make_unique<BinaryPrimitive>(null_type);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700471 }
472
Adam Lesinskib54ef102016-10-21 13:38:42 -0700473 // This is a normal reference.
474 return util::make_unique<Reference>(data, type);
475 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700476
Adam Lesinskib54ef102016-10-21 13:38:42 -0700477 // Treat this as a raw binary primitive.
478 return util::make_unique<BinaryPrimitive>(*value);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700479}
480
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700481std::unique_ptr<Value> BinaryResourceParser::ParseMapEntry(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700482 const ResourceNameRef& name, const ConfigDescription& config,
483 const ResTable_map_entry* map) {
484 switch (name.type) {
485 case ResourceType::kStyle:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700486 return ParseStyle(name, config, map);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700487 case ResourceType::kAttrPrivate:
488 // fallthrough
489 case ResourceType::kAttr:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700490 return ParseAttr(name, config, map);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700491 case ResourceType::kArray:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700492 return ParseArray(name, config, map);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700493 case ResourceType::kPlurals:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700494 return ParsePlural(name, config, map);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700495 default:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700496 LOG(FATAL) << "unknown map type";
Adam Lesinskib54ef102016-10-21 13:38:42 -0700497 break;
498 }
499 return {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700500}
501
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700502std::unique_ptr<Style> BinaryResourceParser::ParseStyle(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700503 const ResourceNameRef& name, const ConfigDescription& config,
504 const ResTable_map_entry* map) {
505 std::unique_ptr<Style> style = util::make_unique<Style>();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700506 if (util::DeviceToHost32(map->parent.ident) != 0) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700507 // The parent is a regular reference to a resource.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700508 style->parent = Reference(util::DeviceToHost32(map->parent.ident));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700509 }
510
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700511 for (const ResTable_map& map_entry : map) {
512 if (Res_INTERNALID(util::DeviceToHost32(map_entry.name.ident))) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700513 continue;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700514 }
515
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700516 Style::Entry style_entry;
517 style_entry.key = Reference(util::DeviceToHost32(map_entry.name.ident));
518 style_entry.value = ParseValue(name, config, &map_entry.value, 0);
519 if (!style_entry.value) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700520 return {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700521 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700522 style->entries.push_back(std::move(style_entry));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700523 }
524 return style;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700525}
526
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700527std::unique_ptr<Attribute> BinaryResourceParser::ParseAttr(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700528 const ResourceNameRef& name, const ConfigDescription& config,
529 const ResTable_map_entry* map) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700530 const bool is_weak =
531 (util::DeviceToHost16(map->flags) & ResTable_entry::FLAG_WEAK) != 0;
532 std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(is_weak);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700533
Adam Lesinskib54ef102016-10-21 13:38:42 -0700534 // First we must discover what type of attribute this is. Find the type mask.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700535 auto type_mask_iter =
Adam Lesinskib54ef102016-10-21 13:38:42 -0700536 std::find_if(begin(map), end(map), [](const ResTable_map& entry) -> bool {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700537 return util::DeviceToHost32(entry.name.ident) ==
Adam Lesinskib54ef102016-10-21 13:38:42 -0700538 ResTable_map::ATTR_TYPE;
539 });
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700540
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700541 if (type_mask_iter != end(map)) {
542 attr->type_mask = util::DeviceToHost32(type_mask_iter->value.data);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700543 }
544
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700545 for (const ResTable_map& map_entry : map) {
546 if (Res_INTERNALID(util::DeviceToHost32(map_entry.name.ident))) {
547 switch (util::DeviceToHost32(map_entry.name.ident)) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700548 case ResTable_map::ATTR_MIN:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700549 attr->min_int = static_cast<int32_t>(map_entry.value.data);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700550 break;
551 case ResTable_map::ATTR_MAX:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700552 attr->max_int = static_cast<int32_t>(map_entry.value.data);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700553 break;
554 }
555 continue;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700556 }
557
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700558 if (attr->type_mask &
559 (ResTable_map::TYPE_ENUM | ResTable_map::TYPE_FLAGS)) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700560 Attribute::Symbol symbol;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700561 symbol.value = util::DeviceToHost32(map_entry.value.data);
562 symbol.symbol = Reference(util::DeviceToHost32(map_entry.name.ident));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700563 attr->symbols.push_back(std::move(symbol));
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700564 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700565 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700566
Adam Lesinskib54ef102016-10-21 13:38:42 -0700567 // TODO(adamlesinski): Find i80n, attributes.
568 return attr;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700569}
570
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700571std::unique_ptr<Array> BinaryResourceParser::ParseArray(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700572 const ResourceNameRef& name, const ConfigDescription& config,
573 const ResTable_map_entry* map) {
574 std::unique_ptr<Array> array = util::make_unique<Array>();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700575 for (const ResTable_map& map_entry : map) {
576 array->items.push_back(ParseValue(name, config, &map_entry.value, 0));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700577 }
578 return array;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700579}
580
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700581std::unique_ptr<Plural> BinaryResourceParser::ParsePlural(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700582 const ResourceNameRef& name, const ConfigDescription& config,
583 const ResTable_map_entry* map) {
584 std::unique_ptr<Plural> plural = util::make_unique<Plural>();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700585 for (const ResTable_map& map_entry : map) {
586 std::unique_ptr<Item> item = ParseValue(name, config, &map_entry.value, 0);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700587 if (!item) {
588 return {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700589 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700590
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700591 switch (util::DeviceToHost32(map_entry.name.ident)) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700592 case ResTable_map::ATTR_ZERO:
593 plural->values[Plural::Zero] = std::move(item);
594 break;
595 case ResTable_map::ATTR_ONE:
596 plural->values[Plural::One] = std::move(item);
597 break;
598 case ResTable_map::ATTR_TWO:
599 plural->values[Plural::Two] = std::move(item);
600 break;
601 case ResTable_map::ATTR_FEW:
602 plural->values[Plural::Few] = std::move(item);
603 break;
604 case ResTable_map::ATTR_MANY:
605 plural->values[Plural::Many] = std::move(item);
606 break;
607 case ResTable_map::ATTR_OTHER:
608 plural->values[Plural::Other] = std::move(item);
609 break;
610 }
611 }
612 return plural;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700613}
614
Adam Lesinskib54ef102016-10-21 13:38:42 -0700615} // namespace aapt