diff options
Diffstat (limited to 'tools/aapt2/ResourceTableResolver.cpp')
-rw-r--r-- | tools/aapt2/ResourceTableResolver.cpp | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/tools/aapt2/ResourceTableResolver.cpp b/tools/aapt2/ResourceTableResolver.cpp new file mode 100644 index 000000000000..0a9f52124e0e --- /dev/null +++ b/tools/aapt2/ResourceTableResolver.cpp @@ -0,0 +1,194 @@ +/* + * 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 "Maybe.h" +#include "NameMangler.h" +#include "Resource.h" +#include "ResourceTable.h" +#include "ResourceTableResolver.h" +#include "ResourceValues.h" +#include "Util.h" + +#include <androidfw/AssetManager.h> +#include <androidfw/ResourceTypes.h> +#include <memory> +#include <vector> + +namespace aapt { + +ResourceTableResolver::ResourceTableResolver( + std::shared_ptr<const ResourceTable> table, + std::shared_ptr<const android::AssetManager> sources) : + mTable(table), mSources(sources) { + const android::ResTable& resTable = mSources->getResources(false); + const size_t packageCount = resTable.getBasePackageCount(); + for (size_t i = 0; i < packageCount; i++) { + std::u16string packageName = resTable.getBasePackageName(i).string(); + mIncludedPackages.insert(std::move(packageName)); + } +} + +Maybe<ResourceId> ResourceTableResolver::findId(const ResourceName& name) { + Maybe<Entry> result = findAttribute(name); + if (result) { + return result.value().id; + } + return {}; +} + +Maybe<IResolver::Entry> ResourceTableResolver::findAttribute(const ResourceName& name) { + auto cacheIter = mCache.find(name); + if (cacheIter != std::end(mCache)) { + return Entry{ cacheIter->second.id, cacheIter->second.attr.get() }; + } + + ResourceName mangledName; + const ResourceName* nameToSearch = &name; + if (name.package != mTable->getPackage()) { + // This may be a reference to an included resource or + // to a mangled resource. + if (mIncludedPackages.find(name.package) == mIncludedPackages.end()) { + // This is not in our included set, so mangle the name and + // check for that. + mangledName.entry = name.entry; + NameMangler::mangle(name.package, &mangledName.entry); + mangledName.package = mTable->getPackage(); + mangledName.type = name.type; + nameToSearch = &mangledName; + } else { + const CacheEntry* cacheEntry = buildCacheEntry(name); + if (cacheEntry) { + return Entry{ cacheEntry->id, cacheEntry->attr.get() }; + } + return {}; + } + } + + const ResourceTableType* type; + const ResourceEntry* entry; + std::tie(type, entry) = mTable->findResource(*nameToSearch); + if (type && entry) { + Entry result = {}; + if (mTable->getPackageId() != ResourceTable::kUnsetPackageId && + type->typeId != ResourceTableType::kUnsetTypeId && + entry->entryId != ResourceEntry::kUnsetEntryId) { + result.id = ResourceId(mTable->getPackageId(), type->typeId, entry->entryId); + } + + if (!entry->values.empty()) { + visitFunc<Attribute>(*entry->values.front().value, [&result](Attribute& attr) { + result.attr = &attr; + }); + } + return result; + } + return {}; +} + +Maybe<ResourceName> ResourceTableResolver::findName(ResourceId resId) { + const android::ResTable& table = mSources->getResources(false); + + android::ResTable::resource_name resourceName; + if (!table.getResourceName(resId.id, false, &resourceName)) { + return {}; + } + + const ResourceType* type = parseResourceType(StringPiece16(resourceName.type, + resourceName.typeLen)); + assert(type); + return ResourceName{ + { resourceName.package, resourceName.packageLen }, + *type, + { resourceName.name, resourceName.nameLen } }; +} + +/** + * This is called when we need to lookup a resource name in the AssetManager. + * Since the values in the AssetManager are not parsed like in a ResourceTable, + * we must create Attribute objects here if we find them. + */ +const ResourceTableResolver::CacheEntry* ResourceTableResolver::buildCacheEntry( + const ResourceName& name) { + const android::ResTable& table = mSources->getResources(false); + + const StringPiece16 type16 = toString(name.type); + ResourceId resId { + table.identifierForName( + name.entry.data(), name.entry.size(), + type16.data(), type16.size(), + name.package.data(), name.package.size()) + }; + + if (!resId.isValid()) { + return nullptr; + } + + CacheEntry& entry = mCache[name]; + entry.id = resId; + + // + // Now check to see if this resource is an Attribute. + // + + const android::ResTable::bag_entry* bagBegin; + ssize_t bags = table.lockBag(resId.id, &bagBegin); + if (bags < 1) { + table.unlockBag(bagBegin); + return &entry; + } + + // Look for the ATTR_TYPE key in the bag and check the types it supports. + uint32_t attrTypeMask = 0; + for (ssize_t i = 0; i < bags; i++) { + if (bagBegin[i].map.name.ident == android::ResTable_map::ATTR_TYPE) { + attrTypeMask = bagBegin[i].map.value.data; + } + } + + entry.attr = util::make_unique<Attribute>(false); + + if (attrTypeMask & android::ResTable_map::TYPE_ENUM || + attrTypeMask & android::ResTable_map::TYPE_FLAGS) { + for (ssize_t i = 0; i < bags; i++) { + if (Res_INTERNALID(bagBegin[i].map.name.ident)) { + // Internal IDs are special keys, which are not enum/flag symbols, so skip. + continue; + } + + android::ResTable::resource_name symbolName; + bool result = table.getResourceName(bagBegin[i].map.name.ident, false, + &symbolName); + assert(result); + const ResourceType* type = parseResourceType( + StringPiece16(symbolName.type, symbolName.typeLen)); + assert(type); + + entry.attr->symbols.push_back(Attribute::Symbol{ + Reference(ResourceNameRef( + StringPiece16(symbolName.package, symbolName.packageLen), + *type, + StringPiece16(symbolName.name, symbolName.nameLen))), + bagBegin[i].map.value.data + }); + } + } + + entry.attr->typeMask |= attrTypeMask; + table.unlockBag(bagBegin); + return &entry; +} + +} // namespace aapt |