1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "ResourceTable.h"
18 
19 #include <algorithm>
20 #include <memory>
21 #include <string>
22 #include <tuple>
23 
24 #include "android-base/logging.h"
25 #include "android-base/stringprintf.h"
26 #include "androidfw/ResourceTypes.h"
27 
28 #include "ConfigDescription.h"
29 #include "NameMangler.h"
30 #include "ResourceValues.h"
31 #include "ValueVisitor.h"
32 #include "text/Unicode.h"
33 #include "util/Util.h"
34 
35 using ::aapt::text::IsValidResourceEntryName;
36 using ::android::StringPiece;
37 using ::android::base::StringPrintf;
38 
39 namespace aapt {
40 
less_than_type(const std::unique_ptr<ResourceTableType> & lhs,ResourceType rhs)41 static bool less_than_type(const std::unique_ptr<ResourceTableType>& lhs, ResourceType rhs) {
42   return lhs->type < rhs;
43 }
44 
45 template <typename T>
less_than_struct_with_name(const std::unique_ptr<T> & lhs,const StringPiece & rhs)46 static bool less_than_struct_with_name(const std::unique_ptr<T>& lhs, const StringPiece& rhs) {
47   return lhs->name.compare(0, lhs->name.size(), rhs.data(), rhs.size()) < 0;
48 }
49 
50 template <typename T>
less_than_struct_with_name_and_id(const std::unique_ptr<T> & lhs,const std::pair<StringPiece,Maybe<uint8_t>> & rhs)51 static bool less_than_struct_with_name_and_id(const std::unique_ptr<T>& lhs,
52                                               const std::pair<StringPiece, Maybe<uint8_t>>& rhs) {
53   int name_cmp = lhs->name.compare(0, lhs->name.size(), rhs.first.data(), rhs.first.size());
54   return name_cmp < 0 || (name_cmp == 0 && lhs->id < rhs.second);
55 }
56 
FindPackage(const StringPiece & name) const57 ResourceTablePackage* ResourceTable::FindPackage(const StringPiece& name) const {
58   const auto last = packages.end();
59   auto iter = std::lower_bound(packages.begin(), last, name,
60                                less_than_struct_with_name<ResourceTablePackage>);
61   if (iter != last && name == (*iter)->name) {
62     return iter->get();
63   }
64   return nullptr;
65 }
66 
FindPackageById(uint8_t id) const67 ResourceTablePackage* ResourceTable::FindPackageById(uint8_t id) const {
68   for (auto& package : packages) {
69     if (package->id && package->id.value() == id) {
70       return package.get();
71     }
72   }
73   return nullptr;
74 }
75 
CreatePackage(const StringPiece & name,Maybe<uint8_t> id)76 ResourceTablePackage* ResourceTable::CreatePackage(const StringPiece& name, Maybe<uint8_t> id) {
77   ResourceTablePackage* package = FindOrCreatePackage(name);
78   if (id && !package->id) {
79     package->id = id;
80     return package;
81   }
82 
83   if (id && package->id && package->id.value() != id.value()) {
84     return nullptr;
85   }
86   return package;
87 }
88 
CreatePackageAllowingDuplicateNames(const StringPiece & name,const Maybe<uint8_t> id)89 ResourceTablePackage* ResourceTable::CreatePackageAllowingDuplicateNames(const StringPiece& name,
90                                                                          const Maybe<uint8_t> id) {
91   const auto last = packages.end();
92   auto iter = std::lower_bound(packages.begin(), last, std::make_pair(name, id),
93                                less_than_struct_with_name_and_id<ResourceTablePackage>);
94 
95   if (iter != last && name == (*iter)->name && id == (*iter)->id) {
96     return iter->get();
97   }
98 
99   std::unique_ptr<ResourceTablePackage> new_package = util::make_unique<ResourceTablePackage>();
100   new_package->name = name.to_string();
101   new_package->id = id;
102   return packages.emplace(iter, std::move(new_package))->get();
103 }
104 
FindOrCreatePackage(const StringPiece & name)105 ResourceTablePackage* ResourceTable::FindOrCreatePackage(const StringPiece& name) {
106   const auto last = packages.end();
107   auto iter = std::lower_bound(packages.begin(), last, name,
108                                less_than_struct_with_name<ResourceTablePackage>);
109   if (iter != last && name == (*iter)->name) {
110     return iter->get();
111   }
112 
113   std::unique_ptr<ResourceTablePackage> new_package = util::make_unique<ResourceTablePackage>();
114   new_package->name = name.to_string();
115   return packages.emplace(iter, std::move(new_package))->get();
116 }
117 
FindType(ResourceType type)118 ResourceTableType* ResourceTablePackage::FindType(ResourceType type) {
119   const auto last = types.end();
120   auto iter = std::lower_bound(types.begin(), last, type, less_than_type);
121   if (iter != last && (*iter)->type == type) {
122     return iter->get();
123   }
124   return nullptr;
125 }
126 
FindOrCreateType(ResourceType type)127 ResourceTableType* ResourceTablePackage::FindOrCreateType(ResourceType type) {
128   const auto last = types.end();
129   auto iter = std::lower_bound(types.begin(), last, type, less_than_type);
130   if (iter != last && (*iter)->type == type) {
131     return iter->get();
132   }
133   return types.emplace(iter, new ResourceTableType(type))->get();
134 }
135 
FindEntry(const StringPiece & name)136 ResourceEntry* ResourceTableType::FindEntry(const StringPiece& name) {
137   const auto last = entries.end();
138   auto iter =
139       std::lower_bound(entries.begin(), last, name, less_than_struct_with_name<ResourceEntry>);
140   if (iter != last && name == (*iter)->name) {
141     return iter->get();
142   }
143   return nullptr;
144 }
145 
FindOrCreateEntry(const StringPiece & name)146 ResourceEntry* ResourceTableType::FindOrCreateEntry(const StringPiece& name) {
147   auto last = entries.end();
148   auto iter =
149       std::lower_bound(entries.begin(), last, name, less_than_struct_with_name<ResourceEntry>);
150   if (iter != last && name == (*iter)->name) {
151     return iter->get();
152   }
153   return entries.emplace(iter, new ResourceEntry(name))->get();
154 }
155 
FindValue(const ConfigDescription & config)156 ResourceConfigValue* ResourceEntry::FindValue(const ConfigDescription& config) {
157   return FindValue(config, StringPiece());
158 }
159 
160 struct ConfigKey {
161   const ConfigDescription* config;
162   const StringPiece& product;
163 };
164 
lt_config_key_ref(const std::unique_ptr<ResourceConfigValue> & lhs,const ConfigKey & rhs)165 bool lt_config_key_ref(const std::unique_ptr<ResourceConfigValue>& lhs, const ConfigKey& rhs) {
166   int cmp = lhs->config.compare(*rhs.config);
167   if (cmp == 0) {
168     cmp = StringPiece(lhs->product).compare(rhs.product);
169   }
170   return cmp < 0;
171 }
172 
FindValue(const ConfigDescription & config,const StringPiece & product)173 ResourceConfigValue* ResourceEntry::FindValue(const ConfigDescription& config,
174                                               const StringPiece& product) {
175   auto iter = std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product},
176                                lt_config_key_ref);
177   if (iter != values.end()) {
178     ResourceConfigValue* value = iter->get();
179     if (value->config == config && StringPiece(value->product) == product) {
180       return value;
181     }
182   }
183   return nullptr;
184 }
185 
FindOrCreateValue(const ConfigDescription & config,const StringPiece & product)186 ResourceConfigValue* ResourceEntry::FindOrCreateValue(const ConfigDescription& config,
187                                                       const StringPiece& product) {
188   auto iter = std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product},
189                                lt_config_key_ref);
190   if (iter != values.end()) {
191     ResourceConfigValue* value = iter->get();
192     if (value->config == config && StringPiece(value->product) == product) {
193       return value;
194     }
195   }
196   ResourceConfigValue* newValue =
197       values.insert(iter, util::make_unique<ResourceConfigValue>(config, product))->get();
198   return newValue;
199 }
200 
FindAllValues(const ConfigDescription & config)201 std::vector<ResourceConfigValue*> ResourceEntry::FindAllValues(const ConfigDescription& config) {
202   std::vector<ResourceConfigValue*> results;
203 
204   auto iter = values.begin();
205   for (; iter != values.end(); ++iter) {
206     ResourceConfigValue* value = iter->get();
207     if (value->config == config) {
208       results.push_back(value);
209       ++iter;
210       break;
211     }
212   }
213 
214   for (; iter != values.end(); ++iter) {
215     ResourceConfigValue* value = iter->get();
216     if (value->config == config) {
217       results.push_back(value);
218     }
219   }
220   return results;
221 }
222 
HasDefaultValue() const223 bool ResourceEntry::HasDefaultValue() const {
224   const ConfigDescription& default_config = ConfigDescription::DefaultConfig();
225 
226   // The default config should be at the top of the list, since the list is sorted.
227   for (auto& config_value : values) {
228     if (config_value->config == default_config) {
229       return true;
230     }
231   }
232   return false;
233 }
234 
235 // The default handler for collisions.
236 //
237 // Typically, a weak value will be overridden by a strong value. An existing weak
238 // value will not be overridden by an incoming weak value.
239 //
240 // There are some exceptions:
241 //
242 // Attributes: There are two types of Attribute values: USE and DECL.
243 //
244 // USE is anywhere an Attribute is declared without a format, and in a place that would
245 // be legal to declare if the Attribute already existed. This is typically in a
246 // <declare-styleable> tag. Attributes defined in a <declare-styleable> are also weak.
247 //
248 // DECL is an absolute declaration of an Attribute and specifies an explicit format.
249 //
250 // A DECL will override a USE without error. Two DECLs must match in their format for there to be
251 // no error.
ResolveValueCollision(Value * existing,Value * incoming)252 ResourceTable::CollisionResult ResourceTable::ResolveValueCollision(Value* existing,
253                                                                     Value* incoming) {
254   Attribute* existing_attr = ValueCast<Attribute>(existing);
255   Attribute* incoming_attr = ValueCast<Attribute>(incoming);
256   if (!incoming_attr) {
257     if (incoming->IsWeak()) {
258       // We're trying to add a weak resource but a resource
259       // already exists. Keep the existing.
260       return CollisionResult::kKeepOriginal;
261     } else if (existing->IsWeak()) {
262       // Override the weak resource with the new strong resource.
263       return CollisionResult::kTakeNew;
264     }
265     // The existing and incoming values are strong, this is an error
266     // if the values are not both attributes.
267     return CollisionResult::kConflict;
268   }
269 
270   if (!existing_attr) {
271     if (existing->IsWeak()) {
272       // The existing value is not an attribute and it is weak,
273       // so take the incoming attribute value.
274       return CollisionResult::kTakeNew;
275     }
276     // The existing value is not an attribute and it is strong,
277     // so the incoming attribute value is an error.
278     return CollisionResult::kConflict;
279   }
280 
281   CHECK(incoming_attr != nullptr && existing_attr != nullptr);
282 
283   //
284   // Attribute specific handling. At this point we know both
285   // values are attributes. Since we can declare and define
286   // attributes all-over, we do special handling to see
287   // which definition sticks.
288   //
289   if (existing_attr->IsCompatibleWith(*incoming_attr)) {
290     // The two attributes are both DECLs, but they are plain attributes with compatible formats.
291     // Keep the strongest one.
292     return existing_attr->IsWeak() ? CollisionResult::kTakeNew : CollisionResult::kKeepOriginal;
293   }
294 
295   if (existing_attr->IsWeak() && existing_attr->type_mask == android::ResTable_map::TYPE_ANY) {
296     // Any incoming attribute is better than this.
297     return CollisionResult::kTakeNew;
298   }
299 
300   if (incoming_attr->IsWeak() && incoming_attr->type_mask == android::ResTable_map::TYPE_ANY) {
301     // The incoming attribute may be a USE instead of a DECL.
302     // Keep the existing attribute.
303     return CollisionResult::kKeepOriginal;
304   }
305   return CollisionResult::kConflict;
306 }
307 
ResourceNameValidator(const StringPiece & name)308 static StringPiece ResourceNameValidator(const StringPiece& name) {
309   if (!IsValidResourceEntryName(name)) {
310     return name;
311   }
312   return {};
313 }
314 
SkipNameValidator(const StringPiece &)315 static StringPiece SkipNameValidator(const StringPiece& /*name*/) {
316   return {};
317 }
318 
AddResource(const ResourceNameRef & name,const ConfigDescription & config,const StringPiece & product,std::unique_ptr<Value> value,IDiagnostics * diag)319 bool ResourceTable::AddResource(const ResourceNameRef& name,
320                                 const ConfigDescription& config,
321                                 const StringPiece& product,
322                                 std::unique_ptr<Value> value,
323                                 IDiagnostics* diag) {
324   return AddResourceImpl(name, {}, config, product, std::move(value), ResourceNameValidator,
325                          ResolveValueCollision, diag);
326 }
327 
AddResourceWithId(const ResourceNameRef & name,const ResourceId & res_id,const ConfigDescription & config,const StringPiece & product,std::unique_ptr<Value> value,IDiagnostics * diag)328 bool ResourceTable::AddResourceWithId(const ResourceNameRef& name, const ResourceId& res_id,
329                                       const ConfigDescription& config, const StringPiece& product,
330                                       std::unique_ptr<Value> value, IDiagnostics* diag) {
331   return AddResourceImpl(name, res_id, config, product, std::move(value), ResourceNameValidator,
332                          ResolveValueCollision, diag);
333 }
334 
AddFileReference(const ResourceNameRef & name,const ConfigDescription & config,const Source & source,const StringPiece & path,IDiagnostics * diag)335 bool ResourceTable::AddFileReference(const ResourceNameRef& name,
336                                      const ConfigDescription& config,
337                                      const Source& source,
338                                      const StringPiece& path,
339                                      IDiagnostics* diag) {
340   return AddFileReferenceImpl(name, config, source, path, nullptr, ResourceNameValidator, diag);
341 }
342 
AddFileReferenceMangled(const ResourceNameRef & name,const ConfigDescription & config,const Source & source,const StringPiece & path,io::IFile * file,IDiagnostics * diag)343 bool ResourceTable::AddFileReferenceMangled(const ResourceNameRef& name,
344                                             const ConfigDescription& config, const Source& source,
345                                             const StringPiece& path, io::IFile* file,
346                                             IDiagnostics* diag) {
347   return AddFileReferenceImpl(name, config, source, path, file, SkipNameValidator, diag);
348 }
349 
AddFileReferenceImpl(const ResourceNameRef & name,const ConfigDescription & config,const Source & source,const StringPiece & path,io::IFile * file,NameValidator name_validator,IDiagnostics * diag)350 bool ResourceTable::AddFileReferenceImpl(const ResourceNameRef& name,
351                                          const ConfigDescription& config, const Source& source,
352                                          const StringPiece& path, io::IFile* file,
353                                          NameValidator name_validator, IDiagnostics* diag) {
354   std::unique_ptr<FileReference> fileRef =
355       util::make_unique<FileReference>(string_pool.MakeRef(path));
356   fileRef->SetSource(source);
357   fileRef->file = file;
358   return AddResourceImpl(name, ResourceId{}, config, StringPiece{}, std::move(fileRef),
359                          name_validator, ResolveValueCollision, diag);
360 }
361 
AddResourceMangled(const ResourceNameRef & name,const ConfigDescription & config,const StringPiece & product,std::unique_ptr<Value> value,IDiagnostics * diag)362 bool ResourceTable::AddResourceMangled(const ResourceNameRef& name, const ConfigDescription& config,
363                                        const StringPiece& product, std::unique_ptr<Value> value,
364                                        IDiagnostics* diag) {
365   return AddResourceImpl(name, ResourceId{}, config, product, std::move(value), SkipNameValidator,
366                          ResolveValueCollision, diag);
367 }
368 
AddResourceWithIdMangled(const ResourceNameRef & name,const ResourceId & id,const ConfigDescription & config,const StringPiece & product,std::unique_ptr<Value> value,IDiagnostics * diag)369 bool ResourceTable::AddResourceWithIdMangled(const ResourceNameRef& name, const ResourceId& id,
370                                              const ConfigDescription& config,
371                                              const StringPiece& product,
372                                              std::unique_ptr<Value> value, IDiagnostics* diag) {
373   return AddResourceImpl(name, id, config, product, std::move(value), SkipNameValidator,
374                          ResolveValueCollision, diag);
375 }
376 
ValidateName(NameValidator name_validator,const ResourceNameRef & name,const Source & source,IDiagnostics * diag)377 bool ResourceTable::ValidateName(NameValidator name_validator, const ResourceNameRef& name,
378                                  const Source& source, IDiagnostics* diag) {
379   const StringPiece bad_char = name_validator(name.entry);
380   if (!bad_char.empty()) {
381     diag->Error(DiagMessage(source) << "resource '" << name << "' has invalid entry name '"
382                                     << name.entry << "'. Invalid character '" << bad_char << "'");
383     return false;
384   }
385   return true;
386 }
387 
AddResourceImpl(const ResourceNameRef & name,const ResourceId & res_id,const ConfigDescription & config,const StringPiece & product,std::unique_ptr<Value> value,NameValidator name_validator,const CollisionResolverFunc & conflict_resolver,IDiagnostics * diag)388 bool ResourceTable::AddResourceImpl(const ResourceNameRef& name, const ResourceId& res_id,
389                                     const ConfigDescription& config, const StringPiece& product,
390                                     std::unique_ptr<Value> value, NameValidator name_validator,
391                                     const CollisionResolverFunc& conflict_resolver,
392                                     IDiagnostics* diag) {
393   CHECK(value != nullptr);
394   CHECK(diag != nullptr);
395 
396   const Source& source = value->GetSource();
397   if (!ValidateName(name_validator, name, source, diag)) {
398     return false;
399   }
400 
401   ResourceTablePackage* package = FindOrCreatePackage(name.package);
402   if (res_id.is_valid_dynamic() && package->id && package->id.value() != res_id.package_id()) {
403     diag->Error(DiagMessage(source) << "trying to add resource '" << name << "' with ID " << res_id
404                                     << " but package '" << package->name << "' already has ID "
405                                     << StringPrintf("%02x", package->id.value()));
406     return false;
407   }
408 
409   ResourceTableType* type = package->FindOrCreateType(name.type);
410   if (res_id.is_valid_dynamic() && type->id && type->id.value() != res_id.type_id()) {
411     diag->Error(DiagMessage(source)
412                 << "trying to add resource '" << name << "' with ID " << res_id << " but type '"
413                 << type->type << "' already has ID " << StringPrintf("%02x", type->id.value()));
414     return false;
415   }
416 
417   ResourceEntry* entry = type->FindOrCreateEntry(name.entry);
418   if (res_id.is_valid_dynamic() && entry->id && entry->id.value() != res_id.entry_id()) {
419     diag->Error(DiagMessage(source)
420                 << "trying to add resource '" << name << "' with ID " << res_id
421                 << " but resource already has ID "
422                 << ResourceId(package->id.value(), type->id.value(), entry->id.value()));
423     return false;
424   }
425 
426   ResourceConfigValue* config_value = entry->FindOrCreateValue(config, product);
427   if (config_value->value == nullptr) {
428     // Resource does not exist, add it now.
429     config_value->value = std::move(value);
430   } else {
431     switch (conflict_resolver(config_value->value.get(), value.get())) {
432       case CollisionResult::kTakeNew:
433         // Take the incoming value.
434         config_value->value = std::move(value);
435         break;
436 
437       case CollisionResult::kConflict:
438         diag->Error(DiagMessage(source) << "duplicate value for resource '" << name << "' "
439                                         << "with config '" << config << "'");
440         diag->Error(DiagMessage(source) << "resource previously defined here");
441         return false;
442 
443       case CollisionResult::kKeepOriginal:
444         break;
445     }
446   }
447 
448   if (res_id.is_valid_dynamic()) {
449     package->id = res_id.package_id();
450     type->id = res_id.type_id();
451     entry->id = res_id.entry_id();
452   }
453   return true;
454 }
455 
SetVisibility(const ResourceNameRef & name,const Visibility & visibility,IDiagnostics * diag)456 bool ResourceTable::SetVisibility(const ResourceNameRef& name, const Visibility& visibility,
457                                   IDiagnostics* diag) {
458   return SetVisibilityImpl(name, visibility, ResourceId{}, ResourceNameValidator, diag);
459 }
460 
SetVisibilityMangled(const ResourceNameRef & name,const Visibility & visibility,IDiagnostics * diag)461 bool ResourceTable::SetVisibilityMangled(const ResourceNameRef& name, const Visibility& visibility,
462                                          IDiagnostics* diag) {
463   return SetVisibilityImpl(name, visibility, ResourceId{}, SkipNameValidator, diag);
464 }
465 
SetVisibilityWithId(const ResourceNameRef & name,const Visibility & visibility,const ResourceId & res_id,IDiagnostics * diag)466 bool ResourceTable::SetVisibilityWithId(const ResourceNameRef& name, const Visibility& visibility,
467                                         const ResourceId& res_id, IDiagnostics* diag) {
468   return SetVisibilityImpl(name, visibility, res_id, ResourceNameValidator, diag);
469 }
470 
SetVisibilityWithIdMangled(const ResourceNameRef & name,const Visibility & visibility,const ResourceId & res_id,IDiagnostics * diag)471 bool ResourceTable::SetVisibilityWithIdMangled(const ResourceNameRef& name,
472                                                const Visibility& visibility,
473                                                const ResourceId& res_id, IDiagnostics* diag) {
474   return SetVisibilityImpl(name, visibility, res_id, SkipNameValidator, diag);
475 }
476 
SetVisibilityImpl(const ResourceNameRef & name,const Visibility & visibility,const ResourceId & res_id,NameValidator name_validator,IDiagnostics * diag)477 bool ResourceTable::SetVisibilityImpl(const ResourceNameRef& name, const Visibility& visibility,
478                                       const ResourceId& res_id, NameValidator name_validator,
479                                       IDiagnostics* diag) {
480   CHECK(diag != nullptr);
481 
482   const Source& source = visibility.source;
483   if (!ValidateName(name_validator, name, source, diag)) {
484     return false;
485   }
486 
487   ResourceTablePackage* package = FindOrCreatePackage(name.package);
488   if (res_id.is_valid_dynamic() && package->id && package->id.value() != res_id.package_id()) {
489     diag->Error(DiagMessage(source) << "trying to add resource '" << name << "' with ID " << res_id
490                                     << " but package '" << package->name << "' already has ID "
491                                     << StringPrintf("%02x", package->id.value()));
492     return false;
493   }
494 
495   ResourceTableType* type = package->FindOrCreateType(name.type);
496   if (res_id.is_valid_dynamic() && type->id && type->id.value() != res_id.type_id()) {
497     diag->Error(DiagMessage(source)
498                 << "trying to add resource '" << name << "' with ID " << res_id << " but type '"
499                 << type->type << "' already has ID " << StringPrintf("%02x", type->id.value()));
500     return false;
501   }
502 
503   ResourceEntry* entry = type->FindOrCreateEntry(name.entry);
504   if (res_id.is_valid_dynamic() && entry->id && entry->id.value() != res_id.entry_id()) {
505     diag->Error(DiagMessage(source)
506                 << "trying to add resource '" << name << "' with ID " << res_id
507                 << " but resource already has ID "
508                 << ResourceId(package->id.value(), type->id.value(), entry->id.value()));
509     return false;
510   }
511 
512   if (res_id.is_valid_dynamic()) {
513     package->id = res_id.package_id();
514     type->id = res_id.type_id();
515     entry->id = res_id.entry_id();
516   }
517 
518   // Only mark the type visibility level as public, it doesn't care about being private.
519   if (visibility.level == Visibility::Level::kPublic) {
520     type->visibility_level = Visibility::Level::kPublic;
521   }
522 
523   if (visibility.level == Visibility::Level::kUndefined &&
524       entry->visibility.level != Visibility::Level::kUndefined) {
525     // We can't undefine a symbol (remove its visibility). Ignore.
526     return true;
527   }
528 
529   if (visibility.level < entry->visibility.level) {
530     // We can't downgrade public to private. Ignore.
531     return true;
532   }
533 
534   // This symbol definition takes precedence, replace.
535   entry->visibility = visibility;
536   return true;
537 }
538 
SetAllowNew(const ResourceNameRef & name,const AllowNew & allow_new,IDiagnostics * diag)539 bool ResourceTable::SetAllowNew(const ResourceNameRef& name, const AllowNew& allow_new,
540                                 IDiagnostics* diag) {
541   return SetAllowNewImpl(name, allow_new, ResourceNameValidator, diag);
542 }
543 
SetAllowNewMangled(const ResourceNameRef & name,const AllowNew & allow_new,IDiagnostics * diag)544 bool ResourceTable::SetAllowNewMangled(const ResourceNameRef& name, const AllowNew& allow_new,
545                                        IDiagnostics* diag) {
546   return SetAllowNewImpl(name, allow_new, SkipNameValidator, diag);
547 }
548 
SetAllowNewImpl(const ResourceNameRef & name,const AllowNew & allow_new,NameValidator name_validator,IDiagnostics * diag)549 bool ResourceTable::SetAllowNewImpl(const ResourceNameRef& name, const AllowNew& allow_new,
550                                     NameValidator name_validator, IDiagnostics* diag) {
551   CHECK(diag != nullptr);
552 
553   if (!ValidateName(name_validator, name, allow_new.source, diag)) {
554     return false;
555   }
556 
557   ResourceTablePackage* package = FindOrCreatePackage(name.package);
558   ResourceTableType* type = package->FindOrCreateType(name.type);
559   ResourceEntry* entry = type->FindOrCreateEntry(name.entry);
560   entry->allow_new = allow_new;
561   return true;
562 }
563 
SetOverlayable(const ResourceNameRef & name,const Overlayable & overlayable,IDiagnostics * diag)564 bool ResourceTable::SetOverlayable(const ResourceNameRef& name, const Overlayable& overlayable,
565                                    IDiagnostics* diag) {
566   return SetOverlayableImpl(name, overlayable, ResourceNameValidator, diag);
567 }
568 
SetOverlayableMangled(const ResourceNameRef & name,const Overlayable & overlayable,IDiagnostics * diag)569 bool ResourceTable::SetOverlayableMangled(const ResourceNameRef& name,
570                                           const Overlayable& overlayable, IDiagnostics* diag) {
571   return SetOverlayableImpl(name, overlayable, SkipNameValidator, diag);
572 }
573 
SetOverlayableImpl(const ResourceNameRef & name,const Overlayable & overlayable,NameValidator name_validator,IDiagnostics * diag)574 bool ResourceTable::SetOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable,
575                                        NameValidator name_validator, IDiagnostics* diag) {
576   CHECK(diag != nullptr);
577 
578   if (!ValidateName(name_validator, name, overlayable.source, diag)) {
579     return false;
580   }
581 
582   ResourceTablePackage* package = FindOrCreatePackage(name.package);
583   ResourceTableType* type = package->FindOrCreateType(name.type);
584   ResourceEntry* entry = type->FindOrCreateEntry(name.entry);
585   if (entry->overlayable) {
586     diag->Error(DiagMessage(overlayable.source)
587                 << "duplicate overlayable declaration for resource '" << name << "'");
588     diag->Error(DiagMessage(entry->overlayable.value().source) << "previous declaration here");
589     return false;
590   }
591   entry->overlayable = overlayable;
592   return true;
593 }
594 
FindResource(const ResourceNameRef & name) const595 Maybe<ResourceTable::SearchResult> ResourceTable::FindResource(const ResourceNameRef& name) const {
596   ResourceTablePackage* package = FindPackage(name.package);
597   if (package == nullptr) {
598     return {};
599   }
600 
601   ResourceTableType* type = package->FindType(name.type);
602   if (type == nullptr) {
603     return {};
604   }
605 
606   ResourceEntry* entry = type->FindEntry(name.entry);
607   if (entry == nullptr) {
608     return {};
609   }
610   return SearchResult{package, type, entry};
611 }
612 
Clone() const613 std::unique_ptr<ResourceTable> ResourceTable::Clone() const {
614   std::unique_ptr<ResourceTable> new_table = util::make_unique<ResourceTable>();
615   for (const auto& pkg : packages) {
616     ResourceTablePackage* new_pkg = new_table->CreatePackage(pkg->name, pkg->id);
617     for (const auto& type : pkg->types) {
618       ResourceTableType* new_type = new_pkg->FindOrCreateType(type->type);
619       new_type->id = type->id;
620       new_type->visibility_level = type->visibility_level;
621 
622       for (const auto& entry : type->entries) {
623         ResourceEntry* new_entry = new_type->FindOrCreateEntry(entry->name);
624         new_entry->id = entry->id;
625         new_entry->visibility = entry->visibility;
626         new_entry->allow_new = entry->allow_new;
627         new_entry->overlayable = entry->overlayable;
628 
629         for (const auto& config_value : entry->values) {
630           ResourceConfigValue* new_value =
631               new_entry->FindOrCreateValue(config_value->config, config_value->product);
632           new_value->value.reset(config_value->value->Clone(&new_table->string_pool));
633         }
634       }
635     }
636   }
637   return new_table;
638 }
639 
640 }  // namespace aapt
641