Home | History | Annotate | Download | only in aapt2
      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 
     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>
     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>
     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 
     57 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 
     67 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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    223 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.
    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 
    308 static StringPiece ResourceNameValidator(const StringPiece& name) {
    309   if (!IsValidResourceEntryName(name)) {
    310     return name;
    311   }
    312   return {};
    313 }
    314 
    315 static StringPiece SkipNameValidator(const StringPiece& /*name*/) {
    316   return {};
    317 }
    318 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    456 bool ResourceTable::SetVisibility(const ResourceNameRef& name, const Visibility& visibility,
    457                                   IDiagnostics* diag) {
    458   return SetVisibilityImpl(name, visibility, ResourceId{}, ResourceNameValidator, diag);
    459 }
    460 
    461 bool ResourceTable::SetVisibilityMangled(const ResourceNameRef& name, const Visibility& visibility,
    462                                          IDiagnostics* diag) {
    463   return SetVisibilityImpl(name, visibility, ResourceId{}, SkipNameValidator, diag);
    464 }
    465 
    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 
    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 
    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 
    539 bool ResourceTable::SetAllowNew(const ResourceNameRef& name, const AllowNew& allow_new,
    540                                 IDiagnostics* diag) {
    541   return SetAllowNewImpl(name, allow_new, ResourceNameValidator, diag);
    542 }
    543 
    544 bool ResourceTable::SetAllowNewMangled(const ResourceNameRef& name, const AllowNew& allow_new,
    545                                        IDiagnostics* diag) {
    546   return SetAllowNewImpl(name, allow_new, SkipNameValidator, diag);
    547 }
    548 
    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 
    564 bool ResourceTable::SetOverlayable(const ResourceNameRef& name, const Overlayable& overlayable,
    565                                    IDiagnostics* diag) {
    566   return SetOverlayableImpl(name, overlayable, ResourceNameValidator, diag);
    567 }
    568 
    569 bool ResourceTable::SetOverlayableMangled(const ResourceNameRef& name,
    570                                           const Overlayable& overlayable, IDiagnostics* diag) {
    571   return SetOverlayableImpl(name, overlayable, SkipNameValidator, diag);
    572 }
    573 
    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 
    595 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 
    613 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