From 467f171315f9c2037fcd3eb5edcfabc40671bf7b Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Mon, 16 Nov 2015 17:35:44 -0800 Subject: AAPT2: Fail compiling when private symbols are referenced Also moved some XML specific stuff into its own directory, and refactored ReferenceLinker a bit. Change-Id: I912247a82023c1bbf72dc191fbdaf62858cbec0c --- tools/aapt2/Android.mk | 10 +- tools/aapt2/ResourceParser.cpp | 239 ++++++------ tools/aapt2/ResourceParser.h | 40 +-- tools/aapt2/ResourceParser_test.cpp | 26 +- tools/aapt2/ResourceUtils.cpp | 60 +++- tools/aapt2/ResourceUtils.h | 7 + tools/aapt2/ResourceUtils_test.cpp | 31 +- tools/aapt2/ResourceValues.cpp | 39 +- tools/aapt2/XmlDom.cpp | 401 --------------------- tools/aapt2/XmlDom.h | 259 ------------- tools/aapt2/XmlDom_test.cpp | 50 --- tools/aapt2/XmlPullParser.cpp | 286 --------------- tools/aapt2/XmlPullParser.h | 282 --------------- tools/aapt2/XmlPullParser_test.cpp | 55 --- tools/aapt2/compile/Compile.cpp | 9 +- tools/aapt2/compile/XmlIdCollector.cpp | 5 +- tools/aapt2/compile/XmlIdCollector.h | 3 +- tools/aapt2/compile/XmlIdCollector_test.cpp | 4 +- tools/aapt2/flatten/ResourceTypeExtensions.h | 2 +- tools/aapt2/flatten/TableFlattener.cpp | 54 ++- tools/aapt2/flatten/TableFlattener_test.cpp | 4 +- tools/aapt2/flatten/XmlFlattener.cpp | 7 +- tools/aapt2/flatten/XmlFlattener.h | 10 +- tools/aapt2/flatten/XmlFlattener_test.cpp | 15 +- tools/aapt2/java/AnnotationProcessor_test.cpp | 6 +- tools/aapt2/java/ClassDefinitionWriter.h | 1 + tools/aapt2/java/ManifestClassGenerator.cpp | 5 +- tools/aapt2/java/ManifestClassGenerator.h | 4 +- tools/aapt2/java/ManifestClassGenerator_test.cpp | 5 +- tools/aapt2/java/ProguardRules.cpp | 12 +- tools/aapt2/java/ProguardRules.h | 7 +- tools/aapt2/link/Link.cpp | 47 ++- tools/aapt2/link/Linkers.h | 23 +- tools/aapt2/link/ManifestFixer.cpp | 5 +- tools/aapt2/link/ManifestFixer.h | 6 +- tools/aapt2/link/ManifestFixer_test.cpp | 11 +- tools/aapt2/link/PrivateAttributeMover.cpp | 1 - tools/aapt2/link/ReferenceLinker.cpp | 249 +++++++++---- tools/aapt2/link/ReferenceLinker.h | 99 +++++ tools/aapt2/link/ReferenceLinkerVisitor.h | 109 ------ tools/aapt2/link/ReferenceLinker_test.cpp | 86 ++++- tools/aapt2/link/XmlReferenceLinker.cpp | 92 +++-- tools/aapt2/link/XmlReferenceLinker_test.cpp | 74 ++-- tools/aapt2/process/IResourceTableConsumer.h | 16 +- tools/aapt2/process/SymbolTable.cpp | 57 ++- tools/aapt2/test/Builders.h | 16 +- tools/aapt2/test/Context.h | 13 +- tools/aapt2/unflatten/BinaryResourceParser.cpp | 92 +++-- tools/aapt2/unflatten/BinaryResourceParser.h | 2 +- tools/aapt2/util/Util.cpp | 15 - tools/aapt2/util/Util.h | 9 - tools/aapt2/xml/XmlDom.cpp | 440 +++++++++++++++++++++++ tools/aapt2/xml/XmlDom.h | 220 ++++++++++++ tools/aapt2/xml/XmlDom_test.cpp | 50 +++ tools/aapt2/xml/XmlPullParser.cpp | 308 ++++++++++++++++ tools/aapt2/xml/XmlPullParser.h | 298 +++++++++++++++ tools/aapt2/xml/XmlPullParser_test.cpp | 55 +++ tools/aapt2/xml/XmlUtil.cpp | 67 ++++ tools/aapt2/xml/XmlUtil.h | 85 +++++ tools/aapt2/xml/XmlUtil_test.cpp | 54 +++ 60 files changed, 2539 insertions(+), 1998 deletions(-) delete mode 100644 tools/aapt2/XmlDom.cpp delete mode 100644 tools/aapt2/XmlDom.h delete mode 100644 tools/aapt2/XmlDom_test.cpp delete mode 100644 tools/aapt2/XmlPullParser.cpp delete mode 100644 tools/aapt2/XmlPullParser.h delete mode 100644 tools/aapt2/XmlPullParser_test.cpp create mode 100644 tools/aapt2/link/ReferenceLinker.h delete mode 100644 tools/aapt2/link/ReferenceLinkerVisitor.h create mode 100644 tools/aapt2/xml/XmlDom.cpp create mode 100644 tools/aapt2/xml/XmlDom.h create mode 100644 tools/aapt2/xml/XmlDom_test.cpp create mode 100644 tools/aapt2/xml/XmlPullParser.cpp create mode 100644 tools/aapt2/xml/XmlPullParser.h create mode 100644 tools/aapt2/xml/XmlPullParser_test.cpp create mode 100644 tools/aapt2/xml/XmlUtil.cpp create mode 100644 tools/aapt2/xml/XmlUtil.h create mode 100644 tools/aapt2/xml/XmlUtil_test.cpp diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk index ec29c3818bdc..d8e0aac678f0 100644 --- a/tools/aapt2/Android.mk +++ b/tools/aapt2/Android.mk @@ -58,8 +58,9 @@ sources := \ ResourceValues.cpp \ SdkConstants.cpp \ StringPool.cpp \ - XmlDom.cpp \ - XmlPullParser.cpp + xml/XmlDom.cpp \ + xml/XmlPullParser.cpp \ + xml/XmlUtil.cpp testSources := \ compile/IdAssigner_test.cpp \ @@ -90,8 +91,9 @@ testSources := \ ResourceUtils_test.cpp \ StringPool_test.cpp \ ValueVisitor_test.cpp \ - XmlDom_test.cpp \ - XmlPullParser_test.cpp + xml/XmlDom_test.cpp \ + xml/XmlPullParser_test.cpp \ + xml/XmlUtil_test.cpp toolSources := \ compile/Compile.cpp \ diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp index d292f623a33e..02fe59c0a03b 100644 --- a/tools/aapt2/ResourceParser.cpp +++ b/tools/aapt2/ResourceParser.cpp @@ -19,9 +19,8 @@ #include "ResourceUtils.h" #include "ResourceValues.h" #include "ValueVisitor.h" -#include "XmlPullParser.h" - #include "util/Util.h" +#include "xml/XmlPullParser.h" #include @@ -29,26 +28,6 @@ namespace aapt { constexpr const char16_t* sXliffNamespaceUri = u"urn:oasis:names:tc:xliff:document:1.2"; -static Maybe findAttribute(XmlPullParser* parser, const StringPiece16& name) { - auto iter = parser->findAttribute(u"", name); - if (iter != parser->endAttributes()) { - return StringPiece16(util::trimWhitespace(iter->value)); - } - return {}; -} - -static Maybe findNonEmptyAttribute(XmlPullParser* parser, - const StringPiece16& name) { - auto iter = parser->findAttribute(u"", name); - if (iter != parser->endAttributes()) { - StringPiece16 trimmed = util::trimWhitespace(iter->value); - if (!trimmed.empty()) { - return trimmed; - } - } - return {}; -} - /** * Returns true if the element is or and can be safely ignored. */ @@ -65,7 +44,7 @@ ResourceParser::ResourceParser(IDiagnostics* diag, ResourceTable* table, const S /** * Build a string from XML that converts nested elements into Span objects. */ -bool ResourceParser::flattenXmlSubtree(XmlPullParser* parser, std::u16string* outRawString, +bool ResourceParser::flattenXmlSubtree(xml::XmlPullParser* parser, std::u16string* outRawString, StyleString* outStyleString) { std::vector spanStack; @@ -74,9 +53,9 @@ bool ResourceParser::flattenXmlSubtree(XmlPullParser* parser, std::u16string* ou outStyleString->spans.clear(); util::StringBuilder builder; size_t depth = 1; - while (XmlPullParser::isGoodEvent(parser->next())) { - const XmlPullParser::Event event = parser->getEvent(); - if (event == XmlPullParser::Event::kEndElement) { + while (xml::XmlPullParser::isGoodEvent(parser->next())) { + const xml::XmlPullParser::Event event = parser->getEvent(); + if (event == xml::XmlPullParser::Event::kEndElement) { if (!parser->getElementNamespace().empty()) { // We already warned and skipped the start element, so just skip here too continue; @@ -91,11 +70,11 @@ bool ResourceParser::flattenXmlSubtree(XmlPullParser* parser, std::u16string* ou outStyleString->spans.push_back(spanStack.back()); spanStack.pop_back(); - } else if (event == XmlPullParser::Event::kText) { + } else if (event == xml::XmlPullParser::Event::kText) { outRawString->append(parser->getText()); builder.append(parser->getText()); - } else if (event == XmlPullParser::Event::kStartElement) { + } else if (event == xml::XmlPullParser::Event::kStartElement) { if (!parser->getElementNamespace().empty()) { if (parser->getElementNamespace() != sXliffNamespaceUri) { // Only warn if this isn't an xliff namespace. @@ -128,7 +107,7 @@ bool ResourceParser::flattenXmlSubtree(XmlPullParser* parser, std::u16string* ou spanStack.push_back(Span{ spanName, static_cast(builder.str().size()) }); } - } else if (event == XmlPullParser::Event::kComment) { + } else if (event == xml::XmlPullParser::Event::kComment) { // Skip } else { assert(false); @@ -140,11 +119,11 @@ bool ResourceParser::flattenXmlSubtree(XmlPullParser* parser, std::u16string* ou return !error; } -bool ResourceParser::parse(XmlPullParser* parser) { +bool ResourceParser::parse(xml::XmlPullParser* parser) { bool error = false; const size_t depth = parser->getDepth(); - while (XmlPullParser::nextChildNode(parser, depth)) { - if (parser->getEvent() != XmlPullParser::Event::kStartElement) { + while (xml::XmlPullParser::nextChildNode(parser, depth)) { + if (parser->getEvent() != xml::XmlPullParser::Event::kStartElement) { // Skip comments and text. continue; } @@ -159,7 +138,7 @@ bool ResourceParser::parse(XmlPullParser* parser) { break; }; - if (parser->getEvent() == XmlPullParser::Event::kBadDocument) { + if (parser->getEvent() == xml::XmlPullParser::Event::kBadDocument) { mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) << "xml parser error: " << parser->getLastError()); return false; @@ -167,10 +146,11 @@ bool ResourceParser::parse(XmlPullParser* parser) { return !error; } -static bool shouldStripResource(XmlPullParser* parser, const Maybe productToMatch) { - assert(parser->getEvent() == XmlPullParser::Event::kStartElement); +static bool shouldStripResource(const xml::XmlPullParser* parser, + const Maybe productToMatch) { + assert(parser->getEvent() == xml::XmlPullParser::Event::kStartElement); - if (Maybe maybeProduct = findNonEmptyAttribute(parser, u"product")) { + if (Maybe maybeProduct = xml::findNonEmptyAttribute(parser, u"product")) { if (!productToMatch) { if (maybeProduct.value() != u"default" && maybeProduct.value() != u"phone") { // We didn't specify a product and this is not a default product, so skip. @@ -229,20 +209,20 @@ static bool addResourcesToTable(ResourceTable* table, const ConfigDescription& c return !error; } -bool ResourceParser::parseResources(XmlPullParser* parser) { +bool ResourceParser::parseResources(xml::XmlPullParser* parser) { std::set strippedResources; bool error = false; std::u16string comment; const size_t depth = parser->getDepth(); - while (XmlPullParser::nextChildNode(parser, depth)) { - const XmlPullParser::Event event = parser->getEvent(); - if (event == XmlPullParser::Event::kComment) { + while (xml::XmlPullParser::nextChildNode(parser, depth)) { + const xml::XmlPullParser::Event event = parser->getEvent(); + if (event == xml::XmlPullParser::Event::kComment) { comment = parser->getComment(); continue; } - if (event == XmlPullParser::Event::kText) { + if (event == xml::XmlPullParser::Event::kText) { if (!util::trimWhitespace(parser->getText()).empty()) { mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) << "plain text not allowed here"); @@ -251,7 +231,7 @@ bool ResourceParser::parseResources(XmlPullParser* parser) { continue; } - assert(event == XmlPullParser::Event::kStartElement); + assert(event == xml::XmlPullParser::Event::kStartElement); if (!parser->getElementNamespace().empty()) { // Skip unknown namespace. @@ -266,7 +246,7 @@ bool ResourceParser::parseResources(XmlPullParser* parser) { if (elementName == u"item") { // Items simply have their type encoded in the type attribute. - if (Maybe maybeType = findNonEmptyAttribute(parser, u"type")) { + if (Maybe maybeType = xml::findNonEmptyAttribute(parser, u"type")) { elementName = maybeType.value().toString(); } else { mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) @@ -280,7 +260,7 @@ bool ResourceParser::parseResources(XmlPullParser* parser) { parsedResource.source = mSource.withLine(parser->getLineNumber()); parsedResource.comment = std::move(comment); - if (Maybe maybeName = findNonEmptyAttribute(parser, u"name")) { + if (Maybe maybeName = xml::findNonEmptyAttribute(parser, u"name")) { parsedResource.name.entry = maybeName.value().toString(); } else if (elementName != u"public-group") { @@ -403,7 +383,7 @@ enum { * an Item. If allowRawValue is false, nullptr is returned in this * case. */ -std::unique_ptr ResourceParser::parseXml(XmlPullParser* parser, const uint32_t typeMask, +std::unique_ptr ResourceParser::parseXml(xml::XmlPullParser* parser, const uint32_t typeMask, const bool allowRawValue) { const size_t beginXmlLine = parser->getLineNumber(); @@ -432,10 +412,7 @@ std::unique_ptr ResourceParser::parseXml(XmlPullParser* parser, const uint if (processedItem) { // Fix up the reference. if (Reference* ref = valueCast(processedItem.get())) { - if (Maybe transformedName = - parser->transformPackage(ref->name.value(), u"")) { - ref->name = std::move(transformedName); - } + transformReferenceFromNamespace(parser, u"", ref); } return processedItem; } @@ -456,11 +433,11 @@ std::unique_ptr ResourceParser::parseXml(XmlPullParser* parser, const uint return {}; } -bool ResourceParser::parseString(XmlPullParser* parser, ParsedResource* outResource) { +bool ResourceParser::parseString(xml::XmlPullParser* parser, ParsedResource* outResource) { const Source source = mSource.withLine(parser->getLineNumber()); bool formatted = true; - if (Maybe formattedAttr = findAttribute(parser, u"formatted")) { + if (Maybe formattedAttr = xml::findAttribute(parser, u"formatted")) { if (!ResourceUtils::tryParseBool(formattedAttr.value(), &formatted)) { mDiag->error(DiagMessage(source) << "invalid value for 'formatted'. Must be a boolean"); return false; @@ -468,7 +445,7 @@ bool ResourceParser::parseString(XmlPullParser* parser, ParsedResource* outResou } bool translateable = mOptions.translatable; - if (Maybe translateableAttr = findAttribute(parser, u"translatable")) { + if (Maybe translateableAttr = xml::findAttribute(parser, u"translatable")) { if (!ResourceUtils::tryParseBool(translateableAttr.value(), &translateable)) { mDiag->error(DiagMessage(source) << "invalid value for 'translatable'. Must be a boolean"); @@ -495,7 +472,7 @@ bool ResourceParser::parseString(XmlPullParser* parser, ParsedResource* outResou return true; } -bool ResourceParser::parseColor(XmlPullParser* parser, ParsedResource* outResource) { +bool ResourceParser::parseColor(xml::XmlPullParser* parser, ParsedResource* outResource) { const Source source = mSource.withLine(parser->getLineNumber()); outResource->value = parseXml(parser, android::ResTable_map::TYPE_COLOR, kNoRawString); @@ -506,7 +483,7 @@ bool ResourceParser::parseColor(XmlPullParser* parser, ParsedResource* outResour return true; } -bool ResourceParser::parsePrimitive(XmlPullParser* parser, ParsedResource* outResource) { +bool ResourceParser::parsePrimitive(xml::XmlPullParser* parser, ParsedResource* outResource) { const Source source = mSource.withLine(parser->getLineNumber()); uint32_t typeMask = 0; @@ -540,10 +517,10 @@ bool ResourceParser::parsePrimitive(XmlPullParser* parser, ParsedResource* outRe return true; } -bool ResourceParser::parsePublic(XmlPullParser* parser, ParsedResource* outResource) { +bool ResourceParser::parsePublic(xml::XmlPullParser* parser, ParsedResource* outResource) { const Source source = mSource.withLine(parser->getLineNumber()); - Maybe maybeType = findNonEmptyAttribute(parser, u"type"); + Maybe maybeType = xml::findNonEmptyAttribute(parser, u"type"); if (!maybeType) { mDiag->error(DiagMessage(source) << " must have a 'type' attribute"); return false; @@ -558,7 +535,7 @@ bool ResourceParser::parsePublic(XmlPullParser* parser, ParsedResource* outResou outResource->name.type = *parsedType; - if (Maybe maybeId = findNonEmptyAttribute(parser, u"id")) { + if (Maybe maybeId = xml::findNonEmptyAttribute(parser, u"id")) { android::Res_value val; bool result = android::ResTable::stringToInt(maybeId.value().data(), maybeId.value().size(), &val); @@ -580,10 +557,10 @@ bool ResourceParser::parsePublic(XmlPullParser* parser, ParsedResource* outResou return true; } -bool ResourceParser::parsePublicGroup(XmlPullParser* parser, ParsedResource* outResource) { +bool ResourceParser::parsePublicGroup(xml::XmlPullParser* parser, ParsedResource* outResource) { const Source source = mSource.withLine(parser->getLineNumber()); - Maybe maybeType = findNonEmptyAttribute(parser, u"type"); + Maybe maybeType = xml::findNonEmptyAttribute(parser, u"type"); if (!maybeType) { mDiag->error(DiagMessage(source) << " must have a 'type' attribute"); return false; @@ -596,7 +573,7 @@ bool ResourceParser::parsePublicGroup(XmlPullParser* parser, ParsedResource* out return false; } - Maybe maybeId = findNonEmptyAttribute(parser, u"first-id"); + Maybe maybeId = xml::findNonEmptyAttribute(parser, u"first-id"); if (!maybeId) { mDiag->error(DiagMessage(source) << " must have a 'first-id' attribute"); return false; @@ -615,11 +592,11 @@ bool ResourceParser::parsePublicGroup(XmlPullParser* parser, ParsedResource* out std::u16string comment; bool error = false; const size_t depth = parser->getDepth(); - while (XmlPullParser::nextChildNode(parser, depth)) { - if (parser->getEvent() == XmlPullParser::Event::kComment) { + while (xml::XmlPullParser::nextChildNode(parser, depth)) { + if (parser->getEvent() == xml::XmlPullParser::Event::kComment) { comment = util::trimWhitespace(parser->getComment()).toString(); continue; - } else if (parser->getEvent() != XmlPullParser::Event::kStartElement) { + } else if (parser->getEvent() != xml::XmlPullParser::Event::kStartElement) { // Skip text. continue; } @@ -628,20 +605,20 @@ bool ResourceParser::parsePublicGroup(XmlPullParser* parser, ParsedResource* out const std::u16string& elementNamespace = parser->getElementNamespace(); const std::u16string& elementName = parser->getElementName(); if (elementNamespace.empty() && elementName == u"public") { - Maybe maybeName = findNonEmptyAttribute(parser, u"name"); + Maybe maybeName = xml::findNonEmptyAttribute(parser, u"name"); if (!maybeName) { mDiag->error(DiagMessage(itemSource) << " must have a 'name' attribute"); error = true; continue; } - if (findNonEmptyAttribute(parser, u"id")) { + if (xml::findNonEmptyAttribute(parser, u"id")) { mDiag->error(DiagMessage(itemSource) << "'id' is ignored within "); error = true; continue; } - if (findNonEmptyAttribute(parser, u"type")) { + if (xml::findNonEmptyAttribute(parser, u"type")) { mDiag->error(DiagMessage(itemSource) << "'type' is ignored within "); error = true; continue; @@ -666,10 +643,10 @@ bool ResourceParser::parsePublicGroup(XmlPullParser* parser, ParsedResource* out return !error; } -bool ResourceParser::parseSymbol(XmlPullParser* parser, ParsedResource* outResource) { +bool ResourceParser::parseSymbol(xml::XmlPullParser* parser, ParsedResource* outResource) { const Source source = mSource.withLine(parser->getLineNumber()); - Maybe maybeType = findNonEmptyAttribute(parser, u"type"); + Maybe maybeType = xml::findNonEmptyAttribute(parser, u"type"); if (!maybeType) { mDiag->error(DiagMessage(source) << "<" << parser->getElementName() << "> must have a " "'type' attribute"); @@ -715,17 +692,16 @@ static uint32_t parseFormatAttribute(const StringPiece16& str) { return mask; } - - -bool ResourceParser::parseAttr(XmlPullParser* parser, ParsedResource* outResource) { +bool ResourceParser::parseAttr(xml::XmlPullParser* parser, ParsedResource* outResource) { outResource->source = mSource.withLine(parser->getLineNumber()); return parseAttrImpl(parser, outResource, false); } -bool ResourceParser::parseAttrImpl(XmlPullParser* parser, ParsedResource* outResource, bool weak) { +bool ResourceParser::parseAttrImpl(xml::XmlPullParser* parser, ParsedResource* outResource, + bool weak) { uint32_t typeMask = 0; - Maybe maybeFormat = findAttribute(parser, u"format"); + Maybe maybeFormat = xml::findAttribute(parser, u"format"); if (maybeFormat) { typeMask = parseFormatAttribute(maybeFormat.value()); if (typeMask == 0) { @@ -735,18 +711,6 @@ bool ResourceParser::parseAttrImpl(XmlPullParser* parser, ParsedResource* outRes } } - // If this is a declaration, the package name may be in the name. Separate these out. - // Eg. - // No format attribute is allowed. - if (weak && !maybeFormat) { - StringPiece16 package, type, name; - ResourceUtils::extractResourceName(outResource->name.entry, &package, &type, &name); - if (type.empty() && !package.empty()) { - outResource->name.package = package.toString(); - outResource->name.entry = name.toString(); - } - } - struct SymbolComparator { bool operator()(const Attribute::Symbol& a, const Attribute::Symbol& b) { return a.symbol.name.value() < b.symbol.name.value(); @@ -758,11 +722,11 @@ bool ResourceParser::parseAttrImpl(XmlPullParser* parser, ParsedResource* outRes std::u16string comment; bool error = false; const size_t depth = parser->getDepth(); - while (XmlPullParser::nextChildNode(parser, depth)) { - if (parser->getEvent() == XmlPullParser::Event::kComment) { + while (xml::XmlPullParser::nextChildNode(parser, depth)) { + if (parser->getEvent() == xml::XmlPullParser::Event::kComment) { comment = util::trimWhitespace(parser->getComment()).toString(); continue; - } else if (parser->getEvent() != XmlPullParser::Event::kStartElement) { + } else if (parser->getEvent() != xml::XmlPullParser::Event::kStartElement) { // Skip text. continue; } @@ -834,17 +798,17 @@ bool ResourceParser::parseAttrImpl(XmlPullParser* parser, ParsedResource* outRes return true; } -Maybe ResourceParser::parseEnumOrFlagItem(XmlPullParser* parser, +Maybe ResourceParser::parseEnumOrFlagItem(xml::XmlPullParser* parser, const StringPiece16& tag) { const Source source = mSource.withLine(parser->getLineNumber()); - Maybe maybeName = findNonEmptyAttribute(parser, u"name"); + Maybe maybeName = xml::findNonEmptyAttribute(parser, u"name"); if (!maybeName) { mDiag->error(DiagMessage(source) << "no attribute 'name' found for tag <" << tag << ">"); return {}; } - Maybe maybeValue = findNonEmptyAttribute(parser, u"value"); + Maybe maybeValue = xml::findNonEmptyAttribute(parser, u"value"); if (!maybeValue) { mDiag->error(DiagMessage(source) << "no attribute 'value' found for tag <" << tag << ">"); return {}; @@ -863,12 +827,19 @@ Maybe ResourceParser::parseEnumOrFlagItem(XmlPullParser* pars val.data }; } -static Maybe parseXmlAttributeName(StringPiece16 str) { +static Maybe parseXmlAttributeName(StringPiece16 str) { str = util::trimWhitespace(str); - const char16_t* const start = str.data(); + const char16_t* start = str.data(); const char16_t* const end = start + str.size(); const char16_t* p = start; + Reference ref; + if (p != end && *p == u'*') { + ref.privateReference = true; + start++; + p++; + } + StringPiece16 package; StringPiece16 name; while (p != end) { @@ -880,28 +851,27 @@ static Maybe parseXmlAttributeName(StringPiece16 str) { p++; } - return ResourceName(package.toString(), ResourceType::kAttr, + ref.name = ResourceName(package.toString(), ResourceType::kAttr, name.empty() ? str.toString() : name.toString()); + return Maybe(std::move(ref)); } -bool ResourceParser::parseStyleItem(XmlPullParser* parser, Style* style) { +bool ResourceParser::parseStyleItem(xml::XmlPullParser* parser, Style* style) { const Source source = mSource.withLine(parser->getLineNumber()); - Maybe maybeName = findNonEmptyAttribute(parser, u"name"); + Maybe maybeName = xml::findNonEmptyAttribute(parser, u"name"); if (!maybeName) { mDiag->error(DiagMessage(source) << " must have a 'name' attribute"); return false; } - Maybe maybeKey = parseXmlAttributeName(maybeName.value()); + Maybe maybeKey = parseXmlAttributeName(maybeName.value()); if (!maybeKey) { mDiag->error(DiagMessage(source) << "invalid attribute name '" << maybeName.value() << "'"); return false; } - if (Maybe transformedName = parser->transformPackage(maybeKey.value(), u"")) { - maybeKey = std::move(transformedName); - } + transformReferenceFromNamespace(parser, u"", &maybeKey.value()); std::unique_ptr value = parseXml(parser, 0, kAllowRawString); if (!value) { @@ -909,15 +879,15 @@ bool ResourceParser::parseStyleItem(XmlPullParser* parser, Style* style) { return false; } - style->entries.push_back(Style::Entry{ Reference(maybeKey.value()), std::move(value) }); + style->entries.push_back(Style::Entry{ std::move(maybeKey.value()), std::move(value) }); return true; } -bool ResourceParser::parseStyle(XmlPullParser* parser, ParsedResource* outResource) { +bool ResourceParser::parseStyle(xml::XmlPullParser* parser, ParsedResource* outResource) { const Source source = mSource.withLine(parser->getLineNumber()); std::unique_ptr