11ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski/*
21ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Copyright (C) 2015 The Android Open Source Project
31ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski *
41ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
51ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * you may not use this file except in compliance with the License.
61ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * You may obtain a copy of the License at
71ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski *
81ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
91ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski *
101ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Unless required by applicable law or agreed to in writing, software
111ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
121ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * See the License for the specific language governing permissions and
141ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * limitations under the License.
151ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski */
161ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
171ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "ConfigDescription.h"
181ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "Resource.h"
19e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski#include "ValueVisitor.h"
201ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "process/SymbolTable.h"
21e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski#include "util/Util.h"
221ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
231ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include <androidfw/AssetManager.h>
241ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include <androidfw/ResourceTypes.h>
251ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
261ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskinamespace aapt {
271ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
2864587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinskivoid SymbolTable::appendSource(std::unique_ptr<ISymbolSource> source) {
2964587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    mSources.push_back(std::move(source));
3064587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski
3164587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    // We do not clear the cache, because sources earlier in the list take precedent.
3264587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski}
3364587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski
3464587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinskivoid SymbolTable::prependSource(std::unique_ptr<ISymbolSource> source) {
3564587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    mSources.insert(mSources.begin(), std::move(source));
3664587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski
3764587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    // We must clear the cache in case we did a lookup before adding this resource.
3864587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    mCache.clear();
3964587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski}
4064587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski
4164587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinskiconst SymbolTable::Symbol* SymbolTable::findByName(const ResourceName& name) {
421ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (const std::shared_ptr<Symbol>& s = mCache.get(name)) {
431ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        return s.get();
441ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
4664587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    // We did not find it in the cache, so look through the sources.
4764587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    for (auto& symbolSource : mSources) {
4864587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski        std::unique_ptr<Symbol> symbol = symbolSource->findByName(name);
4964587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski        if (symbol) {
5064587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski            // Take ownership of the symbol into a shared_ptr. We do this because LruCache
5164587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski            // doesn't support unique_ptr.
5264587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski            std::shared_ptr<Symbol> sharedSymbol = std::shared_ptr<Symbol>(symbol.release());
5364587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski            mCache.put(name, sharedSymbol);
547656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski
557656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski            if (sharedSymbol->id) {
567656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski                // The symbol has an ID, so we can also cache this!
577656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski                mIdCache.put(sharedSymbol->id.value(), sharedSymbol);
587656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski            }
5964587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski            return sharedSymbol.get();
6064587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski        }
6164587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    }
6264587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    return nullptr;
6364587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski}
6464587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski
6564587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinskiconst SymbolTable::Symbol* SymbolTable::findById(ResourceId id) {
6664587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    if (const std::shared_ptr<Symbol>& s = mIdCache.get(id)) {
6764587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski        return s.get();
6864587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    }
6964587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski
7064587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    // We did not find it in the cache, so look through the sources.
7164587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    for (auto& symbolSource : mSources) {
7264587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski        std::unique_ptr<Symbol> symbol = symbolSource->findById(id);
7364587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski        if (symbol) {
7464587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski            // Take ownership of the symbol into a shared_ptr. We do this because LruCache
7564587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski            // doesn't support unique_ptr.
7664587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski            std::shared_ptr<Symbol> sharedSymbol = std::shared_ptr<Symbol>(symbol.release());
7764587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski            mIdCache.put(id, sharedSymbol);
7864587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski            return sharedSymbol.get();
7964587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski        }
8064587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    }
8164587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    return nullptr;
8264587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski}
8364587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski
847656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinskiconst SymbolTable::Symbol* SymbolTable::findByReference(const Reference& ref) {
857656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski    // First try the ID. This is because when we lookup by ID, we only fill in the ID cache.
867656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski    // Looking up by name fills in the name and ID cache. So a cache miss will cause a failed
877656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski    // ID lookup, then a successfull name lookup. Subsequent look ups will hit immediately
887656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski    // because the ID is cached too.
897656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski    //
907656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski    // If we looked up by name first, a cache miss would mean we failed to lookup by name, then
917656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski    // succeeded to lookup by ID. Subsequent lookups will miss then hit.
927656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski    const SymbolTable::Symbol* symbol = nullptr;
937656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski    if (ref.id) {
947656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski        symbol = findById(ref.id.value());
957656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski    }
967656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski
977656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski    if (ref.name && !symbol) {
987656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski        symbol = findByName(ref.name.value());
997656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski    }
1007656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski    return symbol;
1017656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski}
1027656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski
10364587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinskistd::unique_ptr<SymbolTable::Symbol> ResourceTableSymbolSource::findByName(
10464587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski        const ResourceName& name) {
1051ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    Maybe<ResourceTable::SearchResult> result = mTable->findResource(name);
1061ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (!result) {
1071ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        if (name.type == ResourceType::kAttr) {
1081ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            // Recurse and try looking up a private attribute.
109e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski            return findByName(ResourceName(name.package, ResourceType::kAttrPrivate, name.entry));
1101ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        }
1111ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        return {};
1121ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
1131ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
1141ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    ResourceTable::SearchResult sr = result.value();
1151ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
11664587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    std::unique_ptr<SymbolTable::Symbol> symbol = util::make_unique<SymbolTable::Symbol>();
117467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski    symbol->isPublic = (sr.entry->symbolStatus.state == SymbolState::kPublic);
1181ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
11964587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    if (sr.package->id && sr.type->id && sr.entry->id) {
12064587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski        symbol->id = ResourceId(sr.package->id.value(), sr.type->id.value(), sr.entry->id.value());
12164587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    }
12264587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski
1231ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (name.type == ResourceType::kAttr || name.type == ResourceType::kAttrPrivate) {
1241ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        const ConfigDescription kDefaultConfig;
125e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        ResourceConfigValue* configValue = sr.entry->findValue(kDefaultConfig);
126e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        if (configValue) {
1271ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            // This resource has an Attribute.
128e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            if (Attribute* attr = valueCast<Attribute>(configValue->value.get())) {
1297656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski                symbol->attribute = std::make_shared<Attribute>(*attr);
130e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski            } else {
131e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski                return {};
132e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski            }
1331ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        }
1341ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
13564587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    return symbol;
13664587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski}
1371ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
13864587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinskibool AssetManagerSymbolSource::addAssetPath(const StringPiece& path) {
13964587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    int32_t cookie = 0;
14064587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    return mAssets.addAssetPath(android::String8(path.data(), path.size()), &cookie);
1411ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
1421ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
14364587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinskistatic std::unique_ptr<SymbolTable::Symbol> lookupAttributeInTable(const android::ResTable& table,
14464587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski                                                                   ResourceId id) {
1451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    // Try as a bag.
1461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    const android::ResTable::bag_entry* entry;
1471ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    ssize_t count = table.lockBag(id.id, &entry);
1481ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (count < 0) {
1491ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        table.unlockBag(entry);
1501ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        return nullptr;
1511ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
1521ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
1531ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    // We found a resource.
15464587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    std::unique_ptr<SymbolTable::Symbol> s = util::make_unique<SymbolTable::Symbol>();
1551ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    s->id = id;
1561ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
1571ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    // Check to see if it is an attribute.
1581ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    for (size_t i = 0; i < (size_t) count; i++) {
1591ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        if (entry[i].map.name.ident == android::ResTable_map::ATTR_TYPE) {
1607656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski            s->attribute = std::make_shared<Attribute>(false);
1611ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            s->attribute->typeMask = entry[i].map.value.data;
1621ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            break;
1631ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        }
1641ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
1651ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
1661ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (s->attribute) {
1671ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        for (size_t i = 0; i < (size_t) count; i++) {
168a587065721053ad54e34f484868142407d59512dAdam Lesinski            const android::ResTable_map& mapEntry = entry[i].map;
169a587065721053ad54e34f484868142407d59512dAdam Lesinski            if (Res_INTERNALID(mapEntry.name.ident)) {
170a587065721053ad54e34f484868142407d59512dAdam Lesinski                switch (mapEntry.name.ident) {
171a587065721053ad54e34f484868142407d59512dAdam Lesinski                case android::ResTable_map::ATTR_MIN:
172a587065721053ad54e34f484868142407d59512dAdam Lesinski                    s->attribute->minInt = static_cast<int32_t>(mapEntry.value.data);
173a587065721053ad54e34f484868142407d59512dAdam Lesinski                    break;
174a587065721053ad54e34f484868142407d59512dAdam Lesinski                case android::ResTable_map::ATTR_MAX:
175a587065721053ad54e34f484868142407d59512dAdam Lesinski                    s->attribute->maxInt = static_cast<int32_t>(mapEntry.value.data);
176a587065721053ad54e34f484868142407d59512dAdam Lesinski                    break;
1771ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                }
178a587065721053ad54e34f484868142407d59512dAdam Lesinski                continue;
179a587065721053ad54e34f484868142407d59512dAdam Lesinski            }
1801ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
181a587065721053ad54e34f484868142407d59512dAdam Lesinski            android::ResTable::resource_name entryName;
182a587065721053ad54e34f484868142407d59512dAdam Lesinski            if (!table.getResourceName(mapEntry.name.ident, false, &entryName)) {
183a587065721053ad54e34f484868142407d59512dAdam Lesinski                table.unlockBag(entry);
184a587065721053ad54e34f484868142407d59512dAdam Lesinski                return nullptr;
185a587065721053ad54e34f484868142407d59512dAdam Lesinski            }
1861ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
187a587065721053ad54e34f484868142407d59512dAdam Lesinski            const ResourceType* parsedType = parseResourceType(
188a587065721053ad54e34f484868142407d59512dAdam Lesinski                    StringPiece16(entryName.type, entryName.typeLen));
189a587065721053ad54e34f484868142407d59512dAdam Lesinski            if (!parsedType) {
190a587065721053ad54e34f484868142407d59512dAdam Lesinski                table.unlockBag(entry);
191a587065721053ad54e34f484868142407d59512dAdam Lesinski                return nullptr;
1921ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            }
193a587065721053ad54e34f484868142407d59512dAdam Lesinski
194a587065721053ad54e34f484868142407d59512dAdam Lesinski            Attribute::Symbol symbol;
195a587065721053ad54e34f484868142407d59512dAdam Lesinski            symbol.symbol.name = ResourceName(
196a587065721053ad54e34f484868142407d59512dAdam Lesinski                    StringPiece16(entryName.package, entryName.packageLen),
197a587065721053ad54e34f484868142407d59512dAdam Lesinski                    *parsedType,
198a587065721053ad54e34f484868142407d59512dAdam Lesinski                    StringPiece16(entryName.name, entryName.nameLen));
199a587065721053ad54e34f484868142407d59512dAdam Lesinski            symbol.symbol.id = ResourceId(mapEntry.name.ident);
200a587065721053ad54e34f484868142407d59512dAdam Lesinski            symbol.value = mapEntry.value.data;
201a587065721053ad54e34f484868142407d59512dAdam Lesinski            s->attribute->symbols.push_back(std::move(symbol));
2021ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        }
2031ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
2041ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    table.unlockBag(entry);
2051ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    return s;
2061ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
2071ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
20864587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinskistd::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::findByName(
2091ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        const ResourceName& name) {
21064587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    const android::ResTable& table = mAssets.getResources(false);
21164587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    StringPiece16 typeStr = toString(name.type);
21264587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    uint32_t typeSpecFlags = 0;
21364587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    ResourceId resId = table.identifierForName(name.entry.data(), name.entry.size(),
21464587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski                                               typeStr.data(), typeStr.size(),
21564587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski                                               name.package.data(), name.package.size(),
21664587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski                                               &typeSpecFlags);
21764587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    if (!resId.isValid()) {
21864587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski        return {};
2191ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
2201ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
22164587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    std::unique_ptr<SymbolTable::Symbol> s;
22264587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    if (name.type == ResourceType::kAttr) {
22364587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski        s = lookupAttributeInTable(table, resId);
22464587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    } else {
22564587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski        s = util::make_unique<SymbolTable::Symbol>();
22664587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski        s->id = resId;
22764587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    }
228e352b990e1dca7857a4d170f411ddad2065670caAdam Lesinski
22964587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    if (s) {
23064587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski        s->isPublic = (typeSpecFlags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
23164587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski        return s;
2321ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
23364587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    return {};
2341ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
2351ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
236467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinskistatic Maybe<ResourceName> getResourceName(const android::ResTable& table, ResourceId id) {
23764587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    android::ResTable::resource_name resName = {};
238467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski    if (!table.getResourceName(id.id, true, &resName)) {
239467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski        return {};
240467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski    }
241467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski
242467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski    ResourceName name;
243467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski    if (resName.package) {
244467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski        name.package = StringPiece16(resName.package, resName.packageLen).toString();
245467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski    }
246467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski
247467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski    const ResourceType* type;
248467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski    if (resName.type) {
249467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski        type = parseResourceType(StringPiece16(resName.type, resName.typeLen));
250467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski
251467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski    } else if (resName.type8) {
252467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski        type = parseResourceType(util::utf8ToUtf16(StringPiece(resName.type8, resName.typeLen)));
253467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski    } else {
254467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski        return {};
255467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski    }
256467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski
257467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski    if (!type) {
258467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski        return {};
259467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski    }
260467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski
261467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski    name.type = *type;
262467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski
263467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski    if (resName.name) {
264467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski        name.entry = StringPiece16(resName.name, resName.nameLen).toString();
265467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski    } else if (resName.name8) {
266467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski        name.entry = util::utf8ToUtf16(StringPiece(resName.name8, resName.nameLen));
267467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski    } else {
268467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski        return {};
269467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski    }
270467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski
271467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski    return name;
272467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski}
273467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski
27464587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinskistd::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::findById(ResourceId id) {
27564587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    const android::ResTable& table = mAssets.getResources(false);
27664587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    Maybe<ResourceName> maybeName = getResourceName(table, id);
27764587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    if (!maybeName) {
27864587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski        return {};
2791ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
2801ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
28164587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    uint32_t typeSpecFlags = 0;
28264587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    table.getResourceFlags(id.id, &typeSpecFlags);
283e352b990e1dca7857a4d170f411ddad2065670caAdam Lesinski
28464587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    std::unique_ptr<SymbolTable::Symbol> s;
28564587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    if (maybeName.value().type == ResourceType::kAttr) {
28664587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski        s = lookupAttributeInTable(table, id);
28764587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    } else {
28864587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski        s = util::make_unique<SymbolTable::Symbol>();
28964587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski        s->id = id;
2901ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
2911ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
29264587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    if (s) {
29364587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski        s->isPublic = (typeSpecFlags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
29464587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski        return s;
2951ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
2961ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    return {};
2971ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
2981ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
2997656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinskistd::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::findByReference(
3007656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski        const Reference& ref) {
3017656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski    // AssetManager always prefers IDs.
3027656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski    if (ref.id) {
3037656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski        return findById(ref.id.value());
3047656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski    } else if (ref.name) {
3057656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski        return findByName(ref.name.value());
3067656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski    }
3077656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski    return {};
3087656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski}
3097656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski
3101ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} // namespace aapt
311