blob: 35bf618c1635e0784e2960fa904061823b9006a2 [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) {
Adam Lesinski33af6c72017-03-29 13:00:35 -0700171 constexpr size_t kMinPackageSize =
172 sizeof(ResTable_package) - sizeof(ResTable_package::typeIdOffset);
173 const ResTable_package* package_header = ConvertTo<ResTable_package, kMinPackageSize>(chunk);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700174 if (!package_header) {
Adam Lesinski33af6c72017-03-29 13:00:35 -0700175 context_->GetDiagnostics()->Error(DiagMessage(source_) << "corrupt ResTable_package chunk");
Adam Lesinskib54ef102016-10-21 13:38:42 -0700176 return false;
177 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700178
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700179 uint32_t package_id = util::DeviceToHost32(package_header->id);
180 if (package_id > std::numeric_limits<uint8_t>::max()) {
181 context_->GetDiagnostics()->Error(
182 DiagMessage(source_) << "package ID is too big (" << package_id << ")");
Adam Lesinskib54ef102016-10-21 13:38:42 -0700183 return false;
184 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700185
Adam Lesinskib54ef102016-10-21 13:38:42 -0700186 // Extract the package name.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700187 size_t len = strnlen16((const char16_t*)package_header->name,
188 arraysize(package_header->name));
189 std::u16string package_name;
190 package_name.resize(len);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700191 for (size_t i = 0; i < len; i++) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700192 package_name[i] = util::DeviceToHost16(package_header->name[i]);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700193 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700194
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700195 ResourceTablePackage* package = table_->CreatePackage(
196 util::Utf16ToUtf8(package_name), static_cast<uint8_t>(package_id));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700197 if (!package) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700198 context_->GetDiagnostics()->Error(
199 DiagMessage(source_) << "incompatible package '" << package_name
200 << "' with ID " << package_id);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700201 return false;
202 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700203
Adam Lesinskib54ef102016-10-21 13:38:42 -0700204 // There can be multiple packages in a table, so
205 // clear the type and key pool in case they were set from a previous package.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700206 type_pool_.uninit();
207 key_pool_.uninit();
Adam Lesinskie352b992015-11-16 11:59:14 -0800208
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700209 ResChunkPullParser parser(GetChunkData(&package_header->header),
210 GetChunkDataLen(&package_header->header));
211 while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
212 switch (util::DeviceToHost16(parser.chunk()->type)) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700213 case android::RES_STRING_POOL_TYPE:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700214 if (type_pool_.getError() == NO_INIT) {
215 status_t err = type_pool_.setTo(
216 parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700217 if (err != NO_ERROR) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700218 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700219 << "corrupt type string pool in "
220 << "ResTable_package: "
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700221 << type_pool_.getError());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700222 return false;
223 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700224 } else if (key_pool_.getError() == NO_INIT) {
225 status_t err = key_pool_.setTo(
226 parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700227 if (err != NO_ERROR) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700228 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700229 << "corrupt key string pool in "
230 << "ResTable_package: "
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700231 << key_pool_.getError());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700232 return false;
233 }
234 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700235 context_->GetDiagnostics()->Warn(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700236 << "unexpected string pool");
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700237 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700238 break;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700239
Adam Lesinskib54ef102016-10-21 13:38:42 -0700240 case android::RES_TABLE_TYPE_SPEC_TYPE:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700241 if (!ParseTypeSpec(parser.chunk())) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700242 return false;
243 }
244 break;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700245
Adam Lesinskib54ef102016-10-21 13:38:42 -0700246 case android::RES_TABLE_TYPE_TYPE:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700247 if (!ParseType(package, parser.chunk())) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700248 return false;
249 }
250 break;
251
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800252 case android::RES_TABLE_LIBRARY_TYPE:
253 if (!ParseLibrary(parser.chunk())) {
254 return false;
255 }
256 break;
257
Adam Lesinskib54ef102016-10-21 13:38:42 -0700258 default:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700259 context_->GetDiagnostics()->Warn(
260 DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700261 << "unexpected chunk type "
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700262 << (int)util::DeviceToHost16(parser.chunk()->type));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700263 break;
264 }
265 }
266
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700267 if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
268 context_->GetDiagnostics()->Error(
269 DiagMessage(source_) << "corrupt ResTable_package: " << parser.error());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700270 return false;
271 }
272
273 // Now go through the table and change local resource ID references to
274 // symbolic references.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700275 ReferenceIdToNameVisitor visitor(&id_index_);
276 VisitAllValuesInTable(table_, &visitor);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700277 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700278}
279
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700280bool BinaryResourceParser::ParseTypeSpec(const ResChunk_header* chunk) {
281 if (type_pool_.getError() != NO_ERROR) {
282 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700283 << "missing type string pool");
284 return false;
285 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700286
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700287 const ResTable_typeSpec* type_spec = ConvertTo<ResTable_typeSpec>(chunk);
288 if (!type_spec) {
289 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700290 << "corrupt ResTable_typeSpec chunk");
291 return false;
292 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700293
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700294 if (type_spec->id == 0) {
295 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700296 << "ResTable_typeSpec has invalid id: "
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700297 << type_spec->id);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700298 return false;
299 }
300 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700301}
302
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700303bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700304 const ResChunk_header* chunk) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700305 if (type_pool_.getError() != NO_ERROR) {
306 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700307 << "missing type string pool");
308 return false;
309 }
310
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700311 if (key_pool_.getError() != NO_ERROR) {
312 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700313 << "missing key string pool");
314 return false;
315 }
316
Adam Lesinski136fd072017-03-03 13:50:21 -0800317 // Specify a manual size, because ResTable_type contains ResTable_config, which changes
318 // a lot and has its own code to handle variable size.
319 const ResTable_type* type = ConvertTo<ResTable_type, kResTableTypeMinSize>(chunk);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700320 if (!type) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700321 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700322 << "corrupt ResTable_type chunk");
323 return false;
324 }
325
326 if (type->id == 0) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700327 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700328 << "ResTable_type has invalid id: "
329 << (int)type->id);
330 return false;
331 }
332
333 ConfigDescription config;
334 config.copyFromDtoH(type->config);
335
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700336 const std::string type_str = util::GetString(type_pool_, type->id - 1);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700337
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700338 const ResourceType* parsed_type = ParseResourceType(type_str);
339 if (!parsed_type) {
340 context_->GetDiagnostics()->Error(
341 DiagMessage(source_) << "invalid type name '" << type_str
Adam Lesinskib54ef102016-10-21 13:38:42 -0700342 << "' for type with ID " << (int)type->id);
343 return false;
344 }
345
346 TypeVariant tv(type);
347 for (auto it = tv.beginEntries(); it != tv.endEntries(); ++it) {
348 const ResTable_entry* entry = *it;
349 if (!entry) {
350 continue;
351 }
352
353 const ResourceName name(
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700354 package->name, *parsed_type,
355 util::GetString(key_pool_, util::DeviceToHost32(entry->key.index)));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700356
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700357 const ResourceId res_id(package->id.value(), type->id,
358 static_cast<uint16_t>(it.index()));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700359
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700360 std::unique_ptr<Value> resource_value;
Adam Lesinskib54ef102016-10-21 13:38:42 -0700361 if (entry->flags & ResTable_entry::FLAG_COMPLEX) {
362 const ResTable_map_entry* mapEntry =
363 static_cast<const ResTable_map_entry*>(entry);
364
365 // TODO(adamlesinski): Check that the entry count is valid.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700366 resource_value = ParseMapEntry(name, config, mapEntry);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700367 } else {
368 const Res_value* value =
369 (const Res_value*)((const uint8_t*)entry +
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700370 util::DeviceToHost32(entry->size));
371 resource_value = ParseValue(name, config, value, entry->flags);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700372 }
373
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700374 if (!resource_value) {
375 context_->GetDiagnostics()->Error(
376 DiagMessage(source_) << "failed to parse value for resource " << name
377 << " (" << res_id << ") with configuration '"
Adam Lesinskib54ef102016-10-21 13:38:42 -0700378 << config << "'");
379 return false;
380 }
381
Pierre Lecesne2599aa42017-02-01 22:47:03 +0000382 if (!table_->AddResourceAllowMangled(name, res_id, config, {}, std::move(resource_value),
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700383 context_->GetDiagnostics())) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700384 return false;
385 }
386
387 if ((entry->flags & ResTable_entry::FLAG_PUBLIC) != 0) {
388 Symbol symbol;
389 symbol.state = SymbolState::kPublic;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700390 symbol.source = source_.WithLine(0);
391 if (!table_->SetSymbolStateAllowMangled(name, res_id, symbol,
392 context_->GetDiagnostics())) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700393 return false;
Adam Lesinskib54ef102016-10-21 13:38:42 -0700394 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700395 }
396
Adam Lesinskib54ef102016-10-21 13:38:42 -0700397 // Add this resource name->id mapping to the index so
398 // that we can resolve all ID references to name references.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700399 auto cache_iter = id_index_.find(res_id);
400 if (cache_iter == id_index_.end()) {
401 id_index_.insert({res_id, name});
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700402 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700403 }
404 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700405}
406
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800407bool BinaryResourceParser::ParseLibrary(const ResChunk_header* chunk) {
408 DynamicRefTable dynamic_ref_table;
409 if (dynamic_ref_table.load(reinterpret_cast<const ResTable_lib_header*>(chunk)) != NO_ERROR) {
410 return false;
411 }
412
413 const KeyedVector<String16, uint8_t>& entries = dynamic_ref_table.entries();
414 const size_t count = entries.size();
415 for (size_t i = 0; i < count; i++) {
416 table_->included_packages_[entries.valueAt(i)] =
417 util::Utf16ToUtf8(StringPiece16(entries.keyAt(i).string()));
418 }
419 return true;
420}
421
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700422std::unique_ptr<Item> BinaryResourceParser::ParseValue(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700423 const ResourceNameRef& name, const ConfigDescription& config,
424 const Res_value* value, uint16_t flags) {
425 if (name.type == ResourceType::kId) {
426 return util::make_unique<Id>();
427 }
428
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700429 const uint32_t data = util::DeviceToHost32(value->data);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700430
431 if (value->dataType == Res_value::TYPE_STRING) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700432 const std::string str = util::GetString(value_pool_, data);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700433
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700434 const ResStringPool_span* spans = value_pool_.styleAt(data);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700435
436 // Check if the string has a valid style associated with it.
437 if (spans != nullptr && spans->name.index != ResStringPool_span::END) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700438 StyleString style_str = {str};
Adam Lesinskib54ef102016-10-21 13:38:42 -0700439 while (spans->name.index != ResStringPool_span::END) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700440 style_str.spans.push_back(
441 Span{util::GetString(value_pool_, spans->name.index),
Adam Lesinskib54ef102016-10-21 13:38:42 -0700442 spans->firstChar, spans->lastChar});
443 spans++;
444 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700445 return util::make_unique<StyledString>(table_->string_pool.MakeRef(
446 style_str,
Adam Lesinskib54ef102016-10-21 13:38:42 -0700447 StringPool::Context(StringPool::Context::kStylePriority, config)));
448 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700449 if (name.type != ResourceType::kString && util::StartsWith(str, "res/")) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700450 // This must be a FileReference.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700451 return util::make_unique<FileReference>(table_->string_pool.MakeRef(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700452 str,
453 StringPool::Context(StringPool::Context::kHighPriority, config)));
454 }
455
456 // There are no styles associated with this string, so treat it as
457 // a simple string.
458 return util::make_unique<String>(
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700459 table_->string_pool.MakeRef(str, StringPool::Context(config)));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700460 }
461 }
462
463 if (value->dataType == Res_value::TYPE_REFERENCE ||
Adam Lesinskib5dc4bd2017-02-22 19:29:29 -0800464 value->dataType == Res_value::TYPE_ATTRIBUTE ||
465 value->dataType == Res_value::TYPE_DYNAMIC_REFERENCE ||
466 value->dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE) {
467 Reference::Type type = Reference::Type::kResource;
468 if (value->dataType == Res_value::TYPE_ATTRIBUTE ||
469 value->dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE) {
470 type = Reference::Type::kAttribute;
471 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700472
473 if (data == 0) {
474 // A reference of 0, must be the magic @null reference.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700475 Res_value null_type = {};
476 null_type.dataType = Res_value::TYPE_REFERENCE;
477 return util::make_unique<BinaryPrimitive>(null_type);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700478 }
479
Adam Lesinskib54ef102016-10-21 13:38:42 -0700480 // This is a normal reference.
481 return util::make_unique<Reference>(data, type);
482 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700483
Adam Lesinskib54ef102016-10-21 13:38:42 -0700484 // Treat this as a raw binary primitive.
485 return util::make_unique<BinaryPrimitive>(*value);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700486}
487
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700488std::unique_ptr<Value> BinaryResourceParser::ParseMapEntry(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700489 const ResourceNameRef& name, const ConfigDescription& config,
490 const ResTable_map_entry* map) {
491 switch (name.type) {
492 case ResourceType::kStyle:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700493 return ParseStyle(name, config, map);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700494 case ResourceType::kAttrPrivate:
495 // fallthrough
496 case ResourceType::kAttr:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700497 return ParseAttr(name, config, map);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700498 case ResourceType::kArray:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700499 return ParseArray(name, config, map);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700500 case ResourceType::kPlurals:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700501 return ParsePlural(name, config, map);
Adam Lesinski33af6c72017-03-29 13:00:35 -0700502 case ResourceType::kId:
503 // Special case: An ID is not a bag, but some apps have defined the auto-generated
504 // IDs that come from declaring an enum value in an attribute as an empty map...
505 // We can ignore the value here.
506 return util::make_unique<Id>();
Adam Lesinskib54ef102016-10-21 13:38:42 -0700507 default:
Adam Lesinski33af6c72017-03-29 13:00:35 -0700508 context_->GetDiagnostics()->Error(DiagMessage() << "illegal map type '" << ToString(name.type)
509 << "' (" << (int)name.type << ")");
Adam Lesinskib54ef102016-10-21 13:38:42 -0700510 break;
511 }
512 return {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700513}
514
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700515std::unique_ptr<Style> BinaryResourceParser::ParseStyle(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700516 const ResourceNameRef& name, const ConfigDescription& config,
517 const ResTable_map_entry* map) {
518 std::unique_ptr<Style> style = util::make_unique<Style>();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700519 if (util::DeviceToHost32(map->parent.ident) != 0) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700520 // The parent is a regular reference to a resource.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700521 style->parent = Reference(util::DeviceToHost32(map->parent.ident));
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))) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700526 continue;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700527 }
528
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700529 Style::Entry style_entry;
530 style_entry.key = Reference(util::DeviceToHost32(map_entry.name.ident));
531 style_entry.value = ParseValue(name, config, &map_entry.value, 0);
532 if (!style_entry.value) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700533 return {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700534 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700535 style->entries.push_back(std::move(style_entry));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700536 }
537 return style;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700538}
539
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700540std::unique_ptr<Attribute> BinaryResourceParser::ParseAttr(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700541 const ResourceNameRef& name, const ConfigDescription& config,
542 const ResTable_map_entry* map) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700543 const bool is_weak =
544 (util::DeviceToHost16(map->flags) & ResTable_entry::FLAG_WEAK) != 0;
545 std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(is_weak);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700546
Adam Lesinskib54ef102016-10-21 13:38:42 -0700547 // First we must discover what type of attribute this is. Find the type mask.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700548 auto type_mask_iter =
Adam Lesinskib54ef102016-10-21 13:38:42 -0700549 std::find_if(begin(map), end(map), [](const ResTable_map& entry) -> bool {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700550 return util::DeviceToHost32(entry.name.ident) ==
Adam Lesinskib54ef102016-10-21 13:38:42 -0700551 ResTable_map::ATTR_TYPE;
552 });
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700553
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700554 if (type_mask_iter != end(map)) {
555 attr->type_mask = util::DeviceToHost32(type_mask_iter->value.data);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700556 }
557
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700558 for (const ResTable_map& map_entry : map) {
559 if (Res_INTERNALID(util::DeviceToHost32(map_entry.name.ident))) {
560 switch (util::DeviceToHost32(map_entry.name.ident)) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700561 case ResTable_map::ATTR_MIN:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700562 attr->min_int = static_cast<int32_t>(map_entry.value.data);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700563 break;
564 case ResTable_map::ATTR_MAX:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700565 attr->max_int = static_cast<int32_t>(map_entry.value.data);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700566 break;
567 }
568 continue;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700569 }
570
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700571 if (attr->type_mask &
572 (ResTable_map::TYPE_ENUM | ResTable_map::TYPE_FLAGS)) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700573 Attribute::Symbol symbol;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700574 symbol.value = util::DeviceToHost32(map_entry.value.data);
575 symbol.symbol = Reference(util::DeviceToHost32(map_entry.name.ident));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700576 attr->symbols.push_back(std::move(symbol));
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700577 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700578 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700579
Adam Lesinskib54ef102016-10-21 13:38:42 -0700580 // TODO(adamlesinski): Find i80n, attributes.
581 return attr;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700582}
583
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700584std::unique_ptr<Array> BinaryResourceParser::ParseArray(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700585 const ResourceNameRef& name, const ConfigDescription& config,
586 const ResTable_map_entry* map) {
587 std::unique_ptr<Array> array = util::make_unique<Array>();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700588 for (const ResTable_map& map_entry : map) {
589 array->items.push_back(ParseValue(name, config, &map_entry.value, 0));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700590 }
591 return array;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700592}
593
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700594std::unique_ptr<Plural> BinaryResourceParser::ParsePlural(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700595 const ResourceNameRef& name, const ConfigDescription& config,
596 const ResTable_map_entry* map) {
597 std::unique_ptr<Plural> plural = util::make_unique<Plural>();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700598 for (const ResTable_map& map_entry : map) {
599 std::unique_ptr<Item> item = ParseValue(name, config, &map_entry.value, 0);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700600 if (!item) {
601 return {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700602 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700603
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700604 switch (util::DeviceToHost32(map_entry.name.ident)) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700605 case ResTable_map::ATTR_ZERO:
606 plural->values[Plural::Zero] = std::move(item);
607 break;
608 case ResTable_map::ATTR_ONE:
609 plural->values[Plural::One] = std::move(item);
610 break;
611 case ResTable_map::ATTR_TWO:
612 plural->values[Plural::Two] = std::move(item);
613 break;
614 case ResTable_map::ATTR_FEW:
615 plural->values[Plural::Few] = std::move(item);
616 break;
617 case ResTable_map::ATTR_MANY:
618 plural->values[Plural::Many] = std::move(item);
619 break;
620 case ResTable_map::ATTR_OTHER:
621 plural->values[Plural::Other] = std::move(item);
622 break;
623 }
624 }
625 return plural;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700626}
627
Adam Lesinskib54ef102016-10-21 13:38:42 -0700628} // namespace aapt