summaryrefslogtreecommitdiff
path: root/tools/aapt2/ResourceTable.cpp
diff options
context:
space:
mode:
authorBill Peckham <bpeckham@google.com>2018-09-08 10:06:40 -0700
committerBill Peckham <bpeckham@google.com>2018-09-08 10:06:40 -0700
commita74879d25eb0e4ef53855b57181b038bca75d05f (patch)
tree2a1ef83944343e547bebeae9998b098557225070 /tools/aapt2/ResourceTable.cpp
parentb00720941bf751117cf02da40add144683ab51f1 (diff)
Merge QP1A.180823.001
Change-Id: Ia2d6fa811b3c57185c1975db603d59e6eaef73fc
Diffstat (limited to 'tools/aapt2/ResourceTable.cpp')
-rw-r--r--tools/aapt2/ResourceTable.cpp171
1 files changed, 117 insertions, 54 deletions
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index d0faac30425a..58b5e8f0212c 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -26,6 +26,7 @@
#include "androidfw/ResourceTypes.h"
#include "ConfigDescription.h"
+#include "Debug.h"
#include "NameMangler.h"
#include "ResourceValues.h"
#include "ValueVisitor.h"
@@ -38,8 +39,9 @@ using ::android::base::StringPrintf;
namespace aapt {
-static bool less_than_type(const std::unique_ptr<ResourceTableType>& lhs, ResourceType rhs) {
- return lhs->type < rhs;
+static bool less_than_type_and_id(const std::unique_ptr<ResourceTableType>& lhs,
+ const std::pair<ResourceType, Maybe<uint8_t>>& rhs) {
+ return lhs->type < rhs.first || (lhs->type == rhs.first && rhs.second && lhs->id < rhs.second);
}
template <typename T>
@@ -51,7 +53,7 @@ template <typename T>
static bool less_than_struct_with_name_and_id(const std::unique_ptr<T>& lhs,
const std::pair<StringPiece, Maybe<uint8_t>>& rhs) {
int name_cmp = lhs->name.compare(0, lhs->name.size(), rhs.first.data(), rhs.first.size());
- return name_cmp < 0 || (name_cmp == 0 && lhs->id < rhs.second);
+ return name_cmp < 0 || (name_cmp == 0 && rhs.second && lhs->id < rhs.second);
}
ResourceTablePackage* ResourceTable::FindPackage(const StringPiece& name) const {
@@ -115,42 +117,52 @@ ResourceTablePackage* ResourceTable::FindOrCreatePackage(const StringPiece& name
return packages.emplace(iter, std::move(new_package))->get();
}
-ResourceTableType* ResourceTablePackage::FindType(ResourceType type) {
+ResourceTableType* ResourceTablePackage::FindType(ResourceType type, const Maybe<uint8_t> id) {
const auto last = types.end();
- auto iter = std::lower_bound(types.begin(), last, type, less_than_type);
- if (iter != last && (*iter)->type == type) {
+ auto iter = std::lower_bound(types.begin(), last, std::make_pair(type, id),
+ less_than_type_and_id);
+ if (iter != last && (*iter)->type == type && (!id || id == (*iter)->id)) {
return iter->get();
}
return nullptr;
}
-ResourceTableType* ResourceTablePackage::FindOrCreateType(ResourceType type) {
+ResourceTableType* ResourceTablePackage::FindOrCreateType(ResourceType type,
+ const Maybe<uint8_t> id) {
const auto last = types.end();
- auto iter = std::lower_bound(types.begin(), last, type, less_than_type);
- if (iter != last && (*iter)->type == type) {
+ auto iter = std::lower_bound(types.begin(), last, std::make_pair(type, id),
+ less_than_type_and_id);
+ if (iter != last && (*iter)->type == type && (!id || id == (*iter)->id)) {
return iter->get();
}
- return types.emplace(iter, new ResourceTableType(type))->get();
+
+ auto new_type = new ResourceTableType(type);
+ new_type->id = id;
+ return types.emplace(iter, std::move(new_type))->get();
}
-ResourceEntry* ResourceTableType::FindEntry(const StringPiece& name) {
+ResourceEntry* ResourceTableType::FindEntry(const StringPiece& name, const Maybe<uint8_t> id) {
const auto last = entries.end();
- auto iter =
- std::lower_bound(entries.begin(), last, name, less_than_struct_with_name<ResourceEntry>);
- if (iter != last && name == (*iter)->name) {
+ auto iter = std::lower_bound(entries.begin(), last, std::make_pair(name, id),
+ less_than_struct_with_name_and_id<ResourceEntry>);
+ if (iter != last && name == (*iter)->name && (!id || id == (*iter)->id)) {
return iter->get();
}
return nullptr;
}
-ResourceEntry* ResourceTableType::FindOrCreateEntry(const StringPiece& name) {
+ResourceEntry* ResourceTableType::FindOrCreateEntry(const StringPiece& name,
+ const Maybe<uint8_t> id) {
auto last = entries.end();
- auto iter =
- std::lower_bound(entries.begin(), last, name, less_than_struct_with_name<ResourceEntry>);
- if (iter != last && name == (*iter)->name) {
+ auto iter = std::lower_bound(entries.begin(), last, std::make_pair(name, id),
+ less_than_struct_with_name_and_id<ResourceEntry>);
+ if (iter != last && name == (*iter)->name && (!id || id == (*iter)->id)) {
return iter->get();
}
- return entries.emplace(iter, new ResourceEntry(name))->get();
+
+ auto new_entry = new ResourceEntry(name);
+ new_entry->id = id;
+ return entries.emplace(iter, std::move(new_entry))->get();
}
ResourceConfigValue* ResourceEntry::FindValue(const ConfigDescription& config) {
@@ -302,9 +314,15 @@ ResourceTable::CollisionResult ResourceTable::ResolveValueCollision(Value* exist
// Keep the existing attribute.
return CollisionResult::kKeepOriginal;
}
+
return CollisionResult::kConflict;
}
+ResourceTable::CollisionResult ResourceTable::IgnoreCollision(Value* /** existing **/,
+ Value* /** incoming **/) {
+ return CollisionResult::kKeepBoth;
+}
+
static StringPiece ResourceNameValidator(const StringPiece& name) {
if (!IsValidResourceEntryName(name)) {
return name;
@@ -321,15 +339,17 @@ bool ResourceTable::AddResource(const ResourceNameRef& name,
const StringPiece& product,
std::unique_ptr<Value> value,
IDiagnostics* diag) {
- return AddResourceImpl(name, {}, config, product, std::move(value), ResourceNameValidator,
- ResolveValueCollision, diag);
+ return AddResourceImpl(name, ResourceId{}, config, product, std::move(value),
+ (validate_resources_ ? ResourceNameValidator : SkipNameValidator),
+ (validate_resources_ ? ResolveValueCollision : IgnoreCollision), diag);
}
bool ResourceTable::AddResourceWithId(const ResourceNameRef& name, const ResourceId& res_id,
const ConfigDescription& config, const StringPiece& product,
std::unique_ptr<Value> value, IDiagnostics* diag) {
- return AddResourceImpl(name, res_id, config, product, std::move(value), ResourceNameValidator,
- ResolveValueCollision, diag);
+ return AddResourceImpl(name, res_id, config, product, std::move(value),
+ (validate_resources_ ? ResourceNameValidator : SkipNameValidator),
+ (validate_resources_ ? ResolveValueCollision : IgnoreCollision), diag);
}
bool ResourceTable::AddFileReference(const ResourceNameRef& name,
@@ -337,14 +357,18 @@ bool ResourceTable::AddFileReference(const ResourceNameRef& name,
const Source& source,
const StringPiece& path,
IDiagnostics* diag) {
- return AddFileReferenceImpl(name, config, source, path, nullptr, ResourceNameValidator, diag);
+ return AddFileReferenceImpl(name, config, source, path, nullptr,
+ (validate_resources_ ? ResourceNameValidator : SkipNameValidator),
+ diag);
}
bool ResourceTable::AddFileReferenceMangled(const ResourceNameRef& name,
const ConfigDescription& config, const Source& source,
const StringPiece& path, io::IFile* file,
IDiagnostics* diag) {
- return AddFileReferenceImpl(name, config, source, path, file, SkipNameValidator, diag);
+ return AddFileReferenceImpl(name, config, source, path, file,
+ (validate_resources_ ? ResourceNameValidator : SkipNameValidator),
+ diag);
}
bool ResourceTable::AddFileReferenceImpl(const ResourceNameRef& name,
@@ -363,7 +387,7 @@ bool ResourceTable::AddResourceMangled(const ResourceNameRef& name, const Config
const StringPiece& product, std::unique_ptr<Value> value,
IDiagnostics* diag) {
return AddResourceImpl(name, ResourceId{}, config, product, std::move(value), SkipNameValidator,
- ResolveValueCollision, diag);
+ (validate_resources_ ? ResolveValueCollision : IgnoreCollision), diag);
}
bool ResourceTable::AddResourceWithIdMangled(const ResourceNameRef& name, const ResourceId& id,
@@ -371,7 +395,7 @@ bool ResourceTable::AddResourceWithIdMangled(const ResourceNameRef& name, const
const StringPiece& product,
std::unique_ptr<Value> value, IDiagnostics* diag) {
return AddResourceImpl(name, id, config, product, std::move(value), SkipNameValidator,
- ResolveValueCollision, diag);
+ (validate_resources_ ? ResolveValueCollision : IgnoreCollision), diag);
}
bool ResourceTable::ValidateName(NameValidator name_validator, const ResourceNameRef& name,
@@ -398,37 +422,57 @@ bool ResourceTable::AddResourceImpl(const ResourceNameRef& name, const ResourceI
return false;
}
+ // Check for package names appearing twice with two different package ids
ResourceTablePackage* package = FindOrCreatePackage(name.package);
if (res_id.is_valid_dynamic() && package->id && package->id.value() != res_id.package_id()) {
- diag->Error(DiagMessage(source) << "trying to add resource '" << name << "' with ID " << res_id
- << " but package '" << package->name << "' already has ID "
- << StringPrintf("%02x", package->id.value()));
+ diag->Error(DiagMessage(source)
+ << "trying to add resource '" << name << "' with ID " << res_id
+ << " but package '" << package->name << "' already has ID "
+ << StringPrintf("%02x", package->id.value()));
return false;
}
- ResourceTableType* type = package->FindOrCreateType(name.type);
- if (res_id.is_valid_dynamic() && type->id && type->id.value() != res_id.type_id()) {
+ // Whether or not to error on duplicate resources
+ bool check_id = validate_resources_ && res_id.is_valid_dynamic();
+ // Whether or not to create a duplicate resource if the id does not match
+ bool use_id = !validate_resources_ && res_id.is_valid_dynamic();
+
+ ResourceTableType* type = package->FindOrCreateType(name.type, use_id ? res_id.type_id()
+ : Maybe<uint8_t>());
+
+ // Check for types appearing twice with two different type ids
+ if (check_id && type->id && type->id.value() != res_id.type_id()) {
diag->Error(DiagMessage(source)
- << "trying to add resource '" << name << "' with ID " << res_id << " but type '"
- << type->type << "' already has ID " << StringPrintf("%02x", type->id.value()));
+ << "trying to add resource '" << name << "' with ID " << res_id
+ << " but type '" << type->type << "' already has ID "
+ << StringPrintf("%02x", type->id.value()));
return false;
}
- ResourceEntry* entry = type->FindOrCreateEntry(name.entry);
- if (res_id.is_valid_dynamic() && entry->id && entry->id.value() != res_id.entry_id()) {
+ ResourceEntry* entry = type->FindOrCreateEntry(name.entry, use_id ? res_id.entry_id()
+ : Maybe<uint8_t>());
+
+ // Check for entries appearing twice with two different entry ids
+ if (check_id && entry->id && entry->id.value() != res_id.entry_id()) {
diag->Error(DiagMessage(source)
- << "trying to add resource '" << name << "' with ID " << res_id
- << " but resource already has ID "
- << ResourceId(package->id.value(), type->id.value(), entry->id.value()));
+ << "trying to add resource '" << name << "' with ID " << res_id
+ << " but resource already has ID "
+ << ResourceId(package->id.value(), type->id.value(), entry->id.value()));
return false;
}
ResourceConfigValue* config_value = entry->FindOrCreateValue(config, product);
- if (config_value->value == nullptr) {
+ if (!config_value->value) {
// Resource does not exist, add it now.
config_value->value = std::move(value);
} else {
switch (conflict_resolver(config_value->value.get(), value.get())) {
+ case CollisionResult::kKeepBoth:
+ // Insert the value ignoring for duplicate configurations
+ entry->values.push_back(util::make_unique<ResourceConfigValue>(config, product));
+ entry->values.back()->value = std::move(value);
+ break;
+
case CollisionResult::kTakeNew:
// Take the incoming value.
config_value->value = std::move(value);
@@ -450,17 +494,22 @@ bool ResourceTable::AddResourceImpl(const ResourceNameRef& name, const ResourceI
type->id = res_id.type_id();
entry->id = res_id.entry_id();
}
+
return true;
}
+bool ResourceTable::GetValidateResources() {
+ return validate_resources_;
+}
+
bool ResourceTable::SetVisibility(const ResourceNameRef& name, const Visibility& visibility,
IDiagnostics* diag) {
- return SetVisibilityImpl(name, visibility, ResourceId{}, ResourceNameValidator, diag);
+ return SetVisibilityImpl(name, visibility, {}, ResourceNameValidator, diag);
}
bool ResourceTable::SetVisibilityMangled(const ResourceNameRef& name, const Visibility& visibility,
IDiagnostics* diag) {
- return SetVisibilityImpl(name, visibility, ResourceId{}, SkipNameValidator, diag);
+ return SetVisibilityImpl(name, visibility, {}, SkipNameValidator, diag);
}
bool ResourceTable::SetVisibilityWithId(const ResourceNameRef& name, const Visibility& visibility,
@@ -484,28 +533,42 @@ bool ResourceTable::SetVisibilityImpl(const ResourceNameRef& name, const Visibil
return false;
}
+ // Check for package names appearing twice with two different package ids
ResourceTablePackage* package = FindOrCreatePackage(name.package);
if (res_id.is_valid_dynamic() && package->id && package->id.value() != res_id.package_id()) {
- diag->Error(DiagMessage(source) << "trying to add resource '" << name << "' with ID " << res_id
- << " but package '" << package->name << "' already has ID "
- << StringPrintf("%02x", package->id.value()));
+ diag->Error(DiagMessage(source)
+ << "trying to add resource '" << name << "' with ID " << res_id
+ << " but package '" << package->name << "' already has ID "
+ << StringPrintf("%02x", package->id.value()));
return false;
}
- ResourceTableType* type = package->FindOrCreateType(name.type);
- if (res_id.is_valid_dynamic() && type->id && type->id.value() != res_id.type_id()) {
+ // Whether or not to error on duplicate resources
+ bool check_id = validate_resources_ && res_id.is_valid_dynamic();
+ // Whether or not to create a duplicate resource if the id does not match
+ bool use_id = !validate_resources_ && res_id.is_valid_dynamic();
+
+ ResourceTableType* type = package->FindOrCreateType(name.type, use_id ? res_id.type_id()
+ : Maybe<uint8_t>());
+
+ // Check for types appearing twice with two different type ids
+ if (check_id && type->id && type->id.value() != res_id.type_id()) {
diag->Error(DiagMessage(source)
- << "trying to add resource '" << name << "' with ID " << res_id << " but type '"
- << type->type << "' already has ID " << StringPrintf("%02x", type->id.value()));
+ << "trying to add resource '" << name << "' with ID " << res_id
+ << " but type '" << type->type << "' already has ID "
+ << StringPrintf("%02x", type->id.value()));
return false;
}
- ResourceEntry* entry = type->FindOrCreateEntry(name.entry);
- if (res_id.is_valid_dynamic() && entry->id && entry->id.value() != res_id.entry_id()) {
+ ResourceEntry* entry = type->FindOrCreateEntry(name.entry, use_id ? res_id.entry_id()
+ : Maybe<uint8_t>());
+
+ // Check for entries appearing twice with two different entry ids
+ if (check_id && entry->id && entry->id.value() != res_id.entry_id()) {
diag->Error(DiagMessage(source)
- << "trying to add resource '" << name << "' with ID " << res_id
- << " but resource already has ID "
- << ResourceId(package->id.value(), type->id.value(), entry->id.value()));
+ << "trying to add resource '" << name << "' with ID " << res_id
+ << " but resource already has ID "
+ << ResourceId(package->id.value(), type->id.value(), entry->id.value()));
return false;
}