AAPT2: Share split functionality between link and optimize

Generating splits should be possible to do from the optimize command.
This means that a lot of infrastructure around split APKs can be
shared by both the optimize and link phase.

Bug: 35925830
Change-Id: Ia88b9e4bff300a56353b2f7a4a2547c8eb43a299
Test: manual
diff --git a/tools/aapt2/unflatten/BinaryResourceParser.cpp b/tools/aapt2/unflatten/BinaryResourceParser.cpp
index 35bf618..20a4531 100644
--- a/tools/aapt2/unflatten/BinaryResourceParser.cpp
+++ b/tools/aapt2/unflatten/BinaryResourceParser.cpp
@@ -73,15 +73,16 @@
 
 }  // namespace
 
-BinaryResourceParser::BinaryResourceParser(IAaptContext* context,
-                                           ResourceTable* table,
-                                           const Source& source,
-                                           const void* data, size_t len)
+BinaryResourceParser::BinaryResourceParser(IAaptContext* context, ResourceTable* table,
+                                           const Source& source, const void* data, size_t len,
+                                           io::IFileCollection* files)
     : context_(context),
       table_(table),
       source_(source),
       data_(data),
-      data_len_(len) {}
+      data_len_(len),
+      files_(files) {
+}
 
 bool BinaryResourceParser::Parse() {
   ResChunkPullParser parser(data_, data_len_);
@@ -359,16 +360,14 @@
 
     std::unique_ptr<Value> resource_value;
     if (entry->flags & ResTable_entry::FLAG_COMPLEX) {
-      const ResTable_map_entry* mapEntry =
-          static_cast<const ResTable_map_entry*>(entry);
+      const ResTable_map_entry* mapEntry = static_cast<const ResTable_map_entry*>(entry);
 
       // TODO(adamlesinski): Check that the entry count is valid.
       resource_value = ParseMapEntry(name, config, mapEntry);
     } else {
       const Res_value* value =
-          (const Res_value*)((const uint8_t*)entry +
-                             util::DeviceToHost32(entry->size));
-      resource_value = ParseValue(name, config, value, entry->flags);
+          (const Res_value*)((const uint8_t*)entry + util::DeviceToHost32(entry->size));
+      resource_value = ParseValue(name, config, *value);
     }
 
     if (!resource_value) {
@@ -388,8 +387,7 @@
       Symbol symbol;
       symbol.state = SymbolState::kPublic;
       symbol.source = source_.WithLine(0);
-      if (!table_->SetSymbolStateAllowMangled(name, res_id, symbol,
-                                              context_->GetDiagnostics())) {
+      if (!table_->SetSymbolStateAllowMangled(name, res_id, symbol, context_->GetDiagnostics())) {
         return false;
       }
     }
@@ -419,70 +417,25 @@
   return true;
 }
 
-std::unique_ptr<Item> BinaryResourceParser::ParseValue(
-    const ResourceNameRef& name, const ConfigDescription& config,
-    const Res_value* value, uint16_t flags) {
-  if (name.type == ResourceType::kId) {
-    return util::make_unique<Id>();
-  }
-
-  const uint32_t data = util::DeviceToHost32(value->data);
-
-  if (value->dataType == Res_value::TYPE_STRING) {
-    const std::string str = util::GetString(value_pool_, data);
-
-    const ResStringPool_span* spans = value_pool_.styleAt(data);
-
-    // Check if the string has a valid style associated with it.
-    if (spans != nullptr && spans->name.index != ResStringPool_span::END) {
-      StyleString style_str = {str};
-      while (spans->name.index != ResStringPool_span::END) {
-        style_str.spans.push_back(
-            Span{util::GetString(value_pool_, spans->name.index),
-                 spans->firstChar, spans->lastChar});
-        spans++;
+std::unique_ptr<Item> BinaryResourceParser::ParseValue(const ResourceNameRef& name,
+                                                       const ConfigDescription& config,
+                                                       const android::Res_value& value) {
+  std::unique_ptr<Item> item = ResourceUtils::ParseBinaryResValue(name.type, config, value_pool_,
+                                                                  value, &table_->string_pool);
+  if (files_ != nullptr && item != nullptr) {
+    FileReference* file_ref = ValueCast<FileReference>(item.get());
+    if (file_ref != nullptr) {
+      file_ref->file = files_->FindFile(*file_ref->path);
+      if (file_ref->file == nullptr) {
+        context_->GetDiagnostics()->Error(DiagMessage() << "resource " << name << " for config '"
+                                                        << config << "' is a file reference to '"
+                                                        << *file_ref->path
+                                                        << "' but no such path exists");
+        return {};
       }
-      return util::make_unique<StyledString>(table_->string_pool.MakeRef(
-          style_str,
-          StringPool::Context(StringPool::Context::kStylePriority, config)));
-    } else {
-      if (name.type != ResourceType::kString && util::StartsWith(str, "res/")) {
-        // This must be a FileReference.
-        return util::make_unique<FileReference>(table_->string_pool.MakeRef(
-            str,
-            StringPool::Context(StringPool::Context::kHighPriority, config)));
-      }
-
-      // There are no styles associated with this string, so treat it as
-      // a simple string.
-      return util::make_unique<String>(
-          table_->string_pool.MakeRef(str, StringPool::Context(config)));
     }
   }
-
-  if (value->dataType == Res_value::TYPE_REFERENCE ||
-      value->dataType == Res_value::TYPE_ATTRIBUTE ||
-      value->dataType == Res_value::TYPE_DYNAMIC_REFERENCE ||
-      value->dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE) {
-    Reference::Type type = Reference::Type::kResource;
-    if (value->dataType == Res_value::TYPE_ATTRIBUTE ||
-        value->dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE) {
-      type = Reference::Type::kAttribute;
-    }
-
-    if (data == 0) {
-      // A reference of 0, must be the magic @null reference.
-      Res_value null_type = {};
-      null_type.dataType = Res_value::TYPE_REFERENCE;
-      return util::make_unique<BinaryPrimitive>(null_type);
-    }
-
-    // This is a normal reference.
-    return util::make_unique<Reference>(data, type);
-  }
-
-  // Treat this as a raw binary primitive.
-  return util::make_unique<BinaryPrimitive>(*value);
+  return item;
 }
 
 std::unique_ptr<Value> BinaryResourceParser::ParseMapEntry(
@@ -528,7 +481,7 @@
 
     Style::Entry style_entry;
     style_entry.key = Reference(util::DeviceToHost32(map_entry.name.ident));
-    style_entry.value = ParseValue(name, config, &map_entry.value, 0);
+    style_entry.value = ParseValue(name, config, map_entry.value);
     if (!style_entry.value) {
       return {};
     }
@@ -586,7 +539,7 @@
     const ResTable_map_entry* map) {
   std::unique_ptr<Array> array = util::make_unique<Array>();
   for (const ResTable_map& map_entry : map) {
-    array->items.push_back(ParseValue(name, config, &map_entry.value, 0));
+    array->items.push_back(ParseValue(name, config, map_entry.value));
   }
   return array;
 }
@@ -596,7 +549,7 @@
     const ResTable_map_entry* map) {
   std::unique_ptr<Plural> plural = util::make_unique<Plural>();
   for (const ResTable_map& map_entry : map) {
-    std::unique_ptr<Item> item = ParseValue(name, config, &map_entry.value, 0);
+    std::unique_ptr<Item> item = ParseValue(name, config, map_entry.value);
     if (!item) {
       return {};
     }