blob: 93b5e98b1359c4ffe9bc4e9f13b2bd1d33ebda6a [file] [log] [blame]
Adam Lesinski6f6ceb72014-11-14 14:48:12 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Maybe.h"
18#include "Resolver.h"
19#include "Resource.h"
20#include "ResourceTable.h"
21#include "ResourceValues.h"
22#include "Util.h"
23
24#include <androidfw/AssetManager.h>
25#include <androidfw/ResourceTypes.h>
26#include <memory>
27#include <vector>
28
29namespace aapt {
30
31Resolver::Resolver(std::shared_ptr<const ResourceTable> table,
32 std::shared_ptr<const android::AssetManager> sources) :
33 mTable(table), mSources(sources) {
34}
35
36Maybe<ResourceId> Resolver::findId(const ResourceName& name) {
37 Maybe<Entry> result = findAttribute(name);
38 if (result) {
39 return result.value().id;
40 }
41 return {};
42}
43
44Maybe<Resolver::Entry> Resolver::findAttribute(const ResourceName& name) {
45 auto cacheIter = mCache.find(name);
46 if (cacheIter != std::end(mCache)) {
47 return Entry{ cacheIter->second.id, cacheIter->second.attr.get() };
48 }
49
50 const ResourceTableType* type;
51 const ResourceEntry* entry;
52 std::tie(type, entry) = mTable->findResource(name);
53 if (type && entry) {
54 Entry result = {};
55 if (mTable->getPackageId() != ResourceTable::kUnsetPackageId &&
56 type->typeId != ResourceTableType::kUnsetTypeId &&
57 entry->entryId != ResourceEntry::kUnsetEntryId) {
58 result.id = ResourceId(mTable->getPackageId(), type->typeId, entry->entryId);
59 }
60
61 if (!entry->values.empty()) {
62 visitFunc<Attribute>(*entry->values.front().value, [&result](Attribute& attr) {
63 result.attr = &attr;
64 });
65 }
66 return result;
67 }
68
69 const CacheEntry* cacheEntry = buildCacheEntry(name);
70 if (cacheEntry) {
71 return Entry{ cacheEntry->id, cacheEntry->attr.get() };
72 }
73 return {};
74}
75
76/**
77 * This is called when we need to lookup a resource name in the AssetManager.
78 * Since the values in the AssetManager are not parsed like in a ResourceTable,
79 * we must create Attribute objects here if we find them.
80 */
81const Resolver::CacheEntry* Resolver::buildCacheEntry(const ResourceName& name) {
82 const android::ResTable& table = mSources->getResources(false);
83
84 const StringPiece16 type16 = toString(name.type);
85 ResourceId resId {
86 table.identifierForName(
87 name.entry.data(), name.entry.size(),
88 type16.data(), type16.size(),
89 name.package.data(), name.package.size())
90 };
91
92 if (!resId.isValid()) {
93 return nullptr;
94 }
95
96 CacheEntry& entry = mCache[name];
97 entry.id = resId;
98
99 //
100 // Now check to see if this resource is an Attribute.
101 //
102
103 const android::ResTable::bag_entry* bagBegin;
104 ssize_t bags = table.lockBag(resId.id, &bagBegin);
105 if (bags < 1) {
106 table.unlockBag(bagBegin);
107 return &entry;
108 }
109
110 // Look for the ATTR_TYPE key in the bag and check the types it supports.
111 uint32_t attrTypeMask = 0;
112 for (ssize_t i = 0; i < bags; i++) {
113 if (bagBegin[i].map.name.ident == android::ResTable_map::ATTR_TYPE) {
114 attrTypeMask = bagBegin[i].map.value.data;
115 }
116 }
117
118 entry.attr = util::make_unique<Attribute>(false);
119
120 if (attrTypeMask & android::ResTable_map::TYPE_ENUM ||
121 attrTypeMask & android::ResTable_map::TYPE_FLAGS) {
122 for (ssize_t i = 0; i < bags; i++) {
123 if (Res_INTERNALID(bagBegin[i].map.name.ident)) {
124 // Internal IDs are special keys, which are not enum/flag symbols, so skip.
125 continue;
126 }
127
128 android::ResTable::resource_name symbolName;
129 bool result = table.getResourceName(bagBegin[i].map.name.ident, false,
130 &symbolName);
131 assert(result);
132 const ResourceType* type = parseResourceType(
133 StringPiece16(symbolName.type, symbolName.typeLen));
134 assert(type);
135
136 entry.attr->symbols.push_back(Attribute::Symbol{
137 Reference(ResourceNameRef(
138 StringPiece16(symbolName.package, symbolName.packageLen),
139 *type,
140 StringPiece16(symbolName.name, symbolName.nameLen))),
141 bagBegin[i].map.value.data
142 });
143 }
144 }
145
146 entry.attr->typeMask |= attrTypeMask;
147 table.unlockBag(bagBegin);
148 return &entry;
149}
150
151} // namespace aapt