XmlReferenceLinker.cpp revision 1ab598f46c3ff520a67f9d80194847741f3467ab
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 "Diagnostics.h" 18#include "ResourceUtils.h" 19#include "SdkConstants.h" 20#include "XmlDom.h" 21 22#include "link/Linkers.h" 23#include "link/ReferenceLinkerVisitor.h" 24#include "process/IResourceTableConsumer.h" 25#include "process/SymbolTable.h" 26#include "util/Util.h" 27 28namespace aapt { 29 30namespace { 31 32class XmlReferenceLinkerVisitor : public xml::PackageAwareVisitor { 33private: 34 IAaptContext* mContext; 35 ISymbolTable* mSymbols; 36 std::set<int>* mSdkLevelsFound; 37 ReferenceLinkerVisitor mReferenceLinkerVisitor; 38 bool mError = false; 39 40public: 41 using xml::PackageAwareVisitor::visit; 42 43 XmlReferenceLinkerVisitor(IAaptContext* context, ISymbolTable* symbols, 44 std::set<int>* sdkLevelsFound) : 45 mContext(context), mSymbols(symbols), mSdkLevelsFound(sdkLevelsFound), 46 mReferenceLinkerVisitor(context, symbols, this) { 47 } 48 49 void visit(xml::Element* el) override { 50 for (xml::Attribute& attr : el->attributes) { 51 Maybe<std::u16string> maybePackage = 52 util::extractPackageFromNamespace(attr.namespaceUri); 53 if (maybePackage) { 54 // There is a valid package name for this attribute. We will look this up. 55 StringPiece16 package = maybePackage.value(); 56 if (package.empty()) { 57 // Empty package means the 'current' or 'local' package. 58 package = mContext->getCompilationPackage(); 59 } 60 61 attr.compiledAttribute = compileAttribute( 62 ResourceName{ package.toString(), ResourceType::kAttr, attr.name }); 63 64 // Convert the string value into a compiled Value if this is a valid attribute. 65 if (attr.compiledAttribute) { 66 // Record all SDK levels from which the attributes were defined. 67 const int sdkLevel = findAttributeSdkLevel(attr.compiledAttribute.value().id); 68 if (sdkLevel > 1) { 69 mSdkLevelsFound->insert(sdkLevel); 70 } 71 72 const Attribute* attribute = &attr.compiledAttribute.value().attribute; 73 attr.compiledValue = ResourceUtils::parseItemForAttribute(attr.value, 74 attribute); 75 if (!attr.compiledValue && 76 !(attribute->typeMask & android::ResTable_map::TYPE_STRING)) { 77 // We won't be able to encode this as a string. 78 mContext->getDiagnostics()->error( 79 DiagMessage() << "'" << attr.value << "' " 80 << "is incompatible with attribute " 81 << package << ":" << attr.name << " " << *attribute); 82 mError = true; 83 } 84 } else { 85 mContext->getDiagnostics()->error( 86 DiagMessage() << "attribute '" << package << ":" << attr.name 87 << "' was not found"); 88 mError = true; 89 90 } 91 } else { 92 // We still encode references. 93 attr.compiledValue = ResourceUtils::tryParseReference(attr.value); 94 } 95 96 if (attr.compiledValue) { 97 // With a compiledValue, we must resolve the reference and assign it an ID. 98 attr.compiledValue->accept(&mReferenceLinkerVisitor); 99 } 100 } 101 102 // Call the super implementation. 103 xml::PackageAwareVisitor::visit(el); 104 } 105 106 Maybe<xml::AaptAttribute> compileAttribute(const ResourceName& name) { 107 Maybe<ResourceName> mangledName = mContext->getNameMangler()->mangleName(name); 108 if (const ISymbolTable::Symbol* symbol = mSymbols->findByName( 109 mangledName ? mangledName.value() : name)) { 110 if (symbol->attribute) { 111 return xml::AaptAttribute{ symbol->id, *symbol->attribute }; 112 } 113 } 114 return {}; 115 } 116 117 inline bool hasError() { 118 return mError || mReferenceLinkerVisitor.hasError(); 119 } 120}; 121 122} // namespace 123 124bool XmlReferenceLinker::consume(IAaptContext* context, XmlResource* resource) { 125 mSdkLevelsFound.clear(); 126 XmlReferenceLinkerVisitor visitor(context, context->getExternalSymbols(), &mSdkLevelsFound); 127 if (resource->root) { 128 resource->root->accept(&visitor); 129 return !visitor.hasError(); 130 } 131 return false; 132} 133 134} // namespace aapt 135