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
diff --git a/tools/aapt2/flatten/ResourceTypeExtensions.h b/tools/aapt2/flatten/ResourceTypeExtensions.h
index c1ff556..acf5bb5 100644
--- a/tools/aapt2/flatten/ResourceTypeExtensions.h
+++ b/tools/aapt2/flatten/ResourceTypeExtensions.h
@@ -62,7 +62,7 @@
          * A raw string value that hasn't had its escape sequences
          * processed nor whitespace removed.
          */
-        TYPE_RAW_STRING = 0xfe
+        TYPE_RAW_STRING = 0xfe,
     };
 };
 
diff --git a/tools/aapt2/flatten/TableFlattener.cpp b/tools/aapt2/flatten/TableFlattener.cpp
index 6b90fb2..636e977 100644
--- a/tools/aapt2/flatten/TableFlattener.cpp
+++ b/tools/aapt2/flatten/TableFlattener.cpp
@@ -78,10 +78,18 @@
     explicit SymbolWriter(StringPool* pool) : mPool(pool) {
     }
 
-    void addSymbol(const ResourceNameRef& name, size_t offset) {
-        symbols.push_back(Entry{ mPool->makeRef(name.package.toString() + u":" +
-                                               toString(name.type).toString() + u"/" +
-                                               name.entry.toString()), offset });
+    void addSymbol(const Reference& ref, size_t offset) {
+        const ResourceName& name = ref.name.value();
+        std::u16string fullName;
+        if (ref.privateReference) {
+            fullName += u"*";
+        }
+
+        if (!name.package.empty()) {
+            fullName += name.package + u":";
+        }
+        fullName += toString(name.type).toString() + u"/" + name.entry;
+        symbols.push_back(Entry{ mPool->makeRef(fullName), offset });
     }
 
     void shiftAllOffsets(size_t offset) {
@@ -100,20 +108,23 @@
     SymbolWriter* mSymbols;
     FlatEntry* mEntry;
     BigBuffer* mBuffer;
+    bool mUseExtendedChunks;
     size_t mEntryCount = 0;
     Maybe<uint32_t> mParentIdent;
     Maybe<ResourceNameRef> mParentName;
 
-    MapFlattenVisitor(SymbolWriter* symbols, FlatEntry* entry, BigBuffer* buffer) :
-            mSymbols(symbols), mEntry(entry), mBuffer(buffer) {
+    MapFlattenVisitor(SymbolWriter* symbols, FlatEntry* entry, BigBuffer* buffer,
+                      bool useExtendedChunks) :
+            mSymbols(symbols), mEntry(entry), mBuffer(buffer),
+            mUseExtendedChunks(useExtendedChunks) {
     }
 
     void flattenKey(Reference* key, ResTable_map* outEntry) {
-        if (!key->id) {
+        if (!key->id || (key->privateReference && mUseExtendedChunks)) {
             assert(key->name && "reference must have a name");
 
             outEntry->name.ident = util::hostToDevice32(0);
-            mSymbols->addSymbol(key->name.value(), (mBuffer->size() - sizeof(ResTable_map)) +
+            mSymbols->addSymbol(*key, (mBuffer->size() - sizeof(ResTable_map)) +
                                     offsetof(ResTable_map, name));
         } else {
             outEntry->name.ident = util::hostToDevice32(key->id.value().id);
@@ -121,16 +132,21 @@
     }
 
     void flattenValue(Item* value, ResTable_map* outEntry) {
+        bool privateRef = false;
         if (Reference* ref = valueCast<Reference>(value)) {
-            if (!ref->id) {
+            privateRef = ref->privateReference && mUseExtendedChunks;
+            if (!ref->id || privateRef) {
                 assert(ref->name && "reference must have a name");
 
-                mSymbols->addSymbol(ref->name.value(), (mBuffer->size() - sizeof(ResTable_map)) +
+                mSymbols->addSymbol(*ref, (mBuffer->size() - sizeof(ResTable_map)) +
                                         offsetof(ResTable_map, value) + offsetof(Res_value, data));
             }
         }
 
         bool result = value->flatten(&outEntry->value);
+        if (privateRef) {
+            outEntry->value.data = 0;
+        }
         assert(result && "flatten failed");
     }
 
@@ -169,7 +185,8 @@
 
     void visit(Style* style) override {
         if (style->parent) {
-            if (!style->parent.value().id) {
+            bool privateRef = style->parent.value().privateReference && mUseExtendedChunks;
+            if (!style->parent.value().id || privateRef) {
                 assert(style->parent.value().name && "reference must have a name");
                 mParentName = style->parent.value().name;
             } else {
@@ -339,21 +356,28 @@
     bool flattenValue(FlatEntry* entry, BigBuffer* buffer) {
         if (Item* item = valueCast<Item>(entry->value)) {
             writeEntry<ResTable_entry, true>(entry, buffer);
+            bool privateRef = false;
             if (Reference* ref = valueCast<Reference>(entry->value)) {
-                if (!ref->id) {
+                // If there is no ID or the reference is private and we allow extended chunks,
+                // write out a 0 and mark the symbol table with the name of the reference.
+                privateRef = (ref->privateReference && mOptions.useExtendedChunks);
+                if (!ref->id || privateRef) {
                     assert(ref->name && "reference must have at least a name");
-                    mSymbols->addSymbol(ref->name.value(),
-                                        buffer->size() + offsetof(Res_value, data));
+                    mSymbols->addSymbol(*ref, buffer->size() + offsetof(Res_value, data));
                 }
             }
             Res_value* outValue = buffer->nextBlock<Res_value>();
             bool result = item->flatten(outValue);
             assert(result && "flatten failed");
+            if (privateRef) {
+                // Force the value of 0 so we look up the symbol at unflatten time.
+                outValue->data = 0;
+            }
             outValue->size = util::hostToDevice16(sizeof(*outValue));
         } else {
             const size_t beforeEntry = buffer->size();
             ResTable_entry_ext* outEntry = writeEntry<ResTable_entry_ext, false>(entry, buffer);
-            MapFlattenVisitor visitor(mSymbols, entry, buffer);
+            MapFlattenVisitor visitor(mSymbols, entry, buffer, mOptions.useExtendedChunks);
             entry->value->accept(&visitor);
             outEntry->count = util::hostToDevice32(visitor.mEntryCount);
             if (visitor.mParentName) {
diff --git a/tools/aapt2/flatten/TableFlattener_test.cpp b/tools/aapt2/flatten/TableFlattener_test.cpp
index 68a1f47..4ffb980 100644
--- a/tools/aapt2/flatten/TableFlattener_test.cpp
+++ b/tools/aapt2/flatten/TableFlattener_test.cpp
@@ -15,11 +15,11 @@
  */
 
 #include "flatten/TableFlattener.h"
+#include "test/Builders.h"
+#include "test/Context.h"
 #include "unflatten/BinaryResourceParser.h"
 #include "util/Util.h"
 
-#include "test/Builders.h"
-#include "test/Context.h"
 
 #include <gtest/gtest.h>
 
diff --git a/tools/aapt2/flatten/XmlFlattener.cpp b/tools/aapt2/flatten/XmlFlattener.cpp
index 4efb08b..8219462 100644
--- a/tools/aapt2/flatten/XmlFlattener.cpp
+++ b/tools/aapt2/flatten/XmlFlattener.cpp
@@ -15,15 +15,14 @@
  */
 
 #include "SdkConstants.h"
-#include "XmlDom.h"
-
 #include "flatten/ChunkWriter.h"
 #include "flatten/ResourceTypeExtensions.h"
 #include "flatten/XmlFlattener.h"
+#include "xml/XmlDom.h"
 
 #include <androidfw/ResourceTypes.h>
-#include <vector>
 #include <utils/misc.h>
+#include <vector>
 
 using namespace android;
 
@@ -306,7 +305,7 @@
     return true;
 }
 
-bool XmlFlattener::consume(IAaptContext* context, XmlResource* resource) {
+bool XmlFlattener::consume(IAaptContext* context, xml::XmlResource* resource) {
     if (!resource->root) {
         return false;
     }
diff --git a/tools/aapt2/flatten/XmlFlattener.h b/tools/aapt2/flatten/XmlFlattener.h
index b1fb3a7..a688ac9 100644
--- a/tools/aapt2/flatten/XmlFlattener.h
+++ b/tools/aapt2/flatten/XmlFlattener.h
@@ -17,16 +17,12 @@
 #ifndef AAPT_FLATTEN_XMLFLATTENER_H
 #define AAPT_FLATTEN_XMLFLATTENER_H
 
-#include "util/BigBuffer.h"
-
 #include "process/IResourceTableConsumer.h"
+#include "util/BigBuffer.h"
+#include "xml/XmlDom.h"
 
 namespace aapt {
 
-namespace xml {
-struct Node;
-}
-
 struct XmlFlattenerOptions {
     /**
      * Keep attribute raw string values along with typed values.
@@ -45,7 +41,7 @@
             mBuffer(buffer), mOptions(options) {
     }
 
-    bool consume(IAaptContext* context, XmlResource* resource) override;
+    bool consume(IAaptContext* context, xml::XmlResource* resource) override;
 
 private:
     BigBuffer* mBuffer;
diff --git a/tools/aapt2/flatten/XmlFlattener_test.cpp b/tools/aapt2/flatten/XmlFlattener_test.cpp
index 318bcdd..8648879 100644
--- a/tools/aapt2/flatten/XmlFlattener_test.cpp
+++ b/tools/aapt2/flatten/XmlFlattener_test.cpp
@@ -16,11 +16,10 @@
 
 #include "flatten/XmlFlattener.h"
 #include "link/Linkers.h"
-#include "util/BigBuffer.h"
-#include "util/Util.h"
-
 #include "test/Builders.h"
 #include "test/Context.h"
+#include "util/BigBuffer.h"
+#include "util/Util.h"
 
 #include <androidfw/ResourceTypes.h>
 #include <gtest/gtest.h>
@@ -45,7 +44,7 @@
                 .build();
     }
 
-    ::testing::AssertionResult flatten(XmlResource* doc, android::ResXMLTree* outTree,
+    ::testing::AssertionResult flatten(xml::XmlResource* doc, android::ResXMLTree* outTree,
                                        XmlFlattenerOptions options = {}) {
         BigBuffer buffer(1024);
         XmlFlattener flattener(&buffer, options);
@@ -65,7 +64,7 @@
 };
 
 TEST_F(XmlFlattenerTest, FlattenXmlWithNoCompiledAttributes) {
-    std::unique_ptr<XmlResource> doc = test::buildXmlDom(R"EOF(
+    std::unique_ptr<xml::XmlResource> doc = test::buildXmlDom(R"EOF(
             <View xmlns:test="http://com.test"
                   attr="hey">
               <Layout test:hello="hi" />
@@ -144,7 +143,7 @@
 }
 
 TEST_F(XmlFlattenerTest, FlattenCompiledXmlAndStripSdk21) {
-    std::unique_ptr<XmlResource> doc = test::buildXmlDom(R"EOF(
+    std::unique_ptr<xml::XmlResource> doc = test::buildXmlDom(R"EOF(
             <View xmlns:android="http://schemas.android.com/apk/res/android"
                 android:paddingStart="1dp"
                 android:colorAccent="#ffffff"/>)EOF");
@@ -169,7 +168,7 @@
 }
 
 TEST_F(XmlFlattenerTest, AssignSpecialAttributeIndices) {
-    std::unique_ptr<XmlResource> doc = test::buildXmlDom(R"EOF(
+    std::unique_ptr<xml::XmlResource> doc = test::buildXmlDom(R"EOF(
             <View xmlns:android="http://schemas.android.com/apk/res/android"
                   android:id="@id/id"
                   class="str"
@@ -192,7 +191,7 @@
  * namespace.
  */
 TEST_F(XmlFlattenerTest, NoNamespaceIsNotTheSameAsEmptyNamespace) {
-    std::unique_ptr<XmlResource> doc = test::buildXmlDom("<View package=\"android\"/>");
+    std::unique_ptr<xml::XmlResource> doc = test::buildXmlDom("<View package=\"android\"/>");
 
     android::ResXMLTree tree;
     ASSERT_TRUE(flatten(doc.get(), &tree));