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));
         }
     }