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 30namespace aapt { 31 32namespace { 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 */ 41class 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 */ 70class 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 163bool 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