blob: 7098fe9f7cb6ec50be3fa904473d245d24c8730f [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
251 default:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700252 context_->GetDiagnostics()->Warn(
253 DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700254 << "unexpected chunk type "
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700255 << (int)util::DeviceToHost16(parser.chunk()->type));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700256 break;
257 }
258 }
259
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700260 if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
261 context_->GetDiagnostics()->Error(
262 DiagMessage(source_) << "corrupt ResTable_package: " << parser.error());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700263 return false;
264 }
265
266 // Now go through the table and change local resource ID references to
267 // symbolic references.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700268 ReferenceIdToNameVisitor visitor(&id_index_);
269 VisitAllValuesInTable(table_, &visitor);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700270 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700271}
272
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700273bool BinaryResourceParser::ParseTypeSpec(const ResChunk_header* chunk) {
274 if (type_pool_.getError() != NO_ERROR) {
275 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700276 << "missing type string pool");
277 return false;
278 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700279
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700280 const ResTable_typeSpec* type_spec = ConvertTo<ResTable_typeSpec>(chunk);
281 if (!type_spec) {
282 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700283 << "corrupt ResTable_typeSpec chunk");
284 return false;
285 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700286
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700287 if (type_spec->id == 0) {
288 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700289 << "ResTable_typeSpec has invalid id: "
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700290 << type_spec->id);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700291 return false;
292 }
293 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700294}
295
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700296bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700297 const ResChunk_header* chunk) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700298 if (type_pool_.getError() != NO_ERROR) {
299 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700300 << "missing type string pool");
301 return false;
302 }
303
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700304 if (key_pool_.getError() != NO_ERROR) {
305 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700306 << "missing key string pool");
307 return false;
308 }
309
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700310 const ResTable_type* type = ConvertTo<ResTable_type>(chunk);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700311 if (!type) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700312 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700313 << "corrupt ResTable_type chunk");
314 return false;
315 }
316
317 if (type->id == 0) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700318 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700319 << "ResTable_type has invalid id: "
320 << (int)type->id);
321 return false;
322 }
323
324 ConfigDescription config;
325 config.copyFromDtoH(type->config);
326
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700327 const std::string type_str = util::GetString(type_pool_, type->id - 1);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700328
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700329 const ResourceType* parsed_type = ParseResourceType(type_str);
330 if (!parsed_type) {
331 context_->GetDiagnostics()->Error(
332 DiagMessage(source_) << "invalid type name '" << type_str
Adam Lesinskib54ef102016-10-21 13:38:42 -0700333 << "' for type with ID " << (int)type->id);
334 return false;
335 }
336
337 TypeVariant tv(type);
338 for (auto it = tv.beginEntries(); it != tv.endEntries(); ++it) {
339 const ResTable_entry* entry = *it;
340 if (!entry) {
341 continue;
342 }
343
344 const ResourceName name(
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700345 package->name, *parsed_type,
346 util::GetString(key_pool_, util::DeviceToHost32(entry->key.index)));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700347
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700348 const ResourceId res_id(package->id.value(), type->id,
349 static_cast<uint16_t>(it.index()));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700350
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700351 std::unique_ptr<Value> resource_value;
Adam Lesinskib54ef102016-10-21 13:38:42 -0700352 if (entry->flags & ResTable_entry::FLAG_COMPLEX) {
353 const ResTable_map_entry* mapEntry =
354 static_cast<const ResTable_map_entry*>(entry);
355
356 // TODO(adamlesinski): Check that the entry count is valid.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700357 resource_value = ParseMapEntry(name, config, mapEntry);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700358 } else {
359 const Res_value* value =
360 (const Res_value*)((const uint8_t*)entry +
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700361 util::DeviceToHost32(entry->size));
362 resource_value = ParseValue(name, config, value, entry->flags);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700363 }
364
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700365 if (!resource_value) {
366 context_->GetDiagnostics()->Error(
367 DiagMessage(source_) << "failed to parse value for resource " << name
368 << " (" << res_id << ") with configuration '"
Adam Lesinskib54ef102016-10-21 13:38:42 -0700369 << config << "'");
370 return false;
371 }
372
Pierre Lecesne2599aa42017-02-01 22:47:03 +0000373 if (!table_->AddResourceAllowMangled(name, res_id, config, {}, std::move(resource_value),
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700374 context_->GetDiagnostics())) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700375 return false;
376 }
377
378 if ((entry->flags & ResTable_entry::FLAG_PUBLIC) != 0) {
379 Symbol symbol;
380 symbol.state = SymbolState::kPublic;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700381 symbol.source = source_.WithLine(0);
382 if (!table_->SetSymbolStateAllowMangled(name, res_id, symbol,
383 context_->GetDiagnostics())) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700384 return false;
Adam Lesinskib54ef102016-10-21 13:38:42 -0700385 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700386 }
387
Adam Lesinskib54ef102016-10-21 13:38:42 -0700388 // Add this resource name->id mapping to the index so
389 // that we can resolve all ID references to name references.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700390 auto cache_iter = id_index_.find(res_id);
391 if (cache_iter == id_index_.end()) {
392 id_index_.insert({res_id, name});
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700393 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700394 }
395 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700396}
397
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700398std::unique_ptr<Item> BinaryResourceParser::ParseValue(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700399 const ResourceNameRef& name, const ConfigDescription& config,
400 const Res_value* value, uint16_t flags) {
401 if (name.type == ResourceType::kId) {
402 return util::make_unique<Id>();
403 }
404
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700405 const uint32_t data = util::DeviceToHost32(value->data);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700406
407 if (value->dataType == Res_value::TYPE_STRING) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700408 const std::string str = util::GetString(value_pool_, data);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700409
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700410 const ResStringPool_span* spans = value_pool_.styleAt(data);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700411
412 // Check if the string has a valid style associated with it.
413 if (spans != nullptr && spans->name.index != ResStringPool_span::END) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700414 StyleString style_str = {str};
Adam Lesinskib54ef102016-10-21 13:38:42 -0700415 while (spans->name.index != ResStringPool_span::END) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700416 style_str.spans.push_back(
417 Span{util::GetString(value_pool_, spans->name.index),
Adam Lesinskib54ef102016-10-21 13:38:42 -0700418 spans->firstChar, spans->lastChar});
419 spans++;
420 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700421 return util::make_unique<StyledString>(table_->string_pool.MakeRef(
422 style_str,
Adam Lesinskib54ef102016-10-21 13:38:42 -0700423 StringPool::Context(StringPool::Context::kStylePriority, config)));
424 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700425 if (name.type != ResourceType::kString && util::StartsWith(str, "res/")) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700426 // This must be a FileReference.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700427 return util::make_unique<FileReference>(table_->string_pool.MakeRef(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700428 str,
429 StringPool::Context(StringPool::Context::kHighPriority, config)));
430 }
431
432 // There are no styles associated with this string, so treat it as
433 // a simple string.
434 return util::make_unique<String>(
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700435 table_->string_pool.MakeRef(str, StringPool::Context(config)));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700436 }
437 }
438
439 if (value->dataType == Res_value::TYPE_REFERENCE ||
440 value->dataType == Res_value::TYPE_ATTRIBUTE) {
441 const Reference::Type type = (value->dataType == Res_value::TYPE_REFERENCE)
442 ? Reference::Type::kResource
443 : Reference::Type::kAttribute;
444
445 if (data == 0) {
446 // A reference of 0, must be the magic @null reference.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700447 Res_value null_type = {};
448 null_type.dataType = Res_value::TYPE_REFERENCE;
449 return util::make_unique<BinaryPrimitive>(null_type);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700450 }
451
Adam Lesinskib54ef102016-10-21 13:38:42 -0700452 // This is a normal reference.
453 return util::make_unique<Reference>(data, type);
454 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700455
Adam Lesinskib54ef102016-10-21 13:38:42 -0700456 // Treat this as a raw binary primitive.
457 return util::make_unique<BinaryPrimitive>(*value);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700458}
459
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700460std::unique_ptr<Value> BinaryResourceParser::ParseMapEntry(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700461 const ResourceNameRef& name, const ConfigDescription& config,
462 const ResTable_map_entry* map) {
463 switch (name.type) {
464 case ResourceType::kStyle:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700465 return ParseStyle(name, config, map);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700466 case ResourceType::kAttrPrivate:
467 // fallthrough
468 case ResourceType::kAttr:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700469 return ParseAttr(name, config, map);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700470 case ResourceType::kArray:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700471 return ParseArray(name, config, map);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700472 case ResourceType::kPlurals:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700473 return ParsePlural(name, config, map);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700474 default:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700475 LOG(FATAL) << "unknown map type";
Adam Lesinskib54ef102016-10-21 13:38:42 -0700476 break;
477 }
478 return {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700479}
480
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700481std::unique_ptr<Style> BinaryResourceParser::ParseStyle(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700482 const ResourceNameRef& name, const ConfigDescription& config,
483 const ResTable_map_entry* map) {
484 std::unique_ptr<Style> style = util::make_unique<Style>();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700485 if (util::DeviceToHost32(map->parent.ident) != 0) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700486 // The parent is a regular reference to a resource.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700487 style->parent = Reference(util::DeviceToHost32(map->parent.ident));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700488 }
489
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700490 for (const ResTable_map& map_entry : map) {
491 if (Res_INTERNALID(util::DeviceToHost32(map_entry.name.ident))) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700492 continue;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700493 }
494
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700495 Style::Entry style_entry;
496 style_entry.key = Reference(util::DeviceToHost32(map_entry.name.ident));
497 style_entry.value = ParseValue(name, config, &map_entry.value, 0);
498 if (!style_entry.value) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700499 return {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700500 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700501 style->entries.push_back(std::move(style_entry));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700502 }
503 return style;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700504}
505
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700506std::unique_ptr<Attribute> BinaryResourceParser::ParseAttr(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700507 const ResourceNameRef& name, const ConfigDescription& config,
508 const ResTable_map_entry* map) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700509 const bool is_weak =
510 (util::DeviceToHost16(map->flags) & ResTable_entry::FLAG_WEAK) != 0;
511 std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(is_weak);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700512
Adam Lesinskib54ef102016-10-21 13:38:42 -0700513 // First we must discover what type of attribute this is. Find the type mask.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700514 auto type_mask_iter =
Adam Lesinskib54ef102016-10-21 13:38:42 -0700515 std::find_if(begin(map), end(map), [](const ResTable_map& entry) -> bool {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700516 return util::DeviceToHost32(entry.name.ident) ==
Adam Lesinskib54ef102016-10-21 13:38:42 -0700517 ResTable_map::ATTR_TYPE;
518 });
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700519
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700520 if (type_mask_iter != end(map)) {
521 attr->type_mask = util::DeviceToHost32(type_mask_iter->value.data);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700522 }
523
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700524 for (const ResTable_map& map_entry : map) {
525 if (Res_INTERNALID(util::DeviceToHost32(map_entry.name.ident))) {
526 switch (util::DeviceToHost32(map_entry.name.ident)) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700527 case ResTable_map::ATTR_MIN:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700528 attr->min_int = static_cast<int32_t>(map_entry.value.data);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700529 break;
530 case ResTable_map::ATTR_MAX:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700531 attr->max_int = static_cast<int32_t>(map_entry.value.data);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700532 break;
533 }
534 continue;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700535 }
536
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700537 if (attr->type_mask &
538 (ResTable_map::TYPE_ENUM | ResTable_map::TYPE_FLAGS)) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700539 Attribute::Symbol symbol;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700540 symbol.value = util::DeviceToHost32(map_entry.value.data);
541 symbol.symbol = Reference(util::DeviceToHost32(map_entry.name.ident));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700542 attr->symbols.push_back(std::move(symbol));
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700543 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700544 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700545
Adam Lesinskib54ef102016-10-21 13:38:42 -0700546 // TODO(adamlesinski): Find i80n, attributes.
547 return attr;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700548}
549
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700550std::unique_ptr<Array> BinaryResourceParser::ParseArray(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700551 const ResourceNameRef& name, const ConfigDescription& config,
552 const ResTable_map_entry* map) {
553 std::unique_ptr<Array> array = util::make_unique<Array>();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700554 for (const ResTable_map& map_entry : map) {
555 array->items.push_back(ParseValue(name, config, &map_entry.value, 0));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700556 }
557 return array;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700558}
559
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700560std::unique_ptr<Plural> BinaryResourceParser::ParsePlural(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700561 const ResourceNameRef& name, const ConfigDescription& config,
562 const ResTable_map_entry* map) {
563 std::unique_ptr<Plural> plural = util::make_unique<Plural>();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700564 for (const ResTable_map& map_entry : map) {
565 std::unique_ptr<Item> item = ParseValue(name, config, &map_entry.value, 0);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700566 if (!item) {
567 return {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700568 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700569
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700570 switch (util::DeviceToHost32(map_entry.name.ident)) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700571 case ResTable_map::ATTR_ZERO:
572 plural->values[Plural::Zero] = std::move(item);
573 break;
574 case ResTable_map::ATTR_ONE:
575 plural->values[Plural::One] = std::move(item);
576 break;
577 case ResTable_map::ATTR_TWO:
578 plural->values[Plural::Two] = std::move(item);
579 break;
580 case ResTable_map::ATTR_FEW:
581 plural->values[Plural::Few] = std::move(item);
582 break;
583 case ResTable_map::ATTR_MANY:
584 plural->values[Plural::Many] = std::move(item);
585 break;
586 case ResTable_map::ATTR_OTHER:
587 plural->values[Plural::Other] = std::move(item);
588 break;
589 }
590 }
591 return plural;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700592}
593
Adam Lesinskib54ef102016-10-21 13:38:42 -0700594} // namespace aapt