Home | History | Annotate | Download | only in link
      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 "link/Linkers.h"
     18 
     19 #include "androidfw/ResourceTypes.h"
     20 
     21 #include "Diagnostics.h"
     22 #include "ResourceUtils.h"
     23 #include "SdkConstants.h"
     24 #include "link/ReferenceLinker.h"
     25 #include "process/IResourceTableConsumer.h"
     26 #include "process/SymbolTable.h"
     27 #include "util/Util.h"
     28 #include "xml/XmlDom.h"
     29 
     30 namespace aapt {
     31 
     32 namespace {
     33 
     34 /**
     35  * Visits all references (including parents of styles, references in styles,
     36  * arrays, etc) and
     37  * links their symbolic name to their Resource ID, performing mangling and
     38  * package aliasing
     39  * as needed.
     40  */
     41 class ReferenceVisitor : public ValueVisitor {
     42  public:
     43   using ValueVisitor::Visit;
     44 
     45   ReferenceVisitor(const CallSite& callsite, IAaptContext* context, SymbolTable* symbols,
     46                    xml::IPackageDeclStack* decls)
     47       : callsite_(callsite), context_(context), symbols_(symbols), decls_(decls), error_(false) {}
     48 
     49   void Visit(Reference* ref) override {
     50     if (!ReferenceLinker::LinkReference(callsite_, ref, context_, symbols_, decls_)) {
     51       error_ = true;
     52     }
     53   }
     54 
     55   bool HasError() const { return error_; }
     56 
     57  private:
     58   DISALLOW_COPY_AND_ASSIGN(ReferenceVisitor);
     59 
     60   const CallSite& callsite_;
     61   IAaptContext* context_;
     62   SymbolTable* symbols_;
     63   xml::IPackageDeclStack* decls_;
     64   bool error_;
     65 };
     66 
     67 /**
     68  * Visits each xml Element and compiles the attributes within.
     69  */
     70 class XmlVisitor : public xml::PackageAwareVisitor {
     71  public:
     72   using xml::PackageAwareVisitor::Visit;
     73 
     74   XmlVisitor(const Source& source, const CallSite& callsite, IAaptContext* context,
     75              SymbolTable* symbols)
     76       : source_(source),
     77         callsite_(callsite),
     78         context_(context),
     79         symbols_(symbols),
     80         reference_visitor_(callsite, context, symbols, this) {
     81   }
     82 
     83   void Visit(xml::Element* el) override {
     84     // The default Attribute allows everything except enums or flags.
     85     constexpr const static uint32_t kDefaultTypeMask =
     86         0xffffffffu & ~(android::ResTable_map::TYPE_ENUM | android::ResTable_map::TYPE_FLAGS);
     87     const static Attribute kDefaultAttribute(true /* weak */, kDefaultTypeMask);
     88 
     89     const Source source = source_.WithLine(el->line_number);
     90     for (xml::Attribute& attr : el->attributes) {
     91       // If the attribute has no namespace, interpret values as if
     92       // they were assigned to the default Attribute.
     93 
     94       const Attribute* attribute = &kDefaultAttribute;
     95       std::string attribute_package;
     96 
     97       if (Maybe<xml::ExtractedPackage> maybe_package =
     98               xml::ExtractPackageFromNamespace(attr.namespace_uri)) {
     99         // There is a valid package name for this attribute. We will look this up.
    100         attribute_package = maybe_package.value().package;
    101         if (attribute_package.empty()) {
    102           // Empty package means the 'current' or 'local' package.
    103           attribute_package = context_->GetCompilationPackage();
    104         }
    105 
    106         Reference attr_ref(ResourceNameRef(attribute_package, ResourceType::kAttr, attr.name));
    107         attr_ref.private_reference = maybe_package.value().private_namespace;
    108 
    109         std::string err_str;
    110         attr.compiled_attribute =
    111             ReferenceLinker::CompileXmlAttribute(attr_ref, callsite_, symbols_, &err_str);
    112 
    113         if (!attr.compiled_attribute) {
    114           context_->GetDiagnostics()->Error(DiagMessage(source) << "attribute '"
    115                                                                 << attribute_package << ":"
    116                                                                 << attr.name << "' " << err_str);
    117           error_ = true;
    118           continue;
    119         }
    120 
    121         attribute = &attr.compiled_attribute.value().attribute;
    122       }
    123 
    124       attr.compiled_value = ResourceUtils::TryParseItemForAttribute(attr.value, attribute);
    125       if (attr.compiled_value) {
    126         // With a compiledValue, we must resolve the reference and assign it an ID.
    127         attr.compiled_value->SetSource(source);
    128         attr.compiled_value->Accept(&reference_visitor_);
    129       } else if ((attribute->type_mask & android::ResTable_map::TYPE_STRING) == 0) {
    130         // We won't be able to encode this as a string.
    131         DiagMessage msg(source);
    132         msg << "'" << attr.value << "' "
    133             << "is incompatible with attribute ";
    134         if (!attribute_package.empty()) {
    135           msg << attribute_package << ":";
    136         }
    137         msg << attr.name << " " << *attribute;
    138         context_->GetDiagnostics()->Error(msg);
    139         error_ = true;
    140       }
    141     }
    142 
    143     // Call the super implementation.
    144     xml::PackageAwareVisitor::Visit(el);
    145   }
    146 
    147   bool HasError() { return error_ || reference_visitor_.HasError(); }
    148 
    149  private:
    150   DISALLOW_COPY_AND_ASSIGN(XmlVisitor);
    151 
    152   Source source_;
    153   const CallSite& callsite_;
    154   IAaptContext* context_;
    155   SymbolTable* symbols_;
    156 
    157   ReferenceVisitor reference_visitor_;
    158   bool error_ = false;
    159 };
    160 
    161 }  // namespace
    162 
    163 bool XmlReferenceLinker::Consume(IAaptContext* context, xml::XmlResource* resource) {
    164   const CallSite callsite = {resource->file.name};
    165   XmlVisitor visitor(resource->file.source, callsite, context, context->GetExternalSymbols());
    166   if (resource->root) {
    167     resource->root->Accept(&visitor);
    168     return !visitor.HasError();
    169   }
    170   return false;
    171 }
    172 
    173 }  // namespace aapt
    174