blob: 40aaa05c2b30a3df0489dcf7de190edc9af7dadc [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 Lesinski46708052017-09-29 14:49:15 -070017#include "format/binary/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"
Adam Lesinski9431c472017-04-21 16:08:02 -070025#include "android-base/stringprintf.h"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070026#include "androidfw/ResourceTypes.h"
27#include "androidfw/TypeWrappers.h"
28
Adam Lesinski1ab598f2015-08-14 14:26:04 -070029#include "ResourceTable.h"
30#include "ResourceUtils.h"
31#include "ResourceValues.h"
32#include "Source.h"
33#include "ValueVisitor.h"
Adam Lesinski46708052017-09-29 14:49:15 -070034#include "format/binary/ResChunkPullParser.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070035#include "util/Util.h"
36
Adam Lesinski1ab598f2015-08-14 14:26:04 -070037using namespace android;
38
Adam Lesinski060b53d2017-07-28 17:10:35 -070039using ::android::base::StringPrintf;
Adam Lesinski9431c472017-04-21 16:08:02 -070040
Adam Lesinski46708052017-09-29 14:49:15 -070041namespace aapt {
42
Adam Lesinski59e04c62016-02-04 15:59:23 -080043namespace {
44
Ryan Mitchellef5673a2018-12-12 18:45:34 -080045static std::u16string strcpy16_dtoh(const char16_t* src, size_t len) {
46 size_t utf16_len = strnlen16(src, len);
47 if (utf16_len == 0) {
48 return {};
49 }
50 std::u16string dst;
51 dst.resize(utf16_len);
52 for (size_t i = 0; i < utf16_len; i++) {
53 dst[i] = util::DeviceToHost16(src[i]);
54 }
55 return dst;
56}
57
Adam Lesinski060b53d2017-07-28 17:10:35 -070058// Visitor that converts a reference's resource ID to a resource name, given a mapping from
59// resource ID to resource name.
Adam Lesinskid3ffa8442017-09-28 13:34:35 -070060class ReferenceIdToNameVisitor : public DescendingValueVisitor {
Adam Lesinskib54ef102016-10-21 13:38:42 -070061 public:
Adam Lesinskid3ffa8442017-09-28 13:34:35 -070062 using DescendingValueVisitor::Visit;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070063
Adam Lesinski060b53d2017-07-28 17:10:35 -070064 explicit ReferenceIdToNameVisitor(const std::map<ResourceId, ResourceName>* mapping)
Adam Lesinskice5e56e2016-10-21 17:56:45 -070065 : mapping_(mapping) {
66 CHECK(mapping_ != nullptr);
Adam Lesinskib54ef102016-10-21 13:38:42 -070067 }
68
Adam Lesinskice5e56e2016-10-21 17:56:45 -070069 void Visit(Reference* reference) override {
70 if (!reference->id || !reference->id.value().is_valid()) {
Adam Lesinskib54ef102016-10-21 13:38:42 -070071 return;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070072 }
73
Adam Lesinskib54ef102016-10-21 13:38:42 -070074 ResourceId id = reference->id.value();
Adam Lesinskice5e56e2016-10-21 17:56:45 -070075 auto cache_iter = mapping_->find(id);
76 if (cache_iter != mapping_->end()) {
77 reference->name = cache_iter->second;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070078 }
Adam Lesinskib54ef102016-10-21 13:38:42 -070079 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -070080
81 private:
82 DISALLOW_COPY_AND_ASSIGN(ReferenceIdToNameVisitor);
83
84 const std::map<ResourceId, ResourceName>* mapping_;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070085};
86
Adam Lesinskib54ef102016-10-21 13:38:42 -070087} // namespace
Adam Lesinski59e04c62016-02-04 15:59:23 -080088
Adam Lesinski8780eb62017-10-31 17:44:39 -070089BinaryResourceParser::BinaryResourceParser(IDiagnostics* diag, ResourceTable* table,
Adam Lesinskid0f492d2017-04-03 18:12:45 -070090 const Source& source, const void* data, size_t len,
91 io::IFileCollection* files)
Adam Lesinski8780eb62017-10-31 17:44:39 -070092 : diag_(diag), table_(table), source_(source), data_(data), data_len_(len), files_(files) {
Adam Lesinskid0f492d2017-04-03 18:12:45 -070093}
Adam Lesinski1ab598f2015-08-14 14:26:04 -070094
Adam Lesinskice5e56e2016-10-21 17:56:45 -070095bool BinaryResourceParser::Parse() {
96 ResChunkPullParser parser(data_, data_len_);
Adam Lesinski1ab598f2015-08-14 14:26:04 -070097
Adam Lesinski9431c472017-04-21 16:08:02 -070098 if (!ResChunkPullParser::IsGoodEvent(parser.Next())) {
Adam Lesinski8780eb62017-10-31 17:44:39 -070099 diag_->Error(DiagMessage(source_) << "corrupt resources.arsc: " << parser.error());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700100 return false;
101 }
Adam Lesinski9431c472017-04-21 16:08:02 -0700102
103 if (parser.chunk()->type != android::RES_TABLE_TYPE) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700104 diag_->Error(DiagMessage(source_) << StringPrintf("unknown chunk of type 0x%02x",
Adam Lesinski060b53d2017-07-28 17:10:35 -0700105 static_cast<int>(parser.chunk()->type)));
Adam Lesinski9431c472017-04-21 16:08:02 -0700106 return false;
107 }
108
109 if (!ParseTable(parser.chunk())) {
110 return false;
111 }
112
113 if (parser.Next() != ResChunkPullParser::Event::kEndDocument) {
114 if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700115 diag_->Warn(DiagMessage(source_)
116 << "invalid chunk trailing RES_TABLE_TYPE: " << parser.error());
Adam Lesinski9431c472017-04-21 16:08:02 -0700117 } else {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700118 diag_->Warn(DiagMessage(source_)
119 << StringPrintf("unexpected chunk of type 0x%02x trailing RES_TABLE_TYPE",
120 static_cast<int>(parser.chunk()->type)));
Adam Lesinski9431c472017-04-21 16:08:02 -0700121 }
122 }
123 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700124}
125
Adam Lesinski46708052017-09-29 14:49:15 -0700126// Parses the resource table, which contains all the packages, types, and entries.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700127bool BinaryResourceParser::ParseTable(const ResChunk_header* chunk) {
128 const ResTable_header* table_header = ConvertTo<ResTable_header>(chunk);
129 if (!table_header) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700130 diag_->Error(DiagMessage(source_) << "corrupt ResTable_header chunk");
Adam Lesinskib54ef102016-10-21 13:38:42 -0700131 return false;
132 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700133
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700134 ResChunkPullParser parser(GetChunkData(&table_header->header),
135 GetChunkDataLen(&table_header->header));
136 while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
137 switch (util::DeviceToHost16(parser.chunk()->type)) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700138 case android::RES_STRING_POOL_TYPE:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700139 if (value_pool_.getError() == NO_INIT) {
Adam Lesinski46708052017-09-29 14:49:15 -0700140 status_t err =
141 value_pool_.setTo(parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700142 if (err != NO_ERROR) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700143 diag_->Error(DiagMessage(source_)
144 << "corrupt string pool in ResTable: " << value_pool_.getError());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700145 return false;
146 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700147
Adam Lesinskib54ef102016-10-21 13:38:42 -0700148 // Reserve some space for the strings we are going to add.
Adam Lesinski46708052017-09-29 14:49:15 -0700149 table_->string_pool.HintWillAdd(value_pool_.size(), value_pool_.styleCount());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700150 } else {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700151 diag_->Warn(DiagMessage(source_) << "unexpected string pool in ResTable");
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700152 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700153 break;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700154
Adam Lesinskib54ef102016-10-21 13:38:42 -0700155 case android::RES_TABLE_PACKAGE_TYPE:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700156 if (!ParsePackage(parser.chunk())) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700157 return false;
158 }
159 break;
160
161 default:
Adam Lesinski8780eb62017-10-31 17:44:39 -0700162 diag_->Warn(DiagMessage(source_)
163 << "unexpected chunk type "
164 << static_cast<int>(util::DeviceToHost16(parser.chunk()->type)));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700165 break;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700166 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700167 }
168
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700169 if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700170 diag_->Error(DiagMessage(source_) << "corrupt resource table: " << parser.error());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700171 return false;
172 }
173 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700174}
175
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700176bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) {
Adam Lesinski33af6c72017-03-29 13:00:35 -0700177 constexpr size_t kMinPackageSize =
178 sizeof(ResTable_package) - sizeof(ResTable_package::typeIdOffset);
179 const ResTable_package* package_header = ConvertTo<ResTable_package, kMinPackageSize>(chunk);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700180 if (!package_header) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700181 diag_->Error(DiagMessage(source_) << "corrupt ResTable_package chunk");
Adam Lesinskib54ef102016-10-21 13:38:42 -0700182 return false;
183 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700184
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700185 uint32_t package_id = util::DeviceToHost32(package_header->id);
186 if (package_id > std::numeric_limits<uint8_t>::max()) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700187 diag_->Error(DiagMessage(source_) << "package ID is too big (" << package_id << ")");
Adam Lesinskib54ef102016-10-21 13:38:42 -0700188 return false;
189 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700190
Adam Lesinskib54ef102016-10-21 13:38:42 -0700191 // Extract the package name.
Ryan Mitchellef5673a2018-12-12 18:45:34 -0800192 std::u16string package_name = strcpy16_dtoh((const char16_t*)package_header->name,
193 arraysize(package_header->name));
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700194
Adam Lesinski46708052017-09-29 14:49:15 -0700195 ResourceTablePackage* package =
196 table_->CreatePackage(util::Utf16ToUtf8(package_name), static_cast<uint8_t>(package_id));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700197 if (!package) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700198 diag_->Error(DiagMessage(source_)
199 << "incompatible package '" << package_name << "' 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) {
Adam Lesinski46708052017-09-29 14:49:15 -0700214 status_t err =
215 type_pool_.setTo(parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700216 if (err != NO_ERROR) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700217 diag_->Error(DiagMessage(source_) << "corrupt type string pool in "
Adam Lesinski46708052017-09-29 14:49:15 -0700218 << "ResTable_package: " << type_pool_.getError());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700219 return false;
220 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700221 } else if (key_pool_.getError() == NO_INIT) {
Adam Lesinski46708052017-09-29 14:49:15 -0700222 status_t err =
223 key_pool_.setTo(parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700224 if (err != NO_ERROR) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700225 diag_->Error(DiagMessage(source_) << "corrupt key string pool in "
Adam Lesinski46708052017-09-29 14:49:15 -0700226 << "ResTable_package: " << key_pool_.getError());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700227 return false;
228 }
229 } else {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700230 diag_->Warn(DiagMessage(source_) << "unexpected string pool");
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700231 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700232 break;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700233
Adam Lesinskib54ef102016-10-21 13:38:42 -0700234 case android::RES_TABLE_TYPE_SPEC_TYPE:
Adam Lesinski71be7052017-12-12 16:48:07 -0800235 if (!ParseTypeSpec(package, parser.chunk())) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700236 return false;
237 }
238 break;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700239
Adam Lesinskib54ef102016-10-21 13:38:42 -0700240 case android::RES_TABLE_TYPE_TYPE:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700241 if (!ParseType(package, parser.chunk())) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700242 return false;
243 }
244 break;
245
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800246 case android::RES_TABLE_LIBRARY_TYPE:
247 if (!ParseLibrary(parser.chunk())) {
248 return false;
249 }
250 break;
251
Ryan Mitchell75e20dd2018-11-06 16:39:36 -0800252 case android::RES_TABLE_OVERLAYABLE_TYPE:
253 if (!ParseOverlayable(parser.chunk())) {
254 return false;
255 }
256 break;
257
Adam Lesinskib54ef102016-10-21 13:38:42 -0700258 default:
Adam Lesinski8780eb62017-10-31 17:44:39 -0700259 diag_->Warn(DiagMessage(source_)
260 << "unexpected chunk type "
261 << static_cast<int>(util::DeviceToHost16(parser.chunk()->type)));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700262 break;
263 }
264 }
265
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700266 if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700267 diag_->Error(DiagMessage(source_) << "corrupt ResTable_package: " << parser.error());
Adam Lesinskib54ef102016-10-21 13:38:42 -0700268 return false;
269 }
270
271 // Now go through the table and change local resource ID references to
272 // symbolic references.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700273 ReferenceIdToNameVisitor visitor(&id_index_);
274 VisitAllValuesInTable(table_, &visitor);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700275 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700276}
277
Adam Lesinski71be7052017-12-12 16:48:07 -0800278bool BinaryResourceParser::ParseTypeSpec(const ResourceTablePackage* package,
279 const ResChunk_header* chunk) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700280 if (type_pool_.getError() != NO_ERROR) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700281 diag_->Error(DiagMessage(source_) << "missing type string pool");
Adam Lesinskib54ef102016-10-21 13:38:42 -0700282 return false;
283 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700284
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700285 const ResTable_typeSpec* type_spec = ConvertTo<ResTable_typeSpec>(chunk);
286 if (!type_spec) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700287 diag_->Error(DiagMessage(source_) << "corrupt ResTable_typeSpec chunk");
Adam Lesinskib54ef102016-10-21 13:38:42 -0700288 return false;
289 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700290
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700291 if (type_spec->id == 0) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700292 diag_->Error(DiagMessage(source_) << "ResTable_typeSpec has invalid id: " << type_spec->id);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700293 return false;
294 }
Adam Lesinski71be7052017-12-12 16:48:07 -0800295
296 // The data portion of this chunk contains entry_count 32bit entries,
297 // each one representing a set of flags.
298 const size_t entry_count = dtohl(type_spec->entryCount);
299
300 // There can only be 2^16 entries in a type, because that is the ID
301 // space for entries (EEEE) in the resource ID 0xPPTTEEEE.
302 if (entry_count > std::numeric_limits<uint16_t>::max()) {
303 diag_->Error(DiagMessage(source_)
304 << "ResTable_typeSpec has too many entries (" << entry_count << ")");
305 return false;
306 }
307
308 const size_t data_size = util::DeviceToHost32(type_spec->header.size) -
309 util::DeviceToHost16(type_spec->header.headerSize);
310 if (entry_count * sizeof(uint32_t) > data_size) {
311 diag_->Error(DiagMessage(source_) << "ResTable_typeSpec too small to hold entries.");
312 return false;
313 }
314
315 // Record the type_spec_flags for later. We don't know resource names yet, and we need those
316 // to mark resources as overlayable.
317 const uint32_t* type_spec_flags = reinterpret_cast<const uint32_t*>(
318 reinterpret_cast<uintptr_t>(type_spec) + util::DeviceToHost16(type_spec->header.headerSize));
319 for (size_t i = 0; i < entry_count; i++) {
320 ResourceId id(package->id.value_or_default(0x0), type_spec->id, static_cast<size_t>(i));
321 entry_type_spec_flags_[id] = util::DeviceToHost32(type_spec_flags[i]);
322 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700323 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700324}
325
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700326bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700327 const ResChunk_header* chunk) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700328 if (type_pool_.getError() != NO_ERROR) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700329 diag_->Error(DiagMessage(source_) << "missing type string pool");
Adam Lesinskib54ef102016-10-21 13:38:42 -0700330 return false;
331 }
332
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700333 if (key_pool_.getError() != NO_ERROR) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700334 diag_->Error(DiagMessage(source_) << "missing key string pool");
Adam Lesinskib54ef102016-10-21 13:38:42 -0700335 return false;
336 }
337
Adam Lesinski136fd072017-03-03 13:50:21 -0800338 // Specify a manual size, because ResTable_type contains ResTable_config, which changes
339 // a lot and has its own code to handle variable size.
340 const ResTable_type* type = ConvertTo<ResTable_type, kResTableTypeMinSize>(chunk);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700341 if (!type) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700342 diag_->Error(DiagMessage(source_) << "corrupt ResTable_type chunk");
Adam Lesinskib54ef102016-10-21 13:38:42 -0700343 return false;
344 }
345
346 if (type->id == 0) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700347 diag_->Error(DiagMessage(source_) << "ResTable_type has invalid id: " << (int)type->id);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700348 return false;
349 }
350
351 ConfigDescription config;
352 config.copyFromDtoH(type->config);
353
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700354 const std::string type_str = util::GetString(type_pool_, type->id - 1);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700355
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700356 // Be lenient on the name of the type if the table is lenient on resource validation.
357 auto parsed_type = ResourceType::kUnknown;
358 if (const ResourceType* parsed = ParseResourceType(type_str)) {
359 parsed_type = *parsed;
360 } else if (table_->GetValidateResources()) {
361 diag_->Error(DiagMessage(source_) << "invalid type name '" << type_str << "' for type with ID "
362 << (int) type->id);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700363 return false;
364 }
365
366 TypeVariant tv(type);
367 for (auto it = tv.beginEntries(); it != tv.endEntries(); ++it) {
368 const ResTable_entry* entry = *it;
369 if (!entry) {
370 continue;
371 }
372
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700373 const ResourceName name(package->name, parsed_type,
Adam Lesinski46708052017-09-29 14:49:15 -0700374 util::GetString(key_pool_, util::DeviceToHost32(entry->key.index)));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700375
Adam Lesinski46708052017-09-29 14:49:15 -0700376 const ResourceId res_id(package->id.value(), type->id, static_cast<uint16_t>(it.index()));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700377
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700378 std::unique_ptr<Value> resource_value;
Adam Lesinskib54ef102016-10-21 13:38:42 -0700379 if (entry->flags & ResTable_entry::FLAG_COMPLEX) {
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700380 const ResTable_map_entry* mapEntry = static_cast<const ResTable_map_entry*>(entry);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700381
382 // TODO(adamlesinski): Check that the entry count is valid.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700383 resource_value = ParseMapEntry(name, config, mapEntry);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700384 } else {
385 const Res_value* value =
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700386 (const Res_value*)((const uint8_t*)entry + util::DeviceToHost32(entry->size));
387 resource_value = ParseValue(name, config, *value);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700388 }
389
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700390 if (!resource_value) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700391 diag_->Error(DiagMessage(source_) << "failed to parse value for resource " << name << " ("
Adam Lesinski46708052017-09-29 14:49:15 -0700392 << res_id << ") with configuration '" << config << "'");
Adam Lesinskib54ef102016-10-21 13:38:42 -0700393 return false;
394 }
395
Adam Lesinski71be7052017-12-12 16:48:07 -0800396 if (!table_->AddResourceWithIdMangled(name, res_id, config, {}, std::move(resource_value),
397 diag_)) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700398 return false;
399 }
400
Ryan Mitchell75e20dd2018-11-06 16:39:36 -0800401 if (entry->flags & ResTable_entry::FLAG_PUBLIC) {
402 Visibility visibility;
403 visibility.level = Visibility::Level::kPublic;
404 visibility.source = source_.WithLine(0);
405 if (!table_->SetVisibilityWithIdMangled(name, visibility, res_id, diag_)) {
406 return false;
Adam Lesinski71be7052017-12-12 16:48:07 -0800407 }
408
409 // Erase the ID from the map once processed, so that we don't mark the same symbol more than
410 // once.
411 entry_type_spec_flags_.erase(res_id);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700412 }
413
Adam Lesinskib54ef102016-10-21 13:38:42 -0700414 // Add this resource name->id mapping to the index so
415 // that we can resolve all ID references to name references.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700416 auto cache_iter = id_index_.find(res_id);
417 if (cache_iter == id_index_.end()) {
418 id_index_.insert({res_id, name});
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700419 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700420 }
421 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700422}
423
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800424bool BinaryResourceParser::ParseLibrary(const ResChunk_header* chunk) {
425 DynamicRefTable dynamic_ref_table;
426 if (dynamic_ref_table.load(reinterpret_cast<const ResTable_lib_header*>(chunk)) != NO_ERROR) {
427 return false;
428 }
429
430 const KeyedVector<String16, uint8_t>& entries = dynamic_ref_table.entries();
431 const size_t count = entries.size();
432 for (size_t i = 0; i < count; i++) {
433 table_->included_packages_[entries.valueAt(i)] =
434 util::Utf16ToUtf8(StringPiece16(entries.keyAt(i).string()));
435 }
436 return true;
437}
438
Ryan Mitchell75e20dd2018-11-06 16:39:36 -0800439bool BinaryResourceParser::ParseOverlayable(const ResChunk_header* chunk) {
440 const ResTable_overlayable_header* header = ConvertTo<ResTable_overlayable_header>(chunk);
441 if (!header) {
442 diag_->Error(DiagMessage(source_) << "corrupt ResTable_category_header chunk");
443 return false;
444 }
445
Ryan Mitchell54237ff2018-12-13 15:44:29 -0800446 auto overlayable = std::make_shared<Overlayable>();
Ryan Mitchellef5673a2018-12-12 18:45:34 -0800447 overlayable->name = util::Utf16ToUtf8(strcpy16_dtoh((const char16_t*)header->name,
448 arraysize(header->name)));
449 overlayable->actor = util::Utf16ToUtf8(strcpy16_dtoh((const char16_t*)header->actor,
450 arraysize(header->name)));
451 overlayable->source = source_.WithLine(0);
Ryan Mitchell54237ff2018-12-13 15:44:29 -0800452
Ryan Mitchell75e20dd2018-11-06 16:39:36 -0800453 ResChunkPullParser parser(GetChunkData(chunk),
454 GetChunkDataLen(chunk));
455 while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
456 if (util::DeviceToHost16(parser.chunk()->type) == android::RES_TABLE_OVERLAYABLE_POLICY_TYPE) {
457 const ResTable_overlayable_policy_header* policy_header =
458 ConvertTo<ResTable_overlayable_policy_header>(parser.chunk());
459
Ryan Mitchell54237ff2018-12-13 15:44:29 -0800460 OverlayableItem::PolicyFlags policies = OverlayableItem::Policy::kNone;
Ryan Mitchell75e20dd2018-11-06 16:39:36 -0800461 if (policy_header->policy_flags & ResTable_overlayable_policy_header::POLICY_PUBLIC) {
Ryan Mitchell54237ff2018-12-13 15:44:29 -0800462 policies |= OverlayableItem::Policy::kPublic;
Ryan Mitchell75e20dd2018-11-06 16:39:36 -0800463 }
464 if (policy_header->policy_flags
465 & ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION) {
Ryan Mitchell54237ff2018-12-13 15:44:29 -0800466 policies |= OverlayableItem::Policy::kSystem;
Ryan Mitchell75e20dd2018-11-06 16:39:36 -0800467 }
468 if (policy_header->policy_flags
469 & ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION) {
Ryan Mitchell54237ff2018-12-13 15:44:29 -0800470 policies |= OverlayableItem::Policy::kVendor;
Ryan Mitchell75e20dd2018-11-06 16:39:36 -0800471 }
472 if (policy_header->policy_flags
473 & ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION) {
Ryan Mitchell54237ff2018-12-13 15:44:29 -0800474 policies |= OverlayableItem::Policy::kProduct;
Ryan Mitchell75e20dd2018-11-06 16:39:36 -0800475 }
Ryan Mitchell75e20dd2018-11-06 16:39:36 -0800476
477 const ResTable_ref* const ref_begin = reinterpret_cast<const ResTable_ref*>(
478 ((uint8_t *)policy_header) + util::DeviceToHost32(policy_header->header.headerSize));
479 const ResTable_ref* const ref_end = ref_begin
480 + util::DeviceToHost32(policy_header->entry_count);
481 for (auto ref_iter = ref_begin; ref_iter != ref_end; ++ref_iter) {
482 ResourceId res_id(util::DeviceToHost32(ref_iter->ident));
483 const auto iter = id_index_.find(res_id);
484
485 // If the overlayable chunk comes before the type chunks, the resource ids and resource name
486 // pairing will not exist at this point.
487 if (iter == id_index_.cend()) {
488 diag_->Error(DiagMessage(source_) << "failed to find resource name for overlayable"
489 << " resource " << res_id);
490 return false;
491 }
492
Ryan Mitchell54237ff2018-12-13 15:44:29 -0800493 OverlayableItem overlayable_item(overlayable);
494 overlayable_item.source = source_.WithLine(0);
495 overlayable_item.policies = policies;
496 if (!table_->SetOverlayable(iter->second, overlayable_item, diag_)) {
Ryan Mitchell1bb1fe02018-11-16 11:21:41 -0800497 return false;
Ryan Mitchell75e20dd2018-11-06 16:39:36 -0800498 }
499 }
500 }
501 }
502
503 return true;
504}
505
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700506std::unique_ptr<Item> BinaryResourceParser::ParseValue(const ResourceNameRef& name,
507 const ConfigDescription& config,
508 const android::Res_value& value) {
509 std::unique_ptr<Item> item = ResourceUtils::ParseBinaryResValue(name.type, config, value_pool_,
510 value, &table_->string_pool);
Adam Lesinski8780eb62017-10-31 17:44:39 -0700511 if (files_ != nullptr) {
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700512 FileReference* file_ref = ValueCast<FileReference>(item.get());
513 if (file_ref != nullptr) {
514 file_ref->file = files_->FindFile(*file_ref->path);
515 if (file_ref->file == nullptr) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700516 diag_->Warn(DiagMessage() << "resource " << name << " for config '" << config
517 << "' is a file reference to '" << *file_ref->path
518 << "' but no such path exists");
Adam Lesinskib54ef102016-10-21 13:38:42 -0700519 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700520 }
521 }
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700522 return item;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700523}
524
Adam Lesinski46708052017-09-29 14:49:15 -0700525std::unique_ptr<Value> BinaryResourceParser::ParseMapEntry(const ResourceNameRef& name,
526 const ConfigDescription& config,
527 const ResTable_map_entry* map) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700528 switch (name.type) {
529 case ResourceType::kStyle:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700530 return ParseStyle(name, config, map);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700531 case ResourceType::kAttrPrivate:
Adam Lesinski8780eb62017-10-31 17:44:39 -0700532 // fallthrough
Adam Lesinskib54ef102016-10-21 13:38:42 -0700533 case ResourceType::kAttr:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700534 return ParseAttr(name, config, map);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700535 case ResourceType::kArray:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700536 return ParseArray(name, config, map);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700537 case ResourceType::kPlurals:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700538 return ParsePlural(name, config, map);
Adam Lesinski33af6c72017-03-29 13:00:35 -0700539 case ResourceType::kId:
540 // Special case: An ID is not a bag, but some apps have defined the auto-generated
541 // IDs that come from declaring an enum value in an attribute as an empty map...
542 // We can ignore the value here.
543 return util::make_unique<Id>();
Adam Lesinskib54ef102016-10-21 13:38:42 -0700544 default:
Adam Lesinski93190b72017-11-03 15:20:17 -0700545 diag_->Error(DiagMessage() << "illegal map type '" << to_string(name.type) << "' ("
Adam Lesinski8780eb62017-10-31 17:44:39 -0700546 << (int)name.type << ")");
Adam Lesinskib54ef102016-10-21 13:38:42 -0700547 break;
548 }
549 return {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700550}
551
Adam Lesinski46708052017-09-29 14:49:15 -0700552std::unique_ptr<Style> BinaryResourceParser::ParseStyle(const ResourceNameRef& name,
553 const ConfigDescription& config,
554 const ResTable_map_entry* map) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700555 std::unique_ptr<Style> style = util::make_unique<Style>();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700556 if (util::DeviceToHost32(map->parent.ident) != 0) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700557 // The parent is a regular reference to a resource.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700558 style->parent = Reference(util::DeviceToHost32(map->parent.ident));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700559 }
560
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700561 for (const ResTable_map& map_entry : map) {
562 if (Res_INTERNALID(util::DeviceToHost32(map_entry.name.ident))) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700563 continue;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700564 }
565
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700566 Style::Entry style_entry;
567 style_entry.key = Reference(util::DeviceToHost32(map_entry.name.ident));
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700568 style_entry.value = ParseValue(name, config, map_entry.value);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700569 if (!style_entry.value) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700570 return {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700571 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700572 style->entries.push_back(std::move(style_entry));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700573 }
574 return style;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700575}
576
Adam Lesinski46708052017-09-29 14:49:15 -0700577std::unique_ptr<Attribute> BinaryResourceParser::ParseAttr(const ResourceNameRef& name,
578 const ConfigDescription& config,
579 const ResTable_map_entry* map) {
Adam Lesinski73bff1e2017-12-08 16:06:10 -0800580 std::unique_ptr<Attribute> attr = util::make_unique<Attribute>();
581 attr->SetWeak((util::DeviceToHost16(map->flags) & ResTable_entry::FLAG_WEAK) != 0);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700582
Adam Lesinskib54ef102016-10-21 13:38:42 -0700583 // First we must discover what type of attribute this is. Find the type mask.
Adam Lesinski46708052017-09-29 14:49:15 -0700584 auto type_mask_iter = std::find_if(begin(map), end(map), [](const ResTable_map& entry) -> bool {
585 return util::DeviceToHost32(entry.name.ident) == ResTable_map::ATTR_TYPE;
586 });
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700587
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700588 if (type_mask_iter != end(map)) {
589 attr->type_mask = util::DeviceToHost32(type_mask_iter->value.data);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700590 }
591
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700592 for (const ResTable_map& map_entry : map) {
593 if (Res_INTERNALID(util::DeviceToHost32(map_entry.name.ident))) {
594 switch (util::DeviceToHost32(map_entry.name.ident)) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700595 case ResTable_map::ATTR_MIN:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700596 attr->min_int = static_cast<int32_t>(map_entry.value.data);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700597 break;
598 case ResTable_map::ATTR_MAX:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700599 attr->max_int = static_cast<int32_t>(map_entry.value.data);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700600 break;
601 }
602 continue;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700603 }
604
Adam Lesinski46708052017-09-29 14:49:15 -0700605 if (attr->type_mask & (ResTable_map::TYPE_ENUM | ResTable_map::TYPE_FLAGS)) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700606 Attribute::Symbol symbol;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700607 symbol.value = util::DeviceToHost32(map_entry.value.data);
608 symbol.symbol = Reference(util::DeviceToHost32(map_entry.name.ident));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700609 attr->symbols.push_back(std::move(symbol));
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700610 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700611 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700612
Adam Lesinskib54ef102016-10-21 13:38:42 -0700613 // TODO(adamlesinski): Find i80n, attributes.
614 return attr;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700615}
616
Adam Lesinski46708052017-09-29 14:49:15 -0700617std::unique_ptr<Array> BinaryResourceParser::ParseArray(const ResourceNameRef& name,
618 const ConfigDescription& config,
619 const ResTable_map_entry* map) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700620 std::unique_ptr<Array> array = util::make_unique<Array>();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700621 for (const ResTable_map& map_entry : map) {
Adam Lesinski4ffea042017-08-10 15:37:28 -0700622 array->elements.push_back(ParseValue(name, config, map_entry.value));
Adam Lesinskib54ef102016-10-21 13:38:42 -0700623 }
624 return array;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700625}
626
Adam Lesinski46708052017-09-29 14:49:15 -0700627std::unique_ptr<Plural> BinaryResourceParser::ParsePlural(const ResourceNameRef& name,
628 const ConfigDescription& config,
629 const ResTable_map_entry* map) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700630 std::unique_ptr<Plural> plural = util::make_unique<Plural>();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700631 for (const ResTable_map& map_entry : map) {
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700632 std::unique_ptr<Item> item = ParseValue(name, config, map_entry.value);
Adam Lesinskib54ef102016-10-21 13:38:42 -0700633 if (!item) {
634 return {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700635 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700636
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700637 switch (util::DeviceToHost32(map_entry.name.ident)) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700638 case ResTable_map::ATTR_ZERO:
639 plural->values[Plural::Zero] = std::move(item);
640 break;
641 case ResTable_map::ATTR_ONE:
642 plural->values[Plural::One] = std::move(item);
643 break;
644 case ResTable_map::ATTR_TWO:
645 plural->values[Plural::Two] = std::move(item);
646 break;
647 case ResTable_map::ATTR_FEW:
648 plural->values[Plural::Few] = std::move(item);
649 break;
650 case ResTable_map::ATTR_MANY:
651 plural->values[Plural::Many] = std::move(item);
652 break;
653 case ResTable_map::ATTR_OTHER:
654 plural->values[Plural::Other] = std::move(item);
655 break;
656 }
657 }
658 return plural;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700659}
660
Adam Lesinskib54ef102016-10-21 13:38:42 -0700661} // namespace aapt