Add namespace handling in attribute values
Previously, you could only reference namespace prefixes in attribute names:
<View xmlns:appcompat="http://schemas.android.com/apk/res/android.support.v7.appcompat"
appcompat:name="hey"
...
Now you can also reference them in resource names within an attribute value:
...
android:text="@appcompat:string/confirm"
...
Which will be treated as "@android.support.v7.appcompat:string/confirm".
Change-Id: Ib076e867a990c80cf877a704eb77cd1ef0b23b52
diff --git a/tools/aapt2/BinaryXmlPullParser.cpp b/tools/aapt2/BinaryXmlPullParser.cpp
index 7a07c06..476a215 100644
--- a/tools/aapt2/BinaryXmlPullParser.cpp
+++ b/tools/aapt2/BinaryXmlPullParser.cpp
@@ -15,6 +15,8 @@
*/
#include "BinaryXmlPullParser.h"
+#include "Maybe.h"
+#include "Util.h"
#include <androidfw/ResourceTypes.h>
#include <memory>
@@ -77,12 +79,31 @@
mEvent = codeToEvent(code);
switch (mEvent) {
case Event::kStartNamespace:
- case Event::kEndNamespace:
+ case Event::kEndNamespace: {
data = mParser->getNamespacePrefix(&len);
- mStr1.assign(data, len);
+ if (data) {
+ mStr1.assign(data, len);
+ } else {
+ mStr1.clear();
+ }
data = mParser->getNamespaceUri(&len);
- mStr2.assign(data, len);
+ if (data) {
+ mStr2.assign(data, len);
+ } else {
+ mStr2.clear();
+ }
+
+ Maybe<std::u16string> result = util::extractPackageFromNamespace(mStr2);
+ if (result) {
+ if (mEvent == Event::kStartNamespace) {
+ mPackageAliases.emplace_back(mStr1, result.value());
+ } else {
+ assert(mPackageAliases.back().second == result.value());
+ mPackageAliases.pop_back();
+ }
+ }
break;
+ }
case Event::kStartElement:
copyAttributes();
@@ -90,14 +111,26 @@
case Event::kEndElement:
data = mParser->getElementNamespace(&len);
- mStr1.assign(data, len);
+ if (data) {
+ mStr1.assign(data, len);
+ } else {
+ mStr1.clear();
+ }
data = mParser->getElementName(&len);
- mStr2.assign(data, len);
+ if (data) {
+ mStr2.assign(data, len);
+ } else {
+ mStr2.clear();
+ }
break;
case Event::kText:
data = mParser->getText(&len);
- mStr1.assign(data, len);
+ if (data) {
+ mStr1.assign(data, len);
+ } else {
+ mStr1.clear();
+ }
break;
default:
@@ -155,6 +188,22 @@
return sEmpty;
}
+bool BinaryXmlPullParser::applyPackageAlias(std::u16string* package,
+ const std::u16string& defaultPackage) const {
+ const auto endIter = mPackageAliases.rend();
+ for (auto iter = mPackageAliases.rbegin(); iter != endIter; ++iter) {
+ if (iter->first == *package) {
+ if (iter->second.empty()) {
+ *package = defaultPackage;
+ } else {
+ *package = iter->second;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
const std::u16string& BinaryXmlPullParser::getElementNamespace() const {
if (!mHasComment && (mEvent == XmlPullParser::Event::kStartElement ||
mEvent == XmlPullParser::Event::kEndElement)) {
@@ -191,11 +240,17 @@
XmlPullParser::Attribute attr;
size_t len;
const char16_t* str = mParser->getAttributeNamespace(i, &len);
- attr.namespaceUri.assign(str, len);
+ if (str) {
+ attr.namespaceUri.assign(str, len);
+ }
str = mParser->getAttributeName(i, &len);
- attr.name.assign(str, len);
+ if (str) {
+ attr.name.assign(str, len);
+ }
str = mParser->getAttributeStringValue(i, &len);
- attr.value.assign(str, len);
+ if (str) {
+ attr.value.assign(str, len);
+ }
mAttributes.push_back(std::move(attr));
}
}