summaryrefslogtreecommitdiff
path: root/tools/aapt2/ResourceParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/aapt2/ResourceParser.cpp')
-rw-r--r--tools/aapt2/ResourceParser.cpp306
1 files changed, 190 insertions, 116 deletions
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 5e5fc5338e29..63629f0d6c10 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -49,8 +49,9 @@ static Maybe<StringPiece16> findNonEmptyAttribute(XmlPullParser* parser,
}
ResourceParser::ResourceParser(IDiagnostics* diag, ResourceTable* table, const Source& source,
- const ConfigDescription& config) :
- mDiag(diag), mTable(table), mSource(source), mConfig(config) {
+ const ConfigDescription& config,
+ const ResourceParserOptions& options) :
+ mDiag(diag), mTable(table), mSource(source), mConfig(config), mOptions(options) {
}
/**
@@ -157,7 +158,62 @@ bool ResourceParser::parse(XmlPullParser* parser) {
return !error;
}
+static bool shouldStripResource(XmlPullParser* parser, const Maybe<std::u16string> productToMatch) {
+ assert(parser->getEvent() == XmlPullParser::Event::kStartElement);
+
+ if (Maybe<StringPiece16> maybeProduct = 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.
+ return true;
+ }
+ } else {
+ if (productToMatch && maybeProduct.value() != productToMatch.value()) {
+ // We specified a product, but they don't match.
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/**
+ * A parsed resource ready to be added to the ResourceTable.
+ */
+struct ParsedResource {
+ ResourceName name;
+ Source source;
+ ResourceId id;
+ bool markPublic = false;
+ std::unique_ptr<Value> value;
+ std::list<ParsedResource> childResources;
+};
+
+// Recursively adds resources to the ResourceTable.
+static bool addResourcesToTable(ResourceTable* table, const ConfigDescription& config,
+ IDiagnostics* diag, ParsedResource* res) {
+ if (res->markPublic && !table->markPublic(res->name, res->id, res->source, diag)) {
+ return false;
+ }
+
+ if (!res->value) {
+ return true;
+ }
+
+ if (!table->addResource(res->name, res->id, config, res->source, std::move(res->value), diag)) {
+ return false;
+ }
+
+ bool error = false;
+ for (ParsedResource& child : res->childResources) {
+ error |= !addResourcesToTable(table, config, diag, &child);
+ }
+ return !error;
+}
+
bool ResourceParser::parseResources(XmlPullParser* parser) {
+ std::set<ResourceName> strippedResources;
+
bool error = false;
std::u16string comment;
const size_t depth = parser->getDepth();
@@ -198,9 +254,8 @@ bool ResourceParser::parseResources(XmlPullParser* parser) {
continue;
}
- // Copy because our iterator will go out of scope when
- // we parse more XML.
- std::u16string name = maybeName.value().toString();
+ // Check if we should skip this product.
+ const bool stripResource = shouldStripResource(parser, mOptions.product);
if (elementName == u"item") {
// Items simply have their type encoded in the type attribute.
@@ -214,48 +269,85 @@ bool ResourceParser::parseResources(XmlPullParser* parser) {
}
}
- if (elementName == u"id") {
- error |= !mTable->addResource(ResourceNameRef{ {}, ResourceType::kId, name },
- {}, mSource.withLine(parser->getLineNumber()),
- util::make_unique<Id>(), mDiag);
+ ParsedResource parsedResource;
+ parsedResource.name.entry = maybeName.value().toString();
+ parsedResource.source = mSource.withLine(parser->getLineNumber());
+ bool result = true;
+ if (elementName == u"id") {
+ parsedResource.name.type = ResourceType::kId;
+ parsedResource.value = util::make_unique<Id>();
} else if (elementName == u"string") {
- error |= !parseString(parser, ResourceNameRef{ {}, ResourceType::kString, name });
+ parsedResource.name.type = ResourceType::kString;
+ result = parseString(parser, &parsedResource);
} else if (elementName == u"color") {
- error |= !parseColor(parser, ResourceNameRef{ {}, ResourceType::kColor, name });
+ parsedResource.name.type = ResourceType::kColor;
+ result = parseColor(parser, &parsedResource);
} else if (elementName == u"drawable") {
- error |= !parseColor(parser, ResourceNameRef{ {}, ResourceType::kDrawable, name });
+ parsedResource.name.type = ResourceType::kDrawable;
+ result = parseColor(parser, &parsedResource);
} else if (elementName == u"bool") {
- error |= !parsePrimitive(parser, ResourceNameRef{ {}, ResourceType::kBool, name });
+ parsedResource.name.type = ResourceType::kBool;
+ result = parsePrimitive(parser, &parsedResource);
} else if (elementName == u"integer") {
- error |= !parsePrimitive(parser, ResourceNameRef{ {}, ResourceType::kInteger, name });
+ parsedResource.name.type = ResourceType::kInteger;
+ result = parsePrimitive(parser, &parsedResource);
} else if (elementName == u"dimen") {
- error |= !parsePrimitive(parser, ResourceNameRef{ {}, ResourceType::kDimen, name });
+ parsedResource.name.type = ResourceType::kDimen;
+ result = parsePrimitive(parser, &parsedResource);
} else if (elementName == u"style") {
- error |= !parseStyle(parser, ResourceNameRef{ {}, ResourceType::kStyle, name });
+ parsedResource.name.type = ResourceType::kStyle;
+ result = parseStyle(parser, &parsedResource);
} else if (elementName == u"plurals") {
- error |= !parsePlural(parser, ResourceNameRef{ {}, ResourceType::kPlurals, name });
+ parsedResource.name.type = ResourceType::kPlurals;
+ result = parsePlural(parser, &parsedResource);
} else if (elementName == u"array") {
- error |= !parseArray(parser, ResourceNameRef{ {}, ResourceType::kArray, name },
- android::ResTable_map::TYPE_ANY);
+ parsedResource.name.type = ResourceType::kArray;
+ result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_ANY);
} else if (elementName == u"string-array") {
- error |= !parseArray(parser, ResourceNameRef{ {}, ResourceType::kArray, name },
- android::ResTable_map::TYPE_STRING);
+ parsedResource.name.type = ResourceType::kArray;
+ result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_STRING);
} else if (elementName == u"integer-array") {
- error |= !parseArray(parser, ResourceNameRef{ {}, ResourceType::kArray, name },
- android::ResTable_map::TYPE_INTEGER);
- } else if (elementName == u"public") {
- error |= !parsePublic(parser, name);
+ parsedResource.name.type = ResourceType::kIntegerArray;
+ result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_INTEGER);
} else if (elementName == u"declare-styleable") {
- error |= !parseDeclareStyleable(parser,
- ResourceNameRef{ {}, ResourceType::kStyleable, name });
+ parsedResource.name.type = ResourceType::kStyleable;
+ result = parseDeclareStyleable(parser, &parsedResource);
} else if (elementName == u"attr") {
- error |= !parseAttr(parser, ResourceNameRef{ {}, ResourceType::kAttr, name });
+ parsedResource.name.type = ResourceType::kAttr;
+ result = parseAttr(parser, &parsedResource);
+ } else if (elementName == u"public") {
+ result = parsePublic(parser, &parsedResource);
} else {
mDiag->warn(DiagMessage(mSource.withLine(parser->getLineNumber()))
<< "unknown resource type '" << elementName << "'");
}
+
+ if (result) {
+ // We successfully parsed the resource.
+
+ if (stripResource) {
+ // Record that we stripped out this resource name.
+ // We will check that at least one variant of this resource was included.
+ strippedResources.insert(parsedResource.name);
+ } else {
+ error |= !addResourcesToTable(mTable, mConfig, mDiag, &parsedResource);
+ }
+ } else {
+ error = true;
+ }
}
+
+ // Check that we included at least one variant of each stripped resource.
+ for (const ResourceName& strippedResource : strippedResources) {
+ if (!mTable->findResource(strippedResource)) {
+ // Failed to find the resource.
+ mDiag->error(DiagMessage(mSource) << "resource '" << strippedResource << "' "
+ "was filtered out but no product variant remains");
+ error = true;
+ }
+ }
+
return !error;
}
@@ -322,53 +414,43 @@ std::unique_ptr<Item> ResourceParser::parseXml(XmlPullParser* parser, uint32_t t
return {};
}
-bool ResourceParser::parseString(XmlPullParser* parser, const ResourceNameRef& resourceName) {
+bool ResourceParser::parseString(XmlPullParser* parser, ParsedResource* outResource) {
const Source source = mSource.withLine(parser->getLineNumber());
// TODO(adamlesinski): Read "untranslateable" attribute.
- if (Maybe<StringPiece16> maybeProduct = findAttribute(parser, u"product")) {
- if (maybeProduct.value() != u"default" && maybeProduct.value() != u"phone") {
- // TODO(adamlesinski): Actually match product.
- return true;
- }
- }
-
- std::unique_ptr<Item> processedItem = parseXml(parser, android::ResTable_map::TYPE_STRING,
- kNoRawString);
- if (!processedItem) {
+ outResource->value = parseXml(parser, android::ResTable_map::TYPE_STRING, kNoRawString);
+ if (!outResource->value) {
mDiag->error(DiagMessage(source) << "not a valid string");
return false;
}
- return mTable->addResource(resourceName, mConfig, source, std::move(processedItem),
- mDiag);
+ return true;
}
-bool ResourceParser::parseColor(XmlPullParser* parser, const ResourceNameRef& resourceName) {
+bool ResourceParser::parseColor(XmlPullParser* parser, ParsedResource* outResource) {
const Source source = mSource.withLine(parser->getLineNumber());
- std::unique_ptr<Item> item = parseXml(parser, android::ResTable_map::TYPE_COLOR, kNoRawString);
- if (!item) {
+ outResource->value = parseXml(parser, android::ResTable_map::TYPE_COLOR, kNoRawString);
+ if (!outResource->value) {
mDiag->error(DiagMessage(source) << "invalid color");
return false;
}
- return mTable->addResource(resourceName, mConfig, source, std::move(item),
- mDiag);
+ return true;
}
-bool ResourceParser::parsePrimitive(XmlPullParser* parser, const ResourceNameRef& resourceName) {
+bool ResourceParser::parsePrimitive(XmlPullParser* parser, ParsedResource* outResource) {
const Source source = mSource.withLine(parser->getLineNumber());
uint32_t typeMask = 0;
- switch (resourceName.type) {
+ switch (outResource->name.type) {
case ResourceType::kInteger:
typeMask |= android::ResTable_map::TYPE_INTEGER;
break;
case ResourceType::kDimen:
typeMask |= android::ResTable_map::TYPE_DIMENSION
- | android::ResTable_map::TYPE_FLOAT
- | android::ResTable_map::TYPE_FRACTION;
+ | android::ResTable_map::TYPE_FLOAT
+ | android::ResTable_map::TYPE_FRACTION;
break;
case ResourceType::kBool:
@@ -380,16 +462,15 @@ bool ResourceParser::parsePrimitive(XmlPullParser* parser, const ResourceNameRef
break;
}
- std::unique_ptr<Item> item = parseXml(parser, typeMask, kNoRawString);
- if (!item) {
- mDiag->error(DiagMessage(source) << "invalid " << resourceName.type);
+ outResource->value = parseXml(parser, typeMask, kNoRawString);
+ if (!outResource->value) {
+ mDiag->error(DiagMessage(source) << "invalid " << outResource->name.type);
return false;
}
- return mTable->addResource(resourceName, mConfig, source, std::move(item),
- mDiag);
+ return true;
}
-bool ResourceParser::parsePublic(XmlPullParser* parser, const StringPiece16& name) {
+bool ResourceParser::parsePublic(XmlPullParser* parser, ParsedResource* outResource) {
const Source source = mSource.withLine(parser->getLineNumber());
Maybe<StringPiece16> maybeType = findNonEmptyAttribute(parser, u"type");
@@ -405,27 +486,28 @@ bool ResourceParser::parsePublic(XmlPullParser* parser, const StringPiece16& nam
return false;
}
- ResourceNameRef resourceName { {}, *parsedType, name };
- ResourceId resourceId;
+ outResource->name.type = *parsedType;
if (Maybe<StringPiece16> maybeId = findNonEmptyAttribute(parser, u"id")) {
android::Res_value val;
bool result = android::ResTable::stringToInt(maybeId.value().data(),
maybeId.value().size(), &val);
- resourceId.id = val.data;
+ ResourceId resourceId(val.data);
if (!result || !resourceId.isValid()) {
mDiag->error(DiagMessage(source) << "invalid resource ID '" << maybeId.value()
<< "' in <public>");
return false;
}
+ outResource->id = resourceId;
}
if (*parsedType == ResourceType::kId) {
// An ID marked as public is also the definition of an ID.
- mTable->addResource(resourceName, {}, source, util::make_unique<Id>(),
- mDiag);
+ outResource->value = util::make_unique<Id>();
}
- return mTable->markPublic(resourceName, resourceId, source, mDiag);
+
+ outResource->markPublic = true;
+ return true;
}
static uint32_t parseFormatType(const StringPiece16& piece) {
@@ -455,20 +537,13 @@ static uint32_t parseFormatAttribute(const StringPiece16& str) {
return mask;
}
-bool ResourceParser::parseAttr(XmlPullParser* parser, const ResourceNameRef& resourceName) {
- const Source source = mSource.withLine(parser->getLineNumber());
- ResourceName actualName = resourceName.toResourceName();
- std::unique_ptr<Attribute> attr = parseAttrImpl(parser, &actualName, false);
- if (!attr) {
- return false;
- }
- return mTable->addResource(actualName, mConfig, source, std::move(attr),
- mDiag);
+
+bool ResourceParser::parseAttr(XmlPullParser* parser, ParsedResource* outResource) {
+ outResource->source = mSource.withLine(parser->getLineNumber());
+ return parseAttrImpl(parser, outResource, false);
}
-std::unique_ptr<Attribute> ResourceParser::parseAttrImpl(XmlPullParser* parser,
- ResourceName* resourceName,
- bool weak) {
+bool ResourceParser::parseAttrImpl(XmlPullParser* parser, ParsedResource* outResource, bool weak) {
uint32_t typeMask = 0;
Maybe<StringPiece16> maybeFormat = findAttribute(parser, u"format");
@@ -477,7 +552,7 @@ std::unique_ptr<Attribute> ResourceParser::parseAttrImpl(XmlPullParser* parser,
if (typeMask == 0) {
mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber()))
<< "invalid attribute format '" << maybeFormat.value() << "'");
- return {};
+ return false;
}
}
@@ -486,10 +561,10 @@ std::unique_ptr<Attribute> ResourceParser::parseAttrImpl(XmlPullParser* parser,
// No format attribute is allowed.
if (weak && !maybeFormat) {
StringPiece16 package, type, name;
- ResourceUtils::extractResourceName(resourceName->entry, &package, &type, &name);
+ ResourceUtils::extractResourceName(outResource->name.entry, &package, &type, &name);
if (type.empty() && !package.empty()) {
- resourceName->package = package.toString();
- resourceName->entry = name.toString();
+ outResource->name.package = package.toString();
+ outResource->name.entry = name.toString();
}
}
@@ -526,14 +601,12 @@ std::unique_ptr<Attribute> ResourceParser::parseAttrImpl(XmlPullParser* parser,
}
if (Maybe<Attribute::Symbol> s = parseEnumOrFlagItem(parser, elementName)) {
- if (mTable->addResource(s.value().symbol.name.value(), mConfig,
- mSource.withLine(parser->getLineNumber()),
- util::make_unique<Id>(),
- mDiag)) {
- items.push_back(std::move(s.value()));
- } else {
- error = true;
- }
+ ParsedResource childResource;
+ childResource.name = s.value().symbol.name.value();
+ childResource.source = mSource.withLine(parser->getLineNumber());
+ childResource.value = util::make_unique<Id>();
+ outResource->childResources.push_back(std::move(childResource));
+ items.push_back(std::move(s.value()));
} else {
error = true;
}
@@ -548,13 +621,14 @@ std::unique_ptr<Attribute> ResourceParser::parseAttrImpl(XmlPullParser* parser,
}
if (error) {
- return {};
+ return false;
}
std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(weak);
attr->symbols.swap(items);
attr->typeMask = typeMask ? typeMask : uint32_t(android::ResTable_map::TYPE_ANY);
- return attr;
+ outResource->value = std::move(attr);
+ return true;
}
Maybe<Attribute::Symbol> ResourceParser::parseEnumOrFlagItem(XmlPullParser* parser,
@@ -582,8 +656,8 @@ Maybe<Attribute::Symbol> ResourceParser::parseEnumOrFlagItem(XmlPullParser* pars
}
return Attribute::Symbol{
- Reference(ResourceName{ {}, ResourceType::kId, maybeName.value().toString() }),
- val.data };
+ Reference(ResourceName{ {}, ResourceType::kId, maybeName.value().toString() }),
+ val.data };
}
static Maybe<ResourceName> parseXmlAttributeName(StringPiece16 str) {
@@ -604,7 +678,7 @@ static Maybe<ResourceName> parseXmlAttributeName(StringPiece16 str) {
}
return ResourceName{ package.toString(), ResourceType::kAttr,
- name.empty() ? str.toString() : name.toString() };
+ name.empty() ? str.toString() : name.toString() };
}
@@ -637,7 +711,7 @@ bool ResourceParser::parseStyleItem(XmlPullParser* parser, Style* style) {
return true;
}
-bool ResourceParser::parseStyle(XmlPullParser* parser, const ResourceNameRef& resourceName) {
+bool ResourceParser::parseStyle(XmlPullParser* parser, ParsedResource* outResource) {
const Source source = mSource.withLine(parser->getLineNumber());
std::unique_ptr<Style> style = util::make_unique<Style>();
@@ -660,12 +734,12 @@ bool ResourceParser::parseStyle(XmlPullParser* parser, const ResourceNameRef& re
} else {
// No parent was specified, so try inferring it from the style name.
- std::u16string styleName = resourceName.entry.toString();
+ std::u16string styleName = outResource->name.entry;
size_t pos = styleName.find_last_of(u'.');
if (pos != std::string::npos) {
style->parentInferred = true;
- style->parent = Reference(ResourceName{
- {}, ResourceType::kStyle, styleName.substr(0, pos) });
+ style->parent = Reference(
+ ResourceName({}, ResourceType::kStyle, styleName.substr(0, pos)));
}
}
@@ -697,11 +771,12 @@ bool ResourceParser::parseStyle(XmlPullParser* parser, const ResourceNameRef& re
if (error) {
return false;
}
- return mTable->addResource(resourceName, mConfig, source, std::move(style),
- mDiag);
+
+ outResource->value = std::move(style);
+ return true;
}
-bool ResourceParser::parseArray(XmlPullParser* parser, const ResourceNameRef& resourceName,
+bool ResourceParser::parseArray(XmlPullParser* parser, ParsedResource* outResource,
uint32_t typeMask) {
const Source source = mSource.withLine(parser->getLineNumber());
std::unique_ptr<Array> array = util::make_unique<Array>();
@@ -741,11 +816,12 @@ bool ResourceParser::parseArray(XmlPullParser* parser, const ResourceNameRef& re
if (error) {
return false;
}
- return mTable->addResource(resourceName, mConfig, source, std::move(array),
- mDiag);
+
+ outResource->value = std::move(array);
+ return true;
}
-bool ResourceParser::parsePlural(XmlPullParser* parser, const ResourceNameRef& resourceName) {
+bool ResourceParser::parsePlural(XmlPullParser* parser, ParsedResource* outResource) {
const Source source = mSource.withLine(parser->getLineNumber());
std::unique_ptr<Plural> plural = util::make_unique<Plural>();
@@ -816,11 +892,12 @@ bool ResourceParser::parsePlural(XmlPullParser* parser, const ResourceNameRef& r
if (error) {
return false;
}
- return mTable->addResource(resourceName, mConfig, source, std::move(plural), mDiag);
+
+ outResource->value = std::move(plural);
+ return true;
}
-bool ResourceParser::parseDeclareStyleable(XmlPullParser* parser,
- const ResourceNameRef& resourceName) {
+bool ResourceParser::parseDeclareStyleable(XmlPullParser* parser, ParsedResource* outResource) {
const Source source = mSource.withLine(parser->getLineNumber());
std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
@@ -844,22 +921,17 @@ bool ResourceParser::parseDeclareStyleable(XmlPullParser* parser,
continue;
}
- // Copy because our iterator will be invalidated.
- ResourceName attrResourceName = { {}, ResourceType::kAttr, attrIter->value };
+ ParsedResource childResource;
+ childResource.name = ResourceName({}, ResourceType::kAttr, attrIter->value);
+ childResource.source = mSource.withLine(parser->getLineNumber());
- std::unique_ptr<Attribute> attr = parseAttrImpl(parser, &attrResourceName, true);
- if (!attr) {
+ if (!parseAttrImpl(parser, &childResource, true)) {
error = true;
continue;
}
- styleable->entries.emplace_back(attrResourceName);
-
- // Add the attribute to the resource table. Since it is weakly defined,
- // it won't collide.
- error |= !mTable->addResource(attrResourceName, mConfig,
- mSource.withLine(parser->getLineNumber()),
- std::move(attr), mDiag);
+ styleable->entries.push_back(Reference(childResource.name));
+ outResource->childResources.push_back(std::move(childResource));
} else if (elementNamespace.empty() &&
(elementName == u"skip" || elementName == u"eat-comment")) {
@@ -875,7 +947,9 @@ bool ResourceParser::parseDeclareStyleable(XmlPullParser* parser,
if (error) {
return false;
}
- return mTable->addResource(resourceName, mConfig, source, std::move(styleable), mDiag);
+
+ outResource->value = std::move(styleable);
+ return true;
}
} // namespace aapt