blob: 6e4b450b65e54225bed225985182e398f9499d9d [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
Adam Lesinskicacb28f2016-10-19 12:18:14 -070017#include "ResourceTable.h"
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080018#include "ConfigDescription.h"
Adam Lesinski769de982015-04-10 19:43:55 -070019#include "NameMangler.h"
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080020#include "ResourceValues.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070021#include "ValueVisitor.h"
22#include "util/Util.h"
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080023
Adam Lesinskice5e56e2016-10-21 17:56:45 -070024#include <android-base/logging.h>
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080025#include <androidfw/ResourceTypes.h>
Adam Lesinskicacb28f2016-10-19 12:18:14 -070026#include <algorithm>
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080027#include <memory>
28#include <string>
29#include <tuple>
30
Adam Lesinskid5083f62017-01-16 15:07:21 -080031using android::StringPiece;
32
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080033namespace aapt {
34
Adam Lesinskice5e56e2016-10-21 17:56:45 -070035static bool less_than_type(const std::unique_ptr<ResourceTableType>& lhs,
36 ResourceType rhs) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070037 return lhs->type < rhs;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080038}
39
Adam Lesinski1ab598f2015-08-14 14:26:04 -070040template <typename T>
Adam Lesinskice5e56e2016-10-21 17:56:45 -070041static bool less_than_struct_with_name(const std::unique_ptr<T>& lhs,
42 const StringPiece& rhs) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070043 return lhs->name.compare(0, lhs->name.size(), rhs.data(), rhs.size()) < 0;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080044}
45
Adam Lesinskice5e56e2016-10-21 17:56:45 -070046ResourceTablePackage* ResourceTable::FindPackage(const StringPiece& name) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070047 const auto last = packages.end();
Adam Lesinskice5e56e2016-10-21 17:56:45 -070048 auto iter =
49 std::lower_bound(packages.begin(), last, name,
50 less_than_struct_with_name<ResourceTablePackage>);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070051 if (iter != last && name == (*iter)->name) {
52 return iter->get();
53 }
54 return nullptr;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080055}
56
Adam Lesinskice5e56e2016-10-21 17:56:45 -070057ResourceTablePackage* ResourceTable::FindPackageById(uint8_t id) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070058 for (auto& package : packages) {
59 if (package->id && package->id.value() == id) {
60 return package.get();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080061 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -070062 }
63 return nullptr;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080064}
65
Adam Lesinskice5e56e2016-10-21 17:56:45 -070066ResourceTablePackage* ResourceTable::CreatePackage(const StringPiece& name,
Adam Lesinskicacb28f2016-10-19 12:18:14 -070067 Maybe<uint8_t> id) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070068 ResourceTablePackage* package = FindOrCreatePackage(name);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070069 if (id && !package->id) {
70 package->id = id;
Adam Lesinski9ba47d82015-10-13 11:37:10 -070071 return package;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070072 }
73
74 if (id && package->id && package->id.value() != id.value()) {
75 return nullptr;
76 }
77 return package;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080078}
79
Adam Lesinskice5e56e2016-10-21 17:56:45 -070080ResourceTablePackage* ResourceTable::FindOrCreatePackage(
Adam Lesinskicacb28f2016-10-19 12:18:14 -070081 const StringPiece& name) {
82 const auto last = packages.end();
Adam Lesinskice5e56e2016-10-21 17:56:45 -070083 auto iter =
84 std::lower_bound(packages.begin(), last, name,
85 less_than_struct_with_name<ResourceTablePackage>);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070086 if (iter != last && name == (*iter)->name) {
87 return iter->get();
88 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080089
Adam Lesinskice5e56e2016-10-21 17:56:45 -070090 std::unique_ptr<ResourceTablePackage> new_package =
Adam Lesinskicacb28f2016-10-19 12:18:14 -070091 util::make_unique<ResourceTablePackage>();
Adam Lesinskid5083f62017-01-16 15:07:21 -080092 new_package->name = name.to_string();
Adam Lesinskice5e56e2016-10-21 17:56:45 -070093 return packages.emplace(iter, std::move(new_package))->get();
Adam Lesinski1ab598f2015-08-14 14:26:04 -070094}
95
Adam Lesinskice5e56e2016-10-21 17:56:45 -070096ResourceTableType* ResourceTablePackage::FindType(ResourceType type) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070097 const auto last = types.end();
Adam Lesinskice5e56e2016-10-21 17:56:45 -070098 auto iter = std::lower_bound(types.begin(), last, type, less_than_type);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070099 if (iter != last && (*iter)->type == type) {
100 return iter->get();
101 }
102 return nullptr;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700103}
104
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700105ResourceTableType* ResourceTablePackage::FindOrCreateType(ResourceType type) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700106 const auto last = types.end();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700107 auto iter = std::lower_bound(types.begin(), last, type, less_than_type);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700108 if (iter != last && (*iter)->type == type) {
109 return iter->get();
110 }
111 return types.emplace(iter, new ResourceTableType(type))->get();
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700112}
113
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700114ResourceEntry* ResourceTableType::FindEntry(const StringPiece& name) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700115 const auto last = entries.end();
116 auto iter = std::lower_bound(entries.begin(), last, name,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700117 less_than_struct_with_name<ResourceEntry>);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700118 if (iter != last && name == (*iter)->name) {
119 return iter->get();
120 }
121 return nullptr;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700122}
123
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700124ResourceEntry* ResourceTableType::FindOrCreateEntry(const StringPiece& name) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700125 auto last = entries.end();
126 auto iter = std::lower_bound(entries.begin(), last, name,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700127 less_than_struct_with_name<ResourceEntry>);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700128 if (iter != last && name == (*iter)->name) {
129 return iter->get();
130 }
131 return entries.emplace(iter, new ResourceEntry(name))->get();
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700132}
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800133
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700134ResourceConfigValue* ResourceEntry::FindValue(const ConfigDescription& config) {
135 return FindValue(config, StringPiece());
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800136}
137
138struct ConfigKey {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700139 const ConfigDescription* config;
140 const StringPiece& product;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800141};
142
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700143bool ltConfigKeyRef(const std::unique_ptr<ResourceConfigValue>& lhs,
144 const ConfigKey& rhs) {
145 int cmp = lhs->config.compare(*rhs.config);
146 if (cmp == 0) {
147 cmp = StringPiece(lhs->product).compare(rhs.product);
148 }
149 return cmp < 0;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800150}
151
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700152ResourceConfigValue* ResourceEntry::FindValue(const ConfigDescription& config,
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800153 const StringPiece& product) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700154 auto iter = std::lower_bound(values.begin(), values.end(),
155 ConfigKey{&config, product}, ltConfigKeyRef);
156 if (iter != values.end()) {
157 ResourceConfigValue* value = iter->get();
158 if (value->config == config && StringPiece(value->product) == product) {
159 return value;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800160 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700161 }
162 return nullptr;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800163}
164
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700165ResourceConfigValue* ResourceEntry::FindOrCreateValue(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700166 const ConfigDescription& config, const StringPiece& product) {
167 auto iter = std::lower_bound(values.begin(), values.end(),
168 ConfigKey{&config, product}, ltConfigKeyRef);
169 if (iter != values.end()) {
170 ResourceConfigValue* value = iter->get();
171 if (value->config == config && StringPiece(value->product) == product) {
172 return value;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800173 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700174 }
175 ResourceConfigValue* newValue =
176 values
177 .insert(iter, util::make_unique<ResourceConfigValue>(config, product))
178 ->get();
179 return newValue;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800180}
181
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700182std::vector<ResourceConfigValue*> ResourceEntry::findAllValues(
183 const ConfigDescription& config) {
184 std::vector<ResourceConfigValue*> results;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800185
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700186 auto iter = values.begin();
187 for (; iter != values.end(); ++iter) {
188 ResourceConfigValue* value = iter->get();
189 if (value->config == config) {
190 results.push_back(value);
191 ++iter;
192 break;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800193 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700194 }
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800195
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700196 for (; iter != values.end(); ++iter) {
197 ResourceConfigValue* value = iter->get();
198 if (value->config == config) {
199 results.push_back(value);
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800200 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700201 }
202 return results;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800203}
204
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700205std::vector<ResourceConfigValue*> ResourceEntry::FindValuesIf(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700206 const std::function<bool(ResourceConfigValue*)>& f) {
207 std::vector<ResourceConfigValue*> results;
208 for (auto& configValue : values) {
209 if (f(configValue.get())) {
210 results.push_back(configValue.get());
Adam Lesinski458b8772016-04-25 14:20:21 -0700211 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700212 }
213 return results;
Adam Lesinski458b8772016-04-25 14:20:21 -0700214}
215
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800216/**
Adam Lesinski5c3464c2016-08-24 16:03:48 -0700217 * The default handler for collisions.
Adam Lesinski8197cc462016-08-19 12:16:49 -0700218 *
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700219 * Typically, a weak value will be overridden by a strong value. An existing
220 * weak
Adam Lesinski8197cc462016-08-19 12:16:49 -0700221 * value will not be overridden by an incoming weak value.
222 *
223 * There are some exceptions:
224 *
225 * Attributes: There are two types of Attribute values: USE and DECL.
226 *
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700227 * USE is anywhere an Attribute is declared without a format, and in a place
228 * that would
Adam Lesinski8197cc462016-08-19 12:16:49 -0700229 * be legal to declare if the Attribute already existed. This is typically in a
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700230 * <declare-styleable> tag. Attributes defined in a <declare-styleable> are also
231 * weak.
Adam Lesinski8197cc462016-08-19 12:16:49 -0700232 *
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700233 * DECL is an absolute declaration of an Attribute and specifies an explicit
234 * format.
Adam Lesinski8197cc462016-08-19 12:16:49 -0700235 *
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700236 * A DECL will override a USE without error. Two DECLs must match in their
237 * format for there to be
Adam Lesinski8197cc462016-08-19 12:16:49 -0700238 * no error.
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800239 */
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700240ResourceTable::CollisionResult ResourceTable::ResolveValueCollision(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700241 Value* existing, Value* incoming) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700242 Attribute* existing_attr = ValueCast<Attribute>(existing);
243 Attribute* incoming_attr = ValueCast<Attribute>(incoming);
244 if (!incoming_attr) {
245 if (incoming->IsWeak()) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700246 // We're trying to add a weak resource but a resource
247 // already exists. Keep the existing.
248 return CollisionResult::kKeepOriginal;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700249 } else if (existing->IsWeak()) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700250 // Override the weak resource with the new strong resource.
251 return CollisionResult::kTakeNew;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800252 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700253 // The existing and incoming values are strong, this is an error
254 // if the values are not both attributes.
Adam Lesinski5c3464c2016-08-24 16:03:48 -0700255 return CollisionResult::kConflict;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700256 }
257
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700258 if (!existing_attr) {
259 if (existing->IsWeak()) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700260 // The existing value is not an attribute and it is weak,
261 // so take the incoming attribute value.
262 return CollisionResult::kTakeNew;
263 }
264 // The existing value is not an attribute and it is strong,
265 // so the incoming attribute value is an error.
266 return CollisionResult::kConflict;
267 }
268
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700269 CHECK(incoming_attr != nullptr && existing_attr != nullptr);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700270
271 //
272 // Attribute specific handling. At this point we know both
273 // values are attributes. Since we can declare and define
274 // attributes all-over, we do special handling to see
275 // which definition sticks.
276 //
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700277 if (existing_attr->type_mask == incoming_attr->type_mask) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700278 // The two attributes are both DECLs, but they are plain attributes
279 // with the same formats.
280 // Keep the strongest one.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700281 return existing_attr->IsWeak() ? CollisionResult::kTakeNew
282 : CollisionResult::kKeepOriginal;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700283 }
284
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700285 if (existing_attr->IsWeak() &&
286 existing_attr->type_mask == android::ResTable_map::TYPE_ANY) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700287 // Any incoming attribute is better than this.
288 return CollisionResult::kTakeNew;
289 }
290
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700291 if (incoming_attr->IsWeak() &&
292 incoming_attr->type_mask == android::ResTable_map::TYPE_ANY) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700293 // The incoming attribute may be a USE instead of a DECL.
294 // Keep the existing attribute.
295 return CollisionResult::kKeepOriginal;
296 }
297 return CollisionResult::kConflict;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800298}
299
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700300static constexpr const char* kValidNameChars = "._-";
301static constexpr const char* kValidNameMangledChars = "._-$";
Adam Lesinski330edcd2015-05-04 17:40:56 -0700302
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700303bool ResourceTable::AddResource(const ResourceNameRef& name,
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800304 const ConfigDescription& config,
305 const StringPiece& product,
306 std::unique_ptr<Value> value,
Adam Lesinskie78fd612015-10-22 12:48:43 -0700307 IDiagnostics* diag) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700308 return AddResourceImpl(name, {}, config, product, std::move(value),
309 kValidNameChars, ResolveValueCollision, diag);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700310}
311
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700312bool ResourceTable::AddResource(const ResourceNameRef& name,
313 const ResourceId& res_id,
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800314 const ConfigDescription& config,
315 const StringPiece& product,
316 std::unique_ptr<Value> value,
317 IDiagnostics* diag) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700318 return AddResourceImpl(name, res_id, config, product, std::move(value),
319 kValidNameChars, ResolveValueCollision, diag);
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800320}
321
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700322bool ResourceTable::AddFileReference(const ResourceNameRef& name,
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800323 const ConfigDescription& config,
324 const Source& source,
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700325 const StringPiece& path,
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700326 IDiagnostics* diag) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700327 return AddFileReferenceImpl(name, config, source, path, nullptr,
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700328 kValidNameChars, diag);
Adam Lesinskifb48d292015-11-07 15:52:13 -0800329}
330
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700331bool ResourceTable::AddFileReferenceAllowMangled(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700332 const ResourceNameRef& name, const ConfigDescription& config,
333 const Source& source, const StringPiece& path, io::IFile* file,
334 IDiagnostics* diag) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700335 return AddFileReferenceImpl(name, config, source, path, file,
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700336 kValidNameMangledChars, diag);
Adam Lesinski355f2852016-02-13 20:26:45 -0800337}
338
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700339bool ResourceTable::AddFileReferenceImpl(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700340 const ResourceNameRef& name, const ConfigDescription& config,
341 const Source& source, const StringPiece& path, io::IFile* file,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700342 const char* valid_chars, IDiagnostics* diag) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700343 std::unique_ptr<FileReference> fileRef =
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700344 util::make_unique<FileReference>(string_pool.MakeRef(path));
345 fileRef->SetSource(source);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700346 fileRef->file = file;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700347 return AddResourceImpl(name, ResourceId{}, config, StringPiece{},
348 std::move(fileRef), valid_chars, ResolveValueCollision,
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700349 diag);
Adam Lesinski330edcd2015-05-04 17:40:56 -0700350}
351
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700352bool ResourceTable::AddResourceAllowMangled(const ResourceNameRef& name,
Adam Lesinski330edcd2015-05-04 17:40:56 -0700353 const ConfigDescription& config,
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800354 const StringPiece& product,
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700355 std::unique_ptr<Value> value,
356 IDiagnostics* diag) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700357 return AddResourceImpl(name, ResourceId{}, config, product, std::move(value),
358 kValidNameMangledChars, ResolveValueCollision, diag);
Adam Lesinski330edcd2015-05-04 17:40:56 -0700359}
360
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700361bool ResourceTable::AddResourceAllowMangled(const ResourceNameRef& name,
Chih-Hung Hsieh9b8528f2016-08-10 14:15:30 -0700362 const ResourceId& id,
Adam Lesinski9e10ac72015-10-16 14:37:48 -0700363 const ConfigDescription& config,
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800364 const StringPiece& product,
Adam Lesinski9e10ac72015-10-16 14:37:48 -0700365 std::unique_ptr<Value> value,
366 IDiagnostics* diag) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700367 return AddResourceImpl(name, id, config, product, std::move(value),
368 kValidNameMangledChars, ResolveValueCollision, diag);
Adam Lesinski9e10ac72015-10-16 14:37:48 -0700369}
370
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700371bool ResourceTable::AddResourceImpl(
372 const ResourceNameRef& name, const ResourceId& res_id,
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700373 const ConfigDescription& config, const StringPiece& product,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700374 std::unique_ptr<Value> value, const char* valid_chars,
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700375 const CollisionResolverFunc& conflictResolver, IDiagnostics* diag) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700376 CHECK(value != nullptr);
377 CHECK(diag != nullptr);
Adam Lesinskie78fd612015-10-22 12:48:43 -0700378
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700379 auto bad_char_iter =
380 util::FindNonAlphaNumericAndNotInSet(name.entry, valid_chars);
381 if (bad_char_iter != name.entry.end()) {
382 diag->Error(DiagMessage(value->GetSource())
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700383 << "resource '" << name << "' has invalid entry name '"
384 << name.entry << "'. Invalid character '"
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700385 << StringPiece(bad_char_iter, 1) << "'");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700386 return false;
387 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800388
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700389 ResourceTablePackage* package = FindOrCreatePackage(name.package);
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800390 if (res_id.is_valid_dynamic() && package->id && package->id.value() != res_id.package_id()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700391 diag->Error(DiagMessage(value->GetSource())
392 << "trying to add resource '" << name << "' with ID " << res_id
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700393 << " but package '" << package->name << "' already has ID "
394 << std::hex << (int)package->id.value() << std::dec);
395 return false;
396 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800397
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700398 ResourceTableType* type = package->FindOrCreateType(name.type);
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800399 if (res_id.is_valid_dynamic() && type->id && type->id.value() != res_id.type_id()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700400 diag->Error(DiagMessage(value->GetSource())
401 << "trying to add resource '" << name << "' with ID " << res_id
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700402 << " but type '" << type->type << "' already has ID "
403 << std::hex << (int)type->id.value() << std::dec);
404 return false;
405 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800406
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700407 ResourceEntry* entry = type->FindOrCreateEntry(name.entry);
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800408 if (res_id.is_valid_dynamic() && entry->id && entry->id.value() != res_id.entry_id()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700409 diag->Error(DiagMessage(value->GetSource())
410 << "trying to add resource '" << name << "' with ID " << res_id
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700411 << " but resource already has ID "
412 << ResourceId(package->id.value(), type->id.value(),
413 entry->id.value()));
414 return false;
415 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700416
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700417 ResourceConfigValue* config_value = entry->FindOrCreateValue(config, product);
418 if (!config_value->value) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700419 // Resource does not exist, add it now.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700420 config_value->value = std::move(value);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700421
422 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700423 switch (conflictResolver(config_value->value.get(), value.get())) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700424 case CollisionResult::kTakeNew:
425 // Take the incoming value.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700426 config_value->value = std::move(value);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700427 break;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800428
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700429 case CollisionResult::kConflict:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700430 diag->Error(DiagMessage(value->GetSource())
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700431 << "duplicate value for resource '" << name << "' "
432 << "with config '" << config << "'");
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700433 diag->Error(DiagMessage(config_value->value->GetSource())
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700434 << "resource previously defined here");
435 return false;
Adam Lesinski5c3464c2016-08-24 16:03:48 -0700436
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700437 case CollisionResult::kKeepOriginal:
438 break;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800439 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700440 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800441
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800442 if (res_id.is_valid_dynamic()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700443 package->id = res_id.package_id();
444 type->id = res_id.type_id();
445 entry->id = res_id.entry_id();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700446 }
447 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800448}
449
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700450bool ResourceTable::SetSymbolState(const ResourceNameRef& name,
451 const ResourceId& res_id,
Adam Lesinskie78fd612015-10-22 12:48:43 -0700452 const Symbol& symbol, IDiagnostics* diag) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700453 return SetSymbolStateImpl(name, res_id, symbol, kValidNameChars, diag);
Adam Lesinski330edcd2015-05-04 17:40:56 -0700454}
455
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700456bool ResourceTable::SetSymbolStateAllowMangled(const ResourceNameRef& name,
457 const ResourceId& res_id,
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700458 const Symbol& symbol,
459 IDiagnostics* diag) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700460 return SetSymbolStateImpl(name, res_id, symbol, kValidNameMangledChars, diag);
Adam Lesinski330edcd2015-05-04 17:40:56 -0700461}
462
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700463bool ResourceTable::SetSymbolStateImpl(const ResourceNameRef& name,
464 const ResourceId& res_id,
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700465 const Symbol& symbol,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700466 const char* valid_chars,
Adam Lesinskie78fd612015-10-22 12:48:43 -0700467 IDiagnostics* diag) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700468 CHECK(diag != nullptr);
Adam Lesinskie78fd612015-10-22 12:48:43 -0700469
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700470 auto bad_char_iter =
471 util::FindNonAlphaNumericAndNotInSet(name.entry, valid_chars);
472 if (bad_char_iter != name.entry.end()) {
473 diag->Error(DiagMessage(symbol.source)
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700474 << "resource '" << name << "' has invalid entry name '"
475 << name.entry << "'. Invalid character '"
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700476 << StringPiece(bad_char_iter, 1) << "'");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700477 return false;
478 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800479
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700480 ResourceTablePackage* package = FindOrCreatePackage(name.package);
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800481 if (res_id.is_valid_dynamic() && package->id && package->id.value() != res_id.package_id()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700482 diag->Error(DiagMessage(symbol.source)
483 << "trying to add resource '" << name << "' with ID " << res_id
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700484 << " but package '" << package->name << "' already has ID "
485 << std::hex << (int)package->id.value() << std::dec);
486 return false;
487 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800488
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700489 ResourceTableType* type = package->FindOrCreateType(name.type);
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800490 if (res_id.is_valid_dynamic() && type->id && type->id.value() != res_id.type_id()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700491 diag->Error(DiagMessage(symbol.source)
492 << "trying to add resource '" << name << "' with ID " << res_id
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700493 << " but type '" << type->type << "' already has ID "
494 << std::hex << (int)type->id.value() << std::dec);
495 return false;
496 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700497
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700498 ResourceEntry* entry = type->FindOrCreateEntry(name.entry);
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800499 if (res_id.is_valid_dynamic() && entry->id && entry->id.value() != res_id.entry_id()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700500 diag->Error(DiagMessage(symbol.source)
501 << "trying to add resource '" << name << "' with ID " << res_id
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700502 << " but resource already has ID "
503 << ResourceId(package->id.value(), type->id.value(),
504 entry->id.value()));
505 return false;
506 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800507
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800508 if (res_id.is_valid_dynamic()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700509 package->id = res_id.package_id();
510 type->id = res_id.type_id();
511 entry->id = res_id.entry_id();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700512 }
Adam Lesinskia6fe3452015-12-09 15:20:52 -0800513
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700514 // Only mark the type state as public, it doesn't care about being private.
515 if (symbol.state == SymbolState::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700516 type->symbol_status.state = SymbolState::kPublic;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700517 }
Adam Lesinskia6fe3452015-12-09 15:20:52 -0800518
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700519 if (symbol.state == SymbolState::kUndefined &&
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700520 entry->symbol_status.state != SymbolState::kUndefined) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700521 // We can't undefine a symbol (remove its visibility). Ignore.
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800522 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700523 }
524
525 if (symbol.state == SymbolState::kPrivate &&
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700526 entry->symbol_status.state == SymbolState::kPublic) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700527 // We can't downgrade public to private. Ignore.
528 return true;
529 }
530
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700531 entry->symbol_status = std::move(symbol);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700532 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800533}
534
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700535Maybe<ResourceTable::SearchResult> ResourceTable::FindResource(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700536 const ResourceNameRef& name) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700537 ResourceTablePackage* package = FindPackage(name.package);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700538 if (!package) {
539 return {};
540 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800541
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700542 ResourceTableType* type = package->FindType(name.type);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700543 if (!type) {
544 return {};
545 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800546
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700547 ResourceEntry* entry = type->FindEntry(name.entry);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700548 if (!entry) {
549 return {};
550 }
551 return SearchResult{package, type, entry};
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800552}
553
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700554} // namespace aapt