blob: 168004f0b7218a300eb156494ff039f51e1068e5 [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 Lesinskib1afa072017-03-29 13:52:38 -070035static bool less_than_type(const std::unique_ptr<ResourceTableType>& lhs, ResourceType rhs) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070036 return lhs->type < rhs;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080037}
38
Adam Lesinski1ab598f2015-08-14 14:26:04 -070039template <typename T>
Adam Lesinskib1afa072017-03-29 13:52:38 -070040static bool less_than_struct_with_name(const std::unique_ptr<T>& lhs, const StringPiece& rhs) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070041 return lhs->name.compare(0, lhs->name.size(), rhs.data(), rhs.size()) < 0;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080042}
43
Adam Lesinskice5e56e2016-10-21 17:56:45 -070044ResourceTablePackage* ResourceTable::FindPackage(const StringPiece& name) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070045 const auto last = packages.end();
Adam Lesinskib1afa072017-03-29 13:52:38 -070046 auto iter = std::lower_bound(packages.begin(), last, name,
47 less_than_struct_with_name<ResourceTablePackage>);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070048 if (iter != last && name == (*iter)->name) {
49 return iter->get();
50 }
51 return nullptr;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080052}
53
Adam Lesinskice5e56e2016-10-21 17:56:45 -070054ResourceTablePackage* ResourceTable::FindPackageById(uint8_t id) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070055 for (auto& package : packages) {
56 if (package->id && package->id.value() == id) {
57 return package.get();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080058 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -070059 }
60 return nullptr;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080061}
62
Adam Lesinskib1afa072017-03-29 13:52:38 -070063ResourceTablePackage* ResourceTable::CreatePackage(const StringPiece& name, Maybe<uint8_t> id) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070064 ResourceTablePackage* package = FindOrCreatePackage(name);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070065 if (id && !package->id) {
66 package->id = id;
Adam Lesinski9ba47d82015-10-13 11:37:10 -070067 return package;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070068 }
69
70 if (id && package->id && package->id.value() != id.value()) {
71 return nullptr;
72 }
73 return package;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080074}
75
Adam Lesinskib1afa072017-03-29 13:52:38 -070076ResourceTablePackage* ResourceTable::FindOrCreatePackage(const StringPiece& name) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070077 const auto last = packages.end();
Adam Lesinskib1afa072017-03-29 13:52:38 -070078 auto iter = std::lower_bound(packages.begin(), last, name,
79 less_than_struct_with_name<ResourceTablePackage>);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070080 if (iter != last && name == (*iter)->name) {
81 return iter->get();
82 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080083
Adam Lesinskib1afa072017-03-29 13:52:38 -070084 std::unique_ptr<ResourceTablePackage> new_package = util::make_unique<ResourceTablePackage>();
Adam Lesinskid5083f62017-01-16 15:07:21 -080085 new_package->name = name.to_string();
Adam Lesinskice5e56e2016-10-21 17:56:45 -070086 return packages.emplace(iter, std::move(new_package))->get();
Adam Lesinski1ab598f2015-08-14 14:26:04 -070087}
88
Adam Lesinskice5e56e2016-10-21 17:56:45 -070089ResourceTableType* ResourceTablePackage::FindType(ResourceType type) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070090 const auto last = types.end();
Adam Lesinskice5e56e2016-10-21 17:56:45 -070091 auto iter = std::lower_bound(types.begin(), last, type, less_than_type);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070092 if (iter != last && (*iter)->type == type) {
93 return iter->get();
94 }
95 return nullptr;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070096}
97
Adam Lesinskice5e56e2016-10-21 17:56:45 -070098ResourceTableType* ResourceTablePackage::FindOrCreateType(ResourceType type) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070099 const auto last = types.end();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700100 auto iter = std::lower_bound(types.begin(), last, type, less_than_type);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700101 if (iter != last && (*iter)->type == type) {
102 return iter->get();
103 }
104 return types.emplace(iter, new ResourceTableType(type))->get();
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700105}
106
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700107ResourceEntry* ResourceTableType::FindEntry(const StringPiece& name) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700108 const auto last = entries.end();
Adam Lesinskib1afa072017-03-29 13:52:38 -0700109 auto iter =
110 std::lower_bound(entries.begin(), last, name, less_than_struct_with_name<ResourceEntry>);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700111 if (iter != last && name == (*iter)->name) {
112 return iter->get();
113 }
114 return nullptr;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700115}
116
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700117ResourceEntry* ResourceTableType::FindOrCreateEntry(const StringPiece& name) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700118 auto last = entries.end();
Adam Lesinskib1afa072017-03-29 13:52:38 -0700119 auto iter =
120 std::lower_bound(entries.begin(), last, name, less_than_struct_with_name<ResourceEntry>);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700121 if (iter != last && name == (*iter)->name) {
122 return iter->get();
123 }
124 return entries.emplace(iter, new ResourceEntry(name))->get();
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700125}
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800126
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700127ResourceConfigValue* ResourceEntry::FindValue(const ConfigDescription& config) {
128 return FindValue(config, StringPiece());
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800129}
130
131struct ConfigKey {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700132 const ConfigDescription* config;
133 const StringPiece& product;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800134};
135
Adam Lesinskib1afa072017-03-29 13:52:38 -0700136bool ltConfigKeyRef(const std::unique_ptr<ResourceConfigValue>& lhs, const ConfigKey& rhs) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700137 int cmp = lhs->config.compare(*rhs.config);
138 if (cmp == 0) {
139 cmp = StringPiece(lhs->product).compare(rhs.product);
140 }
141 return cmp < 0;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800142}
143
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700144ResourceConfigValue* ResourceEntry::FindValue(const ConfigDescription& config,
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800145 const StringPiece& product) {
Adam Lesinskib1afa072017-03-29 13:52:38 -0700146 auto iter =
147 std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product}, ltConfigKeyRef);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700148 if (iter != values.end()) {
149 ResourceConfigValue* value = iter->get();
150 if (value->config == config && StringPiece(value->product) == product) {
151 return value;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800152 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700153 }
154 return nullptr;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800155}
156
Adam Lesinskib1afa072017-03-29 13:52:38 -0700157ResourceConfigValue* ResourceEntry::FindOrCreateValue(const ConfigDescription& config,
158 const StringPiece& product) {
159 auto iter =
160 std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product}, ltConfigKeyRef);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700161 if (iter != values.end()) {
162 ResourceConfigValue* value = iter->get();
163 if (value->config == config && StringPiece(value->product) == product) {
164 return value;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800165 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700166 }
167 ResourceConfigValue* newValue =
Adam Lesinskib1afa072017-03-29 13:52:38 -0700168 values.insert(iter, util::make_unique<ResourceConfigValue>(config, product))->get();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700169 return newValue;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800170}
171
Adam Lesinskib1afa072017-03-29 13:52:38 -0700172std::vector<ResourceConfigValue*> ResourceEntry::FindAllValues(const ConfigDescription& config) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700173 std::vector<ResourceConfigValue*> results;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800174
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700175 auto iter = values.begin();
176 for (; iter != values.end(); ++iter) {
177 ResourceConfigValue* value = iter->get();
178 if (value->config == config) {
179 results.push_back(value);
180 ++iter;
181 break;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800182 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700183 }
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800184
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700185 for (; iter != values.end(); ++iter) {
186 ResourceConfigValue* value = iter->get();
187 if (value->config == config) {
188 results.push_back(value);
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800189 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700190 }
191 return results;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800192}
193
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700194std::vector<ResourceConfigValue*> ResourceEntry::FindValuesIf(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700195 const std::function<bool(ResourceConfigValue*)>& f) {
196 std::vector<ResourceConfigValue*> results;
197 for (auto& configValue : values) {
198 if (f(configValue.get())) {
199 results.push_back(configValue.get());
Adam Lesinski458b8772016-04-25 14:20:21 -0700200 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700201 }
202 return results;
Adam Lesinski458b8772016-04-25 14:20:21 -0700203}
204
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800205/**
Adam Lesinski5c3464c2016-08-24 16:03:48 -0700206 * The default handler for collisions.
Adam Lesinski8197cc462016-08-19 12:16:49 -0700207 *
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700208 * Typically, a weak value will be overridden by a strong value. An existing
209 * weak
Adam Lesinski8197cc462016-08-19 12:16:49 -0700210 * value will not be overridden by an incoming weak value.
211 *
212 * There are some exceptions:
213 *
214 * Attributes: There are two types of Attribute values: USE and DECL.
215 *
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700216 * USE is anywhere an Attribute is declared without a format, and in a place
217 * that would
Adam Lesinski8197cc462016-08-19 12:16:49 -0700218 * be legal to declare if the Attribute already existed. This is typically in a
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700219 * <declare-styleable> tag. Attributes defined in a <declare-styleable> are also
220 * weak.
Adam Lesinski8197cc462016-08-19 12:16:49 -0700221 *
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700222 * DECL is an absolute declaration of an Attribute and specifies an explicit
223 * format.
Adam Lesinski8197cc462016-08-19 12:16:49 -0700224 *
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700225 * A DECL will override a USE without error. Two DECLs must match in their
226 * format for there to be
Adam Lesinski8197cc462016-08-19 12:16:49 -0700227 * no error.
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800228 */
Adam Lesinskib1afa072017-03-29 13:52:38 -0700229ResourceTable::CollisionResult ResourceTable::ResolveValueCollision(Value* existing,
230 Value* incoming) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700231 Attribute* existing_attr = ValueCast<Attribute>(existing);
232 Attribute* incoming_attr = ValueCast<Attribute>(incoming);
233 if (!incoming_attr) {
234 if (incoming->IsWeak()) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700235 // We're trying to add a weak resource but a resource
236 // already exists. Keep the existing.
237 return CollisionResult::kKeepOriginal;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700238 } else if (existing->IsWeak()) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700239 // Override the weak resource with the new strong resource.
240 return CollisionResult::kTakeNew;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800241 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700242 // The existing and incoming values are strong, this is an error
243 // if the values are not both attributes.
Adam Lesinski5c3464c2016-08-24 16:03:48 -0700244 return CollisionResult::kConflict;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700245 }
246
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700247 if (!existing_attr) {
248 if (existing->IsWeak()) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700249 // The existing value is not an attribute and it is weak,
250 // so take the incoming attribute value.
251 return CollisionResult::kTakeNew;
252 }
253 // The existing value is not an attribute and it is strong,
254 // so the incoming attribute value is an error.
255 return CollisionResult::kConflict;
256 }
257
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700258 CHECK(incoming_attr != nullptr && existing_attr != nullptr);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700259
260 //
261 // Attribute specific handling. At this point we know both
262 // values are attributes. Since we can declare and define
263 // attributes all-over, we do special handling to see
264 // which definition sticks.
265 //
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700266 if (existing_attr->type_mask == incoming_attr->type_mask) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700267 // The two attributes are both DECLs, but they are plain attributes
268 // with the same formats.
269 // Keep the strongest one.
Adam Lesinskib1afa072017-03-29 13:52:38 -0700270 return existing_attr->IsWeak() ? CollisionResult::kTakeNew : CollisionResult::kKeepOriginal;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700271 }
272
Adam Lesinskib1afa072017-03-29 13:52:38 -0700273 if (existing_attr->IsWeak() && existing_attr->type_mask == android::ResTable_map::TYPE_ANY) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700274 // Any incoming attribute is better than this.
275 return CollisionResult::kTakeNew;
276 }
277
Adam Lesinskib1afa072017-03-29 13:52:38 -0700278 if (incoming_attr->IsWeak() && incoming_attr->type_mask == android::ResTable_map::TYPE_ANY) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700279 // The incoming attribute may be a USE instead of a DECL.
280 // Keep the existing attribute.
281 return CollisionResult::kKeepOriginal;
282 }
283 return CollisionResult::kConflict;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800284}
285
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700286static constexpr const char* kValidNameChars = "._-";
Adam Lesinskib1afa072017-03-29 13:52:38 -0700287
288static StringPiece ValidateName(const StringPiece& name) {
289 auto iter = util::FindNonAlphaNumericAndNotInSet(name, kValidNameChars);
290 if (iter != name.end()) {
291 return StringPiece(iter, 1);
292 }
293 return {};
294}
295
296static StringPiece SkipValidateName(const StringPiece& /*name*/) {
297 return {};
298}
Adam Lesinski330edcd2015-05-04 17:40:56 -0700299
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700300bool ResourceTable::AddResource(const ResourceNameRef& name,
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800301 const ConfigDescription& config,
302 const StringPiece& product,
303 std::unique_ptr<Value> value,
Adam Lesinskie78fd612015-10-22 12:48:43 -0700304 IDiagnostics* diag) {
Adam Lesinskib1afa072017-03-29 13:52:38 -0700305 return AddResourceImpl(name, {}, config, product, std::move(value), ValidateName,
306 ResolveValueCollision, diag);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700307}
308
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700309bool ResourceTable::AddResource(const ResourceNameRef& name,
310 const ResourceId& res_id,
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800311 const ConfigDescription& config,
312 const StringPiece& product,
313 std::unique_ptr<Value> value,
314 IDiagnostics* diag) {
Adam Lesinskib1afa072017-03-29 13:52:38 -0700315 return AddResourceImpl(name, res_id, config, product, std::move(value), ValidateName,
316 ResolveValueCollision, diag);
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800317}
318
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700319bool ResourceTable::AddFileReference(const ResourceNameRef& name,
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800320 const ConfigDescription& config,
321 const Source& source,
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700322 const StringPiece& path,
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700323 IDiagnostics* diag) {
Adam Lesinskib1afa072017-03-29 13:52:38 -0700324 return AddFileReferenceImpl(name, config, source, path, nullptr, ValidateName, diag);
Adam Lesinskifb48d292015-11-07 15:52:13 -0800325}
326
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700327bool ResourceTable::AddFileReferenceAllowMangled(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700328 const ResourceNameRef& name, const ConfigDescription& config,
329 const Source& source, const StringPiece& path, io::IFile* file,
330 IDiagnostics* diag) {
Adam Lesinskib1afa072017-03-29 13:52:38 -0700331 return AddFileReferenceImpl(name, config, source, path, file, SkipValidateName, diag);
Adam Lesinski355f2852016-02-13 20:26:45 -0800332}
333
Adam Lesinskib1afa072017-03-29 13:52:38 -0700334bool ResourceTable::AddFileReferenceImpl(const ResourceNameRef& name,
335 const ConfigDescription& config, const Source& source,
336 const StringPiece& path, io::IFile* file,
337 NameValidator name_validator, IDiagnostics* diag) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700338 std::unique_ptr<FileReference> fileRef =
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700339 util::make_unique<FileReference>(string_pool.MakeRef(path));
340 fileRef->SetSource(source);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700341 fileRef->file = file;
Adam Lesinskib1afa072017-03-29 13:52:38 -0700342 return AddResourceImpl(name, ResourceId{}, config, StringPiece{}, std::move(fileRef),
343 name_validator, ResolveValueCollision, diag);
Adam Lesinski330edcd2015-05-04 17:40:56 -0700344}
345
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700346bool ResourceTable::AddResourceAllowMangled(const ResourceNameRef& name,
Adam Lesinski330edcd2015-05-04 17:40:56 -0700347 const ConfigDescription& config,
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800348 const StringPiece& product,
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700349 std::unique_ptr<Value> value,
350 IDiagnostics* diag) {
Adam Lesinskib1afa072017-03-29 13:52:38 -0700351 return AddResourceImpl(name, ResourceId{}, config, product, std::move(value), SkipValidateName,
352 ResolveValueCollision, diag);
Adam Lesinski330edcd2015-05-04 17:40:56 -0700353}
354
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700355bool ResourceTable::AddResourceAllowMangled(const ResourceNameRef& name,
Chih-Hung Hsieh9b8528f2016-08-10 14:15:30 -0700356 const ResourceId& id,
Adam Lesinski9e10ac72015-10-16 14:37:48 -0700357 const ConfigDescription& config,
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800358 const StringPiece& product,
Adam Lesinski9e10ac72015-10-16 14:37:48 -0700359 std::unique_ptr<Value> value,
360 IDiagnostics* diag) {
Adam Lesinskib1afa072017-03-29 13:52:38 -0700361 return AddResourceImpl(name, id, config, product, std::move(value), SkipValidateName,
362 ResolveValueCollision, diag);
Adam Lesinski9e10ac72015-10-16 14:37:48 -0700363}
364
Adam Lesinskib1afa072017-03-29 13:52:38 -0700365bool ResourceTable::AddResourceImpl(const ResourceNameRef& name, const ResourceId& res_id,
366 const ConfigDescription& config, const StringPiece& product,
367 std::unique_ptr<Value> value, NameValidator name_validator,
368 const CollisionResolverFunc& conflictResolver,
369 IDiagnostics* diag) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700370 CHECK(value != nullptr);
371 CHECK(diag != nullptr);
Adam Lesinskie78fd612015-10-22 12:48:43 -0700372
Adam Lesinskib1afa072017-03-29 13:52:38 -0700373 const StringPiece bad_char = name_validator(name.entry);
374 if (!bad_char.empty()) {
375 diag->Error(DiagMessage(value->GetSource()) << "resource '" << name
376 << "' has invalid entry name '" << name.entry
377 << "'. Invalid character '" << bad_char << "'");
378
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700379 return false;
380 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800381
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700382 ResourceTablePackage* package = FindOrCreatePackage(name.package);
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800383 if (res_id.is_valid_dynamic() && package->id && package->id.value() != res_id.package_id()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700384 diag->Error(DiagMessage(value->GetSource())
385 << "trying to add resource '" << name << "' with ID " << res_id
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700386 << " but package '" << package->name << "' already has ID "
387 << std::hex << (int)package->id.value() << std::dec);
388 return false;
389 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800390
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700391 ResourceTableType* type = package->FindOrCreateType(name.type);
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800392 if (res_id.is_valid_dynamic() && type->id && type->id.value() != res_id.type_id()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700393 diag->Error(DiagMessage(value->GetSource())
394 << "trying to add resource '" << name << "' with ID " << res_id
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700395 << " but type '" << type->type << "' already has ID "
396 << std::hex << (int)type->id.value() << std::dec);
397 return false;
398 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800399
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700400 ResourceEntry* entry = type->FindOrCreateEntry(name.entry);
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800401 if (res_id.is_valid_dynamic() && entry->id && entry->id.value() != res_id.entry_id()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700402 diag->Error(DiagMessage(value->GetSource())
403 << "trying to add resource '" << name << "' with ID " << res_id
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700404 << " but resource already has ID "
405 << ResourceId(package->id.value(), type->id.value(),
406 entry->id.value()));
407 return false;
408 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700409
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700410 ResourceConfigValue* config_value = entry->FindOrCreateValue(config, product);
411 if (!config_value->value) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700412 // Resource does not exist, add it now.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700413 config_value->value = std::move(value);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700414
415 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700416 switch (conflictResolver(config_value->value.get(), value.get())) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700417 case CollisionResult::kTakeNew:
418 // Take the incoming value.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700419 config_value->value = std::move(value);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700420 break;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800421
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700422 case CollisionResult::kConflict:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700423 diag->Error(DiagMessage(value->GetSource())
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700424 << "duplicate value for resource '" << name << "' "
425 << "with config '" << config << "'");
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700426 diag->Error(DiagMessage(config_value->value->GetSource())
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700427 << "resource previously defined here");
428 return false;
Adam Lesinski5c3464c2016-08-24 16:03:48 -0700429
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700430 case CollisionResult::kKeepOriginal:
431 break;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800432 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700433 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800434
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800435 if (res_id.is_valid_dynamic()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700436 package->id = res_id.package_id();
437 type->id = res_id.type_id();
438 entry->id = res_id.entry_id();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700439 }
440 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800441}
442
Adam Lesinski4488f1c2017-05-26 17:33:38 -0700443bool ResourceTable::SetSymbolState(const ResourceNameRef& name, const ResourceId& res_id,
Adam Lesinskie78fd612015-10-22 12:48:43 -0700444 const Symbol& symbol, IDiagnostics* diag) {
Adam Lesinskib1afa072017-03-29 13:52:38 -0700445 return SetSymbolStateImpl(name, res_id, symbol, ValidateName, diag);
Adam Lesinski330edcd2015-05-04 17:40:56 -0700446}
447
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700448bool ResourceTable::SetSymbolStateAllowMangled(const ResourceNameRef& name,
449 const ResourceId& res_id,
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700450 const Symbol& symbol,
451 IDiagnostics* diag) {
Adam Lesinskib1afa072017-03-29 13:52:38 -0700452 return SetSymbolStateImpl(name, res_id, symbol, SkipValidateName, diag);
Adam Lesinski330edcd2015-05-04 17:40:56 -0700453}
454
Adam Lesinskib1afa072017-03-29 13:52:38 -0700455bool ResourceTable::SetSymbolStateImpl(const ResourceNameRef& name, const ResourceId& res_id,
456 const Symbol& symbol, NameValidator name_validator,
Adam Lesinskie78fd612015-10-22 12:48:43 -0700457 IDiagnostics* diag) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700458 CHECK(diag != nullptr);
Adam Lesinskie78fd612015-10-22 12:48:43 -0700459
Adam Lesinskib1afa072017-03-29 13:52:38 -0700460 const StringPiece bad_char = name_validator(name.entry);
461 if (!bad_char.empty()) {
462 diag->Error(DiagMessage(symbol.source) << "resource '" << name << "' has invalid entry name '"
463 << name.entry << "'. Invalid character '" << bad_char
464 << "'");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700465 return false;
466 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800467
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700468 ResourceTablePackage* package = FindOrCreatePackage(name.package);
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800469 if (res_id.is_valid_dynamic() && package->id && package->id.value() != res_id.package_id()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700470 diag->Error(DiagMessage(symbol.source)
471 << "trying to add resource '" << name << "' with ID " << res_id
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700472 << " but package '" << package->name << "' already has ID "
473 << std::hex << (int)package->id.value() << std::dec);
474 return false;
475 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800476
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700477 ResourceTableType* type = package->FindOrCreateType(name.type);
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800478 if (res_id.is_valid_dynamic() && type->id && type->id.value() != res_id.type_id()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700479 diag->Error(DiagMessage(symbol.source)
480 << "trying to add resource '" << name << "' with ID " << res_id
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700481 << " but type '" << type->type << "' already has ID "
482 << std::hex << (int)type->id.value() << std::dec);
483 return false;
484 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700485
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700486 ResourceEntry* entry = type->FindOrCreateEntry(name.entry);
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800487 if (res_id.is_valid_dynamic() && entry->id && entry->id.value() != res_id.entry_id()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700488 diag->Error(DiagMessage(symbol.source)
489 << "trying to add resource '" << name << "' with ID " << res_id
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700490 << " but resource already has ID "
Adam Lesinski4488f1c2017-05-26 17:33:38 -0700491 << ResourceId(package->id.value(), type->id.value(), entry->id.value()));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700492 return false;
493 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800494
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800495 if (res_id.is_valid_dynamic()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700496 package->id = res_id.package_id();
497 type->id = res_id.type_id();
498 entry->id = res_id.entry_id();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700499 }
Adam Lesinskia6fe3452015-12-09 15:20:52 -0800500
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700501 // Only mark the type state as public, it doesn't care about being private.
502 if (symbol.state == SymbolState::kPublic) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700503 type->symbol_status.state = SymbolState::kPublic;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700504 }
Adam Lesinskia6fe3452015-12-09 15:20:52 -0800505
Adam Lesinski4488f1c2017-05-26 17:33:38 -0700506 if (symbol.allow_new) {
507 // This symbol can be added as a new resource when merging (if it belongs to an overlay).
508 entry->symbol_status.allow_new = true;
509 }
510
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700511 if (symbol.state == SymbolState::kUndefined &&
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700512 entry->symbol_status.state != SymbolState::kUndefined) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700513 // We can't undefine a symbol (remove its visibility). Ignore.
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800514 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700515 }
516
517 if (symbol.state == SymbolState::kPrivate &&
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700518 entry->symbol_status.state == SymbolState::kPublic) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700519 // We can't downgrade public to private. Ignore.
520 return true;
521 }
522
Adam Lesinski4488f1c2017-05-26 17:33:38 -0700523 // This symbol definition takes precedence, replace.
524 entry->symbol_status.state = symbol.state;
525 entry->symbol_status.source = symbol.source;
526 entry->symbol_status.comment = symbol.comment;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700527 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800528}
529
Adam Lesinskib1afa072017-03-29 13:52:38 -0700530Maybe<ResourceTable::SearchResult> ResourceTable::FindResource(const ResourceNameRef& name) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700531 ResourceTablePackage* package = FindPackage(name.package);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700532 if (!package) {
533 return {};
534 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800535
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700536 ResourceTableType* type = package->FindType(name.type);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700537 if (!type) {
538 return {};
539 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800540
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700541 ResourceEntry* entry = type->FindEntry(name.entry);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700542 if (!entry) {
543 return {};
544 }
545 return SearchResult{package, type, entry};
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800546}
547
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700548} // namespace aapt