blob: 7c0619f33851d4aacc12010a7a77e8bbbff082b3 [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
Adam Lesinskicacb28f2016-10-19 12:18:14 -070019#include <algorithm>
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080020#include <memory>
21#include <string>
22#include <tuple>
23
Adam Lesinski66ea8402017-06-28 11:44:11 -070024#include "android-base/logging.h"
Adam Lesinski71be7052017-12-12 16:48:07 -080025#include "android-base/stringprintf.h"
Mårten Kongstad24c9aa62018-06-20 08:46:41 +020026#include "androidfw/ConfigDescription.h"
Adam Lesinski66ea8402017-06-28 11:44:11 -070027#include "androidfw/ResourceTypes.h"
28
Ryan Mitchell83a37ad2018-08-06 16:32:24 -070029#include "Debug.h"
Adam Lesinski66ea8402017-06-28 11:44:11 -070030#include "NameMangler.h"
31#include "ResourceValues.h"
32#include "ValueVisitor.h"
Fabien Sanglard2d34e762019-02-21 15:13:29 -080033#include "trace/TraceBuffer.h"
Adam Lesinski66ea8402017-06-28 11:44:11 -070034#include "text/Unicode.h"
35#include "util/Util.h"
36
37using ::aapt::text::IsValidResourceEntryName;
Mårten Kongstad24c9aa62018-06-20 08:46:41 +020038using ::android::ConfigDescription;
Adam Lesinski66ea8402017-06-28 11:44:11 -070039using ::android::StringPiece;
Adam Lesinski71be7052017-12-12 16:48:07 -080040using ::android::base::StringPrintf;
Adam Lesinskid5083f62017-01-16 15:07:21 -080041
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080042namespace aapt {
43
Ryan Mitchell54237ff2018-12-13 15:44:29 -080044const char* Overlayable::kActorScheme = "overlay";
45
Ryan Mitchell83a37ad2018-08-06 16:32:24 -070046static bool less_than_type_and_id(const std::unique_ptr<ResourceTableType>& lhs,
47 const std::pair<ResourceType, Maybe<uint8_t>>& rhs) {
48 return lhs->type < rhs.first || (lhs->type == rhs.first && rhs.second && lhs->id < rhs.second);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080049}
50
Adam Lesinski1ab598f2015-08-14 14:26:04 -070051template <typename T>
Adam Lesinskib1afa072017-03-29 13:52:38 -070052static bool less_than_struct_with_name(const std::unique_ptr<T>& lhs, const StringPiece& rhs) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070053 return lhs->name.compare(0, lhs->name.size(), rhs.data(), rhs.size()) < 0;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080054}
55
David Chaloupkae3c1a4a2018-01-18 13:44:36 +000056template <typename T>
57static bool less_than_struct_with_name_and_id(const std::unique_ptr<T>& lhs,
Ryan Mitchell8d4ee972018-08-27 11:24:04 -070058 const std::pair<StringPiece, Maybe<uint16_t>>& rhs) {
David Chaloupkae3c1a4a2018-01-18 13:44:36 +000059 int name_cmp = lhs->name.compare(0, lhs->name.size(), rhs.first.data(), rhs.first.size());
Ryan Mitchell83a37ad2018-08-06 16:32:24 -070060 return name_cmp < 0 || (name_cmp == 0 && rhs.second && lhs->id < rhs.second);
David Chaloupkae3c1a4a2018-01-18 13:44:36 +000061}
62
Adam Lesinski71be7052017-12-12 16:48:07 -080063ResourceTablePackage* ResourceTable::FindPackage(const StringPiece& name) const {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070064 const auto last = packages.end();
Adam Lesinskib1afa072017-03-29 13:52:38 -070065 auto iter = std::lower_bound(packages.begin(), last, name,
66 less_than_struct_with_name<ResourceTablePackage>);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070067 if (iter != last && name == (*iter)->name) {
68 return iter->get();
69 }
70 return nullptr;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080071}
72
Adam Lesinski71be7052017-12-12 16:48:07 -080073ResourceTablePackage* ResourceTable::FindPackageById(uint8_t id) const {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070074 for (auto& package : packages) {
75 if (package->id && package->id.value() == id) {
76 return package.get();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080077 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -070078 }
79 return nullptr;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080080}
81
Adam Lesinskib1afa072017-03-29 13:52:38 -070082ResourceTablePackage* ResourceTable::CreatePackage(const StringPiece& name, Maybe<uint8_t> id) {
Fabien Sanglard2d34e762019-02-21 15:13:29 -080083 TRACE_CALL();
Adam Lesinskice5e56e2016-10-21 17:56:45 -070084 ResourceTablePackage* package = FindOrCreatePackage(name);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070085 if (id && !package->id) {
86 package->id = id;
Adam Lesinski9ba47d82015-10-13 11:37:10 -070087 return package;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070088 }
89
90 if (id && package->id && package->id.value() != id.value()) {
91 return nullptr;
92 }
93 return package;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080094}
95
David Chaloupkae3c1a4a2018-01-18 13:44:36 +000096ResourceTablePackage* ResourceTable::CreatePackageAllowingDuplicateNames(const StringPiece& name,
97 const Maybe<uint8_t> id) {
98 const auto last = packages.end();
99 auto iter = std::lower_bound(packages.begin(), last, std::make_pair(name, id),
100 less_than_struct_with_name_and_id<ResourceTablePackage>);
101
102 if (iter != last && name == (*iter)->name && id == (*iter)->id) {
103 return iter->get();
104 }
105
106 std::unique_ptr<ResourceTablePackage> new_package = util::make_unique<ResourceTablePackage>();
107 new_package->name = name.to_string();
108 new_package->id = id;
109 return packages.emplace(iter, std::move(new_package))->get();
110}
111
Adam Lesinskib1afa072017-03-29 13:52:38 -0700112ResourceTablePackage* ResourceTable::FindOrCreatePackage(const StringPiece& name) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700113 const auto last = packages.end();
Adam Lesinskib1afa072017-03-29 13:52:38 -0700114 auto iter = std::lower_bound(packages.begin(), last, name,
115 less_than_struct_with_name<ResourceTablePackage>);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700116 if (iter != last && name == (*iter)->name) {
117 return iter->get();
118 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800119
Adam Lesinskib1afa072017-03-29 13:52:38 -0700120 std::unique_ptr<ResourceTablePackage> new_package = util::make_unique<ResourceTablePackage>();
Adam Lesinskid5083f62017-01-16 15:07:21 -0800121 new_package->name = name.to_string();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700122 return packages.emplace(iter, std::move(new_package))->get();
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700123}
124
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700125ResourceTableType* ResourceTablePackage::FindType(ResourceType type, const Maybe<uint8_t> id) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700126 const auto last = types.end();
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700127 auto iter = std::lower_bound(types.begin(), last, std::make_pair(type, id),
128 less_than_type_and_id);
129 if (iter != last && (*iter)->type == type && (!id || id == (*iter)->id)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700130 return iter->get();
131 }
132 return nullptr;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700133}
134
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700135ResourceTableType* ResourceTablePackage::FindOrCreateType(ResourceType type,
136 const Maybe<uint8_t> id) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700137 const auto last = types.end();
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700138 auto iter = std::lower_bound(types.begin(), last, std::make_pair(type, id),
139 less_than_type_and_id);
140 if (iter != last && (*iter)->type == type && (!id || id == (*iter)->id)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700141 return iter->get();
142 }
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700143
144 auto new_type = new ResourceTableType(type);
145 new_type->id = id;
146 return types.emplace(iter, std::move(new_type))->get();
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700147}
148
Ryan Mitchell8d4ee972018-08-27 11:24:04 -0700149ResourceEntry* ResourceTableType::FindEntry(const StringPiece& name, const Maybe<uint16_t> id) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700150 const auto last = entries.end();
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700151 auto iter = std::lower_bound(entries.begin(), last, std::make_pair(name, id),
152 less_than_struct_with_name_and_id<ResourceEntry>);
153 if (iter != last && name == (*iter)->name && (!id || id == (*iter)->id)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700154 return iter->get();
155 }
156 return nullptr;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700157}
158
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700159ResourceEntry* ResourceTableType::FindOrCreateEntry(const StringPiece& name,
Ryan Mitchell8d4ee972018-08-27 11:24:04 -0700160 const Maybe<uint16_t > id) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700161 auto last = entries.end();
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700162 auto iter = std::lower_bound(entries.begin(), last, std::make_pair(name, id),
163 less_than_struct_with_name_and_id<ResourceEntry>);
164 if (iter != last && name == (*iter)->name && (!id || id == (*iter)->id)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700165 return iter->get();
166 }
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700167
168 auto new_entry = new ResourceEntry(name);
169 new_entry->id = id;
170 return entries.emplace(iter, std::move(new_entry))->get();
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700171}
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800172
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700173ResourceConfigValue* ResourceEntry::FindValue(const ConfigDescription& config) {
174 return FindValue(config, StringPiece());
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800175}
176
177struct ConfigKey {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700178 const ConfigDescription* config;
179 const StringPiece& product;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800180};
181
Adam Lesinski34a16872018-02-23 16:18:10 -0800182bool lt_config_key_ref(const std::unique_ptr<ResourceConfigValue>& lhs, const ConfigKey& rhs) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700183 int cmp = lhs->config.compare(*rhs.config);
184 if (cmp == 0) {
185 cmp = StringPiece(lhs->product).compare(rhs.product);
186 }
187 return cmp < 0;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800188}
189
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700190ResourceConfigValue* ResourceEntry::FindValue(const ConfigDescription& config,
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800191 const StringPiece& product) {
Adam Lesinski34a16872018-02-23 16:18:10 -0800192 auto iter = std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product},
193 lt_config_key_ref);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700194 if (iter != values.end()) {
195 ResourceConfigValue* value = iter->get();
196 if (value->config == config && StringPiece(value->product) == product) {
197 return value;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800198 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700199 }
200 return nullptr;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800201}
202
Adam Lesinskib1afa072017-03-29 13:52:38 -0700203ResourceConfigValue* ResourceEntry::FindOrCreateValue(const ConfigDescription& config,
204 const StringPiece& product) {
Adam Lesinski34a16872018-02-23 16:18:10 -0800205 auto iter = std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product},
206 lt_config_key_ref);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700207 if (iter != values.end()) {
208 ResourceConfigValue* value = iter->get();
209 if (value->config == config && StringPiece(value->product) == product) {
210 return value;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800211 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700212 }
213 ResourceConfigValue* newValue =
Adam Lesinskib1afa072017-03-29 13:52:38 -0700214 values.insert(iter, util::make_unique<ResourceConfigValue>(config, product))->get();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700215 return newValue;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800216}
217
Adam Lesinskib1afa072017-03-29 13:52:38 -0700218std::vector<ResourceConfigValue*> ResourceEntry::FindAllValues(const ConfigDescription& config) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700219 std::vector<ResourceConfigValue*> results;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800220
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700221 auto iter = values.begin();
222 for (; iter != values.end(); ++iter) {
223 ResourceConfigValue* value = iter->get();
224 if (value->config == config) {
225 results.push_back(value);
226 ++iter;
227 break;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800228 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700229 }
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800230
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700231 for (; iter != values.end(); ++iter) {
232 ResourceConfigValue* value = iter->get();
233 if (value->config == config) {
234 results.push_back(value);
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800235 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700236 }
237 return results;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800238}
239
Adam Lesinski34a16872018-02-23 16:18:10 -0800240bool ResourceEntry::HasDefaultValue() const {
241 const ConfigDescription& default_config = ConfigDescription::DefaultConfig();
242
243 // The default config should be at the top of the list, since the list is sorted.
244 for (auto& config_value : values) {
245 if (config_value->config == default_config) {
246 return true;
Adam Lesinski458b8772016-04-25 14:20:21 -0700247 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700248 }
Adam Lesinski34a16872018-02-23 16:18:10 -0800249 return false;
Adam Lesinski458b8772016-04-25 14:20:21 -0700250}
251
Adam Lesinski71be7052017-12-12 16:48:07 -0800252// The default handler for collisions.
253//
254// Typically, a weak value will be overridden by a strong value. An existing weak
255// value will not be overridden by an incoming weak value.
256//
257// There are some exceptions:
258//
259// Attributes: There are two types of Attribute values: USE and DECL.
260//
261// USE is anywhere an Attribute is declared without a format, and in a place that would
262// be legal to declare if the Attribute already existed. This is typically in a
263// <declare-styleable> tag. Attributes defined in a <declare-styleable> are also weak.
264//
265// DECL is an absolute declaration of an Attribute and specifies an explicit format.
266//
267// A DECL will override a USE without error. Two DECLs must match in their format for there to be
268// no error.
Adam Lesinskib1afa072017-03-29 13:52:38 -0700269ResourceTable::CollisionResult ResourceTable::ResolveValueCollision(Value* existing,
270 Value* incoming) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700271 Attribute* existing_attr = ValueCast<Attribute>(existing);
272 Attribute* incoming_attr = ValueCast<Attribute>(incoming);
273 if (!incoming_attr) {
274 if (incoming->IsWeak()) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700275 // We're trying to add a weak resource but a resource
276 // already exists. Keep the existing.
277 return CollisionResult::kKeepOriginal;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700278 } else if (existing->IsWeak()) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700279 // Override the weak resource with the new strong resource.
280 return CollisionResult::kTakeNew;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800281 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700282 // The existing and incoming values are strong, this is an error
283 // if the values are not both attributes.
Adam Lesinski5c3464c2016-08-24 16:03:48 -0700284 return CollisionResult::kConflict;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700285 }
286
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700287 if (!existing_attr) {
288 if (existing->IsWeak()) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700289 // The existing value is not an attribute and it is weak,
290 // so take the incoming attribute value.
291 return CollisionResult::kTakeNew;
292 }
293 // The existing value is not an attribute and it is strong,
294 // so the incoming attribute value is an error.
295 return CollisionResult::kConflict;
296 }
297
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700298 CHECK(incoming_attr != nullptr && existing_attr != nullptr);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700299
300 //
301 // Attribute specific handling. At this point we know both
302 // values are attributes. Since we can declare and define
303 // attributes all-over, we do special handling to see
304 // which definition sticks.
305 //
Adam Lesinski73bff1e2017-12-08 16:06:10 -0800306 if (existing_attr->IsCompatibleWith(*incoming_attr)) {
307 // The two attributes are both DECLs, but they are plain attributes with compatible formats.
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700308 // Keep the strongest one.
Adam Lesinskib1afa072017-03-29 13:52:38 -0700309 return existing_attr->IsWeak() ? CollisionResult::kTakeNew : CollisionResult::kKeepOriginal;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700310 }
311
Adam Lesinskib1afa072017-03-29 13:52:38 -0700312 if (existing_attr->IsWeak() && existing_attr->type_mask == android::ResTable_map::TYPE_ANY) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700313 // Any incoming attribute is better than this.
314 return CollisionResult::kTakeNew;
315 }
316
Adam Lesinskib1afa072017-03-29 13:52:38 -0700317 if (incoming_attr->IsWeak() && incoming_attr->type_mask == android::ResTable_map::TYPE_ANY) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700318 // The incoming attribute may be a USE instead of a DECL.
319 // Keep the existing attribute.
320 return CollisionResult::kKeepOriginal;
321 }
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700322
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700323 return CollisionResult::kConflict;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800324}
325
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700326ResourceTable::CollisionResult ResourceTable::IgnoreCollision(Value* /** existing **/,
327 Value* /** incoming **/) {
328 return CollisionResult::kKeepBoth;
329}
330
Adam Lesinski71be7052017-12-12 16:48:07 -0800331static StringPiece ResourceNameValidator(const StringPiece& name) {
Adam Lesinski66ea8402017-06-28 11:44:11 -0700332 if (!IsValidResourceEntryName(name)) {
333 return name;
Adam Lesinskib1afa072017-03-29 13:52:38 -0700334 }
335 return {};
336}
337
Adam Lesinski71be7052017-12-12 16:48:07 -0800338static StringPiece SkipNameValidator(const StringPiece& /*name*/) {
Adam Lesinskib1afa072017-03-29 13:52:38 -0700339 return {};
340}
Adam Lesinski330edcd2015-05-04 17:40:56 -0700341
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700342bool ResourceTable::AddResource(const ResourceNameRef& name,
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800343 const ConfigDescription& config,
344 const StringPiece& product,
345 std::unique_ptr<Value> value,
Adam Lesinskie78fd612015-10-22 12:48:43 -0700346 IDiagnostics* diag) {
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700347 return AddResourceImpl(name, ResourceId{}, config, product, std::move(value),
348 (validate_resources_ ? ResourceNameValidator : SkipNameValidator),
349 (validate_resources_ ? ResolveValueCollision : IgnoreCollision), diag);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700350}
351
Adam Lesinski71be7052017-12-12 16:48:07 -0800352bool ResourceTable::AddResourceWithId(const ResourceNameRef& name, const ResourceId& res_id,
353 const ConfigDescription& config, const StringPiece& product,
354 std::unique_ptr<Value> value, IDiagnostics* diag) {
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700355 return AddResourceImpl(name, res_id, config, product, std::move(value),
356 (validate_resources_ ? ResourceNameValidator : SkipNameValidator),
357 (validate_resources_ ? ResolveValueCollision : IgnoreCollision), diag);
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800358}
359
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700360bool ResourceTable::AddFileReference(const ResourceNameRef& name,
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800361 const ConfigDescription& config,
362 const Source& source,
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700363 const StringPiece& path,
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700364 IDiagnostics* diag) {
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700365 return AddFileReferenceImpl(name, config, source, path, nullptr,
366 (validate_resources_ ? ResourceNameValidator : SkipNameValidator),
367 diag);
Adam Lesinskifb48d292015-11-07 15:52:13 -0800368}
369
Adam Lesinski71be7052017-12-12 16:48:07 -0800370bool ResourceTable::AddFileReferenceMangled(const ResourceNameRef& name,
371 const ConfigDescription& config, const Source& source,
372 const StringPiece& path, io::IFile* file,
373 IDiagnostics* diag) {
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700374 return AddFileReferenceImpl(name, config, source, path, file,
375 (validate_resources_ ? ResourceNameValidator : SkipNameValidator),
376 diag);
Adam Lesinski355f2852016-02-13 20:26:45 -0800377}
378
Adam Lesinskib1afa072017-03-29 13:52:38 -0700379bool ResourceTable::AddFileReferenceImpl(const ResourceNameRef& name,
380 const ConfigDescription& config, const Source& source,
381 const StringPiece& path, io::IFile* file,
382 NameValidator name_validator, IDiagnostics* diag) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700383 std::unique_ptr<FileReference> fileRef =
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700384 util::make_unique<FileReference>(string_pool.MakeRef(path));
385 fileRef->SetSource(source);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700386 fileRef->file = file;
Adam Lesinskib1afa072017-03-29 13:52:38 -0700387 return AddResourceImpl(name, ResourceId{}, config, StringPiece{}, std::move(fileRef),
388 name_validator, ResolveValueCollision, diag);
Adam Lesinski330edcd2015-05-04 17:40:56 -0700389}
390
Adam Lesinski71be7052017-12-12 16:48:07 -0800391bool ResourceTable::AddResourceMangled(const ResourceNameRef& name, const ConfigDescription& config,
392 const StringPiece& product, std::unique_ptr<Value> value,
393 IDiagnostics* diag) {
394 return AddResourceImpl(name, ResourceId{}, config, product, std::move(value), SkipNameValidator,
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700395 (validate_resources_ ? ResolveValueCollision : IgnoreCollision), diag);
Adam Lesinski330edcd2015-05-04 17:40:56 -0700396}
397
Adam Lesinski71be7052017-12-12 16:48:07 -0800398bool ResourceTable::AddResourceWithIdMangled(const ResourceNameRef& name, const ResourceId& id,
399 const ConfigDescription& config,
400 const StringPiece& product,
401 std::unique_ptr<Value> value, IDiagnostics* diag) {
402 return AddResourceImpl(name, id, config, product, std::move(value), SkipNameValidator,
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700403 (validate_resources_ ? ResolveValueCollision : IgnoreCollision), diag);
Adam Lesinski9e10ac72015-10-16 14:37:48 -0700404}
405
Adam Lesinski71be7052017-12-12 16:48:07 -0800406bool ResourceTable::ValidateName(NameValidator name_validator, const ResourceNameRef& name,
407 const Source& source, IDiagnostics* diag) {
408 const StringPiece bad_char = name_validator(name.entry);
409 if (!bad_char.empty()) {
410 diag->Error(DiagMessage(source) << "resource '" << name << "' has invalid entry name '"
411 << name.entry << "'. Invalid character '" << bad_char << "'");
412 return false;
413 }
414 return true;
415}
416
Adam Lesinskib1afa072017-03-29 13:52:38 -0700417bool ResourceTable::AddResourceImpl(const ResourceNameRef& name, const ResourceId& res_id,
418 const ConfigDescription& config, const StringPiece& product,
419 std::unique_ptr<Value> value, NameValidator name_validator,
Adam Lesinski71be7052017-12-12 16:48:07 -0800420 const CollisionResolverFunc& conflict_resolver,
Adam Lesinskib1afa072017-03-29 13:52:38 -0700421 IDiagnostics* diag) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700422 CHECK(value != nullptr);
423 CHECK(diag != nullptr);
Adam Lesinskie78fd612015-10-22 12:48:43 -0700424
Adam Lesinski71be7052017-12-12 16:48:07 -0800425 const Source& source = value->GetSource();
426 if (!ValidateName(name_validator, name, source, diag)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700427 return false;
428 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800429
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700430 // Check for package names appearing twice with two different package ids
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700431 ResourceTablePackage* package = FindOrCreatePackage(name.package);
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800432 if (res_id.is_valid_dynamic() && package->id && package->id.value() != res_id.package_id()) {
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700433 diag->Error(DiagMessage(source)
434 << "trying to add resource '" << name << "' with ID " << res_id
435 << " but package '" << package->name << "' already has ID "
436 << StringPrintf("%02x", package->id.value()));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700437 return false;
438 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800439
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700440 // Whether or not to error on duplicate resources
441 bool check_id = validate_resources_ && res_id.is_valid_dynamic();
442 // Whether or not to create a duplicate resource if the id does not match
443 bool use_id = !validate_resources_ && res_id.is_valid_dynamic();
444
445 ResourceTableType* type = package->FindOrCreateType(name.type, use_id ? res_id.type_id()
446 : Maybe<uint8_t>());
447
448 // Check for types appearing twice with two different type ids
449 if (check_id && type->id && type->id.value() != res_id.type_id()) {
Adam Lesinski71be7052017-12-12 16:48:07 -0800450 diag->Error(DiagMessage(source)
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700451 << "trying to add resource '" << name << "' with ID " << res_id
452 << " but type '" << type->type << "' already has ID "
453 << StringPrintf("%02x", type->id.value()));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700454 return false;
455 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800456
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700457 ResourceEntry* entry = type->FindOrCreateEntry(name.entry, use_id ? res_id.entry_id()
Ryan Mitchell8d4ee972018-08-27 11:24:04 -0700458 : Maybe<uint16_t>());
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700459
460 // Check for entries appearing twice with two different entry ids
461 if (check_id && entry->id && entry->id.value() != res_id.entry_id()) {
Adam Lesinski71be7052017-12-12 16:48:07 -0800462 diag->Error(DiagMessage(source)
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700463 << "trying to add resource '" << name << "' with ID " << res_id
464 << " but resource already has ID "
465 << ResourceId(package->id.value(), type->id.value(), entry->id.value()));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700466 return false;
467 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700468
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700469 ResourceConfigValue* config_value = entry->FindOrCreateValue(config, product);
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700470 if (!config_value->value) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700471 // Resource does not exist, add it now.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700472 config_value->value = std::move(value);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700473 } else {
Adam Lesinski71be7052017-12-12 16:48:07 -0800474 switch (conflict_resolver(config_value->value.get(), value.get())) {
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700475 case CollisionResult::kKeepBoth:
476 // Insert the value ignoring for duplicate configurations
477 entry->values.push_back(util::make_unique<ResourceConfigValue>(config, product));
478 entry->values.back()->value = std::move(value);
479 break;
480
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700481 case CollisionResult::kTakeNew:
482 // Take the incoming value.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700483 config_value->value = std::move(value);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700484 break;
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800485
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700486 case CollisionResult::kConflict:
Adam Lesinski71be7052017-12-12 16:48:07 -0800487 diag->Error(DiagMessage(source) << "duplicate value for resource '" << name << "' "
488 << "with config '" << config << "'");
489 diag->Error(DiagMessage(source) << "resource previously defined here");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700490 return false;
Adam Lesinski5c3464c2016-08-24 16:03:48 -0700491
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700492 case CollisionResult::kKeepOriginal:
493 break;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800494 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700495 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800496
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800497 if (res_id.is_valid_dynamic()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700498 package->id = res_id.package_id();
499 type->id = res_id.type_id();
500 entry->id = res_id.entry_id();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700501 }
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700502
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700503 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800504}
505
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700506bool ResourceTable::GetValidateResources() {
507 return validate_resources_;
508}
509
Adam Lesinski71be7052017-12-12 16:48:07 -0800510bool ResourceTable::SetVisibility(const ResourceNameRef& name, const Visibility& visibility,
511 IDiagnostics* diag) {
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700512 return SetVisibilityImpl(name, visibility, {}, ResourceNameValidator, diag);
Adam Lesinski330edcd2015-05-04 17:40:56 -0700513}
514
Adam Lesinski71be7052017-12-12 16:48:07 -0800515bool ResourceTable::SetVisibilityMangled(const ResourceNameRef& name, const Visibility& visibility,
516 IDiagnostics* diag) {
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700517 return SetVisibilityImpl(name, visibility, {}, SkipNameValidator, diag);
Adam Lesinski330edcd2015-05-04 17:40:56 -0700518}
519
Adam Lesinski71be7052017-12-12 16:48:07 -0800520bool ResourceTable::SetVisibilityWithId(const ResourceNameRef& name, const Visibility& visibility,
521 const ResourceId& res_id, IDiagnostics* diag) {
522 return SetVisibilityImpl(name, visibility, res_id, ResourceNameValidator, diag);
523}
524
525bool ResourceTable::SetVisibilityWithIdMangled(const ResourceNameRef& name,
526 const Visibility& visibility,
527 const ResourceId& res_id, IDiagnostics* diag) {
528 return SetVisibilityImpl(name, visibility, res_id, SkipNameValidator, diag);
529}
530
531bool ResourceTable::SetVisibilityImpl(const ResourceNameRef& name, const Visibility& visibility,
532 const ResourceId& res_id, NameValidator name_validator,
533 IDiagnostics* diag) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700534 CHECK(diag != nullptr);
Adam Lesinskie78fd612015-10-22 12:48:43 -0700535
Adam Lesinski71be7052017-12-12 16:48:07 -0800536 const Source& source = visibility.source;
537 if (!ValidateName(name_validator, name, source, diag)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700538 return false;
539 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800540
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700541 // Check for package names appearing twice with two different package ids
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700542 ResourceTablePackage* package = FindOrCreatePackage(name.package);
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800543 if (res_id.is_valid_dynamic() && package->id && package->id.value() != res_id.package_id()) {
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700544 diag->Error(DiagMessage(source)
545 << "trying to add resource '" << name << "' with ID " << res_id
546 << " but package '" << package->name << "' already has ID "
547 << StringPrintf("%02x", package->id.value()));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700548 return false;
549 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800550
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700551 // Whether or not to error on duplicate resources
552 bool check_id = validate_resources_ && res_id.is_valid_dynamic();
553 // Whether or not to create a duplicate resource if the id does not match
554 bool use_id = !validate_resources_ && res_id.is_valid_dynamic();
555
556 ResourceTableType* type = package->FindOrCreateType(name.type, use_id ? res_id.type_id()
557 : Maybe<uint8_t>());
558
559 // Check for types appearing twice with two different type ids
560 if (check_id && type->id && type->id.value() != res_id.type_id()) {
Adam Lesinski71be7052017-12-12 16:48:07 -0800561 diag->Error(DiagMessage(source)
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700562 << "trying to add resource '" << name << "' with ID " << res_id
563 << " but type '" << type->type << "' already has ID "
564 << StringPrintf("%02x", type->id.value()));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700565 return false;
566 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700567
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700568 ResourceEntry* entry = type->FindOrCreateEntry(name.entry, use_id ? res_id.entry_id()
Ryan Mitchell8d4ee972018-08-27 11:24:04 -0700569 : Maybe<uint16_t>());
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700570
571 // Check for entries appearing twice with two different entry ids
572 if (check_id && entry->id && entry->id.value() != res_id.entry_id()) {
Adam Lesinski71be7052017-12-12 16:48:07 -0800573 diag->Error(DiagMessage(source)
Ryan Mitchell83a37ad2018-08-06 16:32:24 -0700574 << "trying to add resource '" << name << "' with ID " << res_id
575 << " but resource already has ID "
576 << ResourceId(package->id.value(), type->id.value(), entry->id.value()));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700577 return false;
578 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800579
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800580 if (res_id.is_valid_dynamic()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700581 package->id = res_id.package_id();
582 type->id = res_id.type_id();
583 entry->id = res_id.entry_id();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700584 }
Adam Lesinskia6fe3452015-12-09 15:20:52 -0800585
Adam Lesinski71be7052017-12-12 16:48:07 -0800586 // Only mark the type visibility level as public, it doesn't care about being private.
587 if (visibility.level == Visibility::Level::kPublic) {
588 type->visibility_level = Visibility::Level::kPublic;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700589 }
Adam Lesinskia6fe3452015-12-09 15:20:52 -0800590
Adam Lesinski71be7052017-12-12 16:48:07 -0800591 if (visibility.level == Visibility::Level::kUndefined &&
592 entry->visibility.level != Visibility::Level::kUndefined) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700593 // We can't undefine a symbol (remove its visibility). Ignore.
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800594 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700595 }
596
Adam Lesinski71be7052017-12-12 16:48:07 -0800597 if (visibility.level < entry->visibility.level) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700598 // We can't downgrade public to private. Ignore.
599 return true;
600 }
601
Adam Lesinski4488f1c2017-05-26 17:33:38 -0700602 // This symbol definition takes precedence, replace.
Adam Lesinski71be7052017-12-12 16:48:07 -0800603 entry->visibility = visibility;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700604 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800605}
606
Adam Lesinski71be7052017-12-12 16:48:07 -0800607bool ResourceTable::SetAllowNew(const ResourceNameRef& name, const AllowNew& allow_new,
608 IDiagnostics* diag) {
609 return SetAllowNewImpl(name, allow_new, ResourceNameValidator, diag);
610}
611
612bool ResourceTable::SetAllowNewMangled(const ResourceNameRef& name, const AllowNew& allow_new,
613 IDiagnostics* diag) {
614 return SetAllowNewImpl(name, allow_new, SkipNameValidator, diag);
615}
616
617bool ResourceTable::SetAllowNewImpl(const ResourceNameRef& name, const AllowNew& allow_new,
618 NameValidator name_validator, IDiagnostics* diag) {
619 CHECK(diag != nullptr);
620
621 if (!ValidateName(name_validator, name, allow_new.source, diag)) {
622 return false;
623 }
624
625 ResourceTablePackage* package = FindOrCreatePackage(name.package);
626 ResourceTableType* type = package->FindOrCreateType(name.type);
627 ResourceEntry* entry = type->FindOrCreateEntry(name.entry);
628 entry->allow_new = allow_new;
629 return true;
630}
631
Ryan Mitchell54237ff2018-12-13 15:44:29 -0800632bool ResourceTable::SetOverlayable(const ResourceNameRef& name, const OverlayableItem& overlayable,
Adam Lesinski71be7052017-12-12 16:48:07 -0800633 IDiagnostics* diag) {
Ryan Mitchell1bb1fe02018-11-16 11:21:41 -0800634 return SetOverlayableImpl(name, overlayable, ResourceNameValidator, diag);
Adam Lesinski71be7052017-12-12 16:48:07 -0800635}
636
Ryan Mitchell1bb1fe02018-11-16 11:21:41 -0800637bool ResourceTable::SetOverlayableMangled(const ResourceNameRef& name,
Ryan Mitchell54237ff2018-12-13 15:44:29 -0800638 const OverlayableItem& overlayable, IDiagnostics* diag) {
Ryan Mitchell1bb1fe02018-11-16 11:21:41 -0800639 return SetOverlayableImpl(name, overlayable, SkipNameValidator, diag);
Adam Lesinski71be7052017-12-12 16:48:07 -0800640}
641
Ryan Mitchell54237ff2018-12-13 15:44:29 -0800642bool ResourceTable::SetOverlayableImpl(const ResourceNameRef& name,
643 const OverlayableItem& overlayable,
Ryan Mitchell1bb1fe02018-11-16 11:21:41 -0800644 NameValidator name_validator, IDiagnostics *diag) {
Adam Lesinski71be7052017-12-12 16:48:07 -0800645 CHECK(diag != nullptr);
646
647 if (!ValidateName(name_validator, name, overlayable.source, diag)) {
648 return false;
649 }
650
651 ResourceTablePackage* package = FindOrCreatePackage(name.package);
652 ResourceTableType* type = package->FindOrCreateType(name.type);
653 ResourceEntry* entry = type->FindOrCreateEntry(name.entry);
Ryan Mitchelle4e989c2018-10-29 02:21:50 -0700654
Ryan Mitchell54237ff2018-12-13 15:44:29 -0800655 if (entry->overlayable_item) {
Ryan Mitchell1bb1fe02018-11-16 11:21:41 -0800656 diag->Error(DiagMessage(overlayable.source)
Ryan Mitchell54237ff2018-12-13 15:44:29 -0800657 << "duplicate overlayable declaration for resource '" << name << "'");
658 diag->Error(DiagMessage(entry->overlayable_item.value().source)
659 << "previous declaration here");
Ryan Mitchell1bb1fe02018-11-16 11:21:41 -0800660 return false;
Adam Lesinski71be7052017-12-12 16:48:07 -0800661 }
Ryan Mitchelle4e989c2018-10-29 02:21:50 -0700662
Ryan Mitchell54237ff2018-12-13 15:44:29 -0800663 entry->overlayable_item = overlayable;
Adam Lesinski71be7052017-12-12 16:48:07 -0800664 return true;
665}
666
667Maybe<ResourceTable::SearchResult> ResourceTable::FindResource(const ResourceNameRef& name) const {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700668 ResourceTablePackage* package = FindPackage(name.package);
Adam Lesinski71be7052017-12-12 16:48:07 -0800669 if (package == nullptr) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700670 return {};
671 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800672
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700673 ResourceTableType* type = package->FindType(name.type);
Adam Lesinski71be7052017-12-12 16:48:07 -0800674 if (type == nullptr) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700675 return {};
676 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800677
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700678 ResourceEntry* entry = type->FindEntry(name.entry);
Adam Lesinski71be7052017-12-12 16:48:07 -0800679 if (entry == nullptr) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700680 return {};
681 }
682 return SearchResult{package, type, entry};
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800683}
684
Shane Farmer0a5b2012017-06-22 12:24:12 -0700685std::unique_ptr<ResourceTable> ResourceTable::Clone() const {
686 std::unique_ptr<ResourceTable> new_table = util::make_unique<ResourceTable>();
687 for (const auto& pkg : packages) {
688 ResourceTablePackage* new_pkg = new_table->CreatePackage(pkg->name, pkg->id);
689 for (const auto& type : pkg->types) {
690 ResourceTableType* new_type = new_pkg->FindOrCreateType(type->type);
Adam Lesinski71be7052017-12-12 16:48:07 -0800691 new_type->id = type->id;
692 new_type->visibility_level = type->visibility_level;
Shane Farmer0a5b2012017-06-22 12:24:12 -0700693
694 for (const auto& entry : type->entries) {
695 ResourceEntry* new_entry = new_type->FindOrCreateEntry(entry->name);
Adam Lesinski71be7052017-12-12 16:48:07 -0800696 new_entry->id = entry->id;
697 new_entry->visibility = entry->visibility;
698 new_entry->allow_new = entry->allow_new;
Ryan Mitchell54237ff2018-12-13 15:44:29 -0800699 new_entry->overlayable_item = entry->overlayable_item;
Shane Farmer0a5b2012017-06-22 12:24:12 -0700700
701 for (const auto& config_value : entry->values) {
702 ResourceConfigValue* new_value =
703 new_entry->FindOrCreateValue(config_value->config, config_value->product);
Adam Lesinski71be7052017-12-12 16:48:07 -0800704 new_value->value.reset(config_value->value->Clone(&new_table->string_pool));
Shane Farmer0a5b2012017-06-22 12:24:12 -0700705 }
706 }
707 }
708 }
709 return new_table;
710}
711
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700712} // namespace aapt