16f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/*
26f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Copyright (C) 2015 The Android Open Source Project
36f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski *
46f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
56f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * you may not use this file except in compliance with the License.
66f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * You may obtain a copy of the License at
76f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski *
86f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
96f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski *
106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Unless required by applicable law or agreed to in writing, software
116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * See the License for the specific language governing permissions and
146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * limitations under the License.
156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */
166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
176f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "Maybe.h"
18769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#include "NameMangler.h"
196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "Resource.h"
206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "ResourceTable.h"
2124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski#include "ResourceTableResolver.h"
226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "ResourceValues.h"
236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "Util.h"
246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <androidfw/AssetManager.h>
266f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <androidfw/ResourceTypes.h>
276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <memory>
286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <vector>
296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskinamespace aapt {
316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3224aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiResourceTableResolver::ResourceTableResolver(
3324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski        std::shared_ptr<const ResourceTable> table,
34330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        const std::vector<std::shared_ptr<const android::AssetManager>>& sources) :
356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        mTable(table), mSources(sources) {
36330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    for (const auto& assetManager : mSources) {
37330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        const android::ResTable& resTable = assetManager->getResources(false);
38330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        const size_t packageCount = resTable.getBasePackageCount();
39330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        for (size_t i = 0; i < packageCount; i++) {
40330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            std::u16string packageName = resTable.getBasePackageName(i).string();
41330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            mIncludedPackages.insert(std::move(packageName));
42330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        }
43769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
446f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
456f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
4624aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiMaybe<ResourceId> ResourceTableResolver::findId(const ResourceName& name) {
476f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    Maybe<Entry> result = findAttribute(name);
486f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    if (result) {
496f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return result.value().id;
506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
516f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    return {};
526f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
536f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
5424aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiMaybe<IResolver::Entry> ResourceTableResolver::findAttribute(const ResourceName& name) {
556f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    auto cacheIter = mCache.find(name);
566f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    if (cacheIter != std::end(mCache)) {
576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return Entry{ cacheIter->second.id, cacheIter->second.attr.get() };
586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
60769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    ResourceName mangledName;
61769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    const ResourceName* nameToSearch = &name;
62769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (name.package != mTable->getPackage()) {
63769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        // This may be a reference to an included resource or
64769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        // to a mangled resource.
65769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (mIncludedPackages.find(name.package) == mIncludedPackages.end()) {
66769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            // This is not in our included set, so mangle the name and
67769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            // check for that.
68769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            mangledName.entry = name.entry;
69769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            NameMangler::mangle(name.package, &mangledName.entry);
70769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            mangledName.package = mTable->getPackage();
71769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            mangledName.type = name.type;
72769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            nameToSearch = &mangledName;
73769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        } else {
74769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            const CacheEntry* cacheEntry = buildCacheEntry(name);
75769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            if (cacheEntry) {
76769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                return Entry{ cacheEntry->id, cacheEntry->attr.get() };
77769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            }
78769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            return {};
79769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        }
80769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
81769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    const ResourceTableType* type;
836f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    const ResourceEntry* entry;
84769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    std::tie(type, entry) = mTable->findResource(*nameToSearch);
856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    if (type && entry) {
866f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        Entry result = {};
876f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        if (mTable->getPackageId() != ResourceTable::kUnsetPackageId &&
886f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                type->typeId != ResourceTableType::kUnsetTypeId &&
896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                entry->entryId != ResourceEntry::kUnsetEntryId) {
906f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            result.id = ResourceId(mTable->getPackageId(), type->typeId, entry->entryId);
916f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        }
926f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        if (!entry->values.empty()) {
946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            visitFunc<Attribute>(*entry->values.front().value, [&result](Attribute& attr) {
956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                    result.attr = &attr;
966f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            });
976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        }
986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return result;
996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
1006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    return {};
1016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
1026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
10324aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiMaybe<ResourceName> ResourceTableResolver::findName(ResourceId resId) {
104330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    for (const auto& assetManager : mSources) {
105330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        const android::ResTable& table = assetManager->getResources(false);
10624aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
107330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        android::ResTable::resource_name resourceName;
108330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        if (!table.getResourceName(resId.id, false, &resourceName)) {
109330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            continue;
110330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        }
11124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
112330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        const ResourceType* type = parseResourceType(StringPiece16(resourceName.type,
113330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                                                                   resourceName.typeLen));
114330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        assert(type);
115330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        return ResourceName{
116330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                { resourceName.package, resourceName.packageLen },
117330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                *type,
118330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                { resourceName.name, resourceName.nameLen } };
119330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    }
120330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    return {};
12124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski}
12224aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
1236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/**
1246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * This is called when we need to lookup a resource name in the AssetManager.
1256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Since the values in the AssetManager are not parsed like in a ResourceTable,
1266f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * we must create Attribute objects here if we find them.
1276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */
12824aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinskiconst ResourceTableResolver::CacheEntry* ResourceTableResolver::buildCacheEntry(
12924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski        const ResourceName& name) {
130330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    for (const auto& assetManager : mSources) {
131330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        const android::ResTable& table = assetManager->getResources(false);
132330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
133330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        const StringPiece16 type16 = toString(name.type);
134330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        ResourceId resId {
135330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            table.identifierForName(
136330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                    name.entry.data(), name.entry.size(),
137330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                    type16.data(), type16.size(),
138330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                    name.package.data(), name.package.size())
139330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        };
140330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
141330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        if (!resId.isValid()) {
142330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            continue;
143330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        }
1446f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
145330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        CacheEntry& entry = mCache[name];
146330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        entry.id = resId;
1476f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
148330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        //
149330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        // Now check to see if this resource is an Attribute.
150330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        //
1516f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
152330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        const android::ResTable::bag_entry* bagBegin;
153330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        ssize_t bags = table.lockBag(resId.id, &bagBegin);
154330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        if (bags < 1) {
155330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            table.unlockBag(bagBegin);
156330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            return &entry;
1576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        }
1586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
159330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        // Look for the ATTR_TYPE key in the bag and check the types it supports.
160330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        uint32_t attrTypeMask = 0;
1616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        for (ssize_t i = 0; i < bags; i++) {
162330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            if (bagBegin[i].map.name.ident == android::ResTable_map::ATTR_TYPE) {
163330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                attrTypeMask = bagBegin[i].map.value.data;
1646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            }
165330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        }
1666f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
167330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        entry.attr = util::make_unique<Attribute>(false);
168330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
169330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        if (attrTypeMask & android::ResTable_map::TYPE_ENUM ||
170330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                attrTypeMask & android::ResTable_map::TYPE_FLAGS) {
171330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            for (ssize_t i = 0; i < bags; i++) {
172330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                if (Res_INTERNALID(bagBegin[i].map.name.ident)) {
173330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                    // Internal IDs are special keys, which are not enum/flag symbols, so skip.
174330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                    continue;
175330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                }
176330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
177330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                android::ResTable::resource_name symbolName;
178330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                bool result = table.getResourceName(bagBegin[i].map.name.ident, false,
179330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                        &symbolName);
180330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                assert(result);
181330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                const ResourceType* type = parseResourceType(
182330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                        StringPiece16(symbolName.type, symbolName.typeLen));
183330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                assert(type);
184330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
185330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                entry.attr->symbols.push_back(Attribute::Symbol{
186330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                        Reference(ResourceNameRef(
187330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                                    StringPiece16(symbolName.package, symbolName.packageLen),
188330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                                    *type,
189330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                                    StringPiece16(symbolName.name, symbolName.nameLen))),
190330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                                bagBegin[i].map.value.data
191330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                });
192330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            }
1936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        }
1946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
195330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        entry.attr->typeMask |= attrTypeMask;
196330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        table.unlockBag(bagBegin);
197330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        return &entry;
198330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    }
199330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    return nullptr;
2006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
2016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} // namespace aapt
203