summaryrefslogtreecommitdiff
path: root/tools/aapt2/unflatten/BinaryResourceParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/aapt2/unflatten/BinaryResourceParser.cpp')
-rw-r--r--tools/aapt2/unflatten/BinaryResourceParser.cpp586
1 files changed, 0 insertions, 586 deletions
diff --git a/tools/aapt2/unflatten/BinaryResourceParser.cpp b/tools/aapt2/unflatten/BinaryResourceParser.cpp
deleted file mode 100644
index 892aee6fadcb..000000000000
--- a/tools/aapt2/unflatten/BinaryResourceParser.cpp
+++ /dev/null
@@ -1,586 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "unflatten/BinaryResourceParser.h"
-
-#include <algorithm>
-#include <map>
-#include <string>
-
-#include "android-base/logging.h"
-#include "android-base/macros.h"
-#include "android-base/stringprintf.h"
-#include "androidfw/ResourceTypes.h"
-#include "androidfw/TypeWrappers.h"
-
-#include "ResourceTable.h"
-#include "ResourceUtils.h"
-#include "ResourceValues.h"
-#include "Source.h"
-#include "ValueVisitor.h"
-#include "unflatten/ResChunkPullParser.h"
-#include "util/Util.h"
-
-namespace aapt {
-
-using namespace android;
-
-using ::android::base::StringPrintf;
-
-namespace {
-
-// Visitor that converts a reference's resource ID to a resource name, given a mapping from
-// resource ID to resource name.
-class ReferenceIdToNameVisitor : public ValueVisitor {
- public:
- using ValueVisitor::Visit;
-
- explicit ReferenceIdToNameVisitor(const std::map<ResourceId, ResourceName>* mapping)
- : mapping_(mapping) {
- CHECK(mapping_ != nullptr);
- }
-
- void Visit(Reference* reference) override {
- if (!reference->id || !reference->id.value().is_valid()) {
- return;
- }
-
- ResourceId id = reference->id.value();
- auto cache_iter = mapping_->find(id);
- if (cache_iter != mapping_->end()) {
- reference->name = cache_iter->second;
- }
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ReferenceIdToNameVisitor);
-
- const std::map<ResourceId, ResourceName>* mapping_;
-};
-
-} // namespace
-
-BinaryResourceParser::BinaryResourceParser(IAaptContext* context, ResourceTable* table,
- const Source& source, const void* data, size_t len,
- io::IFileCollection* files)
- : context_(context),
- table_(table),
- source_(source),
- data_(data),
- data_len_(len),
- files_(files) {
-}
-
-bool BinaryResourceParser::Parse() {
- ResChunkPullParser parser(data_, data_len_);
-
- if (!ResChunkPullParser::IsGoodEvent(parser.Next())) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "corrupt resources.arsc: " << parser.error());
- return false;
- }
-
- if (parser.chunk()->type != android::RES_TABLE_TYPE) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << StringPrintf("unknown chunk of type 0x%02x",
- static_cast<int>(parser.chunk()->type)));
- return false;
- }
-
- if (!ParseTable(parser.chunk())) {
- return false;
- }
-
- if (parser.Next() != ResChunkPullParser::Event::kEndDocument) {
- if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
- context_->GetDiagnostics()->Warn(
- DiagMessage(source_) << "invalid chunk trailing RES_TABLE_TYPE: " << parser.error());
- } else {
- context_->GetDiagnostics()->Warn(
- DiagMessage(source_) << StringPrintf(
- "unexpected chunk of type 0x%02x trailing RES_TABLE_TYPE",
- static_cast<int>(parser.chunk()->type)));
- }
- }
- return true;
-}
-
-/**
- * Parses the resource table, which contains all the packages, types, and
- * entries.
- */
-bool BinaryResourceParser::ParseTable(const ResChunk_header* chunk) {
- const ResTable_header* table_header = ConvertTo<ResTable_header>(chunk);
- if (!table_header) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "corrupt ResTable_header chunk");
- return false;
- }
-
- ResChunkPullParser parser(GetChunkData(&table_header->header),
- GetChunkDataLen(&table_header->header));
- while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
- switch (util::DeviceToHost16(parser.chunk()->type)) {
- case android::RES_STRING_POOL_TYPE:
- if (value_pool_.getError() == NO_INIT) {
- status_t err = value_pool_.setTo(
- parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
- if (err != NO_ERROR) {
- context_->GetDiagnostics()->Error(
- DiagMessage(source_) << "corrupt string pool in ResTable: "
- << value_pool_.getError());
- return false;
- }
-
- // Reserve some space for the strings we are going to add.
- table_->string_pool.HintWillAdd(value_pool_.size(),
- value_pool_.styleCount());
- } else {
- context_->GetDiagnostics()->Warn(
- DiagMessage(source_) << "unexpected string pool in ResTable");
- }
- break;
-
- case android::RES_TABLE_PACKAGE_TYPE:
- if (!ParsePackage(parser.chunk())) {
- return false;
- }
- break;
-
- default:
- context_->GetDiagnostics()->Warn(
- DiagMessage(source_) << "unexpected chunk type "
- << static_cast<int>(util::DeviceToHost16(parser.chunk()->type)));
- break;
- }
- }
-
- if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
- context_->GetDiagnostics()->Error(
- DiagMessage(source_) << "corrupt resource table: " << parser.error());
- return false;
- }
- return true;
-}
-
-bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) {
- constexpr size_t kMinPackageSize =
- sizeof(ResTable_package) - sizeof(ResTable_package::typeIdOffset);
- const ResTable_package* package_header = ConvertTo<ResTable_package, kMinPackageSize>(chunk);
- if (!package_header) {
- context_->GetDiagnostics()->Error(DiagMessage(source_) << "corrupt ResTable_package chunk");
- return false;
- }
-
- uint32_t package_id = util::DeviceToHost32(package_header->id);
- if (package_id > std::numeric_limits<uint8_t>::max()) {
- context_->GetDiagnostics()->Error(
- DiagMessage(source_) << "package ID is too big (" << package_id << ")");
- return false;
- }
-
- // Extract the package name.
- size_t len = strnlen16((const char16_t*)package_header->name,
- arraysize(package_header->name));
- std::u16string package_name;
- package_name.resize(len);
- for (size_t i = 0; i < len; i++) {
- package_name[i] = util::DeviceToHost16(package_header->name[i]);
- }
-
- ResourceTablePackage* package = table_->CreatePackage(
- util::Utf16ToUtf8(package_name), static_cast<uint8_t>(package_id));
- if (!package) {
- context_->GetDiagnostics()->Error(
- DiagMessage(source_) << "incompatible package '" << package_name
- << "' with ID " << package_id);
- return false;
- }
-
- // There can be multiple packages in a table, so
- // clear the type and key pool in case they were set from a previous package.
- type_pool_.uninit();
- key_pool_.uninit();
-
- ResChunkPullParser parser(GetChunkData(&package_header->header),
- GetChunkDataLen(&package_header->header));
- while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
- switch (util::DeviceToHost16(parser.chunk()->type)) {
- case android::RES_STRING_POOL_TYPE:
- if (type_pool_.getError() == NO_INIT) {
- status_t err = type_pool_.setTo(
- parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
- if (err != NO_ERROR) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "corrupt type string pool in "
- << "ResTable_package: "
- << type_pool_.getError());
- return false;
- }
- } else if (key_pool_.getError() == NO_INIT) {
- status_t err = key_pool_.setTo(
- parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
- if (err != NO_ERROR) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "corrupt key string pool in "
- << "ResTable_package: "
- << key_pool_.getError());
- return false;
- }
- } else {
- context_->GetDiagnostics()->Warn(DiagMessage(source_) << "unexpected string pool");
- }
- break;
-
- case android::RES_TABLE_TYPE_SPEC_TYPE:
- if (!ParseTypeSpec(parser.chunk())) {
- return false;
- }
- break;
-
- case android::RES_TABLE_TYPE_TYPE:
- if (!ParseType(package, parser.chunk())) {
- return false;
- }
- break;
-
- case android::RES_TABLE_LIBRARY_TYPE:
- if (!ParseLibrary(parser.chunk())) {
- return false;
- }
- break;
-
- default:
- context_->GetDiagnostics()->Warn(
- DiagMessage(source_) << "unexpected chunk type "
- << static_cast<int>(util::DeviceToHost16(parser.chunk()->type)));
- break;
- }
- }
-
- if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
- context_->GetDiagnostics()->Error(
- DiagMessage(source_) << "corrupt ResTable_package: " << parser.error());
- return false;
- }
-
- // Now go through the table and change local resource ID references to
- // symbolic references.
- ReferenceIdToNameVisitor visitor(&id_index_);
- VisitAllValuesInTable(table_, &visitor);
- return true;
-}
-
-bool BinaryResourceParser::ParseTypeSpec(const ResChunk_header* chunk) {
- if (type_pool_.getError() != NO_ERROR) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "missing type string pool");
- return false;
- }
-
- const ResTable_typeSpec* type_spec = ConvertTo<ResTable_typeSpec>(chunk);
- if (!type_spec) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "corrupt ResTable_typeSpec chunk");
- return false;
- }
-
- if (type_spec->id == 0) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "ResTable_typeSpec has invalid id: "
- << type_spec->id);
- return false;
- }
- return true;
-}
-
-bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
- const ResChunk_header* chunk) {
- if (type_pool_.getError() != NO_ERROR) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "missing type string pool");
- return false;
- }
-
- if (key_pool_.getError() != NO_ERROR) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "missing key string pool");
- return false;
- }
-
- // Specify a manual size, because ResTable_type contains ResTable_config, which changes
- // a lot and has its own code to handle variable size.
- const ResTable_type* type = ConvertTo<ResTable_type, kResTableTypeMinSize>(chunk);
- if (!type) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "corrupt ResTable_type chunk");
- return false;
- }
-
- if (type->id == 0) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "ResTable_type has invalid id: "
- << (int)type->id);
- return false;
- }
-
- ConfigDescription config;
- config.copyFromDtoH(type->config);
-
- const std::string type_str = util::GetString(type_pool_, type->id - 1);
-
- const ResourceType* parsed_type = ParseResourceType(type_str);
- if (!parsed_type) {
- context_->GetDiagnostics()->Error(
- DiagMessage(source_) << "invalid type name '" << type_str
- << "' for type with ID " << (int)type->id);
- return false;
- }
-
- TypeVariant tv(type);
- for (auto it = tv.beginEntries(); it != tv.endEntries(); ++it) {
- const ResTable_entry* entry = *it;
- if (!entry) {
- continue;
- }
-
- const ResourceName name(
- package->name, *parsed_type,
- util::GetString(key_pool_, util::DeviceToHost32(entry->key.index)));
-
- const ResourceId res_id(package->id.value(), type->id,
- static_cast<uint16_t>(it.index()));
-
- std::unique_ptr<Value> resource_value;
- if (entry->flags & ResTable_entry::FLAG_COMPLEX) {
- const ResTable_map_entry* mapEntry = static_cast<const ResTable_map_entry*>(entry);
-
- // TODO(adamlesinski): Check that the entry count is valid.
- resource_value = ParseMapEntry(name, config, mapEntry);
- } else {
- const Res_value* value =
- (const Res_value*)((const uint8_t*)entry + util::DeviceToHost32(entry->size));
- resource_value = ParseValue(name, config, *value);
- }
-
- if (!resource_value) {
- context_->GetDiagnostics()->Error(
- DiagMessage(source_) << "failed to parse value for resource " << name
- << " (" << res_id << ") with configuration '"
- << config << "'");
- return false;
- }
-
- if (!table_->AddResourceAllowMangled(name, res_id, config, {}, std::move(resource_value),
- context_->GetDiagnostics())) {
- return false;
- }
-
- if ((entry->flags & ResTable_entry::FLAG_PUBLIC) != 0) {
- Symbol symbol;
- symbol.state = SymbolState::kPublic;
- symbol.source = source_.WithLine(0);
- if (!table_->SetSymbolStateAllowMangled(name, res_id, symbol, context_->GetDiagnostics())) {
- return false;
- }
- }
-
- // Add this resource name->id mapping to the index so
- // that we can resolve all ID references to name references.
- auto cache_iter = id_index_.find(res_id);
- if (cache_iter == id_index_.end()) {
- id_index_.insert({res_id, name});
- }
- }
- return true;
-}
-
-bool BinaryResourceParser::ParseLibrary(const ResChunk_header* chunk) {
- DynamicRefTable dynamic_ref_table;
- if (dynamic_ref_table.load(reinterpret_cast<const ResTable_lib_header*>(chunk)) != NO_ERROR) {
- return false;
- }
-
- const KeyedVector<String16, uint8_t>& entries = dynamic_ref_table.entries();
- const size_t count = entries.size();
- for (size_t i = 0; i < count; i++) {
- table_->included_packages_[entries.valueAt(i)] =
- util::Utf16ToUtf8(StringPiece16(entries.keyAt(i).string()));
- }
- return true;
-}
-
-std::unique_ptr<Item> BinaryResourceParser::ParseValue(const ResourceNameRef& name,
- const ConfigDescription& config,
- const android::Res_value& value) {
- std::unique_ptr<Item> item = ResourceUtils::ParseBinaryResValue(name.type, config, value_pool_,
- value, &table_->string_pool);
- if (files_ != nullptr && item != nullptr) {
- FileReference* file_ref = ValueCast<FileReference>(item.get());
- if (file_ref != nullptr) {
- file_ref->file = files_->FindFile(*file_ref->path);
- if (file_ref->file == nullptr) {
- context_->GetDiagnostics()->Warn(DiagMessage() << "resource " << name << " for config '"
- << config << "' is a file reference to '"
- << *file_ref->path
- << "' but no such path exists");
- }
- }
- }
- return item;
-}
-
-std::unique_ptr<Value> BinaryResourceParser::ParseMapEntry(
- const ResourceNameRef& name, const ConfigDescription& config,
- const ResTable_map_entry* map) {
- switch (name.type) {
- case ResourceType::kStyle:
- return ParseStyle(name, config, map);
- case ResourceType::kAttrPrivate:
- // fallthrough
- case ResourceType::kAttr:
- return ParseAttr(name, config, map);
- case ResourceType::kArray:
- return ParseArray(name, config, map);
- case ResourceType::kPlurals:
- return ParsePlural(name, config, map);
- case ResourceType::kId:
- // Special case: An ID is not a bag, but some apps have defined the auto-generated
- // IDs that come from declaring an enum value in an attribute as an empty map...
- // We can ignore the value here.
- return util::make_unique<Id>();
- default:
- context_->GetDiagnostics()->Error(DiagMessage() << "illegal map type '" << ToString(name.type)
- << "' (" << (int)name.type << ")");
- break;
- }
- return {};
-}
-
-std::unique_ptr<Style> BinaryResourceParser::ParseStyle(
- const ResourceNameRef& name, const ConfigDescription& config,
- const ResTable_map_entry* map) {
- std::unique_ptr<Style> style = util::make_unique<Style>();
- if (util::DeviceToHost32(map->parent.ident) != 0) {
- // The parent is a regular reference to a resource.
- style->parent = Reference(util::DeviceToHost32(map->parent.ident));
- }
-
- for (const ResTable_map& map_entry : map) {
- if (Res_INTERNALID(util::DeviceToHost32(map_entry.name.ident))) {
- continue;
- }
-
- Style::Entry style_entry;
- style_entry.key = Reference(util::DeviceToHost32(map_entry.name.ident));
- style_entry.value = ParseValue(name, config, map_entry.value);
- if (!style_entry.value) {
- return {};
- }
- style->entries.push_back(std::move(style_entry));
- }
- return style;
-}
-
-std::unique_ptr<Attribute> BinaryResourceParser::ParseAttr(
- const ResourceNameRef& name, const ConfigDescription& config,
- const ResTable_map_entry* map) {
- const bool is_weak =
- (util::DeviceToHost16(map->flags) & ResTable_entry::FLAG_WEAK) != 0;
- std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(is_weak);
-
- // First we must discover what type of attribute this is. Find the type mask.
- auto type_mask_iter =
- std::find_if(begin(map), end(map), [](const ResTable_map& entry) -> bool {
- return util::DeviceToHost32(entry.name.ident) ==
- ResTable_map::ATTR_TYPE;
- });
-
- if (type_mask_iter != end(map)) {
- attr->type_mask = util::DeviceToHost32(type_mask_iter->value.data);
- }
-
- for (const ResTable_map& map_entry : map) {
- if (Res_INTERNALID(util::DeviceToHost32(map_entry.name.ident))) {
- switch (util::DeviceToHost32(map_entry.name.ident)) {
- case ResTable_map::ATTR_MIN:
- attr->min_int = static_cast<int32_t>(map_entry.value.data);
- break;
- case ResTable_map::ATTR_MAX:
- attr->max_int = static_cast<int32_t>(map_entry.value.data);
- break;
- }
- continue;
- }
-
- if (attr->type_mask &
- (ResTable_map::TYPE_ENUM | ResTable_map::TYPE_FLAGS)) {
- Attribute::Symbol symbol;
- symbol.value = util::DeviceToHost32(map_entry.value.data);
- symbol.symbol = Reference(util::DeviceToHost32(map_entry.name.ident));
- attr->symbols.push_back(std::move(symbol));
- }
- }
-
- // TODO(adamlesinski): Find i80n, attributes.
- return attr;
-}
-
-std::unique_ptr<Array> BinaryResourceParser::ParseArray(
- const ResourceNameRef& name, const ConfigDescription& config,
- const ResTable_map_entry* map) {
- std::unique_ptr<Array> array = util::make_unique<Array>();
- for (const ResTable_map& map_entry : map) {
- array->elements.push_back(ParseValue(name, config, map_entry.value));
- }
- return array;
-}
-
-std::unique_ptr<Plural> BinaryResourceParser::ParsePlural(
- const ResourceNameRef& name, const ConfigDescription& config,
- const ResTable_map_entry* map) {
- std::unique_ptr<Plural> plural = util::make_unique<Plural>();
- for (const ResTable_map& map_entry : map) {
- std::unique_ptr<Item> item = ParseValue(name, config, map_entry.value);
- if (!item) {
- return {};
- }
-
- switch (util::DeviceToHost32(map_entry.name.ident)) {
- case ResTable_map::ATTR_ZERO:
- plural->values[Plural::Zero] = std::move(item);
- break;
- case ResTable_map::ATTR_ONE:
- plural->values[Plural::One] = std::move(item);
- break;
- case ResTable_map::ATTR_TWO:
- plural->values[Plural::Two] = std::move(item);
- break;
- case ResTable_map::ATTR_FEW:
- plural->values[Plural::Few] = std::move(item);
- break;
- case ResTable_map::ATTR_MANY:
- plural->values[Plural::Many] = std::move(item);
- break;
- case ResTable_map::ATTR_OTHER:
- plural->values[Plural::Other] = std::move(item);
- break;
- }
- }
- return plural;
-}
-
-} // namespace aapt