blob: 20a45312993ddc9a78662f8470f9f3e17d661285 [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 Lesinskid0f492d2017-04-03 18:12:45 -070076BinaryResourceParser::BinaryResourceParser(IAaptContext* context, ResourceTable* table,
77 const Source& source, const void* data, size_t len,
78 io::IFileCollection* files)
Adam Lesinskice5e56e2016-10-21 17:56:45 -070079 : context_(context),
80 table_(table),
81 source_(source),
82 data_(data),
Adam Lesinskid0f492d2017-04-03 18:12:45 -070083 data_len_(len),
84 files_(files) {
85}
Adam Lesinski1ab598f2015-08-14 14:26:04 -070086
Adam Lesinskice5e56e2016-10-21 17:56:45 -070087bool BinaryResourceParser::Parse() {
88 ResChunkPullParser parser(data_, data_len_);
Adam Lesinski1ab598f2015-08-14 14:26:04 -070089
Adam Lesinskib54ef102016-10-21 13:38:42 -070090 bool error = false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -070091 while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
92 if (parser.chunk()->type != android::RES_TABLE_TYPE) {
93 context_->GetDiagnostics()->Warn(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -070094 << "unknown chunk of type '"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070095 << (int)parser.chunk()->type << "'");
Adam Lesinskib54ef102016-10-21 13:38:42 -070096 continue;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070097 }
98
Adam Lesinskice5e56e2016-10-21 17:56:45 -070099 if (!ParseTable(parser.chunk())) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700100 error = true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700101 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700102 }
103
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700104 if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
105 context_->GetDiagnostics()->Error(
106 DiagMessage(source_) << "corrupt resource table: " << parser.error());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700107 return false;
108 }
109 return !error;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700110}
111
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700112/**
Adam Lesinskib54ef102016-10-21 13:38:42 -0700113 * Parses the resource table, which contains all the packages, types, and
114 * entries.
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700115 */
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700116bool BinaryResourceParser::ParseTable(const ResChunk_header* chunk) {
117 const ResTable_header* table_header = ConvertTo<ResTable_header>(chunk);
118 if (!table_header) {
119 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700120 << "corrupt ResTable_header chunk");
121 return false;
122 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700123
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700124 ResChunkPullParser parser(GetChunkData(&table_header->header),
125 GetChunkDataLen(&table_header->header));
126 while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
127 switch (util::DeviceToHost16(parser.chunk()->type)) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700128 case android::RES_STRING_POOL_TYPE:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700129 if (value_pool_.getError() == NO_INIT) {
130 status_t err = value_pool_.setTo(
131 parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700132 if (err != NO_ERROR) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700133 context_->GetDiagnostics()->Error(
134 DiagMessage(source_) << "corrupt string pool in ResTable: "
135 << value_pool_.getError());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700136 return false;
137 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700138
Adam Lesinskib54ef102016-10-21 13:38:42 -0700139 // Reserve some space for the strings we are going to add.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700140 table_->string_pool.HintWillAdd(value_pool_.size(),
141 value_pool_.styleCount());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700142 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700143 context_->GetDiagnostics()->Warn(
144 DiagMessage(source_) << "unexpected string pool in ResTable");
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700145 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700146 break;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700147
Adam Lesinskib54ef102016-10-21 13:38:42 -0700148 case android::RES_TABLE_PACKAGE_TYPE:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700149 if (!ParsePackage(parser.chunk())) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700150 return false;
151 }
152 break;
153
154 default:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700155 context_->GetDiagnostics()->Warn(
156 DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700157 << "unexpected chunk type "
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700158 << (int)util::DeviceToHost16(parser.chunk()->type));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700159 break;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700160 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700161 }
162
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700163 if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
164 context_->GetDiagnostics()->Error(
165 DiagMessage(source_) << "corrupt resource table: " << parser.error());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700166 return false;
167 }
168 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700169}
170
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700171bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) {
Adam Lesinski33af6c72017-03-29 13:00:35 -0700172 constexpr size_t kMinPackageSize =
173 sizeof(ResTable_package) - sizeof(ResTable_package::typeIdOffset);
174 const ResTable_package* package_header = ConvertTo<ResTable_package, kMinPackageSize>(chunk);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700175 if (!package_header) {
Adam Lesinski33af6c72017-03-29 13:00:35 -0700176 context_->GetDiagnostics()->Error(DiagMessage(source_) << "corrupt ResTable_package chunk");
Adam Lesinskib54ef102016-10-21 13:38:42 -0700177 return false;
178 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700179
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700180 uint32_t package_id = util::DeviceToHost32(package_header->id);
181 if (package_id > std::numeric_limits<uint8_t>::max()) {
182 context_->GetDiagnostics()->Error(
183 DiagMessage(source_) << "package ID is too big (" << package_id << ")");
Adam Lesinskib54ef102016-10-21 13:38:42 -0700184 return false;
185 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700186
Adam Lesinskib54ef102016-10-21 13:38:42 -0700187 // Extract the package name.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700188 size_t len = strnlen16((const char16_t*)package_header->name,
189 arraysize(package_header->name));
190 std::u16string package_name;
191 package_name.resize(len);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700192 for (size_t i = 0; i < len; i++) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700193 package_name[i] = util::DeviceToHost16(package_header->name[i]);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700194 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700195
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700196 ResourceTablePackage* package = table_->CreatePackage(
197 util::Utf16ToUtf8(package_name), static_cast<uint8_t>(package_id));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700198 if (!package) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700199 context_->GetDiagnostics()->Error(
200 DiagMessage(source_) << "incompatible package '" << package_name
201 << "' with ID " << package_id);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700202 return false;
203 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700204
Adam Lesinskib54ef102016-10-21 13:38:42 -0700205 // There can be multiple packages in a table, so
206 // clear the type and key pool in case they were set from a previous package.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700207 type_pool_.uninit();
208 key_pool_.uninit();
Adam Lesinskie352b992015-11-16 11:59:14 -0800209
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700210 ResChunkPullParser parser(GetChunkData(&package_header->header),
211 GetChunkDataLen(&package_header->header));
212 while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
213 switch (util::DeviceToHost16(parser.chunk()->type)) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700214 case android::RES_STRING_POOL_TYPE:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700215 if (type_pool_.getError() == NO_INIT) {
216 status_t err = type_pool_.setTo(
217 parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700218 if (err != NO_ERROR) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700219 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700220 << "corrupt type string pool in "
221 << "ResTable_package: "
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700222 << type_pool_.getError());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700223 return false;
224 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700225 } else if (key_pool_.getError() == NO_INIT) {
226 status_t err = key_pool_.setTo(
227 parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700228 if (err != NO_ERROR) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700229 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700230 << "corrupt key string pool in "
231 << "ResTable_package: "
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700232 << key_pool_.getError());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700233 return false;
234 }
235 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700236 context_->GetDiagnostics()->Warn(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700237 << "unexpected string pool");
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700238 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700239 break;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700240
Adam Lesinskib54ef102016-10-21 13:38:42 -0700241 case android::RES_TABLE_TYPE_SPEC_TYPE:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700242 if (!ParseTypeSpec(parser.chunk())) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700243 return false;
244 }
245 break;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700246
Adam Lesinskib54ef102016-10-21 13:38:42 -0700247 case android::RES_TABLE_TYPE_TYPE:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700248 if (!ParseType(package, parser.chunk())) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700249 return false;
250 }
251 break;
252
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800253 case android::RES_TABLE_LIBRARY_TYPE:
254 if (!ParseLibrary(parser.chunk())) {
255 return false;
256 }
257 break;
258
Adam Lesinskib54ef102016-10-21 13:38:42 -0700259 default:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700260 context_->GetDiagnostics()->Warn(
261 DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700262 << "unexpected chunk type "
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700263 << (int)util::DeviceToHost16(parser.chunk()->type));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700264 break;
265 }
266 }
267
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700268 if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
269 context_->GetDiagnostics()->Error(
270 DiagMessage(source_) << "corrupt ResTable_package: " << parser.error());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700271 return false;
272 }
273
274 // Now go through the table and change local resource ID references to
275 // symbolic references.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700276 ReferenceIdToNameVisitor visitor(&id_index_);
277 VisitAllValuesInTable(table_, &visitor);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700278 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700279}
280
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700281bool BinaryResourceParser::ParseTypeSpec(const ResChunk_header* chunk) {
282 if (type_pool_.getError() != NO_ERROR) {
283 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700284 << "missing type string pool");
285 return false;
286 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700287
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700288 const ResTable_typeSpec* type_spec = ConvertTo<ResTable_typeSpec>(chunk);
289 if (!type_spec) {
290 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700291 << "corrupt ResTable_typeSpec chunk");
292 return false;
293 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700294
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700295 if (type_spec->id == 0) {
296 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700297 << "ResTable_typeSpec has invalid id: "
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700298 << type_spec->id);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700299 return false;
300 }
301 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700302}
303
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700304bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700305 const ResChunk_header* chunk) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700306 if (type_pool_.getError() != NO_ERROR) {
307 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700308 << "missing type string pool");
309 return false;
310 }
311
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700312 if (key_pool_.getError() != NO_ERROR) {
313 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700314 << "missing key string pool");
315 return false;
316 }
317
Adam Lesinski136fd072017-03-03 13:50:21 -0800318 // Specify a manual size, because ResTable_type contains ResTable_config, which changes
319 // a lot and has its own code to handle variable size.
320 const ResTable_type* type = ConvertTo<ResTable_type, kResTableTypeMinSize>(chunk);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700321 if (!type) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700322 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700323 << "corrupt ResTable_type chunk");
324 return false;
325 }
326
327 if (type->id == 0) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700328 context_->GetDiagnostics()->Error(DiagMessage(source_)
Adam Lesinskib54ef102016-10-21 13:38:42 -0700329 << "ResTable_type has invalid id: "
330 << (int)type->id);
331 return false;
332 }
333
334 ConfigDescription config;
335 config.copyFromDtoH(type->config);
336
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700337 const std::string type_str = util::GetString(type_pool_, type->id - 1);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700338
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700339 const ResourceType* parsed_type = ParseResourceType(type_str);
340 if (!parsed_type) {
341 context_->GetDiagnostics()->Error(
342 DiagMessage(source_) << "invalid type name '" << type_str
Adam Lesinskib54ef102016-10-21 13:38:42 -0700343 << "' for type with ID " << (int)type->id);
344 return false;
345 }
346
347 TypeVariant tv(type);
348 for (auto it = tv.beginEntries(); it != tv.endEntries(); ++it) {
349 const ResTable_entry* entry = *it;
350 if (!entry) {
351 continue;
352 }
353
354 const ResourceName name(
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700355 package->name, *parsed_type,
356 util::GetString(key_pool_, util::DeviceToHost32(entry->key.index)));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700357
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700358 const ResourceId res_id(package->id.value(), type->id,
359 static_cast<uint16_t>(it.index()));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700360
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700361 std::unique_ptr<Value> resource_value;
Adam Lesinskib54ef102016-10-21 13:38:42 -0700362 if (entry->flags & ResTable_entry::FLAG_COMPLEX) {
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700363 const ResTable_map_entry* mapEntry = static_cast<const ResTable_map_entry*>(entry);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700364
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 =
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700369 (const Res_value*)((const uint8_t*)entry + util::DeviceToHost32(entry->size));
370 resource_value = ParseValue(name, config, *value);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700371 }
372
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700373 if (!resource_value) {
374 context_->GetDiagnostics()->Error(
375 DiagMessage(source_) << "failed to parse value for resource " << name
376 << " (" << res_id << ") with configuration '"
Adam Lesinskib54ef102016-10-21 13:38:42 -0700377 << config << "'");
378 return false;
379 }
380
Pierre Lecesne2599aa42017-02-01 22:47:03 +0000381 if (!table_->AddResourceAllowMangled(name, res_id, config, {}, std::move(resource_value),
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700382 context_->GetDiagnostics())) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700383 return false;
384 }
385
386 if ((entry->flags & ResTable_entry::FLAG_PUBLIC) != 0) {
387 Symbol symbol;
388 symbol.state = SymbolState::kPublic;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700389 symbol.source = source_.WithLine(0);
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700390 if (!table_->SetSymbolStateAllowMangled(name, res_id, symbol, context_->GetDiagnostics())) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700391 return false;
Adam Lesinskib54ef102016-10-21 13:38:42 -0700392 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700393 }
394
Adam Lesinskib54ef102016-10-21 13:38:42 -0700395 // Add this resource name->id mapping to the index so
396 // that we can resolve all ID references to name references.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700397 auto cache_iter = id_index_.find(res_id);
398 if (cache_iter == id_index_.end()) {
399 id_index_.insert({res_id, name});
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700400 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700401 }
402 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700403}
404
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800405bool BinaryResourceParser::ParseLibrary(const ResChunk_header* chunk) {
406 DynamicRefTable dynamic_ref_table;
407 if (dynamic_ref_table.load(reinterpret_cast<const ResTable_lib_header*>(chunk)) != NO_ERROR) {
408 return false;
409 }
410
411 const KeyedVector<String16, uint8_t>& entries = dynamic_ref_table.entries();
412 const size_t count = entries.size();
413 for (size_t i = 0; i < count; i++) {
414 table_->included_packages_[entries.valueAt(i)] =
415 util::Utf16ToUtf8(StringPiece16(entries.keyAt(i).string()));
416 }
417 return true;
418}
419
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700420std::unique_ptr<Item> BinaryResourceParser::ParseValue(const ResourceNameRef& name,
421 const ConfigDescription& config,
422 const android::Res_value& value) {
423 std::unique_ptr<Item> item = ResourceUtils::ParseBinaryResValue(name.type, config, value_pool_,
424 value, &table_->string_pool);
425 if (files_ != nullptr && item != nullptr) {
426 FileReference* file_ref = ValueCast<FileReference>(item.get());
427 if (file_ref != nullptr) {
428 file_ref->file = files_->FindFile(*file_ref->path);
429 if (file_ref->file == nullptr) {
430 context_->GetDiagnostics()->Error(DiagMessage() << "resource " << name << " for config '"
431 << config << "' is a file reference to '"
432 << *file_ref->path
433 << "' but no such path exists");
434 return {};
Adam Lesinskib54ef102016-10-21 13:38:42 -0700435 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700436 }
437 }
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700438 return item;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700439}
440
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700441std::unique_ptr<Value> BinaryResourceParser::ParseMapEntry(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700442 const ResourceNameRef& name, const ConfigDescription& config,
443 const ResTable_map_entry* map) {
444 switch (name.type) {
445 case ResourceType::kStyle:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700446 return ParseStyle(name, config, map);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700447 case ResourceType::kAttrPrivate:
448 // fallthrough
449 case ResourceType::kAttr:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700450 return ParseAttr(name, config, map);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700451 case ResourceType::kArray:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700452 return ParseArray(name, config, map);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700453 case ResourceType::kPlurals:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700454 return ParsePlural(name, config, map);
Adam Lesinski33af6c72017-03-29 13:00:35 -0700455 case ResourceType::kId:
456 // Special case: An ID is not a bag, but some apps have defined the auto-generated
457 // IDs that come from declaring an enum value in an attribute as an empty map...
458 // We can ignore the value here.
459 return util::make_unique<Id>();
Adam Lesinskib54ef102016-10-21 13:38:42 -0700460 default:
Adam Lesinski33af6c72017-03-29 13:00:35 -0700461 context_->GetDiagnostics()->Error(DiagMessage() << "illegal map type '" << ToString(name.type)
462 << "' (" << (int)name.type << ")");
Adam Lesinskib54ef102016-10-21 13:38:42 -0700463 break;
464 }
465 return {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700466}
467
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700468std::unique_ptr<Style> BinaryResourceParser::ParseStyle(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700469 const ResourceNameRef& name, const ConfigDescription& config,
470 const ResTable_map_entry* map) {
471 std::unique_ptr<Style> style = util::make_unique<Style>();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700472 if (util::DeviceToHost32(map->parent.ident) != 0) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700473 // The parent is a regular reference to a resource.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700474 style->parent = Reference(util::DeviceToHost32(map->parent.ident));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700475 }
476
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700477 for (const ResTable_map& map_entry : map) {
478 if (Res_INTERNALID(util::DeviceToHost32(map_entry.name.ident))) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700479 continue;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700480 }
481
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700482 Style::Entry style_entry;
483 style_entry.key = Reference(util::DeviceToHost32(map_entry.name.ident));
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700484 style_entry.value = ParseValue(name, config, map_entry.value);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700485 if (!style_entry.value) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700486 return {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700487 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700488 style->entries.push_back(std::move(style_entry));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700489 }
490 return style;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700491}
492
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700493std::unique_ptr<Attribute> BinaryResourceParser::ParseAttr(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700494 const ResourceNameRef& name, const ConfigDescription& config,
495 const ResTable_map_entry* map) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700496 const bool is_weak =
497 (util::DeviceToHost16(map->flags) & ResTable_entry::FLAG_WEAK) != 0;
498 std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(is_weak);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700499
Adam Lesinskib54ef102016-10-21 13:38:42 -0700500 // First we must discover what type of attribute this is. Find the type mask.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700501 auto type_mask_iter =
Adam Lesinskib54ef102016-10-21 13:38:42 -0700502 std::find_if(begin(map), end(map), [](const ResTable_map& entry) -> bool {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700503 return util::DeviceToHost32(entry.name.ident) ==
Adam Lesinskib54ef102016-10-21 13:38:42 -0700504 ResTable_map::ATTR_TYPE;
505 });
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700506
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700507 if (type_mask_iter != end(map)) {
508 attr->type_mask = util::DeviceToHost32(type_mask_iter->value.data);
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))) {
513 switch (util::DeviceToHost32(map_entry.name.ident)) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700514 case ResTable_map::ATTR_MIN:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700515 attr->min_int = static_cast<int32_t>(map_entry.value.data);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700516 break;
517 case ResTable_map::ATTR_MAX:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700518 attr->max_int = static_cast<int32_t>(map_entry.value.data);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700519 break;
520 }
521 continue;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700522 }
523
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700524 if (attr->type_mask &
525 (ResTable_map::TYPE_ENUM | ResTable_map::TYPE_FLAGS)) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700526 Attribute::Symbol symbol;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700527 symbol.value = util::DeviceToHost32(map_entry.value.data);
528 symbol.symbol = Reference(util::DeviceToHost32(map_entry.name.ident));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700529 attr->symbols.push_back(std::move(symbol));
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700530 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700531 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700532
Adam Lesinskib54ef102016-10-21 13:38:42 -0700533 // TODO(adamlesinski): Find i80n, attributes.
534 return attr;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700535}
536
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700537std::unique_ptr<Array> BinaryResourceParser::ParseArray(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700538 const ResourceNameRef& name, const ConfigDescription& config,
539 const ResTable_map_entry* map) {
540 std::unique_ptr<Array> array = util::make_unique<Array>();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700541 for (const ResTable_map& map_entry : map) {
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700542 array->items.push_back(ParseValue(name, config, map_entry.value));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700543 }
544 return array;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700545}
546
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700547std::unique_ptr<Plural> BinaryResourceParser::ParsePlural(
Adam Lesinskib54ef102016-10-21 13:38:42 -0700548 const ResourceNameRef& name, const ConfigDescription& config,
549 const ResTable_map_entry* map) {
550 std::unique_ptr<Plural> plural = util::make_unique<Plural>();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700551 for (const ResTable_map& map_entry : map) {
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700552 std::unique_ptr<Item> item = ParseValue(name, config, map_entry.value);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700553 if (!item) {
554 return {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700555 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700556
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700557 switch (util::DeviceToHost32(map_entry.name.ident)) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700558 case ResTable_map::ATTR_ZERO:
559 plural->values[Plural::Zero] = std::move(item);
560 break;
561 case ResTable_map::ATTR_ONE:
562 plural->values[Plural::One] = std::move(item);
563 break;
564 case ResTable_map::ATTR_TWO:
565 plural->values[Plural::Two] = std::move(item);
566 break;
567 case ResTable_map::ATTR_FEW:
568 plural->values[Plural::Few] = std::move(item);
569 break;
570 case ResTable_map::ATTR_MANY:
571 plural->values[Plural::Many] = std::move(item);
572 break;
573 case ResTable_map::ATTR_OTHER:
574 plural->values[Plural::Other] = std::move(item);
575 break;
576 }
577 }
578 return plural;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700579}
580
Adam Lesinskib54ef102016-10-21 13:38:42 -0700581} // namespace aapt