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.cpp500
1 files changed, 342 insertions, 158 deletions
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 1c3ac2ad4f17..1b6f8827291b 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -17,6 +17,7 @@
#include "ResourceParser.h"
#include <functional>
+#include <limits>
#include <sstream>
#include "android-base/logging.h"
@@ -25,12 +26,15 @@
#include "ResourceUtils.h"
#include "ResourceValues.h"
#include "ValueVisitor.h"
+#include "text/Utf8Iterator.h"
#include "util/ImmutableMap.h"
#include "util/Maybe.h"
#include "util/Util.h"
#include "xml/XmlPullParser.h"
-using android::StringPiece;
+using ::aapt::ResourceUtils::StringBuilder;
+using ::aapt::text::Utf8Iterator;
+using ::android::StringPiece;
namespace aapt {
@@ -90,9 +94,12 @@ struct ParsedResource {
ConfigDescription config;
std::string product;
Source source;
+
ResourceId id;
- Maybe<SymbolState> symbol_state;
+ Visibility::Level visibility_level = Visibility::Level::kUndefined;
bool allow_new = false;
+ bool overlayable = false;
+
std::string comment;
std::unique_ptr<Value> value;
std::list<ParsedResource> child_resources;
@@ -106,24 +113,41 @@ static bool AddResourcesToTable(ResourceTable* table, IDiagnostics* diag, Parsed
res->comment = trimmed_comment.to_string();
}
- if (res->symbol_state) {
- Symbol symbol;
- symbol.state = res->symbol_state.value();
- symbol.source = res->source;
- symbol.comment = res->comment;
- symbol.allow_new = res->allow_new;
- if (!table->SetSymbolState(res->name, res->id, symbol, diag)) {
+ if (res->visibility_level != Visibility::Level::kUndefined) {
+ Visibility visibility;
+ visibility.level = res->visibility_level;
+ visibility.source = res->source;
+ visibility.comment = res->comment;
+ if (!table->SetVisibilityWithId(res->name, visibility, res->id, diag)) {
+ return false;
+ }
+ }
+
+ if (res->allow_new) {
+ AllowNew allow_new;
+ allow_new.source = res->source;
+ allow_new.comment = res->comment;
+ if (!table->SetAllowNew(res->name, allow_new, diag)) {
+ return false;
+ }
+ }
+
+ if (res->overlayable) {
+ Overlayable overlayable;
+ overlayable.source = res->source;
+ overlayable.comment = res->comment;
+ if (!table->SetOverlayable(res->name, overlayable, diag)) {
return false;
}
}
- if (res->value) {
+ if (res->value != nullptr) {
// Attach the comment, source and config to the value.
res->value->SetComment(std::move(res->comment));
res->value->SetSource(std::move(res->source));
- if (!table->AddResource(res->name, res->id, res->config, res->product, std::move(res->value),
- diag)) {
+ if (!table->AddResourceWithId(res->name, res->id, res->config, res->product,
+ std::move(res->value), diag)) {
return false;
}
}
@@ -148,114 +172,212 @@ ResourceParser::ResourceParser(IDiagnostics* diag, ResourceTable* table,
config_(config),
options_(options) {}
-/**
- * Build a string from XML that converts nested elements into Span objects.
- */
+// Base class Node for representing the various Spans and UntranslatableSections of an XML string.
+// This will be used to traverse and flatten the XML string into a single std::string, with all
+// Span and Untranslatable data maintained in parallel, as indices into the string.
+class Node {
+ public:
+ virtual ~Node() = default;
+
+ // Adds the given child node to this parent node's set of child nodes, moving ownership to the
+ // parent node as well.
+ // Returns a pointer to the child node that was added as a convenience.
+ template <typename T>
+ T* AddChild(std::unique_ptr<T> node) {
+ T* raw_ptr = node.get();
+ children.push_back(std::move(node));
+ return raw_ptr;
+ }
+
+ virtual void Build(StringBuilder* builder) const {
+ for (const auto& child : children) {
+ child->Build(builder);
+ }
+ }
+
+ std::vector<std::unique_ptr<Node>> children;
+};
+
+// A chunk of text in the XML string. This lives between other tags, such as XLIFF tags and Spans.
+class SegmentNode : public Node {
+ public:
+ std::string data;
+
+ void Build(StringBuilder* builder) const override {
+ builder->AppendText(data);
+ }
+};
+
+// A tag that will be encoded into the final flattened string. Tags like <b> or <i>.
+class SpanNode : public Node {
+ public:
+ std::string name;
+
+ void Build(StringBuilder* builder) const override {
+ StringBuilder::SpanHandle span_handle = builder->StartSpan(name);
+ Node::Build(builder);
+ builder->EndSpan(span_handle);
+ }
+};
+
+// An XLIFF 'g' tag, which marks a section of the string as untranslatable.
+class UntranslatableNode : public Node {
+ public:
+ void Build(StringBuilder* builder) const override {
+ StringBuilder::UntranslatableHandle handle = builder->StartUntranslatable();
+ Node::Build(builder);
+ builder->EndUntranslatable(handle);
+ }
+};
+
+// Build a string from XML that converts nested elements into Span objects.
bool ResourceParser::FlattenXmlSubtree(
xml::XmlPullParser* parser, std::string* out_raw_string, StyleString* out_style_string,
std::vector<UntranslatableSection>* out_untranslatable_sections) {
- // Keeps track of formatting tags (<b>, <i>) and the range of characters for which they apply.
- // The stack elements refer to the indices in out_style_string->spans.
- // By first adding to the out_style_string->spans vector, and then using the stack to refer
- // to this vector, the original order of tags is preserved in cases such as <b><i>hello</b></i>.
- std::vector<size_t> span_stack;
-
- // Clear the output variables.
- out_raw_string->clear();
- out_style_string->spans.clear();
- out_untranslatable_sections->clear();
-
- // The StringBuilder will concatenate the various segments of text which are initially
- // separated by tags. It also handles unicode escape codes and quotations.
- util::StringBuilder builder;
+ std::string raw_string;
+ std::string current_text;
// The first occurrence of a <xliff:g> tag. Nested <xliff:g> tags are illegal.
Maybe<size_t> untranslatable_start_depth;
+ Node root;
+ std::vector<Node*> node_stack;
+ node_stack.push_back(&root);
+
+ bool saw_span_node = false;
+ SegmentNode* first_segment = nullptr;
+ SegmentNode* last_segment = nullptr;
+
size_t depth = 1;
- while (xml::XmlPullParser::IsGoodEvent(parser->Next())) {
+ while (depth > 0 && xml::XmlPullParser::IsGoodEvent(parser->Next())) {
const xml::XmlPullParser::Event event = parser->event();
- if (event == xml::XmlPullParser::Event::kStartElement) {
- if (parser->element_namespace().empty()) {
- // This is an HTML tag which we encode as a span. Add it to the span stack.
- std::string span_name = parser->element_name();
- const auto end_attr_iter = parser->end_attributes();
- for (auto attr_iter = parser->begin_attributes(); attr_iter != end_attr_iter; ++attr_iter) {
- span_name += ";";
- span_name += attr_iter->name;
- span_name += "=";
- span_name += attr_iter->value;
+ // First take care of any SegmentNodes that should be created.
+ if (event == xml::XmlPullParser::Event::kStartElement ||
+ event == xml::XmlPullParser::Event::kEndElement) {
+ if (!current_text.empty()) {
+ std::unique_ptr<SegmentNode> segment_node = util::make_unique<SegmentNode>();
+ segment_node->data = std::move(current_text);
+ last_segment = node_stack.back()->AddChild(std::move(segment_node));
+ if (first_segment == nullptr) {
+ first_segment = last_segment;
}
+ current_text = {};
+ }
+ }
- // Make sure the string is representable in our binary format.
- if (builder.Utf16Len() > std::numeric_limits<uint32_t>::max()) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
- << "style string '" << builder.ToString() << "' is too long");
- return false;
- }
+ switch (event) {
+ case xml::XmlPullParser::Event::kText: {
+ current_text += parser->text();
+ raw_string += parser->text();
+ } break;
+
+ case xml::XmlPullParser::Event::kStartElement: {
+ if (parser->element_namespace().empty()) {
+ // This is an HTML tag which we encode as a span. Add it to the span stack.
+ std::unique_ptr<SpanNode> span_node = util::make_unique<SpanNode>();
+ span_node->name = parser->element_name();
+ const auto end_attr_iter = parser->end_attributes();
+ for (auto attr_iter = parser->begin_attributes(); attr_iter != end_attr_iter;
+ ++attr_iter) {
+ span_node->name += ";";
+ span_node->name += attr_iter->name;
+ span_node->name += "=";
+ span_node->name += attr_iter->value;
+ }
- out_style_string->spans.push_back(
- Span{std::move(span_name), static_cast<uint32_t>(builder.Utf16Len())});
- span_stack.push_back(out_style_string->spans.size() - 1);
- } else if (parser->element_namespace() == sXliffNamespaceUri) {
- if (parser->element_name() == "g") {
- if (untranslatable_start_depth) {
- // We've already encountered an <xliff:g> tag, and nested <xliff:g> tags are illegal.
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
- << "illegal nested XLIFF 'g' tag");
- return false;
+ node_stack.push_back(node_stack.back()->AddChild(std::move(span_node)));
+ saw_span_node = true;
+ } else if (parser->element_namespace() == sXliffNamespaceUri) {
+ // This is an XLIFF tag, which is not encoded as a span.
+ if (parser->element_name() == "g") {
+ // Check that an 'untranslatable' tag is not already being processed. Nested
+ // <xliff:g> tags are illegal.
+ if (untranslatable_start_depth) {
+ diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ << "illegal nested XLIFF 'g' tag");
+ return false;
+ } else {
+ // Mark the beginning of an 'untranslatable' section.
+ untranslatable_start_depth = depth;
+ node_stack.push_back(
+ node_stack.back()->AddChild(util::make_unique<UntranslatableNode>()));
+ }
} else {
- // Mark the start of an untranslatable section. Use UTF8 indices/lengths.
- untranslatable_start_depth = depth;
- const size_t current_idx = builder.ToString().size();
- out_untranslatable_sections->push_back(UntranslatableSection{current_idx, current_idx});
+ // Ignore unknown XLIFF tags, but don't warn.
+ node_stack.push_back(node_stack.back()->AddChild(util::make_unique<Node>()));
}
+ } else {
+ // Besides XLIFF, any other namespaced tag is unsupported and ignored.
+ diag_->Warn(DiagMessage(source_.WithLine(parser->line_number()))
+ << "ignoring element '" << parser->element_name()
+ << "' with unknown namespace '" << parser->element_namespace() << "'");
+ node_stack.push_back(node_stack.back()->AddChild(util::make_unique<Node>()));
}
- // Ignore other xliff tags, they get handled by other tools.
- } else {
- // Besides XLIFF, any other namespaced tag is unsupported and ignored.
- diag_->Warn(DiagMessage(source_.WithLine(parser->line_number()))
- << "ignoring element '" << parser->element_name()
- << "' with unknown namespace '" << parser->element_namespace() << "'");
- }
+ // Enter one level inside the element.
+ depth++;
+ } break;
+
+ case xml::XmlPullParser::Event::kEndElement: {
+ // Return one level from within the element.
+ depth--;
+ if (depth == 0) {
+ break;
+ }
+
+ node_stack.pop_back();
+ if (untranslatable_start_depth == make_value(depth)) {
+ // This is the end of an untranslatable section.
+ untranslatable_start_depth = {};
+ }
+ } break;
- // Enter one level inside the element.
- depth++;
- } else if (event == xml::XmlPullParser::Event::kText) {
- // Record both the raw text and append to the builder to deal with escape sequences
- // and quotations.
- out_raw_string->append(parser->text());
- builder.Append(parser->text());
- } else if (event == xml::XmlPullParser::Event::kEndElement) {
- // Return one level from within the element.
- depth--;
- if (depth == 0) {
+ default:
+ // ignore.
break;
+ }
+ }
+
+ // Sanity check to make sure we processed all the nodes.
+ CHECK(node_stack.size() == 1u);
+ CHECK(node_stack.back() == &root);
+
+ if (!saw_span_node) {
+ // If there were no spans, we must treat this string a little differently (according to AAPT).
+ // Find and strip the leading whitespace from the first segment, and the trailing whitespace
+ // from the last segment.
+ if (first_segment != nullptr) {
+ // Trim leading whitespace.
+ StringPiece trimmed = util::TrimLeadingWhitespace(first_segment->data);
+ if (trimmed.size() != first_segment->data.size()) {
+ first_segment->data = trimmed.to_string();
}
+ }
- if (parser->element_namespace().empty()) {
- // This is an HTML tag which we encode as a span. Update the span
- // stack and pop the top entry.
- Span& top_span = out_style_string->spans[span_stack.back()];
- top_span.last_char = builder.Utf16Len() - 1;
- span_stack.pop_back();
- } else if (untranslatable_start_depth == make_value(depth)) {
- // This is the end of an untranslatable section. Use UTF8 indices/lengths.
- UntranslatableSection& untranslatable_section = out_untranslatable_sections->back();
- untranslatable_section.end = builder.ToString().size();
- untranslatable_start_depth = {};
+ if (last_segment != nullptr) {
+ // Trim trailing whitespace.
+ StringPiece trimmed = util::TrimTrailingWhitespace(last_segment->data);
+ if (trimmed.size() != last_segment->data.size()) {
+ last_segment->data = trimmed.to_string();
}
- } else if (event == xml::XmlPullParser::Event::kComment) {
- // Ignore.
- } else {
- LOG(FATAL) << "unhandled XML event";
}
}
- CHECK(span_stack.empty()) << "spans haven't been fully processed";
- out_style_string->str = builder.ToString();
+ // Have the XML structure flatten itself into the StringBuilder. The StringBuilder will take
+ // care of recording the correctly adjusted Spans and UntranslatableSections.
+ StringBuilder builder;
+ root.Build(&builder);
+ if (!builder) {
+ diag_->Error(DiagMessage(source_.WithLine(parser->line_number())) << builder.GetError());
+ return false;
+ }
+
+ ResourceUtils::FlattenedXmlString flattened_string = builder.GetFlattenedString();
+ *out_raw_string = std::move(raw_string);
+ *out_untranslatable_sections = std::move(flattened_string.untranslatable_sections);
+ out_style_string->str = std::move(flattened_string.text);
+ out_style_string->spans = std::move(flattened_string.spans);
return true;
}
@@ -392,6 +514,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
{"declare-styleable", std::mem_fn(&ResourceParser::ParseDeclareStyleable)},
{"integer-array", std::mem_fn(&ResourceParser::ParseIntegerArray)},
{"java-symbol", std::mem_fn(&ResourceParser::ParseSymbol)},
+ {"overlayable", std::mem_fn(&ResourceParser::ParseOverlayable)},
{"plurals", std::mem_fn(&ResourceParser::ParsePlural)},
{"public", std::mem_fn(&ResourceParser::ParsePublic)},
{"public-group", std::mem_fn(&ResourceParser::ParsePublicGroup)},
@@ -498,7 +621,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
const auto bag_iter = elToBagMap.find(resource_type);
if (bag_iter != elToBagMap.end()) {
// Ensure we have a name (unless this is a <public-group>).
- if (resource_type != "public-group") {
+ if (resource_type != "public-group" && resource_type != "overlayable") {
if (!maybe_name) {
diag_->Error(DiagMessage(out_resource->source)
<< "<" << parser->element_name() << "> missing 'name' attribute");
@@ -600,12 +723,11 @@ std::unique_ptr<Item> ResourceParser::ParseXml(xml::XmlPullParser* parser,
// Process the raw value.
std::unique_ptr<Item> processed_item =
- ResourceUtils::TryParseItemForAttribute(raw_value, type_mask,
- on_create_reference);
+ ResourceUtils::TryParseItemForAttribute(raw_value, type_mask, on_create_reference);
if (processed_item) {
// Fix up the reference.
if (Reference* ref = ValueCast<Reference>(processed_item.get())) {
- TransformReferenceFromNamespace(parser, "", ref);
+ ResolvePackage(parser, ref);
}
return processed_item;
}
@@ -688,8 +810,12 @@ bool ResourceParser::ParseString(xml::XmlPullParser* parser,
return true;
}
-bool ResourceParser::ParsePublic(xml::XmlPullParser* parser,
- ParsedResource* out_resource) {
+bool ResourceParser::ParsePublic(xml::XmlPullParser* parser, ParsedResource* out_resource) {
+ if (out_resource->config != ConfigDescription::DefaultConfig()) {
+ diag_->Warn(DiagMessage(out_resource->source)
+ << "ignoring configuration '" << out_resource->config << "' for <public> tag");
+ }
+
Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");
if (!maybe_type) {
diag_->Error(DiagMessage(out_resource->source)
@@ -722,12 +848,17 @@ bool ResourceParser::ParsePublic(xml::XmlPullParser* parser,
out_resource->value = util::make_unique<Id>();
}
- out_resource->symbol_state = SymbolState::kPublic;
+ out_resource->visibility_level = Visibility::Level::kPublic;
return true;
}
-bool ResourceParser::ParsePublicGroup(xml::XmlPullParser* parser,
- ParsedResource* out_resource) {
+bool ResourceParser::ParsePublicGroup(xml::XmlPullParser* parser, ParsedResource* out_resource) {
+ if (out_resource->config != ConfigDescription::DefaultConfig()) {
+ diag_->Warn(DiagMessage(out_resource->source)
+ << "ignoring configuration '" << out_resource->config
+ << "' for <public-group> tag");
+ }
+
Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");
if (!maybe_type) {
diag_->Error(DiagMessage(out_resource->source)
@@ -807,7 +938,7 @@ bool ResourceParser::ParsePublicGroup(xml::XmlPullParser* parser,
child_resource.id = next_id;
child_resource.comment = std::move(comment);
child_resource.source = item_source;
- child_resource.symbol_state = SymbolState::kPublic;
+ child_resource.visibility_level = Visibility::Level::kPublic;
out_resource->child_resources.push_back(std::move(child_resource));
next_id.id += 1;
@@ -842,19 +973,92 @@ bool ResourceParser::ParseSymbolImpl(xml::XmlPullParser* parser,
return true;
}
-bool ResourceParser::ParseSymbol(xml::XmlPullParser* parser,
- ParsedResource* out_resource) {
- if (ParseSymbolImpl(parser, out_resource)) {
- out_resource->symbol_state = SymbolState::kPrivate;
- return true;
+bool ResourceParser::ParseSymbol(xml::XmlPullParser* parser, ParsedResource* out_resource) {
+ if (out_resource->config != ConfigDescription::DefaultConfig()) {
+ diag_->Warn(DiagMessage(out_resource->source)
+ << "ignoring configuration '" << out_resource->config << "' for <"
+ << parser->element_name() << "> tag");
}
- return false;
+
+ if (!ParseSymbolImpl(parser, out_resource)) {
+ return false;
+ }
+
+ out_resource->visibility_level = Visibility::Level::kPrivate;
+ return true;
+}
+
+bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource* out_resource) {
+ if (out_resource->config != ConfigDescription::DefaultConfig()) {
+ diag_->Warn(DiagMessage(out_resource->source)
+ << "ignoring configuration '" << out_resource->config << "' for <overlayable> tag");
+ }
+
+ if (Maybe<StringPiece> maybe_policy = xml::FindNonEmptyAttribute(parser, "policy")) {
+ const StringPiece& policy = maybe_policy.value();
+ if (policy != "system") {
+ diag_->Error(DiagMessage(out_resource->source)
+ << "<overlayable> has invalid policy '" << policy << "'");
+ return false;
+ }
+ }
+
+ bool error = false;
+ const size_t depth = parser->depth();
+ while (xml::XmlPullParser::NextChildNode(parser, depth)) {
+ if (parser->event() != xml::XmlPullParser::Event::kStartElement) {
+ // Skip text/comments.
+ continue;
+ }
+
+ const Source item_source = source_.WithLine(parser->line_number());
+ const std::string& element_namespace = parser->element_namespace();
+ const std::string& element_name = parser->element_name();
+ if (element_namespace.empty() && element_name == "item") {
+ Maybe<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
+ if (!maybe_name) {
+ diag_->Error(DiagMessage(item_source)
+ << "<item> within an <overlayable> tag must have a 'name' attribute");
+ error = true;
+ continue;
+ }
+
+ Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");
+ if (!maybe_type) {
+ diag_->Error(DiagMessage(item_source)
+ << "<item> within an <overlayable> tag must have a 'type' attribute");
+ error = true;
+ continue;
+ }
+
+ const ResourceType* type = ParseResourceType(maybe_type.value());
+ if (type == nullptr) {
+ diag_->Error(DiagMessage(out_resource->source)
+ << "invalid resource type '" << maybe_type.value()
+ << "' in <item> within an <overlayable>");
+ error = true;
+ continue;
+ }
+
+ ParsedResource child_resource;
+ child_resource.name.type = *type;
+ child_resource.name.entry = maybe_name.value().to_string();
+ child_resource.source = item_source;
+ child_resource.overlayable = true;
+ out_resource->child_resources.push_back(std::move(child_resource));
+
+ xml::XmlPullParser::SkipCurrentElement(parser);
+ } else if (!ShouldIgnoreElement(element_namespace, element_name)) {
+ diag_->Error(DiagMessage(item_source) << ":" << element_name << ">");
+ error = true;
+ }
+ }
+ return !error;
}
-bool ResourceParser::ParseAddResource(xml::XmlPullParser* parser,
- ParsedResource* out_resource) {
+bool ResourceParser::ParseAddResource(xml::XmlPullParser* parser, ParsedResource* out_resource) {
if (ParseSymbolImpl(parser, out_resource)) {
- out_resource->symbol_state = SymbolState::kUndefined;
+ out_resource->visibility_level = Visibility::Level::kUndefined;
out_resource->allow_new = true;
return true;
}
@@ -885,8 +1089,7 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
type_mask = ParseFormatAttribute(maybe_format.value());
if (type_mask == 0) {
diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
- << "invalid attribute format '" << maybe_format.value()
- << "'");
+ << "invalid attribute format '" << maybe_format.value() << "'");
return false;
}
}
@@ -898,8 +1101,7 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
if (!min_str.empty()) {
std::u16string min_str16 = util::Utf8ToUtf16(min_str);
android::Res_value value;
- if (android::ResTable::stringToInt(min_str16.data(), min_str16.size(),
- &value)) {
+ if (android::ResTable::stringToInt(min_str16.data(), min_str16.size(), &value)) {
maybe_min = static_cast<int32_t>(value.data);
}
}
@@ -916,8 +1118,7 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
if (!max_str.empty()) {
std::u16string max_str16 = util::Utf8ToUtf16(max_str);
android::Res_value value;
- if (android::ResTable::stringToInt(max_str16.data(), max_str16.size(),
- &value)) {
+ if (android::ResTable::stringToInt(max_str16.data(), max_str16.size(), &value)) {
maybe_max = static_cast<int32_t>(value.data);
}
}
@@ -959,8 +1160,7 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
const Source item_source = source_.WithLine(parser->line_number());
const std::string& element_namespace = parser->element_namespace();
const std::string& element_name = parser->element_name();
- if (element_namespace.empty() &&
- (element_name == "flag" || element_name == "enum")) {
+ if (element_namespace.empty() && (element_name == "flag" || element_name == "enum")) {
if (element_name == "enum") {
if (type_mask & android::ResTable_map::TYPE_FLAGS) {
diag_->Error(DiagMessage(item_source)
@@ -1018,17 +1218,12 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
return false;
}
- std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(weak);
+ std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(
+ type_mask ? type_mask : uint32_t{android::ResTable_map::TYPE_ANY});
+ attr->SetWeak(weak);
attr->symbols = std::vector<Attribute::Symbol>(items.begin(), items.end());
- attr->type_mask =
- type_mask ? type_mask : uint32_t(android::ResTable_map::TYPE_ANY);
- if (maybe_min) {
- attr->min_int = maybe_min.value();
- }
-
- if (maybe_max) {
- attr->max_int = maybe_max.value();
- }
+ attr->min_int = maybe_min.value_or_default(std::numeric_limits<int32_t>::min());
+ attr->max_int = maybe_max.value_or_default(std::numeric_limits<int32_t>::max());
out_resource->value = std::move(attr);
return true;
}
@@ -1074,15 +1269,13 @@ bool ResourceParser::ParseStyleItem(xml::XmlPullParser* parser, Style* style) {
return false;
}
- Maybe<Reference> maybe_key =
- ResourceUtils::ParseXmlAttributeName(maybe_name.value());
+ Maybe<Reference> maybe_key = ResourceUtils::ParseXmlAttributeName(maybe_name.value());
if (!maybe_key) {
- diag_->Error(DiagMessage(source) << "invalid attribute name '"
- << maybe_name.value() << "'");
+ diag_->Error(DiagMessage(source) << "invalid attribute name '" << maybe_name.value() << "'");
return false;
}
- TransformReferenceFromNamespace(parser, "", &maybe_key.value());
+ ResolvePackage(parser, &maybe_key.value());
maybe_key.value().SetSource(source);
std::unique_ptr<Item> value = ParseXml(parser, 0, kAllowRawString);
@@ -1091,8 +1284,7 @@ bool ResourceParser::ParseStyleItem(xml::XmlPullParser* parser, Style* style) {
return false;
}
- style->entries.push_back(
- Style::Entry{std::move(maybe_key.value()), std::move(value)});
+ style->entries.push_back(Style::Entry{std::move(maybe_key.value()), std::move(value)});
return true;
}
@@ -1104,21 +1296,18 @@ bool ResourceParser::ParseStyle(const ResourceType type, xml::XmlPullParser* par
Maybe<StringPiece> maybe_parent = xml::FindAttribute(parser, "parent");
if (maybe_parent) {
- // If the parent is empty, we don't have a parent, but we also don't infer
- // either.
+ // If the parent is empty, we don't have a parent, but we also don't infer either.
if (!maybe_parent.value().empty()) {
std::string err_str;
- style->parent = ResourceUtils::ParseStyleParentReference(
- maybe_parent.value(), &err_str);
+ style->parent = ResourceUtils::ParseStyleParentReference(maybe_parent.value(), &err_str);
if (!style->parent) {
diag_->Error(DiagMessage(out_resource->source) << err_str);
return false;
}
- // Transform the namespace prefix to the actual package name, and mark the
- // reference as
+ // Transform the namespace prefix to the actual package name, and mark the reference as
// private if appropriate.
- TransformReferenceFromNamespace(parser, "", &style->parent.value());
+ ResolvePackage(parser, &style->parent.value());
}
} else {
@@ -1127,8 +1316,7 @@ bool ResourceParser::ParseStyle(const ResourceType type, xml::XmlPullParser* par
size_t pos = style_name.find_last_of(u'.');
if (pos != std::string::npos) {
style->parent_inferred = true;
- style->parent = Reference(
- ResourceName({}, ResourceType::kStyle, style_name.substr(0, pos)));
+ style->parent = Reference(ResourceName({}, ResourceType::kStyle, style_name.substr(0, pos)));
}
}
@@ -1321,9 +1509,8 @@ bool ResourceParser::ParseDeclareStyleable(xml::XmlPullParser* parser,
ParsedResource* out_resource) {
out_resource->name.type = ResourceType::kStyleable;
- // Declare-styleable is kPrivate by default, because it technically only
- // exists in R.java.
- out_resource->symbol_state = SymbolState::kPublic;
+ // Declare-styleable is kPrivate by default, because it technically only exists in R.java.
+ out_resource->visibility_level = Visibility::Level::kPublic;
// Declare-styleable only ends up in default config;
if (out_resource->config != ConfigDescription::DefaultConfig()) {
@@ -1351,11 +1538,9 @@ bool ResourceParser::ParseDeclareStyleable(xml::XmlPullParser* parser,
const std::string& element_namespace = parser->element_namespace();
const std::string& element_name = parser->element_name();
if (element_namespace.empty() && element_name == "attr") {
- Maybe<StringPiece> maybe_name =
- xml::FindNonEmptyAttribute(parser, "name");
+ Maybe<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
if (!maybe_name) {
- diag_->Error(DiagMessage(item_source)
- << "<attr> tag must have a 'name' attribute");
+ diag_->Error(DiagMessage(item_source) << "<attr> tag must have a 'name' attribute");
error = true;
continue;
}
@@ -1363,8 +1548,7 @@ bool ResourceParser::ParseDeclareStyleable(xml::XmlPullParser* parser,
// If this is a declaration, the package name may be in the name. Separate
// these out.
// Eg. <attr name="android:text" />
- Maybe<Reference> maybe_ref =
- ResourceUtils::ParseXmlAttributeName(maybe_name.value());
+ Maybe<Reference> maybe_ref = ResourceUtils::ParseXmlAttributeName(maybe_name.value());
if (!maybe_ref) {
diag_->Error(DiagMessage(item_source) << "<attr> tag has invalid name '"
<< maybe_name.value() << "'");
@@ -1373,7 +1557,7 @@ bool ResourceParser::ParseDeclareStyleable(xml::XmlPullParser* parser,
}
Reference& child_ref = maybe_ref.value();
- xml::TransformReferenceFromNamespace(parser, "", &child_ref);
+ xml::ResolvePackage(parser, &child_ref);
// Create the ParsedResource that will add the attribute to the table.
ParsedResource child_resource;