blob: bb33ea78f4962fd25bf92e1487cb61f308e426b9 [file] [log] [blame]
Adam Lesinski1ab598f2015-08-14 14:26:04 -07001/*
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 "ConfigDescription.h"
18#include "Resource.h"
Adam Lesinskie78fd612015-10-22 12:48:43 -070019#include "ValueVisitor.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070020
21#include "process/SymbolTable.h"
Adam Lesinskie78fd612015-10-22 12:48:43 -070022#include "util/Comparators.h"
23#include "util/Util.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070024
25#include <androidfw/AssetManager.h>
26#include <androidfw/ResourceTypes.h>
27
28namespace aapt {
29
30const ISymbolTable::Symbol* SymbolTableWrapper::findByName(const ResourceName& name) {
31 if (const std::shared_ptr<Symbol>& s = mCache.get(name)) {
32 return s.get();
33 }
34
35 Maybe<ResourceTable::SearchResult> result = mTable->findResource(name);
36 if (!result) {
37 if (name.type == ResourceType::kAttr) {
38 // Recurse and try looking up a private attribute.
Adam Lesinskie78fd612015-10-22 12:48:43 -070039 return findByName(ResourceName(name.package, ResourceType::kAttrPrivate, name.entry));
Adam Lesinski1ab598f2015-08-14 14:26:04 -070040 }
41 return {};
42 }
43
44 ResourceTable::SearchResult sr = result.value();
45
46 // If no ID exists, we treat the symbol as missing. SymbolTables are used to
47 // find symbols to link.
48 if (!sr.package->id || !sr.type->id || !sr.entry->id) {
49 return {};
50 }
51
52 std::shared_ptr<Symbol> symbol = std::make_shared<Symbol>();
Adam Lesinskie78fd612015-10-22 12:48:43 -070053 symbol->id = ResourceId(sr.package->id.value(), sr.type->id.value(), sr.entry->id.value());
Adam Lesinski1ab598f2015-08-14 14:26:04 -070054
55 if (name.type == ResourceType::kAttr || name.type == ResourceType::kAttrPrivate) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -070056 const ConfigDescription kDefaultConfig;
57 auto iter = std::lower_bound(sr.entry->values.begin(), sr.entry->values.end(),
Adam Lesinskib274e352015-11-06 15:14:35 -080058 kDefaultConfig, cmp::lessThanConfig);
Adam Lesinski1ab598f2015-08-14 14:26:04 -070059
60 if (iter != sr.entry->values.end() && iter->config == kDefaultConfig) {
61 // This resource has an Attribute.
Adam Lesinskie78fd612015-10-22 12:48:43 -070062 if (Attribute* attr = valueCast<Attribute>(iter->value.get())) {
63 symbol->attribute = std::unique_ptr<Attribute>(attr->clone(nullptr));
64 } else {
65 return {};
66 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -070067 }
68 }
69
70 if (name.type == ResourceType::kAttrPrivate) {
71 // Masquerade this entry as kAttr.
Adam Lesinskie78fd612015-10-22 12:48:43 -070072 mCache.put(ResourceName(name.package, ResourceType::kAttr, name.entry), symbol);
Adam Lesinski1ab598f2015-08-14 14:26:04 -070073 } else {
74 mCache.put(name, symbol);
75 }
76 return symbol.get();
77}
78
79
Adam Lesinskie352b992015-11-16 11:59:14 -080080static std::shared_ptr<ISymbolTable::Symbol> lookupAttributeInTable(const android::ResTable& table,
81 ResourceId id) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -070082 // Try as a bag.
83 const android::ResTable::bag_entry* entry;
84 ssize_t count = table.lockBag(id.id, &entry);
85 if (count < 0) {
86 table.unlockBag(entry);
87 return nullptr;
88 }
89
90 // We found a resource.
91 std::shared_ptr<ISymbolTable::Symbol> s = std::make_shared<ISymbolTable::Symbol>();
92 s->id = id;
93
94 // Check to see if it is an attribute.
95 for (size_t i = 0; i < (size_t) count; i++) {
96 if (entry[i].map.name.ident == android::ResTable_map::ATTR_TYPE) {
97 s->attribute = util::make_unique<Attribute>(false);
98 s->attribute->typeMask = entry[i].map.value.data;
99 break;
100 }
101 }
102
103 if (s->attribute) {
104 for (size_t i = 0; i < (size_t) count; i++) {
105 if (!Res_INTERNALID(entry[i].map.name.ident)) {
106 android::ResTable::resource_name entryName;
107 if (!table.getResourceName(entry[i].map.name.ident, false, &entryName)) {
108 table.unlockBag(entry);
109 return nullptr;
110 }
111
112 const ResourceType* parsedType = parseResourceType(
113 StringPiece16(entryName.type, entryName.typeLen));
114 if (!parsedType) {
115 table.unlockBag(entry);
116 return nullptr;
117 }
118
119 Attribute::Symbol symbol;
120 symbol.symbol.name = ResourceNameRef(
121 StringPiece16(entryName.package, entryName.packageLen),
122 *parsedType,
123 StringPiece16(entryName.name, entryName.nameLen)).toResourceName();
124 symbol.symbol.id = ResourceId(entry[i].map.name.ident);
125 symbol.value = entry[i].map.value.data;
126 s->attribute->symbols.push_back(std::move(symbol));
127 }
128 }
129 }
130 table.unlockBag(entry);
131 return s;
132}
133
134const ISymbolTable::Symbol* AssetManagerSymbolTableBuilder::AssetManagerSymbolTable::findByName(
135 const ResourceName& name) {
136 if (const std::shared_ptr<Symbol>& s = mCache.get(name)) {
137 return s.get();
138 }
139
140 for (const auto& asset : mAssets) {
141 const android::ResTable& table = asset->getResources(false);
142 StringPiece16 typeStr = toString(name.type);
Adam Lesinskie352b992015-11-16 11:59:14 -0800143 uint32_t typeSpecFlags = 0;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700144 ResourceId resId = table.identifierForName(name.entry.data(), name.entry.size(),
145 typeStr.data(), typeStr.size(),
Adam Lesinskie352b992015-11-16 11:59:14 -0800146 name.package.data(), name.package.size(),
147 &typeSpecFlags);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700148 if (!resId.isValid()) {
149 continue;
150 }
151
Adam Lesinskie352b992015-11-16 11:59:14 -0800152 std::shared_ptr<Symbol> s;
153 if (name.type == ResourceType::kAttr) {
154 s = lookupAttributeInTable(table, resId);
155 } else {
156 s = std::make_shared<Symbol>();
157 s->id = resId;
158 }
159
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700160 if (s) {
161 mCache.put(name, s);
162 return s.get();
163 }
164 }
165 return nullptr;
166}
167
168const ISymbolTable::Symbol* AssetManagerSymbolTableBuilder::AssetManagerSymbolTable::findById(
169 ResourceId id) {
170 if (const std::shared_ptr<Symbol>& s = mIdCache.get(id)) {
171 return s.get();
172 }
173
174 for (const auto& asset : mAssets) {
175 const android::ResTable& table = asset->getResources(false);
176
Adam Lesinskie352b992015-11-16 11:59:14 -0800177 android::ResTable::resource_name name;
178 if (!table.getResourceName(id.id, true, &name)) {
179 continue;
180 }
181
182 bool isAttr = false;
183 if (name.type) {
184 if (const ResourceType* t = parseResourceType(StringPiece16(name.type, name.typeLen))) {
185 isAttr = (*t == ResourceType::kAttr);
186 }
187 } else if (name.type8) {
188 isAttr = (StringPiece(name.type8, name.typeLen) == "attr");
189 }
190
191 std::shared_ptr<Symbol> s;
192 if (isAttr) {
193 s = lookupAttributeInTable(table, id);
194 } else {
195 s = std::make_shared<Symbol>();
196 s->id = id;
197 }
198
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700199 if (s) {
200 mIdCache.put(id, s);
201 return s.get();
202 }
203 }
204 return nullptr;
205}
206
207const ISymbolTable::Symbol* JoinedSymbolTableBuilder::JoinedSymbolTable::findByName(
208 const ResourceName& name) {
209 for (auto& symbolTable : mSymbolTables) {
210 if (const Symbol* s = symbolTable->findByName(name)) {
211 return s;
212 }
213 }
214 return {};
215}
216
217const ISymbolTable::Symbol* JoinedSymbolTableBuilder::JoinedSymbolTable::findById(ResourceId id) {
218 for (auto& symbolTable : mSymbolTables) {
219 if (const Symbol* s = symbolTable->findById(id)) {
220 return s;
221 }
222 }
223 return {};
224}
225
226} // namespace aapt