AAPT2: Cleanup proto classes/methods and add XML serialization

Test: make aapt2_tests
Change-Id: I01ac2285af6771a683533c033a59ae6cfe875d93
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index f0ebf10..7a8a4ee 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -106,9 +106,8 @@
         "optimize/ResourceDeduper.cpp",
         "optimize/VersionCollapser.cpp",
         "process/SymbolTable.cpp",
-        "proto/ProtoHelpers.cpp",
-        "proto/TableProtoDeserializer.cpp",
-        "proto/TableProtoSerializer.cpp",
+        "proto/ProtoDeserialize.cpp",
+        "proto/ProtoSerialize.cpp",
         "split/TableSplitter.cpp",
         "text/Unicode.cpp",
         "text/Utf8Iterator.cpp",
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index 7f5bbf0..0690dc1 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -248,8 +248,9 @@
     // ZeroCopyOutputStream interface.
     CopyingOutputStreamAdaptor copying_adaptor(writer);
 
-    std::unique_ptr<pb::ResourceTable> pb_table = SerializeTableToPb(&table);
-    if (!pb_table->SerializeToZeroCopyStream(&copying_adaptor)) {
+    pb::ResourceTable pb_table;
+    SerializeTableToPb(table, &pb_table);
+    if (!pb_table.SerializeToZeroCopyStream(&copying_adaptor)) {
       context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to write");
       return false;
     }
@@ -282,9 +283,10 @@
     // Number of CompiledFiles.
     output_stream.WriteLittleEndian32(1);
 
-    std::unique_ptr<pb::internal::CompiledFile> compiled_file = SerializeCompiledFileToPb(file);
-    output_stream.WriteCompiledFile(compiled_file.get());
-    output_stream.WriteData(&buffer);
+    pb::internal::CompiledFile pb_compiled_file;
+    SerializeCompiledFileToPb(file, &pb_compiled_file);
+    output_stream.WriteCompiledFile(pb_compiled_file);
+    output_stream.WriteData(buffer);
 
     if (output_stream.HadError()) {
       diag->Error(DiagMessage(output_path) << "failed to write data");
@@ -319,8 +321,9 @@
     // Number of CompiledFiles.
     output_stream.WriteLittleEndian32(1);
 
-    std::unique_ptr<pb::internal::CompiledFile> compiled_file = SerializeCompiledFileToPb(file);
-    output_stream.WriteCompiledFile(compiled_file.get());
+    pb::internal::CompiledFile pb_compiled_file;
+    SerializeCompiledFileToPb(file, &pb_compiled_file);
+    output_stream.WriteCompiledFile(pb_compiled_file);
     output_stream.WriteData(map.getDataPtr(), map.getDataLength());
 
     if (output_stream.HadError()) {
@@ -346,13 +349,13 @@
     return false;
   }
 
-  std::unique_ptr<pb::internal::CompiledFile> pb_compiled_file =
-      SerializeCompiledFileToPb(xmlres->file);
-  out->WriteCompiledFile(pb_compiled_file.get());
-  out->WriteData(&buffer);
+  pb::internal::CompiledFile pb_compiled_file;
+  SerializeCompiledFileToPb(xmlres->file, &pb_compiled_file);
+  out->WriteCompiledFile(pb_compiled_file);
+  out->WriteData(buffer);
 
   if (out->HadError()) {
-    context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to write data");
+    context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to write XML data");
     return false;
   }
   return true;
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index 0965910..0dedc91 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -23,7 +23,7 @@
 #include "Flags.h"
 #include "io/ZipArchive.h"
 #include "process/IResourceTableConsumer.h"
-#include "proto/ProtoSerialize.h"
+#include "proto/ProtoDeserialize.h"
 #include "unflatten/BinaryResourceParser.h"
 #include "util/Files.h"
 
@@ -33,29 +33,28 @@
 
 bool DumpCompiledFile(const pb::internal::CompiledFile& pb_file, const void* data, size_t len,
                       const Source& source, IAaptContext* context) {
-  std::unique_ptr<ResourceFile> file =
-      DeserializeCompiledFileFromPb(pb_file, source, context->GetDiagnostics());
-  if (!file) {
-    context->GetDiagnostics()->Warn(DiagMessage() << "failed to read compiled file");
+  ResourceFile file;
+  std::string error;
+  if (!DeserializeCompiledFileFromPb(pb_file, &file, &error)) {
+    context->GetDiagnostics()->Warn(DiagMessage(source)
+                                    << "failed to read compiled file: " << error);
     return false;
   }
 
-  std::cout << "Resource: " << file->name << "\n"
-            << "Config:   " << file->config << "\n"
-            << "Source:   " << file->source << "\n";
+  std::cout << "Resource: " << file.name << "\n"
+            << "Config:   " << file.config << "\n"
+            << "Source:   " << file.source << "\n";
   return true;
 }
 
 bool TryDumpFile(IAaptContext* context, const std::string& file_path) {
-  std::unique_ptr<ResourceTable> table;
-
   std::string err;
   std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(file_path, &err);
   if (zip) {
-    io::IFile* file = zip->FindFile("resources.arsc.flat");
-    if (file) {
+    ResourceTable table;
+    if (io::IFile* file = zip->FindFile("resources.arsc.flat")) {
       std::unique_ptr<io::IData> data = file->OpenAsData();
-      if (!data) {
+      if (data == nullptr) {
         context->GetDiagnostics()->Error(DiagMessage(file_path)
                                          << "failed to open resources.arsc.flat");
         return false;
@@ -67,83 +66,78 @@
         return false;
       }
 
-      table = DeserializeTableFromPb(pb_table, Source(file_path), context->GetDiagnostics());
-      if (!table) {
+      ResourceTable table;
+      if (!DeserializeTableFromPb(pb_table, &table, &err)) {
+        context->GetDiagnostics()->Error(DiagMessage(file_path)
+                                         << "failed to parse table: " << err);
+        return false;
+      }
+    } else if (io::IFile* file = zip->FindFile("resources.arsc")) {
+      std::unique_ptr<io::IData> data = file->OpenAsData();
+      if (!data) {
+        context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.arsc");
+        return false;
+      }
+
+      BinaryResourceParser parser(context, &table, Source(file_path), data->data(), data->size());
+      if (!parser.Parse()) {
         return false;
       }
     }
 
-    if (!table) {
-      file = zip->FindFile("resources.arsc");
-      if (file) {
-        std::unique_ptr<io::IData> data = file->OpenAsData();
-        if (!data) {
-          context->GetDiagnostics()->Error(DiagMessage(file_path)
-                                           << "failed to open resources.arsc");
-          return false;
-        }
+    DebugPrintTableOptions options;
+    options.show_sources = true;
+    Debug::PrintTable(&table, options);
+    return true;
+  }
 
-        table = util::make_unique<ResourceTable>();
-        BinaryResourceParser parser(context, table.get(), Source(file_path), data->data(),
-                                    data->size());
-        if (!parser.Parse()) {
-          return false;
-        }
-      }
+  err.clear();
+
+  Maybe<android::FileMap> file = file::MmapPath(file_path, &err);
+  if (!file) {
+    context->GetDiagnostics()->Error(DiagMessage(file_path) << err);
+    return false;
+  }
+
+  android::FileMap* file_map = &file.value();
+
+  // Check to see if this is a loose ResourceTable.
+  pb::ResourceTable pb_table;
+  if (pb_table.ParseFromArray(file_map->getDataPtr(), file_map->getDataLength())) {
+    ResourceTable table;
+    if (DeserializeTableFromPb(pb_table, &table, &err)) {
+      DebugPrintTableOptions options;
+      options.show_sources = true;
+      Debug::PrintTable(&table, options);
+      return true;
     }
   }
 
-  if (!table) {
-    Maybe<android::FileMap> file = file::MmapPath(file_path, &err);
-    if (!file) {
-      context->GetDiagnostics()->Error(DiagMessage(file_path) << err);
+  // Try as a compiled file.
+  CompiledFileInputStream input(file_map->getDataPtr(), file_map->getDataLength());
+  uint32_t num_files = 0;
+  if (!input.ReadLittleEndian32(&num_files)) {
+    return false;
+  }
+
+  for (uint32_t i = 0; i < num_files; i++) {
+    pb::internal::CompiledFile compiled_file;
+    if (!input.ReadCompiledFile(&compiled_file)) {
+      context->GetDiagnostics()->Warn(DiagMessage() << "failed to read compiled file");
       return false;
     }
 
-    android::FileMap* file_map = &file.value();
-
-    // Try as a compiled table.
-    pb::ResourceTable pb_table;
-    if (pb_table.ParseFromArray(file_map->getDataPtr(), file_map->getDataLength())) {
-      table = DeserializeTableFromPb(pb_table, Source(file_path), context->GetDiagnostics());
+    uint64_t offset, len;
+    if (!input.ReadDataMetaData(&offset, &len)) {
+      context->GetDiagnostics()->Warn(DiagMessage() << "failed to read meta data");
+      return false;
     }
 
-    if (!table) {
-      // Try as a compiled file.
-      CompiledFileInputStream input(file_map->getDataPtr(), file_map->getDataLength());
-
-      uint32_t num_files = 0;
-      if (!input.ReadLittleEndian32(&num_files)) {
-        return false;
-      }
-
-      for (uint32_t i = 0; i < num_files; i++) {
-        pb::internal::CompiledFile compiled_file;
-        if (!input.ReadCompiledFile(&compiled_file)) {
-          context->GetDiagnostics()->Warn(DiagMessage() << "failed to read compiled file");
-          return false;
-        }
-
-        uint64_t offset, len;
-        if (!input.ReadDataMetaData(&offset, &len)) {
-          context->GetDiagnostics()->Warn(DiagMessage() << "failed to read meta data");
-          return false;
-        }
-
-        const void* data = static_cast<const uint8_t*>(file_map->getDataPtr()) + offset;
-        if (!DumpCompiledFile(compiled_file, data, len, Source(file_path), context)) {
-          return false;
-        }
-      }
+    const void* data = static_cast<const uint8_t*>(file_map->getDataPtr()) + offset;
+    if (!DumpCompiledFile(compiled_file, data, len, Source(file_path), context)) {
+      return false;
     }
   }
-
-  if (table) {
-    DebugPrintTableOptions options;
-    options.show_sources = true;
-    Debug::PrintTable(table.get(), options);
-  }
-
   return true;
 }
 
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index e3ee206d..f72069c 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -58,6 +58,7 @@
 #include "optimize/VersionCollapser.h"
 #include "process/IResourceTableConsumer.h"
 #include "process/SymbolTable.h"
+#include "proto/ProtoDeserialize.h"
 #include "proto/ProtoSerialize.h"
 #include "split/TableSplitter.h"
 #include "unflatten/BinaryResourceParser.h"
@@ -281,8 +282,10 @@
     return {};
   }
 
-  std::unique_ptr<ResourceTable> table = DeserializeTableFromPb(pb_table, source, diag);
-  if (!table) {
+  std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
+  std::string error;
+  if (!DeserializeTableFromPb(pb_table, table.get(), &error)) {
+    diag->Error(DiagMessage(source) << "invalid compiled table: " << error);
     return {};
   }
   return table;
@@ -917,8 +920,9 @@
   }
 
   bool FlattenTableToPb(ResourceTable* table, IArchiveWriter* writer) {
-    std::unique_ptr<pb::ResourceTable> pb_table = SerializeTableToPb(table);
-    return io::CopyProtoToArchive(context_, pb_table.get(), "resources.arsc.flat", 0, writer);
+    pb::ResourceTable pb_table;
+    SerializeTableToPb(*table, &pb_table);
+    return io::CopyProtoToArchive(context_, &pb_table, "resources.arsc.flat", 0, writer);
   }
 
   bool WriteJavaFile(ResourceTable* table, const StringPiece& package_name_to_generate,
@@ -1397,14 +1401,15 @@
           return false;
         }
 
-        std::unique_ptr<ResourceFile> resource_file = DeserializeCompiledFileFromPb(
-            compiled_file, file->GetSource(), context_->GetDiagnostics());
-        if (!resource_file) {
+        ResourceFile resource_file;
+        std::string error;
+        if (!DeserializeCompiledFileFromPb(compiled_file, &resource_file, &error)) {
+          context_->GetDiagnostics()->Error(DiagMessage(src)
+                                            << "failed to read compiled header: " << error);
           return false;
         }
 
-        if (!MergeCompiledFile(file->CreateFileSegment(offset, len), resource_file.get(),
-                               override)) {
+        if (!MergeCompiledFile(file->CreateFileSegment(offset, len), &resource_file, override)) {
           return false;
         }
       }
diff --git a/tools/aapt2/proto/ProtoDeserialize.cpp b/tools/aapt2/proto/ProtoDeserialize.cpp
new file mode 100644
index 0000000..dc13881
--- /dev/null
+++ b/tools/aapt2/proto/ProtoDeserialize.cpp
@@ -0,0 +1,918 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "proto/ProtoDeserialize.h"
+
+#include "android-base/logging.h"
+#include "android-base/macros.h"
+#include "androidfw/ResourceTypes.h"
+
+#include "Locale.h"
+#include "ResourceTable.h"
+#include "ResourceUtils.h"
+#include "ValueVisitor.h"
+
+using ::android::ResStringPool;
+using ::google::protobuf::io::CodedInputStream;
+
+namespace aapt {
+
+namespace {
+
+class ReferenceIdToNameVisitor : public DescendingValueVisitor {
+ public:
+  using DescendingValueVisitor::Visit;
+
+  explicit ReferenceIdToNameVisitor(const std::map<ResourceId, ResourceNameRef>* mapping)
+      : mapping_(mapping) {
+    CHECK(mapping_ != nullptr);
+  }
+
+  void Visit(Reference* reference) override {
+    if (!reference->id || !reference->id.value().is_valid()) {
+      return;
+    }
+
+    ResourceId id = reference->id.value();
+    auto cache_iter = mapping_->find(id);
+    if (cache_iter != mapping_->end()) {
+      reference->name = cache_iter->second.ToResourceName();
+    }
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ReferenceIdToNameVisitor);
+
+  const std::map<ResourceId, ResourceNameRef>* mapping_;
+};
+
+}  // namespace
+
+bool DeserializeConfigFromPb(const pb::Configuration& pb_config, ConfigDescription* out_config,
+                             std::string* out_error) {
+  out_config->mcc = static_cast<uint16_t>(pb_config.mcc());
+  out_config->mnc = static_cast<uint16_t>(pb_config.mnc());
+
+  if (!pb_config.locale().empty()) {
+    LocaleValue lv;
+    if (!lv.InitFromBcp47Tag(pb_config.locale())) {
+      std::ostringstream error;
+      error << "configuration has invalid locale '" << pb_config.locale() << "'";
+      *out_error = error.str();
+      return false;
+    }
+    lv.WriteTo(out_config);
+  }
+
+  switch (pb_config.layout_direction()) {
+    case pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_LTR:
+      out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_LAYOUTDIR) |
+                                 ConfigDescription::LAYOUTDIR_LTR;
+      break;
+
+    case pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_RTL:
+      out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_LAYOUTDIR) |
+                                 ConfigDescription::LAYOUTDIR_RTL;
+      break;
+
+    default:
+      break;
+  }
+
+  out_config->smallestScreenWidthDp = static_cast<uint16_t>(pb_config.smallest_screen_width_dp());
+  out_config->screenWidthDp = static_cast<uint16_t>(pb_config.screen_width_dp());
+  out_config->screenHeightDp = static_cast<uint16_t>(pb_config.screen_height_dp());
+
+  switch (pb_config.screen_layout_size()) {
+    case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_SMALL:
+      out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) |
+                                 ConfigDescription::SCREENSIZE_SMALL;
+      break;
+
+    case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_NORMAL:
+      out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) |
+                                 ConfigDescription::SCREENSIZE_NORMAL;
+      break;
+
+    case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_LARGE:
+      out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) |
+                                 ConfigDescription::SCREENSIZE_LARGE;
+      break;
+
+    case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_XLARGE:
+      out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) |
+                                 ConfigDescription::SCREENSIZE_XLARGE;
+      break;
+
+    default:
+      break;
+  }
+
+  switch (pb_config.screen_layout_long()) {
+    case pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_LONG:
+      out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENLONG) |
+                                 ConfigDescription::SCREENLONG_YES;
+      break;
+
+    case pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_NOTLONG:
+      out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENLONG) |
+                                 ConfigDescription::SCREENLONG_NO;
+      break;
+
+    default:
+      break;
+  }
+
+  switch (pb_config.screen_round()) {
+    case pb::Configuration_ScreenRound_SCREEN_ROUND_ROUND:
+      out_config->screenLayout2 =
+          (out_config->screenLayout2 & ~ConfigDescription::MASK_SCREENROUND) |
+          ConfigDescription::SCREENROUND_YES;
+      break;
+
+    case pb::Configuration_ScreenRound_SCREEN_ROUND_NOTROUND:
+      out_config->screenLayout2 =
+          (out_config->screenLayout2 & ~ConfigDescription::MASK_SCREENROUND) |
+          ConfigDescription::SCREENROUND_NO;
+      break;
+
+    default:
+      break;
+  }
+
+  switch (pb_config.wide_color_gamut()) {
+    case pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_WIDECG:
+      out_config->colorMode = (out_config->colorMode & ~ConfigDescription::MASK_WIDE_COLOR_GAMUT) |
+                              ConfigDescription::WIDE_COLOR_GAMUT_YES;
+      break;
+
+    case pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_NOWIDECG:
+      out_config->colorMode = (out_config->colorMode & ~ConfigDescription::MASK_WIDE_COLOR_GAMUT) |
+                              ConfigDescription::WIDE_COLOR_GAMUT_NO;
+      break;
+
+    default:
+      break;
+  }
+
+  switch (pb_config.hdr()) {
+    case pb::Configuration_Hdr_HDR_HIGHDR:
+      out_config->colorMode =
+          (out_config->colorMode & ~ConfigDescription::MASK_HDR) | ConfigDescription::HDR_YES;
+      break;
+
+    case pb::Configuration_Hdr_HDR_LOWDR:
+      out_config->colorMode =
+          (out_config->colorMode & ~ConfigDescription::MASK_HDR) | ConfigDescription::HDR_NO;
+      break;
+
+    default:
+      break;
+  }
+
+  switch (pb_config.orientation()) {
+    case pb::Configuration_Orientation_ORIENTATION_PORT:
+      out_config->orientation = ConfigDescription::ORIENTATION_PORT;
+      break;
+
+    case pb::Configuration_Orientation_ORIENTATION_LAND:
+      out_config->orientation = ConfigDescription::ORIENTATION_LAND;
+      break;
+
+    case pb::Configuration_Orientation_ORIENTATION_SQUARE:
+      out_config->orientation = ConfigDescription::ORIENTATION_SQUARE;
+      break;
+
+    default:
+      break;
+  }
+
+  switch (pb_config.ui_mode_type()) {
+    case pb::Configuration_UiModeType_UI_MODE_TYPE_NORMAL:
+      out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
+                           ConfigDescription::UI_MODE_TYPE_NORMAL;
+      break;
+
+    case pb::Configuration_UiModeType_UI_MODE_TYPE_DESK:
+      out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
+                           ConfigDescription::UI_MODE_TYPE_DESK;
+      break;
+
+    case pb::Configuration_UiModeType_UI_MODE_TYPE_CAR:
+      out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
+                           ConfigDescription::UI_MODE_TYPE_CAR;
+      break;
+
+    case pb::Configuration_UiModeType_UI_MODE_TYPE_TELEVISION:
+      out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
+                           ConfigDescription::UI_MODE_TYPE_TELEVISION;
+      break;
+
+    case pb::Configuration_UiModeType_UI_MODE_TYPE_APPLIANCE:
+      out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
+                           ConfigDescription::UI_MODE_TYPE_APPLIANCE;
+      break;
+
+    case pb::Configuration_UiModeType_UI_MODE_TYPE_WATCH:
+      out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
+                           ConfigDescription::UI_MODE_TYPE_WATCH;
+      break;
+
+    case pb::Configuration_UiModeType_UI_MODE_TYPE_VRHEADSET:
+      out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
+                           ConfigDescription::UI_MODE_TYPE_VR_HEADSET;
+      break;
+
+    default:
+      break;
+  }
+
+  switch (pb_config.ui_mode_night()) {
+    case pb::Configuration_UiModeNight_UI_MODE_NIGHT_NIGHT:
+      out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_NIGHT) |
+                           ConfigDescription::UI_MODE_NIGHT_YES;
+      break;
+
+    case pb::Configuration_UiModeNight_UI_MODE_NIGHT_NOTNIGHT:
+      out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_NIGHT) |
+                           ConfigDescription::UI_MODE_NIGHT_NO;
+      break;
+
+    default:
+      break;
+  }
+
+  out_config->density = static_cast<uint16_t>(pb_config.density());
+
+  switch (pb_config.touchscreen()) {
+    case pb::Configuration_Touchscreen_TOUCHSCREEN_NOTOUCH:
+      out_config->touchscreen = ConfigDescription::TOUCHSCREEN_NOTOUCH;
+      break;
+
+    case pb::Configuration_Touchscreen_TOUCHSCREEN_STYLUS:
+      out_config->touchscreen = ConfigDescription::TOUCHSCREEN_STYLUS;
+      break;
+
+    case pb::Configuration_Touchscreen_TOUCHSCREEN_FINGER:
+      out_config->touchscreen = ConfigDescription::TOUCHSCREEN_FINGER;
+      break;
+
+    default:
+      break;
+  }
+
+  switch (pb_config.keys_hidden()) {
+    case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSEXPOSED:
+      out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) |
+                               ConfigDescription::KEYSHIDDEN_NO;
+      break;
+
+    case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSHIDDEN:
+      out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) |
+                               ConfigDescription::KEYSHIDDEN_YES;
+      break;
+
+    case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSSOFT:
+      out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) |
+                               ConfigDescription::KEYSHIDDEN_SOFT;
+      break;
+
+    default:
+      break;
+  }
+
+  switch (pb_config.keyboard()) {
+    case pb::Configuration_Keyboard_KEYBOARD_NOKEYS:
+      out_config->keyboard = ConfigDescription::KEYBOARD_NOKEYS;
+      break;
+
+    case pb::Configuration_Keyboard_KEYBOARD_QWERTY:
+      out_config->keyboard = ConfigDescription::KEYBOARD_QWERTY;
+      break;
+
+    case pb::Configuration_Keyboard_KEYBOARD_TWELVEKEY:
+      out_config->keyboard = ConfigDescription::KEYBOARD_12KEY;
+      break;
+
+    default:
+      break;
+  }
+
+  switch (pb_config.nav_hidden()) {
+    case pb::Configuration_NavHidden_NAV_HIDDEN_NAVEXPOSED:
+      out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_NAVHIDDEN) |
+                               ConfigDescription::NAVHIDDEN_NO;
+      break;
+
+    case pb::Configuration_NavHidden_NAV_HIDDEN_NAVHIDDEN:
+      out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_NAVHIDDEN) |
+                               ConfigDescription::NAVHIDDEN_YES;
+      break;
+
+    default:
+      break;
+  }
+
+  switch (pb_config.navigation()) {
+    case pb::Configuration_Navigation_NAVIGATION_NONAV:
+      out_config->navigation = ConfigDescription::NAVIGATION_NONAV;
+      break;
+
+    case pb::Configuration_Navigation_NAVIGATION_DPAD:
+      out_config->navigation = ConfigDescription::NAVIGATION_DPAD;
+      break;
+
+    case pb::Configuration_Navigation_NAVIGATION_TRACKBALL:
+      out_config->navigation = ConfigDescription::NAVIGATION_TRACKBALL;
+      break;
+
+    case pb::Configuration_Navigation_NAVIGATION_WHEEL:
+      out_config->navigation = ConfigDescription::NAVIGATION_WHEEL;
+      break;
+
+    default:
+      break;
+  }
+
+  out_config->screenWidth = static_cast<uint16_t>(pb_config.screen_width());
+  out_config->screenHeight = static_cast<uint16_t>(pb_config.screen_height());
+  out_config->sdkVersion = static_cast<uint16_t>(pb_config.sdk_version());
+  return true;
+}
+
+static void DeserializeSourceFromPb(const pb::Source& pb_source, const ResStringPool& src_pool,
+                                    Source* out_source) {
+  out_source->path = util::GetString(src_pool, pb_source.path_idx());
+  out_source->line = static_cast<size_t>(pb_source.position().line_number());
+}
+
+static SymbolState DeserializeVisibilityFromPb(const pb::SymbolStatus_Visibility& pb_visibility) {
+  switch (pb_visibility) {
+    case pb::SymbolStatus_Visibility_PRIVATE:
+      return SymbolState::kPrivate;
+    case pb::SymbolStatus_Visibility_PUBLIC:
+      return SymbolState::kPublic;
+    default:
+      break;
+  }
+  return SymbolState::kUndefined;
+}
+
+static bool DeserializePackageFromPb(const pb::Package& pb_package, const ResStringPool& src_pool,
+                                     ResourceTable* out_table, std::string* out_error) {
+  Maybe<uint8_t> id;
+  if (pb_package.has_package_id()) {
+    id = static_cast<uint8_t>(pb_package.package_id().id());
+  }
+
+  std::map<ResourceId, ResourceNameRef> id_index;
+
+  ResourceTablePackage* pkg = out_table->CreatePackage(pb_package.package_name(), id);
+  for (const pb::Type& pb_type : pb_package.type()) {
+    const ResourceType* res_type = ParseResourceType(pb_type.name());
+    if (res_type == nullptr) {
+      std::ostringstream error;
+      error << "unknown type '" << pb_type.name() << "'";
+      *out_error = error.str();
+      return false;
+    }
+
+    ResourceTableType* type = pkg->FindOrCreateType(*res_type);
+    for (const pb::Entry& pb_entry : pb_type.entry()) {
+      ResourceEntry* entry = type->FindOrCreateEntry(pb_entry.name());
+
+      // Deserialize the symbol status (public/private with source and comments).
+      if (pb_entry.has_symbol_status()) {
+        const pb::SymbolStatus& pb_status = pb_entry.symbol_status();
+        if (pb_status.has_source()) {
+          DeserializeSourceFromPb(pb_status.source(), src_pool, &entry->symbol_status.source);
+        }
+
+        entry->symbol_status.comment = pb_status.comment();
+        entry->symbol_status.allow_new = pb_status.allow_new();
+
+        const SymbolState visibility = DeserializeVisibilityFromPb(pb_status.visibility());
+        entry->symbol_status.state = visibility;
+
+        if (visibility == SymbolState::kPublic) {
+          // This is a public symbol, we must encode the ID now if there is one.
+          if (pb_entry.has_entry_id()) {
+            entry->id = static_cast<uint16_t>(pb_entry.entry_id().id());
+          }
+
+          if (type->symbol_status.state != SymbolState::kPublic) {
+            // If the type has not been made public, do so now.
+            type->symbol_status.state = SymbolState::kPublic;
+            if (pb_type.has_type_id()) {
+              type->id = static_cast<uint8_t>(pb_type.type_id().id());
+            }
+          }
+        } else if (visibility == SymbolState::kPrivate) {
+          if (type->symbol_status.state == SymbolState::kUndefined) {
+            type->symbol_status.state = SymbolState::kPrivate;
+          }
+        }
+      }
+
+      ResourceId resid(pb_package.package_id().id(), pb_type.type_id().id(),
+                       pb_entry.entry_id().id());
+      if (resid.is_valid()) {
+        id_index[resid] = ResourceNameRef(pkg->name, type->type, entry->name);
+      }
+
+      for (const pb::ConfigValue& pb_config_value : pb_entry.config_value()) {
+        const pb::Configuration& pb_config = pb_config_value.config();
+
+        ConfigDescription config;
+        if (!DeserializeConfigFromPb(pb_config, &config, out_error)) {
+          return false;
+        }
+
+        ResourceConfigValue* config_value = entry->FindOrCreateValue(config, pb_config.product());
+        if (config_value->value != nullptr) {
+          *out_error = "duplicate configuration in resource table";
+          return false;
+        }
+
+        config_value->value = DeserializeValueFromPb(pb_config_value.value(), src_pool, config,
+                                                     &out_table->string_pool, out_error);
+        if (config_value->value == nullptr) {
+          return false;
+        }
+      }
+    }
+  }
+
+  ReferenceIdToNameVisitor visitor(&id_index);
+  VisitAllValuesInPackage(pkg, &visitor);
+  return true;
+}
+
+bool DeserializeTableFromPb(const pb::ResourceTable& pb_table, ResourceTable* out_table,
+                            std::string* out_error) {
+  // We import the android namespace because on Windows NO_ERROR is a macro, not an enum, which
+  // causes errors when qualifying it with android::
+  using namespace android;
+
+  ResStringPool source_pool;
+  if (pb_table.has_source_pool()) {
+    status_t result = source_pool.setTo(pb_table.source_pool().data().data(),
+                                        pb_table.source_pool().data().size());
+    if (result != NO_ERROR) {
+      *out_error = "invalid source pool";
+      return false;
+    }
+  }
+
+  for (const pb::Package& pb_package : pb_table.package()) {
+    if (!DeserializePackageFromPb(pb_package, source_pool, out_table, out_error)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool DeserializeCompiledFileFromPb(const pb::internal::CompiledFile& pb_file,
+                                   ResourceFile* out_file, std::string* out_error) {
+  ResourceNameRef name_ref;
+  if (!ResourceUtils::ParseResourceName(pb_file.resource_name(), &name_ref)) {
+    std::ostringstream error;
+    error << "invalid resource name in compiled file header: " << pb_file.resource_name();
+    *out_error = error.str();
+    return false;
+  }
+
+  out_file->name = name_ref.ToResourceName();
+  out_file->source.path = pb_file.source_path();
+
+  std::string config_error;
+  if (!DeserializeConfigFromPb(pb_file.config(), &out_file->config, &config_error)) {
+    std::ostringstream error;
+    error << "invalid resource configuration in compiled file header: " << config_error;
+    *out_error = error.str();
+    return false;
+  }
+
+  for (const pb::internal::CompiledFile_Symbol& pb_symbol : pb_file.exported_symbol()) {
+    if (!ResourceUtils::ParseResourceName(pb_symbol.resource_name(), &name_ref)) {
+      std::ostringstream error;
+      error << "invalid resource name for exported symbol in compiled file header: "
+            << pb_file.resource_name();
+      *out_error = error.str();
+      return false;
+    }
+
+    size_t line = 0u;
+    if (pb_symbol.has_source()) {
+      line = pb_symbol.source().line_number();
+    }
+    out_file->exported_symbols.push_back(SourcedResourceName{name_ref.ToResourceName(), line});
+  }
+  return true;
+}
+
+static Reference::Type DeserializeReferenceTypeFromPb(const pb::Reference_Type& pb_type) {
+  switch (pb_type) {
+    case pb::Reference_Type_REFERENCE:
+      return Reference::Type::kResource;
+    case pb::Reference_Type_ATTRIBUTE:
+      return Reference::Type::kAttribute;
+    default:
+      break;
+  }
+  return Reference::Type::kResource;
+}
+
+static bool DeserializeReferenceFromPb(const pb::Reference& pb_ref, Reference* out_ref,
+                                       std::string* out_error) {
+  out_ref->reference_type = DeserializeReferenceTypeFromPb(pb_ref.type());
+  out_ref->private_reference = pb_ref.private_();
+
+  if (pb_ref.id() != 0) {
+    out_ref->id = ResourceId(pb_ref.id());
+  }
+
+  if (!pb_ref.name().empty()) {
+    ResourceNameRef name_ref;
+    if (!ResourceUtils::ParseResourceName(pb_ref.name(), &name_ref, nullptr)) {
+      std::ostringstream error;
+      error << "reference has invalid resource name '" << pb_ref.name() << "'";
+      *out_error = error.str();
+      return false;
+    }
+    out_ref->name = name_ref.ToResourceName();
+  }
+  return true;
+}
+
+template <typename T>
+static void DeserializeItemMetaDataFromPb(const T& pb_item, const android::ResStringPool& src_pool,
+                                          Value* out_value) {
+  if (pb_item.has_source()) {
+    Source source;
+    DeserializeSourceFromPb(pb_item.source(), src_pool, &source);
+    out_value->SetSource(std::move(source));
+  }
+  out_value->SetComment(pb_item.comment());
+}
+
+static size_t DeserializePluralEnumFromPb(const pb::Plural_Arity& arity) {
+  switch (arity) {
+    case pb::Plural_Arity_ZERO:
+      return Plural::Zero;
+    case pb::Plural_Arity_ONE:
+      return Plural::One;
+    case pb::Plural_Arity_TWO:
+      return Plural::Two;
+    case pb::Plural_Arity_FEW:
+      return Plural::Few;
+    case pb::Plural_Arity_MANY:
+      return Plural::Many;
+    default:
+      break;
+  }
+  return Plural::Other;
+}
+
+std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
+                                              const android::ResStringPool& src_pool,
+                                              const ConfigDescription& config,
+                                              StringPool* value_pool, std::string* out_error) {
+  std::unique_ptr<Value> value;
+  if (pb_value.has_item()) {
+    value = DeserializeItemFromPb(pb_value.item(), src_pool, config, value_pool, out_error);
+    if (value == nullptr) {
+      return {};
+    }
+
+  } else if (pb_value.has_compound_value()) {
+    const pb::CompoundValue& pb_compound_value = pb_value.compound_value();
+    switch (pb_compound_value.value_case()) {
+      case pb::CompoundValue::kAttr: {
+        const pb::Attribute& pb_attr = pb_compound_value.attr();
+        std::unique_ptr<Attribute> attr = util::make_unique<Attribute>();
+        attr->type_mask = pb_attr.format_flags();
+        attr->min_int = pb_attr.min_int();
+        attr->max_int = pb_attr.max_int();
+        for (const pb::Attribute_Symbol& pb_symbol : pb_attr.symbol()) {
+          Attribute::Symbol symbol;
+          DeserializeItemMetaDataFromPb(pb_symbol, src_pool, &symbol.symbol);
+          if (!DeserializeReferenceFromPb(pb_symbol.name(), &symbol.symbol, out_error)) {
+            return {};
+          }
+          symbol.value = pb_symbol.value();
+          attr->symbols.push_back(std::move(symbol));
+        }
+        value = std::move(attr);
+      } break;
+
+      case pb::CompoundValue::kStyle: {
+        const pb::Style& pb_style = pb_compound_value.style();
+        std::unique_ptr<Style> style = util::make_unique<Style>();
+        if (pb_style.has_parent()) {
+          style->parent = Reference();
+          if (!DeserializeReferenceFromPb(pb_style.parent(), &style->parent.value(), out_error)) {
+            return {};
+          }
+
+          if (pb_style.has_parent_source()) {
+            Source parent_source;
+            DeserializeSourceFromPb(pb_style.parent_source(), src_pool, &parent_source);
+            style->parent.value().SetSource(std::move(parent_source));
+          }
+        }
+
+        for (const pb::Style_Entry& pb_entry : pb_style.entry()) {
+          Style::Entry entry;
+          if (!DeserializeReferenceFromPb(pb_entry.key(), &entry.key, out_error)) {
+            return {};
+          }
+          DeserializeItemMetaDataFromPb(pb_entry, src_pool, &entry.key);
+          entry.value =
+              DeserializeItemFromPb(pb_entry.item(), src_pool, config, value_pool, out_error);
+          if (entry.value == nullptr) {
+            return {};
+          }
+
+          // Copy the meta-data into the value as well.
+          DeserializeItemMetaDataFromPb(pb_entry, src_pool, entry.value.get());
+          style->entries.push_back(std::move(entry));
+        }
+        value = std::move(style);
+      } break;
+
+      case pb::CompoundValue::kStyleable: {
+        const pb::Styleable& pb_styleable = pb_compound_value.styleable();
+        std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
+        for (const pb::Styleable_Entry& pb_entry : pb_styleable.entry()) {
+          Reference attr_ref;
+          DeserializeItemMetaDataFromPb(pb_entry, src_pool, &attr_ref);
+          DeserializeReferenceFromPb(pb_entry.attr(), &attr_ref, out_error);
+          styleable->entries.push_back(std::move(attr_ref));
+        }
+        value = std::move(styleable);
+      } break;
+
+      case pb::CompoundValue::kArray: {
+        const pb::Array& pb_array = pb_compound_value.array();
+        std::unique_ptr<Array> array = util::make_unique<Array>();
+        for (const pb::Array_Element& pb_entry : pb_array.element()) {
+          std::unique_ptr<Item> item =
+              DeserializeItemFromPb(pb_entry.item(), src_pool, config, value_pool, out_error);
+          if (item == nullptr) {
+            return {};
+          }
+
+          DeserializeItemMetaDataFromPb(pb_entry, src_pool, item.get());
+          array->elements.push_back(std::move(item));
+        }
+        value = std::move(array);
+      } break;
+
+      case pb::CompoundValue::kPlural: {
+        const pb::Plural& pb_plural = pb_compound_value.plural();
+        std::unique_ptr<Plural> plural = util::make_unique<Plural>();
+        for (const pb::Plural_Entry& pb_entry : pb_plural.entry()) {
+          size_t plural_idx = DeserializePluralEnumFromPb(pb_entry.arity());
+          plural->values[plural_idx] =
+              DeserializeItemFromPb(pb_entry.item(), src_pool, config, value_pool, out_error);
+          if (!plural->values[plural_idx]) {
+            return {};
+          }
+
+          DeserializeItemMetaDataFromPb(pb_entry, src_pool, plural->values[plural_idx].get());
+        }
+        value = std::move(plural);
+      } break;
+
+      default:
+        LOG(FATAL) << "unknown compound value: " << (int) pb_compound_value.value_case();
+        break;
+    }
+  } else {
+    LOG(FATAL) << "unknown value: " << (int) pb_value.value_case();
+    return {};
+  }
+
+  CHECK(value) << "forgot to set value";
+
+  value->SetWeak(pb_value.weak());
+  DeserializeItemMetaDataFromPb(pb_value, src_pool, value.get());
+  return value;
+}
+
+std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item,
+                                            const android::ResStringPool& src_pool,
+                                            const ConfigDescription& config, StringPool* value_pool,
+                                            std::string* out_error) {
+  switch (pb_item.value_case()) {
+    case pb::Item::kRef: {
+      const pb::Reference& pb_ref = pb_item.ref();
+      std::unique_ptr<Reference> ref = util::make_unique<Reference>();
+      if (!DeserializeReferenceFromPb(pb_ref, ref.get(), out_error)) {
+        return {};
+      }
+      return std::move(ref);
+    } break;
+
+    case pb::Item::kPrim: {
+      const pb::Primitive& pb_prim = pb_item.prim();
+      return util::make_unique<BinaryPrimitive>(static_cast<uint8_t>(pb_prim.type()),
+                                                pb_prim.data());
+    } break;
+
+    case pb::Item::kId: {
+      return util::make_unique<Id>();
+    } break;
+
+    case pb::Item::kStr: {
+      return util::make_unique<String>(
+          value_pool->MakeRef(pb_item.str().value(), StringPool::Context(config)));
+    } break;
+
+    case pb::Item::kRawStr: {
+      return util::make_unique<RawString>(
+          value_pool->MakeRef(pb_item.raw_str().value(), StringPool::Context(config)));
+    } break;
+
+    case pb::Item::kStyledStr: {
+      const pb::StyledString& pb_str = pb_item.styled_str();
+      StyleString style_str{pb_str.value()};
+      for (const pb::StyledString::Span& pb_span : pb_str.span()) {
+        style_str.spans.push_back(Span{pb_span.tag(), pb_span.first_char(), pb_span.last_char()});
+      }
+      return util::make_unique<StyledString>(value_pool->MakeRef(
+          style_str, StringPool::Context(StringPool::Context::kNormalPriority, config)));
+    } break;
+
+    case pb::Item::kFile: {
+      return util::make_unique<FileReference>(value_pool->MakeRef(
+          pb_item.file().path(), StringPool::Context(StringPool::Context::kHighPriority, config)));
+    } break;
+
+    default:
+      LOG(FATAL) << "unknown item: " << (int) pb_item.value_case();
+      break;
+  }
+  return {};
+}
+
+std::unique_ptr<xml::XmlResource> DeserializeXmlResourceFromPb(const pb::XmlNode& pb_node,
+                                                               std::string* out_error) {
+  if (!pb_node.has_element()) {
+    return {};
+  }
+
+  std::unique_ptr<xml::XmlResource> resource = util::make_unique<xml::XmlResource>();
+  resource->root = util::make_unique<xml::Element>();
+  if (!DeserializeXmlFromPb(pb_node, resource->root.get(), &resource->string_pool, out_error)) {
+    return {};
+  }
+  return resource;
+}
+
+bool DeserializeXmlFromPb(const pb::XmlNode& pb_node, xml::Element* out_el, StringPool* value_pool,
+                          std::string* out_error) {
+  const pb::XmlElement& pb_el = pb_node.element();
+  out_el->name = pb_el.name();
+  out_el->namespace_uri = pb_el.namespace_uri();
+  out_el->line_number = pb_node.source().line_number();
+  out_el->column_number = pb_node.source().column_number();
+
+  for (const pb::XmlNamespace& pb_ns : pb_el.namespace_declaration()) {
+    xml::NamespaceDecl decl;
+    decl.uri = pb_ns.uri();
+    decl.prefix = pb_ns.prefix();
+    decl.line_number = pb_ns.source().line_number();
+    decl.column_number = pb_ns.source().column_number();
+    out_el->namespace_decls.push_back(std::move(decl));
+  }
+
+  for (const pb::XmlAttribute& pb_attr : pb_el.attribute()) {
+    xml::Attribute attr;
+    attr.name = pb_attr.name();
+    attr.namespace_uri = pb_attr.namespace_uri();
+    attr.value = pb_attr.value();
+    if (pb_attr.resource_id() != 0u) {
+      attr.compiled_attribute = xml::AaptAttribute{Attribute(), ResourceId(pb_attr.resource_id())};
+    }
+    if (pb_attr.has_compiled_item()) {
+      attr.compiled_value =
+          DeserializeItemFromPb(pb_attr.compiled_item(), {}, {}, value_pool, out_error);
+      if (attr.compiled_value == nullptr) {
+        return {};
+      }
+      attr.compiled_value->SetSource(Source().WithLine(pb_attr.source().line_number()));
+    }
+    out_el->attributes.push_back(std::move(attr));
+  }
+
+  // Deserialize the children.
+  for (const pb::XmlNode& pb_child : pb_el.child()) {
+    switch (pb_child.node_case()) {
+      case pb::XmlNode::NodeCase::kText: {
+        std::unique_ptr<xml::Text> text = util::make_unique<xml::Text>();
+        text->line_number = pb_child.source().line_number();
+        text->column_number = pb_child.source().column_number();
+        text->text = pb_child.text();
+        out_el->AppendChild(std::move(text));
+      } break;
+
+      case pb::XmlNode::NodeCase::kElement: {
+        std::unique_ptr<xml::Element> child_el = util::make_unique<xml::Element>();
+        if (!DeserializeXmlFromPb(pb_child, child_el.get(), value_pool, out_error)) {
+          return false;
+        }
+        out_el->AppendChild(std::move(child_el));
+      } break;
+
+      default:
+        LOG(FATAL) << "unknown XmlNode " << (int) pb_child.node_case();
+        break;
+    }
+  }
+  return true;
+}
+
+CompiledFileInputStream::CompiledFileInputStream(const void* data, size_t size)
+    : in_(static_cast<const uint8_t*>(data), size) {
+}
+
+void CompiledFileInputStream::EnsureAlignedRead() {
+  const int overflow = in_.CurrentPosition() % 4;
+  if (overflow > 0) {
+    // Reads are always 4 byte aligned.
+    in_.Skip(4 - overflow);
+  }
+}
+
+bool CompiledFileInputStream::ReadLittleEndian32(uint32_t* out_val) {
+  EnsureAlignedRead();
+  return in_.ReadLittleEndian32(out_val);
+}
+
+bool CompiledFileInputStream::ReadCompiledFile(pb::internal::CompiledFile* out_val) {
+  EnsureAlignedRead();
+
+  google::protobuf::uint64 pb_size = 0u;
+  if (!in_.ReadLittleEndian64(&pb_size)) {
+    return false;
+  }
+
+  CodedInputStream::Limit l = in_.PushLimit(static_cast<int>(pb_size));
+
+  // Check that we haven't tried to read past the end.
+  if (static_cast<uint64_t>(in_.BytesUntilLimit()) != pb_size) {
+    in_.PopLimit(l);
+    in_.PushLimit(0);
+    return false;
+  }
+
+  if (!out_val->ParsePartialFromCodedStream(&in_)) {
+    in_.PopLimit(l);
+    in_.PushLimit(0);
+    return false;
+  }
+
+  in_.PopLimit(l);
+  return true;
+}
+
+bool CompiledFileInputStream::ReadDataMetaData(uint64_t* out_offset, uint64_t* out_len) {
+  EnsureAlignedRead();
+
+  google::protobuf::uint64 pb_size = 0u;
+  if (!in_.ReadLittleEndian64(&pb_size)) {
+    return false;
+  }
+
+  // Check that we aren't trying to read past the end.
+  if (pb_size > static_cast<uint64_t>(in_.BytesUntilLimit())) {
+    in_.PushLimit(0);
+    return false;
+  }
+
+  uint64_t offset = static_cast<uint64_t>(in_.CurrentPosition());
+  if (!in_.Skip(pb_size)) {
+    return false;
+  }
+
+  *out_offset = offset;
+  *out_len = pb_size;
+  return true;
+}
+
+}  // namespace aapt
diff --git a/tools/aapt2/proto/ProtoDeserialize.h b/tools/aapt2/proto/ProtoDeserialize.h
new file mode 100644
index 0000000..3d76ea4
--- /dev/null
+++ b/tools/aapt2/proto/ProtoDeserialize.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_PROTO_PROTODESERIALIZE_H
+#define AAPT_PROTO_PROTODESERIALIZE_H
+
+#include "android-base/macros.h"
+#include "androidfw/ResourceTypes.h"
+#include "google/protobuf/io/coded_stream.h"
+
+#include "ConfigDescription.h"
+#include "Configuration.pb.h"
+#include "ResourceTable.h"
+#include "ResourceValues.h"
+#include "Resources.pb.h"
+#include "ResourcesInternal.pb.h"
+#include "StringPool.h"
+#include "xml/XmlDom.h"
+
+namespace aapt {
+
+std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
+                                              const android::ResStringPool& src_pool,
+                                              const ConfigDescription& config,
+                                              StringPool* value_pool, std::string* out_error);
+
+std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item,
+                                            const android::ResStringPool& src_pool,
+                                            const ConfigDescription& config, StringPool* value_pool,
+                                            std::string* out_error);
+
+std::unique_ptr<xml::XmlResource> DeserializeXmlResourceFromPb(const pb::XmlNode& pb_node,
+                                                               std::string* out_error);
+
+bool DeserializeXmlFromPb(const pb::XmlNode& pb_node, xml::Element* out_el, StringPool* value_pool,
+                          std::string* out_error);
+
+bool DeserializeConfigFromPb(const pb::Configuration& pb_config, ConfigDescription* out_config,
+                             std::string* out_error);
+
+bool DeserializeTableFromPb(const pb::ResourceTable& pb_table, ResourceTable* out_table,
+                            std::string* out_error);
+
+bool DeserializeCompiledFileFromPb(const pb::internal::CompiledFile& pb_file,
+                                   ResourceFile* out_file, std::string* out_error);
+
+class CompiledFileInputStream {
+ public:
+  explicit CompiledFileInputStream(const void* data, size_t size);
+
+  bool ReadLittleEndian32(uint32_t* outVal);
+  bool ReadCompiledFile(pb::internal::CompiledFile* outVal);
+  bool ReadDataMetaData(uint64_t* outOffset, uint64_t* outLen);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CompiledFileInputStream);
+
+  void EnsureAlignedRead();
+
+  ::google::protobuf::io::CodedInputStream in_;
+};
+
+}  // namespace aapt
+
+#endif /* AAPT_PROTO_PROTODESERIALIZE_H */
diff --git a/tools/aapt2/proto/ProtoHelpers.cpp b/tools/aapt2/proto/ProtoHelpers.cpp
deleted file mode 100644
index 18f7e1d..0000000
--- a/tools/aapt2/proto/ProtoHelpers.cpp
+++ /dev/null
@@ -1,639 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "proto/ProtoHelpers.h"
-
-#include "Locale.h"
-
-namespace aapt {
-
-void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool) {
-  BigBuffer buffer(1024);
-  StringPool::FlattenUtf8(&buffer, pool);
-
-  std::string* data = out_pb_pool->mutable_data();
-  data->reserve(buffer.size());
-
-  size_t offset = 0;
-  for (const BigBuffer::Block& block : buffer) {
-    data->insert(data->begin() + offset, block.buffer.get(), block.buffer.get() + block.size);
-    offset += block.size;
-  }
-}
-
-void SerializeSourceToPb(const Source& source, StringPool* src_pool, pb::Source* out_pb_source) {
-  StringPool::Ref ref = src_pool->MakeRef(source.path);
-  out_pb_source->set_path_idx(static_cast<uint32_t>(ref.index()));
-  if (source.line) {
-    out_pb_source->mutable_position()->set_line_number(static_cast<uint32_t>(source.line.value()));
-  }
-}
-
-void DeserializeSourceFromPb(const pb::Source& pb_source, const android::ResStringPool& src_pool,
-                             Source* out_source) {
-  out_source->path = util::GetString(src_pool, pb_source.path_idx());
-  out_source->line = static_cast<size_t>(pb_source.position().line_number());
-}
-
-pb::SymbolStatus_Visibility SerializeVisibilityToPb(SymbolState state) {
-  switch (state) {
-    case SymbolState::kPrivate:
-      return pb::SymbolStatus_Visibility_PRIVATE;
-    case SymbolState::kPublic:
-      return pb::SymbolStatus_Visibility_PUBLIC;
-    default:
-      break;
-  }
-  return pb::SymbolStatus_Visibility_UNKNOWN;
-}
-
-SymbolState DeserializeVisibilityFromPb(pb::SymbolStatus_Visibility pb_visibility) {
-  switch (pb_visibility) {
-    case pb::SymbolStatus_Visibility_PRIVATE:
-      return SymbolState::kPrivate;
-    case pb::SymbolStatus_Visibility_PUBLIC:
-      return SymbolState::kPublic;
-    default:
-      break;
-  }
-  return SymbolState::kUndefined;
-}
-
-void SerializeConfig(const ConfigDescription& config, pb::Configuration* out_pb_config) {
-  out_pb_config->set_mcc(config.mcc);
-  out_pb_config->set_mnc(config.mnc);
-  out_pb_config->set_locale(config.GetBcp47LanguageTag());
-
-  switch (config.screenLayout & ConfigDescription::MASK_LAYOUTDIR) {
-    case ConfigDescription::LAYOUTDIR_LTR:
-      out_pb_config->set_layout_direction(pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_LTR);
-      break;
-
-    case ConfigDescription::LAYOUTDIR_RTL:
-      out_pb_config->set_layout_direction(pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_RTL);
-      break;
-  }
-
-  out_pb_config->set_screen_width(config.screenWidth);
-  out_pb_config->set_screen_height(config.screenHeight);
-  out_pb_config->set_screen_width_dp(config.screenWidthDp);
-  out_pb_config->set_screen_height_dp(config.screenHeightDp);
-  out_pb_config->set_smallest_screen_width_dp(config.smallestScreenWidthDp);
-
-  switch (config.screenLayout & ConfigDescription::MASK_SCREENSIZE) {
-    case ConfigDescription::SCREENSIZE_SMALL:
-      out_pb_config->set_screen_layout_size(
-          pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_SMALL);
-      break;
-
-    case ConfigDescription::SCREENSIZE_NORMAL:
-      out_pb_config->set_screen_layout_size(
-          pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_NORMAL);
-      break;
-
-    case ConfigDescription::SCREENSIZE_LARGE:
-      out_pb_config->set_screen_layout_size(
-          pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_LARGE);
-      break;
-
-    case ConfigDescription::SCREENSIZE_XLARGE:
-      out_pb_config->set_screen_layout_size(
-          pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_XLARGE);
-      break;
-  }
-
-  switch (config.screenLayout & ConfigDescription::MASK_SCREENLONG) {
-    case ConfigDescription::SCREENLONG_YES:
-      out_pb_config->set_screen_layout_long(
-          pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_LONG);
-      break;
-
-    case ConfigDescription::SCREENLONG_NO:
-      out_pb_config->set_screen_layout_long(
-          pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_NOTLONG);
-      break;
-  }
-
-  switch (config.screenLayout2 & ConfigDescription::MASK_SCREENROUND) {
-    case ConfigDescription::SCREENROUND_YES:
-      out_pb_config->set_screen_round(pb::Configuration_ScreenRound_SCREEN_ROUND_ROUND);
-      break;
-
-    case ConfigDescription::SCREENROUND_NO:
-      out_pb_config->set_screen_round(pb::Configuration_ScreenRound_SCREEN_ROUND_NOTROUND);
-      break;
-  }
-
-  switch (config.colorMode & ConfigDescription::MASK_WIDE_COLOR_GAMUT) {
-    case ConfigDescription::WIDE_COLOR_GAMUT_YES:
-      out_pb_config->set_wide_color_gamut(pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_WIDECG);
-      break;
-
-    case ConfigDescription::WIDE_COLOR_GAMUT_NO:
-      out_pb_config->set_wide_color_gamut(
-          pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_NOWIDECG);
-      break;
-  }
-
-  switch (config.colorMode & ConfigDescription::MASK_HDR) {
-    case ConfigDescription::HDR_YES:
-      out_pb_config->set_hdr(pb::Configuration_Hdr_HDR_HIGHDR);
-      break;
-
-    case ConfigDescription::HDR_NO:
-      out_pb_config->set_hdr(pb::Configuration_Hdr_HDR_LOWDR);
-      break;
-  }
-
-  switch (config.orientation) {
-    case ConfigDescription::ORIENTATION_PORT:
-      out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_PORT);
-      break;
-
-    case ConfigDescription::ORIENTATION_LAND:
-      out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_LAND);
-      break;
-
-    case ConfigDescription::ORIENTATION_SQUARE:
-      out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_SQUARE);
-      break;
-  }
-
-  switch (config.uiMode & ConfigDescription::MASK_UI_MODE_TYPE) {
-    case ConfigDescription::UI_MODE_TYPE_NORMAL:
-      out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_NORMAL);
-      break;
-
-    case ConfigDescription::UI_MODE_TYPE_DESK:
-      out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_DESK);
-      break;
-
-    case ConfigDescription::UI_MODE_TYPE_CAR:
-      out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_CAR);
-      break;
-
-    case ConfigDescription::UI_MODE_TYPE_TELEVISION:
-      out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_TELEVISION);
-      break;
-
-    case ConfigDescription::UI_MODE_TYPE_APPLIANCE:
-      out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_APPLIANCE);
-      break;
-
-    case ConfigDescription::UI_MODE_TYPE_WATCH:
-      out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_WATCH);
-      break;
-
-    case ConfigDescription::UI_MODE_TYPE_VR_HEADSET:
-      out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_VRHEADSET);
-      break;
-  }
-
-  switch (config.uiMode & ConfigDescription::MASK_UI_MODE_NIGHT) {
-    case ConfigDescription::UI_MODE_NIGHT_YES:
-      out_pb_config->set_ui_mode_night(pb::Configuration_UiModeNight_UI_MODE_NIGHT_NIGHT);
-      break;
-
-    case ConfigDescription::UI_MODE_NIGHT_NO:
-      out_pb_config->set_ui_mode_night(pb::Configuration_UiModeNight_UI_MODE_NIGHT_NOTNIGHT);
-      break;
-  }
-
-  out_pb_config->set_density(config.density);
-
-  switch (config.touchscreen) {
-    case ConfigDescription::TOUCHSCREEN_NOTOUCH:
-      out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_NOTOUCH);
-      break;
-
-    case ConfigDescription::TOUCHSCREEN_STYLUS:
-      out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_STYLUS);
-      break;
-
-    case ConfigDescription::TOUCHSCREEN_FINGER:
-      out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_FINGER);
-      break;
-  }
-
-  switch (config.inputFlags & ConfigDescription::MASK_KEYSHIDDEN) {
-    case ConfigDescription::KEYSHIDDEN_NO:
-      out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSEXPOSED);
-      break;
-
-    case ConfigDescription::KEYSHIDDEN_YES:
-      out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSHIDDEN);
-      break;
-
-    case ConfigDescription::KEYSHIDDEN_SOFT:
-      out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSSOFT);
-      break;
-  }
-
-  switch (config.keyboard) {
-    case ConfigDescription::KEYBOARD_NOKEYS:
-      out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_NOKEYS);
-      break;
-
-    case ConfigDescription::KEYBOARD_QWERTY:
-      out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_QWERTY);
-      break;
-
-    case ConfigDescription::KEYBOARD_12KEY:
-      out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_TWELVEKEY);
-      break;
-  }
-
-  switch (config.inputFlags & ConfigDescription::MASK_NAVHIDDEN) {
-    case ConfigDescription::NAVHIDDEN_NO:
-      out_pb_config->set_nav_hidden(pb::Configuration_NavHidden_NAV_HIDDEN_NAVEXPOSED);
-      break;
-
-    case ConfigDescription::NAVHIDDEN_YES:
-      out_pb_config->set_nav_hidden(pb::Configuration_NavHidden_NAV_HIDDEN_NAVHIDDEN);
-      break;
-  }
-
-  switch (config.navigation) {
-    case ConfigDescription::NAVIGATION_NONAV:
-      out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_NONAV);
-      break;
-
-    case ConfigDescription::NAVIGATION_DPAD:
-      out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_DPAD);
-      break;
-
-    case ConfigDescription::NAVIGATION_TRACKBALL:
-      out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_TRACKBALL);
-      break;
-
-    case ConfigDescription::NAVIGATION_WHEEL:
-      out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_WHEEL);
-      break;
-  }
-
-  out_pb_config->set_sdk_version(config.sdkVersion);
-}
-
-bool DeserializeConfigDescriptionFromPb(const pb::Configuration& pb_config,
-                                        ConfigDescription* out_config) {
-  out_config->mcc = static_cast<uint16_t>(pb_config.mcc());
-  out_config->mnc = static_cast<uint16_t>(pb_config.mnc());
-
-  if (!pb_config.locale().empty()) {
-    LocaleValue lv;
-    if (!lv.InitFromBcp47Tag(pb_config.locale())) {
-      return false;
-    }
-    lv.WriteTo(out_config);
-  }
-
-  switch (pb_config.layout_direction()) {
-    case pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_LTR:
-      out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_LAYOUTDIR) |
-                                 ConfigDescription::LAYOUTDIR_LTR;
-      break;
-
-    case pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_RTL:
-      out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_LAYOUTDIR) |
-                                 ConfigDescription::LAYOUTDIR_RTL;
-      break;
-
-    default:
-      break;
-  }
-
-  out_config->smallestScreenWidthDp = static_cast<uint16_t>(pb_config.smallest_screen_width_dp());
-  out_config->screenWidthDp = static_cast<uint16_t>(pb_config.screen_width_dp());
-  out_config->screenHeightDp = static_cast<uint16_t>(pb_config.screen_height_dp());
-
-  switch (pb_config.screen_layout_size()) {
-    case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_SMALL:
-      out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) |
-                                 ConfigDescription::SCREENSIZE_SMALL;
-      break;
-
-    case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_NORMAL:
-      out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) |
-                                 ConfigDescription::SCREENSIZE_NORMAL;
-      break;
-
-    case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_LARGE:
-      out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) |
-                                 ConfigDescription::SCREENSIZE_LARGE;
-      break;
-
-    case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_XLARGE:
-      out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) |
-                                 ConfigDescription::SCREENSIZE_XLARGE;
-      break;
-
-    default:
-      break;
-  }
-
-  switch (pb_config.screen_layout_long()) {
-    case pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_LONG:
-      out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENLONG) |
-                                 ConfigDescription::SCREENLONG_YES;
-      break;
-
-    case pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_NOTLONG:
-      out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENLONG) |
-                                 ConfigDescription::SCREENLONG_NO;
-      break;
-
-    default:
-      break;
-  }
-
-  switch (pb_config.screen_round()) {
-    case pb::Configuration_ScreenRound_SCREEN_ROUND_ROUND:
-      out_config->screenLayout2 =
-          (out_config->screenLayout2 & ~ConfigDescription::MASK_SCREENROUND) |
-          ConfigDescription::SCREENROUND_YES;
-      break;
-
-    case pb::Configuration_ScreenRound_SCREEN_ROUND_NOTROUND:
-      out_config->screenLayout2 =
-          (out_config->screenLayout2 & ~ConfigDescription::MASK_SCREENROUND) |
-          ConfigDescription::SCREENROUND_NO;
-      break;
-
-    default:
-      break;
-  }
-
-  switch (pb_config.wide_color_gamut()) {
-    case pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_WIDECG:
-      out_config->colorMode = (out_config->colorMode & ~ConfigDescription::MASK_WIDE_COLOR_GAMUT) |
-                              ConfigDescription::WIDE_COLOR_GAMUT_YES;
-      break;
-
-    case pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_NOWIDECG:
-      out_config->colorMode = (out_config->colorMode & ~ConfigDescription::MASK_WIDE_COLOR_GAMUT) |
-                              ConfigDescription::WIDE_COLOR_GAMUT_NO;
-      break;
-
-    default:
-      break;
-  }
-
-  switch (pb_config.hdr()) {
-    case pb::Configuration_Hdr_HDR_HIGHDR:
-      out_config->colorMode =
-          (out_config->colorMode & ~ConfigDescription::MASK_HDR) | ConfigDescription::HDR_YES;
-      break;
-
-    case pb::Configuration_Hdr_HDR_LOWDR:
-      out_config->colorMode =
-          (out_config->colorMode & ~ConfigDescription::MASK_HDR) | ConfigDescription::HDR_NO;
-      break;
-
-    default:
-      break;
-  }
-
-  switch (pb_config.orientation()) {
-    case pb::Configuration_Orientation_ORIENTATION_PORT:
-      out_config->orientation = ConfigDescription::ORIENTATION_PORT;
-      break;
-
-    case pb::Configuration_Orientation_ORIENTATION_LAND:
-      out_config->orientation = ConfigDescription::ORIENTATION_LAND;
-      break;
-
-    case pb::Configuration_Orientation_ORIENTATION_SQUARE:
-      out_config->orientation = ConfigDescription::ORIENTATION_SQUARE;
-      break;
-
-    default:
-      break;
-  }
-
-  switch (pb_config.ui_mode_type()) {
-    case pb::Configuration_UiModeType_UI_MODE_TYPE_NORMAL:
-      out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
-                           ConfigDescription::UI_MODE_TYPE_NORMAL;
-      break;
-
-    case pb::Configuration_UiModeType_UI_MODE_TYPE_DESK:
-      out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
-                           ConfigDescription::UI_MODE_TYPE_DESK;
-      break;
-
-    case pb::Configuration_UiModeType_UI_MODE_TYPE_CAR:
-      out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
-                           ConfigDescription::UI_MODE_TYPE_CAR;
-      break;
-
-    case pb::Configuration_UiModeType_UI_MODE_TYPE_TELEVISION:
-      out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
-                           ConfigDescription::UI_MODE_TYPE_TELEVISION;
-      break;
-
-    case pb::Configuration_UiModeType_UI_MODE_TYPE_APPLIANCE:
-      out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
-                           ConfigDescription::UI_MODE_TYPE_APPLIANCE;
-      break;
-
-    case pb::Configuration_UiModeType_UI_MODE_TYPE_WATCH:
-      out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
-                           ConfigDescription::UI_MODE_TYPE_WATCH;
-      break;
-
-    case pb::Configuration_UiModeType_UI_MODE_TYPE_VRHEADSET:
-      out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
-                           ConfigDescription::UI_MODE_TYPE_VR_HEADSET;
-      break;
-
-    default:
-      break;
-  }
-
-  switch (pb_config.ui_mode_night()) {
-    case pb::Configuration_UiModeNight_UI_MODE_NIGHT_NIGHT:
-      out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_NIGHT) |
-                           ConfigDescription::UI_MODE_NIGHT_YES;
-      break;
-
-    case pb::Configuration_UiModeNight_UI_MODE_NIGHT_NOTNIGHT:
-      out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_NIGHT) |
-                           ConfigDescription::UI_MODE_NIGHT_NO;
-      break;
-
-    default:
-      break;
-  }
-
-  out_config->density = static_cast<uint16_t>(pb_config.density());
-
-  switch (pb_config.touchscreen()) {
-    case pb::Configuration_Touchscreen_TOUCHSCREEN_NOTOUCH:
-      out_config->touchscreen = ConfigDescription::TOUCHSCREEN_NOTOUCH;
-      break;
-
-    case pb::Configuration_Touchscreen_TOUCHSCREEN_STYLUS:
-      out_config->touchscreen = ConfigDescription::TOUCHSCREEN_STYLUS;
-      break;
-
-    case pb::Configuration_Touchscreen_TOUCHSCREEN_FINGER:
-      out_config->touchscreen = ConfigDescription::TOUCHSCREEN_FINGER;
-      break;
-
-    default:
-      break;
-  }
-
-  switch (pb_config.keys_hidden()) {
-    case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSEXPOSED:
-      out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) |
-                               ConfigDescription::KEYSHIDDEN_NO;
-      break;
-
-    case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSHIDDEN:
-      out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) |
-                               ConfigDescription::KEYSHIDDEN_YES;
-      break;
-
-    case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSSOFT:
-      out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) |
-                               ConfigDescription::KEYSHIDDEN_SOFT;
-      break;
-
-    default:
-      break;
-  }
-
-  switch (pb_config.keyboard()) {
-    case pb::Configuration_Keyboard_KEYBOARD_NOKEYS:
-      out_config->keyboard = ConfigDescription::KEYBOARD_NOKEYS;
-      break;
-
-    case pb::Configuration_Keyboard_KEYBOARD_QWERTY:
-      out_config->keyboard = ConfigDescription::KEYBOARD_QWERTY;
-      break;
-
-    case pb::Configuration_Keyboard_KEYBOARD_TWELVEKEY:
-      out_config->keyboard = ConfigDescription::KEYBOARD_12KEY;
-      break;
-
-    default:
-      break;
-  }
-
-  switch (pb_config.nav_hidden()) {
-    case pb::Configuration_NavHidden_NAV_HIDDEN_NAVEXPOSED:
-      out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_NAVHIDDEN) |
-                               ConfigDescription::NAVHIDDEN_NO;
-      break;
-
-    case pb::Configuration_NavHidden_NAV_HIDDEN_NAVHIDDEN:
-      out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_NAVHIDDEN) |
-                               ConfigDescription::NAVHIDDEN_YES;
-      break;
-
-    default:
-      break;
-  }
-
-  switch (pb_config.navigation()) {
-    case pb::Configuration_Navigation_NAVIGATION_NONAV:
-      out_config->navigation = ConfigDescription::NAVIGATION_NONAV;
-      break;
-
-    case pb::Configuration_Navigation_NAVIGATION_DPAD:
-      out_config->navigation = ConfigDescription::NAVIGATION_DPAD;
-      break;
-
-    case pb::Configuration_Navigation_NAVIGATION_TRACKBALL:
-      out_config->navigation = ConfigDescription::NAVIGATION_TRACKBALL;
-      break;
-
-    case pb::Configuration_Navigation_NAVIGATION_WHEEL:
-      out_config->navigation = ConfigDescription::NAVIGATION_WHEEL;
-      break;
-
-    default:
-      break;
-  }
-
-  out_config->screenWidth = static_cast<uint16_t>(pb_config.screen_width());
-  out_config->screenHeight = static_cast<uint16_t>(pb_config.screen_height());
-  out_config->sdkVersion = static_cast<uint16_t>(pb_config.sdk_version());
-  return true;
-}
-
-pb::Reference_Type SerializeReferenceTypeToPb(Reference::Type type) {
-  switch (type) {
-    case Reference::Type::kResource:
-      return pb::Reference_Type_REFERENCE;
-    case Reference::Type::kAttribute:
-      return pb::Reference_Type_ATTRIBUTE;
-    default:
-      break;
-  }
-  return pb::Reference_Type_REFERENCE;
-}
-
-Reference::Type DeserializeReferenceTypeFromPb(pb::Reference_Type pb_type) {
-  switch (pb_type) {
-    case pb::Reference_Type_REFERENCE:
-      return Reference::Type::kResource;
-    case pb::Reference_Type_ATTRIBUTE:
-      return Reference::Type::kAttribute;
-    default:
-      break;
-  }
-  return Reference::Type::kResource;
-}
-
-pb::Plural_Arity SerializePluralEnumToPb(size_t plural_idx) {
-  switch (plural_idx) {
-    case Plural::Zero:
-      return pb::Plural_Arity_ZERO;
-    case Plural::One:
-      return pb::Plural_Arity_ONE;
-    case Plural::Two:
-      return pb::Plural_Arity_TWO;
-    case Plural::Few:
-      return pb::Plural_Arity_FEW;
-    case Plural::Many:
-      return pb::Plural_Arity_MANY;
-    default:
-      break;
-  }
-  return pb::Plural_Arity_OTHER;
-}
-
-size_t DeserializePluralEnumFromPb(pb::Plural_Arity arity) {
-  switch (arity) {
-    case pb::Plural_Arity_ZERO:
-      return Plural::Zero;
-    case pb::Plural_Arity_ONE:
-      return Plural::One;
-    case pb::Plural_Arity_TWO:
-      return Plural::Two;
-    case pb::Plural_Arity_FEW:
-      return Plural::Few;
-    case pb::Plural_Arity_MANY:
-      return Plural::Many;
-    default:
-      break;
-  }
-  return Plural::Other;
-}
-
-}  // namespace aapt
diff --git a/tools/aapt2/proto/ProtoHelpers.h b/tools/aapt2/proto/ProtoHelpers.h
deleted file mode 100644
index 714a2b2..0000000
--- a/tools/aapt2/proto/ProtoHelpers.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AAPT_PROTO_PROTOHELPERS_H
-#define AAPT_PROTO_PROTOHELPERS_H
-
-#include "androidfw/ResourceTypes.h"
-
-#include "ConfigDescription.h"
-#include "Configuration.pb.h"
-#include "ResourceTable.h"
-#include "Resources.pb.h"
-#include "ResourcesInternal.pb.h"
-#include "Source.h"
-#include "StringPool.h"
-
-namespace aapt {
-
-void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool);
-
-void SerializeSourceToPb(const Source& source, StringPool* src_pool, pb::Source* out_pb_source);
-
-void DeserializeSourceFromPb(const pb::Source& pb_source, const android::ResStringPool& src_pool,
-                             Source* out_source);
-
-pb::SymbolStatus_Visibility SerializeVisibilityToPb(SymbolState state);
-
-SymbolState DeserializeVisibilityFromPb(pb::SymbolStatus_Visibility pb_visibility);
-
-void SerializeConfig(const ConfigDescription& config, pb::Configuration* out_pb_config);
-
-bool DeserializeConfigDescriptionFromPb(const pb::Configuration& pb_config,
-                                        ConfigDescription* out_config);
-
-pb::Reference_Type SerializeReferenceTypeToPb(Reference::Type type);
-
-Reference::Type DeserializeReferenceTypeFromPb(pb::Reference_Type pb_type);
-
-pb::Plural_Arity SerializePluralEnumToPb(size_t plural_idx);
-
-size_t DeserializePluralEnumFromPb(pb::Plural_Arity arity);
-
-}  // namespace aapt
-
-#endif /* AAPT_PROTO_PROTOHELPERS_H */
diff --git a/tools/aapt2/proto/ProtoSerialize.cpp b/tools/aapt2/proto/ProtoSerialize.cpp
new file mode 100644
index 0000000..d36d668
--- /dev/null
+++ b/tools/aapt2/proto/ProtoSerialize.cpp
@@ -0,0 +1,622 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "proto/ProtoSerialize.h"
+
+#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
+
+#include "ValueVisitor.h"
+#include "util/BigBuffer.h"
+
+using ::google::protobuf::io::CodedOutputStream;
+using ::google::protobuf::io::ZeroCopyOutputStream;
+
+namespace aapt {
+
+void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool) {
+  BigBuffer buffer(1024);
+  StringPool::FlattenUtf8(&buffer, pool);
+
+  std::string* data = out_pb_pool->mutable_data();
+  data->reserve(buffer.size());
+
+  size_t offset = 0;
+  for (const BigBuffer::Block& block : buffer) {
+    data->insert(data->begin() + offset, block.buffer.get(), block.buffer.get() + block.size);
+    offset += block.size;
+  }
+}
+
+void SerializeSourceToPb(const Source& source, StringPool* src_pool, pb::Source* out_pb_source) {
+  StringPool::Ref ref = src_pool->MakeRef(source.path);
+  out_pb_source->set_path_idx(static_cast<uint32_t>(ref.index()));
+  if (source.line) {
+    out_pb_source->mutable_position()->set_line_number(static_cast<uint32_t>(source.line.value()));
+  }
+}
+
+static pb::SymbolStatus_Visibility SerializeVisibilityToPb(SymbolState state) {
+  switch (state) {
+    case SymbolState::kPrivate:
+      return pb::SymbolStatus_Visibility_PRIVATE;
+    case SymbolState::kPublic:
+      return pb::SymbolStatus_Visibility_PUBLIC;
+    default:
+      break;
+  }
+  return pb::SymbolStatus_Visibility_UNKNOWN;
+}
+
+void SerializeConfig(const ConfigDescription& config, pb::Configuration* out_pb_config) {
+  out_pb_config->set_mcc(config.mcc);
+  out_pb_config->set_mnc(config.mnc);
+  out_pb_config->set_locale(config.GetBcp47LanguageTag());
+
+  switch (config.screenLayout & ConfigDescription::MASK_LAYOUTDIR) {
+    case ConfigDescription::LAYOUTDIR_LTR:
+      out_pb_config->set_layout_direction(pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_LTR);
+      break;
+
+    case ConfigDescription::LAYOUTDIR_RTL:
+      out_pb_config->set_layout_direction(pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_RTL);
+      break;
+  }
+
+  out_pb_config->set_screen_width(config.screenWidth);
+  out_pb_config->set_screen_height(config.screenHeight);
+  out_pb_config->set_screen_width_dp(config.screenWidthDp);
+  out_pb_config->set_screen_height_dp(config.screenHeightDp);
+  out_pb_config->set_smallest_screen_width_dp(config.smallestScreenWidthDp);
+
+  switch (config.screenLayout & ConfigDescription::MASK_SCREENSIZE) {
+    case ConfigDescription::SCREENSIZE_SMALL:
+      out_pb_config->set_screen_layout_size(
+          pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_SMALL);
+      break;
+
+    case ConfigDescription::SCREENSIZE_NORMAL:
+      out_pb_config->set_screen_layout_size(
+          pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_NORMAL);
+      break;
+
+    case ConfigDescription::SCREENSIZE_LARGE:
+      out_pb_config->set_screen_layout_size(
+          pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_LARGE);
+      break;
+
+    case ConfigDescription::SCREENSIZE_XLARGE:
+      out_pb_config->set_screen_layout_size(
+          pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_XLARGE);
+      break;
+  }
+
+  switch (config.screenLayout & ConfigDescription::MASK_SCREENLONG) {
+    case ConfigDescription::SCREENLONG_YES:
+      out_pb_config->set_screen_layout_long(
+          pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_LONG);
+      break;
+
+    case ConfigDescription::SCREENLONG_NO:
+      out_pb_config->set_screen_layout_long(
+          pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_NOTLONG);
+      break;
+  }
+
+  switch (config.screenLayout2 & ConfigDescription::MASK_SCREENROUND) {
+    case ConfigDescription::SCREENROUND_YES:
+      out_pb_config->set_screen_round(pb::Configuration_ScreenRound_SCREEN_ROUND_ROUND);
+      break;
+
+    case ConfigDescription::SCREENROUND_NO:
+      out_pb_config->set_screen_round(pb::Configuration_ScreenRound_SCREEN_ROUND_NOTROUND);
+      break;
+  }
+
+  switch (config.colorMode & ConfigDescription::MASK_WIDE_COLOR_GAMUT) {
+    case ConfigDescription::WIDE_COLOR_GAMUT_YES:
+      out_pb_config->set_wide_color_gamut(pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_WIDECG);
+      break;
+
+    case ConfigDescription::WIDE_COLOR_GAMUT_NO:
+      out_pb_config->set_wide_color_gamut(
+          pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_NOWIDECG);
+      break;
+  }
+
+  switch (config.colorMode & ConfigDescription::MASK_HDR) {
+    case ConfigDescription::HDR_YES:
+      out_pb_config->set_hdr(pb::Configuration_Hdr_HDR_HIGHDR);
+      break;
+
+    case ConfigDescription::HDR_NO:
+      out_pb_config->set_hdr(pb::Configuration_Hdr_HDR_LOWDR);
+      break;
+  }
+
+  switch (config.orientation) {
+    case ConfigDescription::ORIENTATION_PORT:
+      out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_PORT);
+      break;
+
+    case ConfigDescription::ORIENTATION_LAND:
+      out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_LAND);
+      break;
+
+    case ConfigDescription::ORIENTATION_SQUARE:
+      out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_SQUARE);
+      break;
+  }
+
+  switch (config.uiMode & ConfigDescription::MASK_UI_MODE_TYPE) {
+    case ConfigDescription::UI_MODE_TYPE_NORMAL:
+      out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_NORMAL);
+      break;
+
+    case ConfigDescription::UI_MODE_TYPE_DESK:
+      out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_DESK);
+      break;
+
+    case ConfigDescription::UI_MODE_TYPE_CAR:
+      out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_CAR);
+      break;
+
+    case ConfigDescription::UI_MODE_TYPE_TELEVISION:
+      out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_TELEVISION);
+      break;
+
+    case ConfigDescription::UI_MODE_TYPE_APPLIANCE:
+      out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_APPLIANCE);
+      break;
+
+    case ConfigDescription::UI_MODE_TYPE_WATCH:
+      out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_WATCH);
+      break;
+
+    case ConfigDescription::UI_MODE_TYPE_VR_HEADSET:
+      out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_VRHEADSET);
+      break;
+  }
+
+  switch (config.uiMode & ConfigDescription::MASK_UI_MODE_NIGHT) {
+    case ConfigDescription::UI_MODE_NIGHT_YES:
+      out_pb_config->set_ui_mode_night(pb::Configuration_UiModeNight_UI_MODE_NIGHT_NIGHT);
+      break;
+
+    case ConfigDescription::UI_MODE_NIGHT_NO:
+      out_pb_config->set_ui_mode_night(pb::Configuration_UiModeNight_UI_MODE_NIGHT_NOTNIGHT);
+      break;
+  }
+
+  out_pb_config->set_density(config.density);
+
+  switch (config.touchscreen) {
+    case ConfigDescription::TOUCHSCREEN_NOTOUCH:
+      out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_NOTOUCH);
+      break;
+
+    case ConfigDescription::TOUCHSCREEN_STYLUS:
+      out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_STYLUS);
+      break;
+
+    case ConfigDescription::TOUCHSCREEN_FINGER:
+      out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_FINGER);
+      break;
+  }
+
+  switch (config.inputFlags & ConfigDescription::MASK_KEYSHIDDEN) {
+    case ConfigDescription::KEYSHIDDEN_NO:
+      out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSEXPOSED);
+      break;
+
+    case ConfigDescription::KEYSHIDDEN_YES:
+      out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSHIDDEN);
+      break;
+
+    case ConfigDescription::KEYSHIDDEN_SOFT:
+      out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSSOFT);
+      break;
+  }
+
+  switch (config.keyboard) {
+    case ConfigDescription::KEYBOARD_NOKEYS:
+      out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_NOKEYS);
+      break;
+
+    case ConfigDescription::KEYBOARD_QWERTY:
+      out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_QWERTY);
+      break;
+
+    case ConfigDescription::KEYBOARD_12KEY:
+      out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_TWELVEKEY);
+      break;
+  }
+
+  switch (config.inputFlags & ConfigDescription::MASK_NAVHIDDEN) {
+    case ConfigDescription::NAVHIDDEN_NO:
+      out_pb_config->set_nav_hidden(pb::Configuration_NavHidden_NAV_HIDDEN_NAVEXPOSED);
+      break;
+
+    case ConfigDescription::NAVHIDDEN_YES:
+      out_pb_config->set_nav_hidden(pb::Configuration_NavHidden_NAV_HIDDEN_NAVHIDDEN);
+      break;
+  }
+
+  switch (config.navigation) {
+    case ConfigDescription::NAVIGATION_NONAV:
+      out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_NONAV);
+      break;
+
+    case ConfigDescription::NAVIGATION_DPAD:
+      out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_DPAD);
+      break;
+
+    case ConfigDescription::NAVIGATION_TRACKBALL:
+      out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_TRACKBALL);
+      break;
+
+    case ConfigDescription::NAVIGATION_WHEEL:
+      out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_WHEEL);
+      break;
+  }
+
+  out_pb_config->set_sdk_version(config.sdkVersion);
+}
+
+void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table) {
+  StringPool source_pool;
+  for (const std::unique_ptr<ResourceTablePackage>& package : table.packages) {
+    pb::Package* pb_package = out_table->add_package();
+    if (package->id) {
+      pb_package->mutable_package_id()->set_id(package->id.value());
+    }
+    pb_package->set_package_name(package->name);
+
+    for (const std::unique_ptr<ResourceTableType>& type : package->types) {
+      pb::Type* pb_type = pb_package->add_type();
+      if (type->id) {
+        pb_type->mutable_type_id()->set_id(type->id.value());
+      }
+      pb_type->set_name(ToString(type->type).to_string());
+
+      for (const std::unique_ptr<ResourceEntry>& entry : type->entries) {
+        pb::Entry* pb_entry = pb_type->add_entry();
+        if (entry->id) {
+          pb_entry->mutable_entry_id()->set_id(entry->id.value());
+        }
+        pb_entry->set_name(entry->name);
+
+        // Write the SymbolStatus struct.
+        pb::SymbolStatus* pb_status = pb_entry->mutable_symbol_status();
+        pb_status->set_visibility(SerializeVisibilityToPb(entry->symbol_status.state));
+        SerializeSourceToPb(entry->symbol_status.source, &source_pool, pb_status->mutable_source());
+        pb_status->set_comment(entry->symbol_status.comment);
+        pb_status->set_allow_new(entry->symbol_status.allow_new);
+
+        for (const std::unique_ptr<ResourceConfigValue>& config_value : entry->values) {
+          pb::ConfigValue* pb_config_value = pb_entry->add_config_value();
+          SerializeConfig(config_value->config, pb_config_value->mutable_config());
+          pb_config_value->mutable_config()->set_product(config_value->product);
+          SerializeValueToPb(*config_value->value, pb_config_value->mutable_value(), &source_pool);
+        }
+      }
+    }
+  }
+  SerializeStringPoolToPb(source_pool, out_table->mutable_source_pool());
+}
+
+static pb::Reference_Type SerializeReferenceTypeToPb(Reference::Type type) {
+  switch (type) {
+    case Reference::Type::kResource:
+      return pb::Reference_Type_REFERENCE;
+    case Reference::Type::kAttribute:
+      return pb::Reference_Type_ATTRIBUTE;
+    default:
+      break;
+  }
+  return pb::Reference_Type_REFERENCE;
+}
+
+static void SerializeReferenceToPb(const Reference& ref, pb::Reference* pb_ref) {
+  pb_ref->set_id(ref.id.value_or_default(ResourceId(0x0)).id);
+
+  if (ref.name) {
+    pb_ref->set_name(ref.name.value().ToString());
+  }
+
+  pb_ref->set_private_(ref.private_reference);
+  pb_ref->set_type(SerializeReferenceTypeToPb(ref.reference_type));
+}
+
+template <typename T>
+static void SerializeItemMetaDataToPb(const Item& item, T* pb_item, StringPool* src_pool) {
+  if (src_pool != nullptr) {
+    SerializeSourceToPb(item.GetSource(), src_pool, pb_item->mutable_source());
+  }
+  pb_item->set_comment(item.GetComment());
+}
+
+static pb::Plural_Arity SerializePluralEnumToPb(size_t plural_idx) {
+  switch (plural_idx) {
+    case Plural::Zero:
+      return pb::Plural_Arity_ZERO;
+    case Plural::One:
+      return pb::Plural_Arity_ONE;
+    case Plural::Two:
+      return pb::Plural_Arity_TWO;
+    case Plural::Few:
+      return pb::Plural_Arity_FEW;
+    case Plural::Many:
+      return pb::Plural_Arity_MANY;
+    default:
+      break;
+  }
+  return pb::Plural_Arity_OTHER;
+}
+
+namespace {
+
+class ValueSerializer : public ConstValueVisitor {
+ public:
+  using ConstValueVisitor::Visit;
+
+  ValueSerializer(pb::Value* out_value, StringPool* src_pool)
+      : out_value_(out_value), src_pool_(src_pool) {
+  }
+
+  void Visit(const Reference* ref) override {
+    SerializeReferenceToPb(*ref, out_value_->mutable_item()->mutable_ref());
+  }
+
+  void Visit(const String* str) override {
+    out_value_->mutable_item()->mutable_str()->set_value(*str->value);
+  }
+
+  void Visit(const RawString* str) override {
+    out_value_->mutable_item()->mutable_raw_str()->set_value(*str->value);
+  }
+
+  void Visit(const StyledString* str) override {
+    pb::StyledString* pb_str = out_value_->mutable_item()->mutable_styled_str();
+    pb_str->set_value(str->value->value);
+    for (const StringPool::Span& span : str->value->spans) {
+      pb::StyledString::Span* pb_span = pb_str->add_span();
+      pb_span->set_tag(*span.name);
+      pb_span->set_first_char(span.first_char);
+      pb_span->set_last_char(span.last_char);
+    }
+  }
+
+  void Visit(const FileReference* file) override {
+    out_value_->mutable_item()->mutable_file()->set_path(*file->path);
+  }
+
+  void Visit(const Id* /*id*/) override {
+    out_value_->mutable_item()->mutable_id();
+  }
+
+  void Visit(const BinaryPrimitive* prim) override {
+    android::Res_value val = {};
+    prim->Flatten(&val);
+
+    pb::Primitive* pb_prim = out_value_->mutable_item()->mutable_prim();
+    pb_prim->set_type(val.dataType);
+    pb_prim->set_data(val.data);
+  }
+
+  void Visit(const Attribute* attr) override {
+    pb::Attribute* pb_attr = out_value_->mutable_compound_value()->mutable_attr();
+    pb_attr->set_format_flags(attr->type_mask);
+    pb_attr->set_min_int(attr->min_int);
+    pb_attr->set_max_int(attr->max_int);
+
+    for (auto& symbol : attr->symbols) {
+      pb::Attribute_Symbol* pb_symbol = pb_attr->add_symbol();
+      SerializeItemMetaDataToPb(symbol.symbol, pb_symbol, src_pool_);
+      SerializeReferenceToPb(symbol.symbol, pb_symbol->mutable_name());
+      pb_symbol->set_value(symbol.value);
+    }
+  }
+
+  void Visit(const Style* style) override {
+    pb::Style* pb_style = out_value_->mutable_compound_value()->mutable_style();
+    if (style->parent) {
+      const Reference& parent = style->parent.value();
+      SerializeReferenceToPb(parent, pb_style->mutable_parent());
+      if (src_pool_ != nullptr) {
+        SerializeSourceToPb(parent.GetSource(), src_pool_, pb_style->mutable_parent_source());
+      }
+    }
+
+    for (const Style::Entry& entry : style->entries) {
+      pb::Style_Entry* pb_entry = pb_style->add_entry();
+      SerializeReferenceToPb(entry.key, pb_entry->mutable_key());
+      SerializeItemMetaDataToPb(entry.key, pb_entry, src_pool_);
+      SerializeItemToPb(*entry.value, pb_entry->mutable_item());
+    }
+  }
+
+  void Visit(const Styleable* styleable) override {
+    pb::Styleable* pb_styleable = out_value_->mutable_compound_value()->mutable_styleable();
+    for (const Reference& entry : styleable->entries) {
+      pb::Styleable_Entry* pb_entry = pb_styleable->add_entry();
+      SerializeItemMetaDataToPb(entry, pb_entry, src_pool_);
+      SerializeReferenceToPb(entry, pb_entry->mutable_attr());
+    }
+  }
+
+  void Visit(const Array* array) override {
+    pb::Array* pb_array = out_value_->mutable_compound_value()->mutable_array();
+    for (const std::unique_ptr<Item>& element : array->elements) {
+      pb::Array_Element* pb_element = pb_array->add_element();
+      SerializeItemMetaDataToPb(*element, pb_element, src_pool_);
+      SerializeItemToPb(*element, pb_element->mutable_item());
+    }
+  }
+
+  void Visit(const Plural* plural) override {
+    pb::Plural* pb_plural = out_value_->mutable_compound_value()->mutable_plural();
+    const size_t count = plural->values.size();
+    for (size_t i = 0; i < count; i++) {
+      if (!plural->values[i]) {
+        // No plural value set here.
+        continue;
+      }
+
+      pb::Plural_Entry* pb_entry = pb_plural->add_entry();
+      pb_entry->set_arity(SerializePluralEnumToPb(i));
+      SerializeItemMetaDataToPb(*plural->values[i], pb_entry, src_pool_);
+      SerializeItemToPb(*plural->values[i], pb_entry->mutable_item());
+    }
+  }
+
+  void VisitAny(const Value* unknown) override {
+    LOG(FATAL) << "unimplemented value: " << *unknown;
+  }
+
+ private:
+  pb::Value* out_value_;
+  StringPool* src_pool_;
+};
+
+}  // namespace
+
+void SerializeValueToPb(const Value& value, pb::Value* out_value, StringPool* src_pool) {
+  ValueSerializer serializer(out_value, src_pool);
+  value.Accept(&serializer);
+
+  // Serialize the meta-data of the Value.
+  out_value->set_comment(value.GetComment());
+  out_value->set_weak(value.IsWeak());
+  if (src_pool != nullptr) {
+    SerializeSourceToPb(value.GetSource(), src_pool, out_value->mutable_source());
+  }
+}
+
+void SerializeItemToPb(const Item& item, pb::Item* out_item) {
+  pb::Value value;
+  ValueSerializer serializer(&value, nullptr);
+  item.Accept(&serializer);
+  out_item->MergeFrom(value.item());
+}
+
+void SerializeCompiledFileToPb(const ResourceFile& file, pb::internal::CompiledFile* out_file) {
+  out_file->set_resource_name(file.name.ToString());
+  out_file->set_source_path(file.source.path);
+  SerializeConfig(file.config, out_file->mutable_config());
+
+  for (const SourcedResourceName& exported : file.exported_symbols) {
+    pb::internal::CompiledFile_Symbol* pb_symbol = out_file->add_exported_symbol();
+    pb_symbol->set_resource_name(exported.name.ToString());
+    pb_symbol->mutable_source()->set_line_number(exported.line);
+  }
+}
+
+static void SerializeXmlCommon(const xml::Node& node, pb::XmlNode* out_node) {
+  pb::SourcePosition* pb_src = out_node->mutable_source();
+  pb_src->set_line_number(node.line_number);
+  pb_src->set_column_number(node.column_number);
+}
+
+void SerializeXmlToPb(const xml::Element& el, pb::XmlNode* out_node) {
+  SerializeXmlCommon(el, out_node);
+
+  pb::XmlElement* pb_element = out_node->mutable_element();
+  pb_element->set_name(el.name);
+  pb_element->set_namespace_uri(el.namespace_uri);
+
+  for (const xml::NamespaceDecl& ns : el.namespace_decls) {
+    pb::XmlNamespace* pb_ns = pb_element->add_namespace_declaration();
+    pb_ns->set_prefix(ns.prefix);
+    pb_ns->set_uri(ns.uri);
+    pb::SourcePosition* pb_src = pb_ns->mutable_source();
+    pb_src->set_line_number(ns.line_number);
+    pb_src->set_column_number(ns.column_number);
+  }
+
+  for (const xml::Attribute& attr : el.attributes) {
+    pb::XmlAttribute* pb_attr = pb_element->add_attribute();
+    pb_attr->set_name(attr.name);
+    pb_attr->set_namespace_uri(attr.namespace_uri);
+    pb_attr->set_value(attr.value);
+    if (attr.compiled_attribute) {
+      const ResourceId attr_id = attr.compiled_attribute.value().id.value_or_default({});
+      pb_attr->set_resource_id(attr_id.id);
+    }
+    if (attr.compiled_value != nullptr) {
+      SerializeItemToPb(*attr.compiled_value, pb_attr->mutable_compiled_item());
+      pb::SourcePosition* pb_src = pb_attr->mutable_source();
+      pb_src->set_line_number(attr.compiled_value->GetSource().line.value_or_default(0));
+    }
+  }
+
+  for (const std::unique_ptr<xml::Node>& child : el.children) {
+    if (const xml::Element* child_el = xml::NodeCast<xml::Element>(child.get())) {
+      SerializeXmlToPb(*child_el, pb_element->add_child());
+    } else if (const xml::Text* text_el = xml::NodeCast<xml::Text>(child.get())) {
+      pb::XmlNode* pb_child_node = pb_element->add_child();
+      SerializeXmlCommon(*text_el, pb_child_node);
+      pb_child_node->set_text(text_el->text);
+    } else {
+      LOG(FATAL) << "unhandled XmlNode type";
+    }
+  }
+}
+
+void SerializeXmlResourceToPb(const xml::XmlResource& resource, pb::XmlNode* out_node) {
+  SerializeXmlToPb(*resource.root, out_node);
+}
+
+CompiledFileOutputStream::CompiledFileOutputStream(ZeroCopyOutputStream* out) : out_(out) {
+}
+
+void CompiledFileOutputStream::EnsureAlignedWrite() {
+  const int overflow = out_.ByteCount() % 4;
+  if (overflow > 0) {
+    uint32_t zero = 0u;
+    out_.WriteRaw(&zero, 4 - overflow);
+  }
+}
+
+void CompiledFileOutputStream::WriteLittleEndian32(uint32_t val) {
+  EnsureAlignedWrite();
+  out_.WriteLittleEndian32(val);
+}
+
+void CompiledFileOutputStream::WriteCompiledFile(const pb::internal::CompiledFile& compiled_file) {
+  EnsureAlignedWrite();
+  out_.WriteLittleEndian64(static_cast<uint64_t>(compiled_file.ByteSize()));
+  compiled_file.SerializeWithCachedSizes(&out_);
+}
+
+void CompiledFileOutputStream::WriteData(const BigBuffer& buffer) {
+  EnsureAlignedWrite();
+  out_.WriteLittleEndian64(static_cast<uint64_t>(buffer.size()));
+  for (const BigBuffer::Block& block : buffer) {
+    out_.WriteRaw(block.buffer.get(), block.size);
+  }
+}
+
+void CompiledFileOutputStream::WriteData(const void* data, size_t len) {
+  EnsureAlignedWrite();
+  out_.WriteLittleEndian64(static_cast<uint64_t>(len));
+  out_.WriteRaw(data, len);
+}
+
+bool CompiledFileOutputStream::HadError() {
+  return out_.HadError();
+}
+
+}  // namespace aapt
diff --git a/tools/aapt2/proto/ProtoSerialize.h b/tools/aapt2/proto/ProtoSerialize.h
index 8c46642..4bf7e1c 100644
--- a/tools/aapt2/proto/ProtoSerialize.h
+++ b/tools/aapt2/proto/ProtoSerialize.h
@@ -19,22 +19,60 @@
 
 #include "android-base/macros.h"
 #include "google/protobuf/io/coded_stream.h"
-#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
 
-#include "Diagnostics.h"
+#include "ConfigDescription.h"
+#include "Configuration.pb.h"
 #include "ResourceTable.h"
-#include "Source.h"
-#include "proto/ProtoHelpers.h"
+#include "ResourceValues.h"
+#include "Resources.pb.h"
+#include "ResourcesInternal.pb.h"
+#include "StringPool.h"
+#include "xml/XmlDom.h"
+
+namespace google {
+namespace protobuf {
+namespace io {
+class ZeroCopyOutputStream;
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
 
 namespace aapt {
 
+// Serializes a Value to its protobuf representation. An optional StringPool will hold the
+// source path string.
+void SerializeValueToPb(const Value& value, pb::Value* out_value, StringPool* src_pool = nullptr);
+
+// Serialize an Item into its protobuf representation. pb::Item does not store the source path nor
+// comments of an Item.
+void SerializeItemToPb(const Item& item, pb::Item* out_item);
+
+// Serializes an XML element into its protobuf representation.
+void SerializeXmlToPb(const xml::Element& el, pb::XmlNode* out_node);
+
+// Serializes an XmlResource into its protobuf representation. The ResourceFile is NOT serialized.
+void SerializeXmlResourceToPb(const xml::XmlResource& resource, pb::XmlNode* out_node);
+
+// Serializes a StringPool into its protobuf representation, which is really just the binary
+// ResStringPool representation stuffed into a bytes field.
+void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool);
+
+// Serializes a ConfigDescription into its protobuf representation.
+void SerializeConfig(const ConfigDescription& config, pb::Configuration* out_pb_config);
+
+// Serializes a ResourceTable into its protobuf representation.
+void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table);
+
+// Serializes a ResourceFile into its protobuf representation.
+void SerializeCompiledFileToPb(const ResourceFile& file, pb::internal::CompiledFile* out_file);
+
 class CompiledFileOutputStream {
  public:
-  explicit CompiledFileOutputStream(google::protobuf::io::ZeroCopyOutputStream* out);
+  explicit CompiledFileOutputStream(::google::protobuf::io::ZeroCopyOutputStream* out);
 
   void WriteLittleEndian32(uint32_t value);
-  void WriteCompiledFile(const pb::internal::CompiledFile* compiledFile);
-  void WriteData(const BigBuffer* buffer);
+  void WriteCompiledFile(const pb::internal::CompiledFile& compiledFile);
+  void WriteData(const BigBuffer& buffer);
   void WriteData(const void* data, size_t len);
   bool HadError();
 
@@ -43,33 +81,9 @@
 
   void EnsureAlignedWrite();
 
-  google::protobuf::io::CodedOutputStream out_;
+  ::google::protobuf::io::CodedOutputStream out_;
 };
 
-class CompiledFileInputStream {
- public:
-  explicit CompiledFileInputStream(const void* data, size_t size);
-
-  bool ReadLittleEndian32(uint32_t* outVal);
-  bool ReadCompiledFile(pb::internal::CompiledFile* outVal);
-  bool ReadDataMetaData(uint64_t* outOffset, uint64_t* outLen);
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(CompiledFileInputStream);
-
-  void EnsureAlignedRead();
-
-  google::protobuf::io::CodedInputStream in_;
-};
-
-std::unique_ptr<pb::ResourceTable> SerializeTableToPb(ResourceTable* table);
-std::unique_ptr<ResourceTable> DeserializeTableFromPb(const pb::ResourceTable& pbTable,
-                                                      const Source& source, IDiagnostics* diag);
-
-std::unique_ptr<pb::internal::CompiledFile> SerializeCompiledFileToPb(const ResourceFile& file);
-std::unique_ptr<ResourceFile> DeserializeCompiledFileFromPb(
-    const pb::internal::CompiledFile& pbFile, const Source& source, IDiagnostics* diag);
-
 }  // namespace aapt
 
 #endif /* AAPT_FLATTEN_TABLEPROTOSERIALIZER_H */
diff --git a/tools/aapt2/proto/ProtoSerialize_test.cpp b/tools/aapt2/proto/ProtoSerialize_test.cpp
new file mode 100644
index 0000000..b263aff
--- /dev/null
+++ b/tools/aapt2/proto/ProtoSerialize_test.cpp
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "proto/ProtoSerialize.h"
+
+#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
+
+#include "ResourceUtils.h"
+#include "proto/ProtoDeserialize.h"
+#include "test/Test.h"
+
+using ::android::StringPiece;
+using ::google::protobuf::io::StringOutputStream;
+using ::testing::Eq;
+using ::testing::IsEmpty;
+using ::testing::NotNull;
+using ::testing::SizeIs;
+using ::testing::StrEq;
+
+namespace aapt {
+
+TEST(ProtoSerializeTest, SerializeSinglePackage) {
+  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+  std::unique_ptr<ResourceTable> table =
+      test::ResourceTableBuilder()
+          .SetPackageId("com.app.a", 0x7f)
+          .AddFileReference("com.app.a:layout/main", ResourceId(0x7f020000), "res/layout/main.xml")
+          .AddReference("com.app.a:layout/other", ResourceId(0x7f020001), "com.app.a:layout/main")
+          .AddString("com.app.a:string/text", {}, "hi")
+          .AddValue("com.app.a:id/foo", {}, util::make_unique<Id>())
+          .SetSymbolState("com.app.a:bool/foo", {}, SymbolState::kUndefined, true /*allow_new*/)
+          .Build();
+
+  Symbol public_symbol;
+  public_symbol.state = SymbolState::kPublic;
+  ASSERT_TRUE(table->SetSymbolState(test::ParseNameOrDie("com.app.a:layout/main"),
+                                    ResourceId(0x7f020000), public_symbol,
+                                    context->GetDiagnostics()));
+
+  Id* id = test::GetValue<Id>(table.get(), "com.app.a:id/foo");
+  ASSERT_THAT(id, NotNull());
+
+  // Make a plural.
+  std::unique_ptr<Plural> plural = util::make_unique<Plural>();
+  plural->values[Plural::One] = util::make_unique<String>(table->string_pool.MakeRef("one"));
+  ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("com.app.a:plurals/hey"), ConfigDescription{},
+                                 {}, std::move(plural), context->GetDiagnostics()));
+
+  // Make a styled string.
+  StyleString style_string;
+  style_string.str = "hello";
+  style_string.spans.push_back(Span{"b", 0u, 4u});
+  ASSERT_TRUE(
+      table->AddResource(test::ParseNameOrDie("com.app.a:string/styled"), ConfigDescription{}, {},
+                         util::make_unique<StyledString>(table->string_pool.MakeRef(style_string)),
+                         context->GetDiagnostics()));
+
+  // Make a resource with different products.
+  ASSERT_TRUE(table->AddResource(
+      test::ParseNameOrDie("com.app.a:integer/one"), test::ParseConfigOrDie("land"), {},
+      test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 123u), context->GetDiagnostics()));
+  ASSERT_TRUE(table->AddResource(
+      test::ParseNameOrDie("com.app.a:integer/one"), test::ParseConfigOrDie("land"), "tablet",
+      test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 321u), context->GetDiagnostics()));
+
+  // Make a reference with both resource name and resource ID.
+  // The reference should point to a resource outside of this table to test that both name and id
+  // get serialized.
+  Reference expected_ref;
+  expected_ref.name = test::ParseNameOrDie("android:layout/main");
+  expected_ref.id = ResourceId(0x01020000);
+  ASSERT_TRUE(table->AddResource(
+      test::ParseNameOrDie("com.app.a:layout/abc"), ConfigDescription::DefaultConfig(), {},
+      util::make_unique<Reference>(expected_ref), context->GetDiagnostics()));
+
+  pb::ResourceTable pb_table;
+  SerializeTableToPb(*table, &pb_table);
+
+  ResourceTable new_table;
+  std::string error;
+  ASSERT_TRUE(DeserializeTableFromPb(pb_table, &new_table, &error));
+  EXPECT_THAT(error, IsEmpty());
+
+  Id* new_id = test::GetValue<Id>(&new_table, "com.app.a:id/foo");
+  ASSERT_THAT(new_id, NotNull());
+  EXPECT_THAT(new_id->IsWeak(), Eq(id->IsWeak()));
+
+  Maybe<ResourceTable::SearchResult> result =
+      new_table.FindResource(test::ParseNameOrDie("com.app.a:layout/main"));
+  ASSERT_TRUE(result);
+
+  EXPECT_THAT(result.value().type->symbol_status.state, Eq(SymbolState::kPublic));
+  EXPECT_THAT(result.value().entry->symbol_status.state, Eq(SymbolState::kPublic));
+
+  result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/foo"));
+  ASSERT_TRUE(result);
+  EXPECT_THAT(result.value().entry->symbol_status.state, Eq(SymbolState::kUndefined));
+  EXPECT_TRUE(result.value().entry->symbol_status.allow_new);
+
+  // Find the product-dependent values
+  BinaryPrimitive* prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
+      &new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), "");
+  ASSERT_THAT(prim, NotNull());
+  EXPECT_THAT(prim->value.data, Eq(123u));
+
+  prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
+      &new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), "tablet");
+  ASSERT_THAT(prim, NotNull());
+  EXPECT_THAT(prim->value.data, Eq(321u));
+
+  Reference* actual_ref = test::GetValue<Reference>(&new_table, "com.app.a:layout/abc");
+  ASSERT_THAT(actual_ref, NotNull());
+  ASSERT_TRUE(actual_ref->name);
+  ASSERT_TRUE(actual_ref->id);
+  EXPECT_THAT(*actual_ref, Eq(expected_ref));
+
+  StyledString* actual_styled_str =
+      test::GetValue<StyledString>(&new_table, "com.app.a:string/styled");
+  ASSERT_THAT(actual_styled_str, NotNull());
+  EXPECT_THAT(actual_styled_str->value->value, Eq("hello"));
+  ASSERT_THAT(actual_styled_str->value->spans, SizeIs(1u));
+  EXPECT_THAT(*actual_styled_str->value->spans[0].name, Eq("b"));
+  EXPECT_THAT(actual_styled_str->value->spans[0].first_char, Eq(0u));
+  EXPECT_THAT(actual_styled_str->value->spans[0].last_char, Eq(4u));
+}
+
+TEST(ProtoSerializeTest, SerializeFileHeader) {
+  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+
+  ResourceFile f;
+  f.config = test::ParseConfigOrDie("hdpi-v9");
+  f.name = test::ParseNameOrDie("com.app.a:layout/main");
+  f.source.path = "res/layout-hdpi-v9/main.xml";
+  f.exported_symbols.push_back(SourcedResourceName{test::ParseNameOrDie("id/unchecked"), 23u});
+
+  const std::string expected_data1 = "123";
+  const std::string expected_data2 = "1234";
+
+  std::string output_str;
+  {
+    pb::internal::CompiledFile pb_f1, pb_f2;
+    SerializeCompiledFileToPb(f, &pb_f1);
+
+    f.name.entry = "__" + f.name.entry + "$0";
+    SerializeCompiledFileToPb(f, &pb_f2);
+
+    StringOutputStream out_stream(&output_str);
+    CompiledFileOutputStream out_file_stream(&out_stream);
+    out_file_stream.WriteLittleEndian32(2);
+    out_file_stream.WriteCompiledFile(pb_f1);
+    out_file_stream.WriteData(expected_data1.data(), expected_data1.size());
+    out_file_stream.WriteCompiledFile(pb_f2);
+    out_file_stream.WriteData(expected_data2.data(), expected_data2.size());
+    ASSERT_FALSE(out_file_stream.HadError());
+  }
+
+  CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
+  uint32_t num_files = 0;
+  ASSERT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
+  ASSERT_EQ(2u, num_files);
+
+  // Read the first compiled file.
+
+  pb::internal::CompiledFile new_pb_f1;
+  ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_f1));
+
+  ResourceFile new_f1;
+  std::string error;
+  ASSERT_TRUE(DeserializeCompiledFileFromPb(new_pb_f1, &new_f1, &error));
+  EXPECT_THAT(error, IsEmpty());
+
+  uint64_t offset, len;
+  ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len));
+
+  std::string actual_data(output_str.data() + offset, len);
+  EXPECT_EQ(expected_data1, actual_data);
+
+  // Expect the data to be aligned.
+  EXPECT_EQ(0u, offset & 0x03);
+
+  ASSERT_EQ(1u, new_f1.exported_symbols.size());
+  EXPECT_EQ(test::ParseNameOrDie("id/unchecked"), new_f1.exported_symbols[0].name);
+
+  // Read the second compiled file.
+
+  pb::internal::CompiledFile new_pb_f2;
+  ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_f2));
+
+  ResourceFile new_f2;
+  ASSERT_TRUE(DeserializeCompiledFileFromPb(new_pb_f2, &new_f2, &error));
+  EXPECT_THAT(error, IsEmpty());
+
+  ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len));
+
+  actual_data = std::string(output_str.data() + offset, len);
+  EXPECT_EQ(expected_data2, actual_data);
+
+  // Expect the data to be aligned.
+  EXPECT_EQ(0u, offset & 0x03);
+}
+
+TEST(ProtoSerializeTest, DeserializeCorruptHeaderSafely) {
+  ResourceFile f;
+  pb::internal::CompiledFile pb_file;
+  SerializeCompiledFileToPb(f, &pb_file);
+
+  const std::string expected_data = "1234";
+
+  std::string output_str;
+  {
+    StringOutputStream out_stream(&output_str);
+    CompiledFileOutputStream out_file_stream(&out_stream);
+    out_file_stream.WriteLittleEndian32(1);
+    out_file_stream.WriteCompiledFile(pb_file);
+    out_file_stream.WriteData(expected_data.data(), expected_data.size());
+    ASSERT_FALSE(out_file_stream.HadError());
+  }
+
+  output_str[4] = 0xff;
+
+  CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
+
+  uint32_t num_files = 0;
+  EXPECT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
+  EXPECT_EQ(1u, num_files);
+
+  pb::internal::CompiledFile new_pb_file;
+  EXPECT_FALSE(in_file_stream.ReadCompiledFile(&new_pb_file));
+
+  uint64_t offset, len;
+  EXPECT_FALSE(in_file_stream.ReadDataMetaData(&offset, &len));
+}
+
+TEST(ProtoSerializeTest, SerializeAndDeserializeXml) {
+  xml::Element element;
+  element.line_number = 22;
+  element.column_number = 23;
+  element.name = "element";
+  element.namespace_uri = "uri://";
+
+  xml::NamespaceDecl decl;
+  decl.prefix = "android";
+  decl.uri = xml::kSchemaAndroid;
+  decl.line_number = 21;
+  decl.column_number = 24;
+
+  element.namespace_decls.push_back(decl);
+
+  xml::Attribute attr;
+  attr.name = "name";
+  attr.namespace_uri = xml::kSchemaAndroid;
+  attr.value = "23dp";
+  attr.compiled_attribute = xml::AaptAttribute({}, ResourceId(0x01010000));
+  attr.compiled_value =
+      ResourceUtils::TryParseItemForAttribute(attr.value, android::ResTable_map::TYPE_DIMENSION);
+  attr.compiled_value->SetSource(Source().WithLine(25));
+  element.attributes.push_back(std::move(attr));
+
+  std::unique_ptr<xml::Text> text = util::make_unique<xml::Text>();
+  text->line_number = 25;
+  text->column_number = 3;
+  text->text = "hey there";
+  element.AppendChild(std::move(text));
+
+  std::unique_ptr<xml::Element> child = util::make_unique<xml::Element>();
+  child->name = "child";
+
+  text = util::make_unique<xml::Text>();
+  text->text = "woah there";
+  child->AppendChild(std::move(text));
+
+  element.AppendChild(std::move(child));
+
+  pb::XmlNode pb_xml;
+  SerializeXmlToPb(element, &pb_xml);
+
+  StringPool pool;
+  xml::Element actual_el;
+  std::string error;
+  ASSERT_TRUE(DeserializeXmlFromPb(pb_xml, &actual_el, &pool, &error));
+  ASSERT_THAT(error, IsEmpty());
+
+  EXPECT_THAT(actual_el.name, StrEq("element"));
+  EXPECT_THAT(actual_el.namespace_uri, StrEq("uri://"));
+  EXPECT_THAT(actual_el.line_number, Eq(22u));
+  EXPECT_THAT(actual_el.column_number, Eq(23u));
+
+  ASSERT_THAT(actual_el.namespace_decls, SizeIs(1u));
+  const xml::NamespaceDecl& actual_decl = actual_el.namespace_decls[0];
+  EXPECT_THAT(actual_decl.prefix, StrEq("android"));
+  EXPECT_THAT(actual_decl.uri, StrEq(xml::kSchemaAndroid));
+  EXPECT_THAT(actual_decl.line_number, Eq(21u));
+  EXPECT_THAT(actual_decl.column_number, Eq(24u));
+
+  ASSERT_THAT(actual_el.attributes, SizeIs(1u));
+  const xml::Attribute& actual_attr = actual_el.attributes[0];
+  EXPECT_THAT(actual_attr.name, StrEq("name"));
+  EXPECT_THAT(actual_attr.namespace_uri, StrEq(xml::kSchemaAndroid));
+  EXPECT_THAT(actual_attr.value, StrEq("23dp"));
+
+  ASSERT_THAT(actual_attr.compiled_value, NotNull());
+  const BinaryPrimitive* prim = ValueCast<BinaryPrimitive>(actual_attr.compiled_value.get());
+  ASSERT_THAT(prim, NotNull());
+  EXPECT_THAT(prim->value.dataType, Eq(android::Res_value::TYPE_DIMENSION));
+
+  ASSERT_TRUE(actual_attr.compiled_attribute);
+  ASSERT_TRUE(actual_attr.compiled_attribute.value().id);
+
+  ASSERT_THAT(actual_el.children, SizeIs(2u));
+  const xml::Text* child_text = xml::NodeCast<xml::Text>(actual_el.children[0].get());
+  ASSERT_THAT(child_text, NotNull());
+  const xml::Element* child_el = xml::NodeCast<xml::Element>(actual_el.children[1].get());
+  ASSERT_THAT(child_el, NotNull());
+
+  EXPECT_THAT(child_text->line_number, Eq(25u));
+  EXPECT_THAT(child_text->column_number, Eq(3u));
+  EXPECT_THAT(child_text->text, StrEq("hey there"));
+
+  EXPECT_THAT(child_el->name, StrEq("child"));
+  ASSERT_THAT(child_el->children, SizeIs(1u));
+
+  child_text = xml::NodeCast<xml::Text>(child_el->children[0].get());
+  ASSERT_THAT(child_text, NotNull());
+  EXPECT_THAT(child_text->text, StrEq("woah there"));
+}
+
+static void ExpectConfigSerializes(const StringPiece& config_str) {
+  const ConfigDescription expected_config = test::ParseConfigOrDie(config_str);
+  pb::Configuration pb_config;
+  SerializeConfig(expected_config, &pb_config);
+
+  ConfigDescription actual_config;
+  std::string error;
+  ASSERT_TRUE(DeserializeConfigFromPb(pb_config, &actual_config, &error));
+  ASSERT_THAT(error, IsEmpty());
+  EXPECT_EQ(expected_config, actual_config);
+}
+
+TEST(ProtoSerializeTest, SerializeDeserializeConfiguration) {
+  ExpectConfigSerializes("");
+
+  ExpectConfigSerializes("mcc123");
+
+  ExpectConfigSerializes("mnc123");
+
+  ExpectConfigSerializes("en");
+  ExpectConfigSerializes("en-rGB");
+  ExpectConfigSerializes("b+en+GB");
+
+  ExpectConfigSerializes("ldltr");
+  ExpectConfigSerializes("ldrtl");
+
+  ExpectConfigSerializes("sw3600dp");
+
+  ExpectConfigSerializes("w300dp");
+
+  ExpectConfigSerializes("h400dp");
+
+  ExpectConfigSerializes("small");
+  ExpectConfigSerializes("normal");
+  ExpectConfigSerializes("large");
+  ExpectConfigSerializes("xlarge");
+
+  ExpectConfigSerializes("long");
+  ExpectConfigSerializes("notlong");
+
+  ExpectConfigSerializes("round");
+  ExpectConfigSerializes("notround");
+
+  ExpectConfigSerializes("widecg");
+  ExpectConfigSerializes("nowidecg");
+
+  ExpectConfigSerializes("highdr");
+  ExpectConfigSerializes("lowdr");
+
+  ExpectConfigSerializes("port");
+  ExpectConfigSerializes("land");
+  ExpectConfigSerializes("square");
+
+  ExpectConfigSerializes("desk");
+  ExpectConfigSerializes("car");
+  ExpectConfigSerializes("television");
+  ExpectConfigSerializes("appliance");
+  ExpectConfigSerializes("watch");
+  ExpectConfigSerializes("vrheadset");
+
+  ExpectConfigSerializes("night");
+  ExpectConfigSerializes("notnight");
+
+  ExpectConfigSerializes("300dpi");
+  ExpectConfigSerializes("hdpi");
+
+  ExpectConfigSerializes("notouch");
+  ExpectConfigSerializes("stylus");
+  ExpectConfigSerializes("finger");
+
+  ExpectConfigSerializes("keysexposed");
+  ExpectConfigSerializes("keyshidden");
+  ExpectConfigSerializes("keyssoft");
+
+  ExpectConfigSerializes("nokeys");
+  ExpectConfigSerializes("qwerty");
+  ExpectConfigSerializes("12key");
+
+  ExpectConfigSerializes("navhidden");
+  ExpectConfigSerializes("navexposed");
+
+  ExpectConfigSerializes("nonav");
+  ExpectConfigSerializes("dpad");
+  ExpectConfigSerializes("trackball");
+  ExpectConfigSerializes("wheel");
+
+  ExpectConfigSerializes("300x200");
+
+  ExpectConfigSerializes("v8");
+
+  ExpectConfigSerializes(
+      "mcc123-mnc456-b+en+GB-ldltr-sw300dp-w300dp-h400dp-large-long-round-widecg-highdr-land-car-"
+      "night-xhdpi-stylus-keysexposed-qwerty-navhidden-dpad-300x200-v23");
+}
+
+}  // namespace aapt
diff --git a/tools/aapt2/proto/TableProtoDeserializer.cpp b/tools/aapt2/proto/TableProtoDeserializer.cpp
deleted file mode 100644
index a49f6f6..0000000
--- a/tools/aapt2/proto/TableProtoDeserializer.cpp
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "proto/ProtoSerialize.h"
-
-#include "android-base/logging.h"
-#include "androidfw/ResourceTypes.h"
-
-#include "ResourceTable.h"
-#include "ResourceUtils.h"
-#include "ValueVisitor.h"
-#include "proto/ProtoHelpers.h"
-
-namespace aapt {
-
-namespace {
-
-class ReferenceIdToNameVisitor : public DescendingValueVisitor {
- public:
-  using DescendingValueVisitor::Visit;
-
-  explicit ReferenceIdToNameVisitor(const std::map<ResourceId, ResourceNameRef>* mapping)
-      : mapping_(mapping) {
-    CHECK(mapping_ != nullptr);
-  }
-
-  void Visit(Reference* reference) override {
-    if (!reference->id || !reference->id.value().is_valid()) {
-      return;
-    }
-
-    ResourceId id = reference->id.value();
-    auto cache_iter = mapping_->find(id);
-    if (cache_iter != mapping_->end()) {
-      reference->name = cache_iter->second.ToResourceName();
-    }
-  }
-
- private:
-  const std::map<ResourceId, ResourceNameRef>* mapping_;
-};
-
-class PackagePbDeserializer {
- public:
-  PackagePbDeserializer(const android::ResStringPool* sourcePool, const Source& source,
-                        IDiagnostics* diag)
-      : source_pool_(sourcePool), source_(source), diag_(diag) {
-  }
-
- public:
-  bool DeserializeFromPb(const pb::Package& pb_package, ResourceTable* table) {
-    Maybe<uint8_t> id;
-    if (pb_package.has_package_id()) {
-      id = static_cast<uint8_t>(pb_package.package_id().id());
-    }
-
-    std::map<ResourceId, ResourceNameRef> id_index;
-
-    ResourceTablePackage* pkg = table->CreatePackage(pb_package.package_name(), id);
-    for (const pb::Type& pb_type : pb_package.type()) {
-      const ResourceType* res_type = ParseResourceType(pb_type.name());
-      if (res_type == nullptr) {
-        diag_->Error(DiagMessage(source_) << "unknown type '" << pb_type.name() << "'");
-        return {};
-      }
-
-      ResourceTableType* type = pkg->FindOrCreateType(*res_type);
-
-      for (const pb::Entry& pb_entry : pb_type.entry()) {
-        ResourceEntry* entry = type->FindOrCreateEntry(pb_entry.name());
-
-        // Deserialize the symbol status (public/private with source and comments).
-        if (pb_entry.has_symbol_status()) {
-          const pb::SymbolStatus& pb_status = pb_entry.symbol_status();
-          if (pb_status.has_source()) {
-            DeserializeSourceFromPb(pb_status.source(), *source_pool_,
-                                    &entry->symbol_status.source);
-          }
-
-          entry->symbol_status.comment = pb_status.comment();
-          entry->symbol_status.allow_new = pb_status.allow_new();
-
-          SymbolState visibility = DeserializeVisibilityFromPb(pb_status.visibility());
-          entry->symbol_status.state = visibility;
-
-          if (visibility == SymbolState::kPublic) {
-            // This is a public symbol, we must encode the ID now if there is one.
-            if (pb_entry.has_entry_id()) {
-              entry->id = static_cast<uint16_t>(pb_entry.entry_id().id());
-            }
-
-            if (type->symbol_status.state != SymbolState::kPublic) {
-              // If the type has not been made public, do so now.
-              type->symbol_status.state = SymbolState::kPublic;
-              if (pb_type.has_type_id()) {
-                type->id = static_cast<uint8_t>(pb_type.type_id().id());
-              }
-            }
-          } else if (visibility == SymbolState::kPrivate) {
-            if (type->symbol_status.state == SymbolState::kUndefined) {
-              type->symbol_status.state = SymbolState::kPrivate;
-            }
-          }
-        }
-
-        ResourceId resid(pb_package.package_id().id(), pb_type.type_id().id(),
-                         pb_entry.entry_id().id());
-        if (resid.is_valid()) {
-          id_index[resid] = ResourceNameRef(pkg->name, type->type, entry->name);
-        }
-
-        for (const pb::ConfigValue& pb_config_value : pb_entry.config_value()) {
-          const pb::Configuration& pb_config = pb_config_value.config();
-
-          ConfigDescription config;
-          if (!DeserializeConfigDescriptionFromPb(pb_config, &config)) {
-            diag_->Error(DiagMessage(source_) << "invalid configuration");
-            return {};
-          }
-
-          ResourceConfigValue* config_value = entry->FindOrCreateValue(config, pb_config.product());
-          if (config_value->value) {
-            // Duplicate config.
-            diag_->Error(DiagMessage(source_) << "duplicate configuration");
-            return {};
-          }
-
-          config_value->value =
-              DeserializeValueFromPb(pb_config_value.value(), config, &table->string_pool);
-          if (!config_value->value) {
-            return {};
-          }
-        }
-      }
-    }
-
-    ReferenceIdToNameVisitor visitor(&id_index);
-    VisitAllValuesInPackage(pkg, &visitor);
-    return true;
-  }
-
- private:
-  std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item,
-                                              const ConfigDescription& config, StringPool* pool) {
-    if (pb_item.has_ref()) {
-      const pb::Reference& pb_ref = pb_item.ref();
-      std::unique_ptr<Reference> ref = util::make_unique<Reference>();
-      if (!DeserializeReferenceFromPb(pb_ref, ref.get())) {
-        return {};
-      }
-      return std::move(ref);
-
-    } else if (pb_item.has_prim()) {
-      const pb::Primitive& pb_prim = pb_item.prim();
-      return util::make_unique<BinaryPrimitive>(static_cast<uint8_t>(pb_prim.type()),
-                                                pb_prim.data());
-
-    } else if (pb_item.has_id()) {
-      return util::make_unique<Id>();
-
-    } else if (pb_item.has_str()) {
-      return util::make_unique<String>(
-          pool->MakeRef(pb_item.str().value(), StringPool::Context(config)));
-
-    } else if (pb_item.has_raw_str()) {
-      return util::make_unique<RawString>(
-          pool->MakeRef(pb_item.raw_str().value(), StringPool::Context(config)));
-
-    } else if (pb_item.has_styled_str()) {
-      const pb::StyledString& pb_str = pb_item.styled_str();
-      StyleString style_str{pb_str.value()};
-      for (const pb::StyledString::Span& pb_span : pb_str.span()) {
-        style_str.spans.push_back(Span{pb_span.tag(), pb_span.first_char(), pb_span.last_char()});
-      }
-      return util::make_unique<StyledString>(pool->MakeRef(
-          style_str, StringPool::Context(StringPool::Context::kNormalPriority, config)));
-
-    } else if (pb_item.has_file()) {
-      return util::make_unique<FileReference>(pool->MakeRef(
-          pb_item.file().path(), StringPool::Context(StringPool::Context::kHighPriority, config)));
-
-    } else {
-      diag_->Error(DiagMessage(source_) << "unknown item");
-    }
-    return {};
-  }
-
-  std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
-                                                const ConfigDescription& config,
-                                                StringPool* pool) {
-    std::unique_ptr<Value> value;
-    if (pb_value.has_item()) {
-      value = DeserializeItemFromPb(pb_value.item(), config, pool);
-      if (!value) {
-        return {};
-      }
-
-    } else if (pb_value.has_compound_value()) {
-      const pb::CompoundValue& pb_compound_value = pb_value.compound_value();
-      if (pb_compound_value.has_attr()) {
-        const pb::Attribute& pb_attr = pb_compound_value.attr();
-        std::unique_ptr<Attribute> attr = util::make_unique<Attribute>();
-        attr->type_mask = pb_attr.format_flags();
-        attr->min_int = pb_attr.min_int();
-        attr->max_int = pb_attr.max_int();
-        for (const pb::Attribute_Symbol& pb_symbol : pb_attr.symbol()) {
-          Attribute::Symbol symbol;
-          DeserializeItemCommon(pb_symbol, &symbol.symbol);
-          if (!DeserializeReferenceFromPb(pb_symbol.name(), &symbol.symbol)) {
-            return {};
-          }
-          symbol.value = pb_symbol.value();
-          attr->symbols.push_back(std::move(symbol));
-        }
-        value = std::move(attr);
-
-      } else if (pb_compound_value.has_style()) {
-        const pb::Style& pb_style = pb_compound_value.style();
-        std::unique_ptr<Style> style = util::make_unique<Style>();
-        if (pb_style.has_parent()) {
-          style->parent = Reference();
-          if (!DeserializeReferenceFromPb(pb_style.parent(), &style->parent.value())) {
-            return {};
-          }
-
-          if (pb_style.has_parent_source()) {
-            Source parent_source;
-            DeserializeSourceFromPb(pb_style.parent_source(), *source_pool_, &parent_source);
-            style->parent.value().SetSource(std::move(parent_source));
-          }
-        }
-
-        for (const pb::Style_Entry& pb_entry : pb_style.entry()) {
-          Style::Entry entry;
-          DeserializeItemCommon(pb_entry, &entry.key);
-          if (!DeserializeReferenceFromPb(pb_entry.key(), &entry.key)) {
-            return {};
-          }
-
-          entry.value = DeserializeItemFromPb(pb_entry.item(), config, pool);
-          if (!entry.value) {
-            return {};
-          }
-
-          DeserializeItemCommon(pb_entry, entry.value.get());
-          style->entries.push_back(std::move(entry));
-        }
-        value = std::move(style);
-
-      } else if (pb_compound_value.has_styleable()) {
-        const pb::Styleable& pb_styleable = pb_compound_value.styleable();
-        std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
-        for (const pb::Styleable_Entry& pb_entry : pb_styleable.entry()) {
-          Reference attr_ref;
-          DeserializeItemCommon(pb_entry, &attr_ref);
-          DeserializeReferenceFromPb(pb_entry.attr(), &attr_ref);
-          styleable->entries.push_back(std::move(attr_ref));
-        }
-        value = std::move(styleable);
-
-      } else if (pb_compound_value.has_array()) {
-        const pb::Array& pb_array = pb_compound_value.array();
-        std::unique_ptr<Array> array = util::make_unique<Array>();
-        for (const pb::Array_Element& pb_entry : pb_array.element()) {
-          std::unique_ptr<Item> item = DeserializeItemFromPb(pb_entry.item(), config, pool);
-          if (!item) {
-            return {};
-          }
-
-          DeserializeItemCommon(pb_entry, item.get());
-          array->elements.push_back(std::move(item));
-        }
-        value = std::move(array);
-
-      } else if (pb_compound_value.has_plural()) {
-        const pb::Plural& pb_plural = pb_compound_value.plural();
-        std::unique_ptr<Plural> plural = util::make_unique<Plural>();
-        for (const pb::Plural_Entry& pb_entry : pb_plural.entry()) {
-          size_t pluralIdx = DeserializePluralEnumFromPb(pb_entry.arity());
-          plural->values[pluralIdx] = DeserializeItemFromPb(pb_entry.item(), config, pool);
-          if (!plural->values[pluralIdx]) {
-            return {};
-          }
-
-          DeserializeItemCommon(pb_entry, plural->values[pluralIdx].get());
-        }
-        value = std::move(plural);
-
-      } else {
-        diag_->Error(DiagMessage(source_) << "unknown compound value");
-        return {};
-      }
-    } else {
-      diag_->Error(DiagMessage(source_) << "unknown value");
-      return {};
-    }
-
-    CHECK(value) << "forgot to set value";
-
-    value->SetWeak(pb_value.weak());
-    DeserializeItemCommon(pb_value, value.get());
-    return value;
-  }
-
-  bool DeserializeReferenceFromPb(const pb::Reference& pb_ref, Reference* out_ref) {
-    out_ref->reference_type = DeserializeReferenceTypeFromPb(pb_ref.type());
-    out_ref->private_reference = pb_ref.private_();
-
-    if (pb_ref.id() != 0) {
-      out_ref->id = ResourceId(pb_ref.id());
-    }
-
-    if (!pb_ref.name().empty()) {
-      ResourceNameRef name_ref;
-      if (!ResourceUtils::ParseResourceName(pb_ref.name(), &name_ref, nullptr)) {
-        diag_->Error(DiagMessage(source_) << "invalid reference name '" << pb_ref.name() << "'");
-        return false;
-      }
-
-      out_ref->name = name_ref.ToResourceName();
-    }
-    return true;
-  }
-
-  template <typename T>
-  void DeserializeItemCommon(const T& pb_item, Value* out_value) {
-    if (pb_item.has_source()) {
-      Source source;
-      DeserializeSourceFromPb(pb_item.source(), *source_pool_, &source);
-      out_value->SetSource(std::move(source));
-    }
-    out_value->SetComment(pb_item.comment());
-  }
-
- private:
-  const android::ResStringPool* source_pool_;
-  const Source source_;
-  IDiagnostics* diag_;
-};
-
-}  // namespace
-
-std::unique_ptr<ResourceTable> DeserializeTableFromPb(const pb::ResourceTable& pb_table,
-                                                      const Source& source, IDiagnostics* diag) {
-  // We import the android namespace because on Windows NO_ERROR is a macro, not an enum, which
-  // causes errors when qualifying it with android::
-  using namespace android;
-
-  std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
-
-  ResStringPool source_pool;
-  if (pb_table.has_source_pool()) {
-    status_t result = source_pool.setTo(pb_table.source_pool().data().data(),
-                                        pb_table.source_pool().data().size());
-    if (result != NO_ERROR) {
-      diag->Error(DiagMessage(source) << "invalid source pool");
-      return {};
-    }
-  }
-
-  PackagePbDeserializer package_pb_deserializer(&source_pool, source, diag);
-  for (const pb::Package& pb_package : pb_table.package()) {
-    if (!package_pb_deserializer.DeserializeFromPb(pb_package, table.get())) {
-      return {};
-    }
-  }
-  return table;
-}
-
-std::unique_ptr<ResourceFile> DeserializeCompiledFileFromPb(
-    const pb::internal::CompiledFile& pb_file, const Source& source, IDiagnostics* diag) {
-  std::unique_ptr<ResourceFile> file = util::make_unique<ResourceFile>();
-
-  ResourceNameRef name_ref;
-
-  // Need to create an lvalue here so that nameRef can point to something real.
-  if (!ResourceUtils::ParseResourceName(pb_file.resource_name(), &name_ref)) {
-    diag->Error(DiagMessage(source)
-                << "invalid resource name in compiled file header: "
-                << pb_file.resource_name());
-    return {};
-  }
-  file->name = name_ref.ToResourceName();
-  file->source.path = pb_file.source_path();
-  if (!DeserializeConfigDescriptionFromPb(pb_file.config(), &file->config)) {
-    diag->Error(DiagMessage(source) << "invalid resource configuration in compiled file header");
-    return {};
-  }
-
-  for (const pb::internal::CompiledFile_Symbol& pb_symbol : pb_file.exported_symbol()) {
-    // Need to create an lvalue here so that nameRef can point to something real.
-    if (!ResourceUtils::ParseResourceName(pb_symbol.resource_name(), &name_ref)) {
-      diag->Error(DiagMessage(source)
-                  << "invalid resource name for exported symbol in compiled file header: "
-                  << pb_file.resource_name());
-      return {};
-    }
-    size_t line = 0u;
-    if (pb_symbol.has_source()) {
-      line = pb_symbol.source().line_number();
-    }
-    file->exported_symbols.push_back(SourcedResourceName{name_ref.ToResourceName(), line});
-  }
-  return file;
-}
-
-}  // namespace aapt
diff --git a/tools/aapt2/proto/TableProtoSerializer.cpp b/tools/aapt2/proto/TableProtoSerializer.cpp
deleted file mode 100644
index e15a0ad..0000000
--- a/tools/aapt2/proto/TableProtoSerializer.cpp
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "proto/ProtoSerialize.h"
-
-#include "android-base/logging.h"
-
-#include "Resource.h"
-#include "ResourceTable.h"
-#include "StringPool.h"
-#include "ValueVisitor.h"
-#include "proto/ProtoHelpers.h"
-#include "util/BigBuffer.h"
-
-using ::google::protobuf::io::CodedInputStream;
-using ::google::protobuf::io::CodedOutputStream;
-using ::google::protobuf::io::ZeroCopyOutputStream;
-
-namespace aapt {
-
-namespace {
-
-class PbSerializerVisitor : public ConstValueVisitor {
- public:
-  using ConstValueVisitor::Visit;
-
-  // Constructor to use when expecting to serialize any value.
-  PbSerializerVisitor(StringPool* source_pool, pb::Value* out_pb_value)
-      : source_pool_(source_pool), out_pb_value_(out_pb_value), out_pb_item_(nullptr) {
-  }
-
-  // Constructor to use when expecting to serialize an Item.
-  PbSerializerVisitor(StringPool* sourcePool, pb::Item* outPbItem)
-      : source_pool_(sourcePool), out_pb_value_(nullptr), out_pb_item_(outPbItem) {
-  }
-
-  void Visit(const Reference* ref) override {
-    SerializeReferenceToPb(*ref, pb_item()->mutable_ref());
-  }
-
-  void Visit(const String* str) override {
-    pb_item()->mutable_str()->set_value(*str->value);
-  }
-
-  void Visit(const RawString* str) override {
-    pb_item()->mutable_raw_str()->set_value(*str->value);
-  }
-
-  void Visit(const StyledString* str) override {
-    pb::StyledString* pb_str = pb_item()->mutable_styled_str();
-    pb_str->set_value(str->value->value);
-
-    for (const StringPool::Span& span : str->value->spans) {
-      pb::StyledString::Span* pb_span = pb_str->add_span();
-      pb_span->set_tag(*span.name);
-      pb_span->set_first_char(span.first_char);
-      pb_span->set_last_char(span.last_char);
-    }
-  }
-
-  void Visit(const FileReference* file) override {
-    pb_item()->mutable_file()->set_path(*file->path);
-  }
-
-  void Visit(const Id* /*id*/) override {
-    pb_item()->mutable_id();
-  }
-
-  void Visit(const BinaryPrimitive* prim) override {
-    android::Res_value val = {};
-    prim->Flatten(&val);
-
-    pb::Primitive* pb_prim = pb_item()->mutable_prim();
-    pb_prim->set_type(val.dataType);
-    pb_prim->set_data(val.data);
-  }
-
-  void VisitItem(const Item* item) override {
-    LOG(FATAL) << "unimplemented item";
-  }
-
-  void Visit(const Attribute* attr) override {
-    pb::Attribute* pb_attr = pb_compound_value()->mutable_attr();
-    pb_attr->set_format_flags(attr->type_mask);
-    pb_attr->set_min_int(attr->min_int);
-    pb_attr->set_max_int(attr->max_int);
-
-    for (const auto& symbol : attr->symbols) {
-      pb::Attribute_Symbol* pb_symbol = pb_attr->add_symbol();
-      SerializeItemCommonToPb(symbol.symbol, pb_symbol);
-      SerializeReferenceToPb(symbol.symbol, pb_symbol->mutable_name());
-      pb_symbol->set_value(symbol.value);
-    }
-  }
-
-  void Visit(const Style* style) override {
-    pb::Style* pb_style = pb_compound_value()->mutable_style();
-    if (style->parent) {
-      SerializeReferenceToPb(style->parent.value(), pb_style->mutable_parent());
-      SerializeSourceToPb(style->parent.value().GetSource(), source_pool_,
-                          pb_style->mutable_parent_source());
-    }
-
-    for (const Style::Entry& entry : style->entries) {
-      pb::Style_Entry* pb_entry = pb_style->add_entry();
-      SerializeReferenceToPb(entry.key, pb_entry->mutable_key());
-
-      pb::Item* pb_item = pb_entry->mutable_item();
-      SerializeItemCommonToPb(entry.key, pb_entry);
-      PbSerializerVisitor sub_visitor(source_pool_, pb_item);
-      entry.value->Accept(&sub_visitor);
-    }
-  }
-
-  void Visit(const Styleable* styleable) override {
-    pb::Styleable* pb_styleable = pb_compound_value()->mutable_styleable();
-    for (const Reference& entry : styleable->entries) {
-      pb::Styleable_Entry* pb_entry = pb_styleable->add_entry();
-      SerializeItemCommonToPb(entry, pb_entry);
-      SerializeReferenceToPb(entry, pb_entry->mutable_attr());
-    }
-  }
-
-  void Visit(const Array* array) override {
-    pb::Array* pb_array = pb_compound_value()->mutable_array();
-    for (const auto& value : array->elements) {
-      pb::Array_Element* pb_element = pb_array->add_element();
-      SerializeItemCommonToPb(*value, pb_element);
-      PbSerializerVisitor sub_visitor(source_pool_, pb_element->mutable_item());
-      value->Accept(&sub_visitor);
-    }
-  }
-
-  void Visit(const Plural* plural) override {
-    pb::Plural* pb_plural = pb_compound_value()->mutable_plural();
-    const size_t count = plural->values.size();
-    for (size_t i = 0; i < count; i++) {
-      if (!plural->values[i]) {
-        // No plural value set here.
-        continue;
-      }
-
-      pb::Plural_Entry* pb_entry = pb_plural->add_entry();
-      pb_entry->set_arity(SerializePluralEnumToPb(i));
-      pb::Item* pb_element = pb_entry->mutable_item();
-      SerializeItemCommonToPb(*plural->values[i], pb_entry);
-      PbSerializerVisitor sub_visitor(source_pool_, pb_element);
-      plural->values[i]->Accept(&sub_visitor);
-    }
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(PbSerializerVisitor);
-
-  pb::Item* pb_item() {
-    if (out_pb_value_) {
-      return out_pb_value_->mutable_item();
-    }
-    return out_pb_item_;
-  }
-
-  pb::CompoundValue* pb_compound_value() {
-    CHECK(out_pb_value_ != nullptr);
-    return out_pb_value_->mutable_compound_value();
-  }
-
-  template <typename T>
-  void SerializeItemCommonToPb(const Item& item, T* pb_item) {
-    SerializeSourceToPb(item.GetSource(), source_pool_, pb_item->mutable_source());
-    pb_item->set_comment(item.GetComment());
-  }
-
-  void SerializeReferenceToPb(const Reference& ref, pb::Reference* pb_ref) {
-    pb_ref->set_id(ref.id.value_or_default(ResourceId(0x0)).id);
-
-    if (ref.name) {
-      pb_ref->set_name(ref.name.value().ToString());
-    }
-
-    pb_ref->set_private_(ref.private_reference);
-    pb_ref->set_type(SerializeReferenceTypeToPb(ref.reference_type));
-  }
-
-  StringPool* source_pool_;
-  pb::Value* out_pb_value_;
-  pb::Item* out_pb_item_;
-};
-
-}  // namespace
-
-std::unique_ptr<pb::ResourceTable> SerializeTableToPb(ResourceTable* table) {
-  // We must do this before writing the resources, since the string pool IDs may change.
-  table->string_pool.Prune();
-  table->string_pool.Sort([](const StringPool::Context& a, const StringPool::Context& b) -> int {
-    int diff = util::compare(a.priority, b.priority);
-    if (diff == 0) {
-      diff = a.config.compare(b.config);
-    }
-    return diff;
-  });
-
-  auto pb_table = util::make_unique<pb::ResourceTable>();
-  StringPool source_pool;
-
-  for (auto& package : table->packages) {
-    pb::Package* pb_package = pb_table->add_package();
-    if (package->id) {
-      pb_package->mutable_package_id()->set_id(package->id.value());
-    }
-    pb_package->set_package_name(package->name);
-
-    for (auto& type : package->types) {
-      pb::Type* pb_type = pb_package->add_type();
-      if (type->id) {
-        pb_type->mutable_type_id()->set_id(type->id.value());
-      }
-      pb_type->set_name(ToString(type->type).to_string());
-
-      for (auto& entry : type->entries) {
-        pb::Entry* pb_entry = pb_type->add_entry();
-        if (entry->id) {
-          pb_entry->mutable_entry_id()->set_id(entry->id.value());
-        }
-        pb_entry->set_name(entry->name);
-
-        // Write the SymbolStatus struct.
-        pb::SymbolStatus* pb_status = pb_entry->mutable_symbol_status();
-        pb_status->set_visibility(SerializeVisibilityToPb(entry->symbol_status.state));
-        SerializeSourceToPb(entry->symbol_status.source, &source_pool, pb_status->mutable_source());
-        pb_status->set_comment(entry->symbol_status.comment);
-        pb_status->set_allow_new(entry->symbol_status.allow_new);
-
-        for (auto& config_value : entry->values) {
-          pb::ConfigValue* pb_config_value = pb_entry->add_config_value();
-          SerializeConfig(config_value->config, pb_config_value->mutable_config());
-          pb_config_value->mutable_config()->set_product(config_value->product);
-
-          pb::Value* pb_value = pb_config_value->mutable_value();
-          SerializeSourceToPb(config_value->value->GetSource(), &source_pool,
-                              pb_value->mutable_source());
-          pb_value->set_comment(config_value->value->GetComment());
-          pb_value->set_weak(config_value->value->IsWeak());
-
-          PbSerializerVisitor visitor(&source_pool, pb_value);
-          config_value->value->Accept(&visitor);
-        }
-      }
-    }
-  }
-
-  SerializeStringPoolToPb(source_pool, pb_table->mutable_source_pool());
-  return pb_table;
-}
-
-std::unique_ptr<pb::internal::CompiledFile> SerializeCompiledFileToPb(const ResourceFile& file) {
-  auto pb_file = util::make_unique<pb::internal::CompiledFile>();
-  pb_file->set_resource_name(file.name.ToString());
-  pb_file->set_source_path(file.source.path);
-  SerializeConfig(file.config, pb_file->mutable_config());
-
-  for (const SourcedResourceName& exported : file.exported_symbols) {
-    pb::internal::CompiledFile_Symbol* pb_symbol = pb_file->add_exported_symbol();
-    pb_symbol->set_resource_name(exported.name.ToString());
-    pb_symbol->mutable_source()->set_line_number(exported.line);
-  }
-  return pb_file;
-}
-
-CompiledFileOutputStream::CompiledFileOutputStream(ZeroCopyOutputStream* out) : out_(out) {
-}
-
-void CompiledFileOutputStream::EnsureAlignedWrite() {
-  const int overflow = out_.ByteCount() % 4;
-  if (overflow > 0) {
-    uint32_t zero = 0u;
-    out_.WriteRaw(&zero, 4 - overflow);
-  }
-}
-
-void CompiledFileOutputStream::WriteLittleEndian32(uint32_t val) {
-  EnsureAlignedWrite();
-  out_.WriteLittleEndian32(val);
-}
-
-void CompiledFileOutputStream::WriteCompiledFile(const pb::internal::CompiledFile* compiled_file) {
-  EnsureAlignedWrite();
-  out_.WriteLittleEndian64(static_cast<uint64_t>(compiled_file->ByteSize()));
-  compiled_file->SerializeWithCachedSizes(&out_);
-}
-
-void CompiledFileOutputStream::WriteData(const BigBuffer* buffer) {
-  EnsureAlignedWrite();
-  out_.WriteLittleEndian64(static_cast<uint64_t>(buffer->size()));
-  for (const BigBuffer::Block& block : *buffer) {
-    out_.WriteRaw(block.buffer.get(), block.size);
-  }
-}
-
-void CompiledFileOutputStream::WriteData(const void* data, size_t len) {
-  EnsureAlignedWrite();
-  out_.WriteLittleEndian64(static_cast<uint64_t>(len));
-  out_.WriteRaw(data, len);
-}
-
-bool CompiledFileOutputStream::HadError() {
-  return out_.HadError();
-}
-
-CompiledFileInputStream::CompiledFileInputStream(const void* data, size_t size)
-    : in_(static_cast<const uint8_t*>(data), size) {}
-
-void CompiledFileInputStream::EnsureAlignedRead() {
-  const int overflow = in_.CurrentPosition() % 4;
-  if (overflow > 0) {
-    // Reads are always 4 byte aligned.
-    in_.Skip(4 - overflow);
-  }
-}
-
-bool CompiledFileInputStream::ReadLittleEndian32(uint32_t* out_val) {
-  EnsureAlignedRead();
-  return in_.ReadLittleEndian32(out_val);
-}
-
-bool CompiledFileInputStream::ReadCompiledFile(pb::internal::CompiledFile* out_val) {
-  EnsureAlignedRead();
-
-  google::protobuf::uint64 pb_size = 0u;
-  if (!in_.ReadLittleEndian64(&pb_size)) {
-    return false;
-  }
-
-  CodedInputStream::Limit l = in_.PushLimit(static_cast<int>(pb_size));
-
-  // Check that we haven't tried to read past the end.
-  if (static_cast<uint64_t>(in_.BytesUntilLimit()) != pb_size) {
-    in_.PopLimit(l);
-    in_.PushLimit(0);
-    return false;
-  }
-
-  if (!out_val->ParsePartialFromCodedStream(&in_)) {
-    in_.PopLimit(l);
-    in_.PushLimit(0);
-    return false;
-  }
-
-  in_.PopLimit(l);
-  return true;
-}
-
-bool CompiledFileInputStream::ReadDataMetaData(uint64_t* out_offset, uint64_t* out_len) {
-  EnsureAlignedRead();
-
-  google::protobuf::uint64 pb_size = 0u;
-  if (!in_.ReadLittleEndian64(&pb_size)) {
-    return false;
-  }
-
-  // Check that we aren't trying to read past the end.
-  if (pb_size > static_cast<uint64_t>(in_.BytesUntilLimit())) {
-    in_.PushLimit(0);
-    return false;
-  }
-
-  uint64_t offset = static_cast<uint64_t>(in_.CurrentPosition());
-  if (!in_.Skip(pb_size)) {
-    return false;
-  }
-
-  *out_offset = offset;
-  *out_len = pb_size;
-  return true;
-}
-
-}  // namespace aapt
diff --git a/tools/aapt2/proto/TableProtoSerializer_test.cpp b/tools/aapt2/proto/TableProtoSerializer_test.cpp
deleted file mode 100644
index 8f6414c..0000000
--- a/tools/aapt2/proto/TableProtoSerializer_test.cpp
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "proto/ProtoSerialize.h"
-
-#include "ResourceTable.h"
-#include "test/Test.h"
-
-using ::android::StringPiece;
-using ::google::protobuf::io::StringOutputStream;
-using ::testing::Eq;
-using ::testing::NotNull;
-using ::testing::SizeIs;
-
-namespace aapt {
-
-TEST(TableProtoSerializer, SerializeSinglePackage) {
-  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
-  std::unique_ptr<ResourceTable> table =
-      test::ResourceTableBuilder()
-          .SetPackageId("com.app.a", 0x7f)
-          .AddFileReference("com.app.a:layout/main", ResourceId(0x7f020000), "res/layout/main.xml")
-          .AddReference("com.app.a:layout/other", ResourceId(0x7f020001), "com.app.a:layout/main")
-          .AddString("com.app.a:string/text", {}, "hi")
-          .AddValue("com.app.a:id/foo", {}, util::make_unique<Id>())
-          .SetSymbolState("com.app.a:bool/foo", {}, SymbolState::kUndefined, true /*allow_new*/)
-          .Build();
-
-  Symbol public_symbol;
-  public_symbol.state = SymbolState::kPublic;
-  ASSERT_TRUE(table->SetSymbolState(test::ParseNameOrDie("com.app.a:layout/main"),
-                                    ResourceId(0x7f020000), public_symbol,
-                                    context->GetDiagnostics()));
-
-  Id* id = test::GetValue<Id>(table.get(), "com.app.a:id/foo");
-  ASSERT_THAT(id, NotNull());
-
-  // Make a plural.
-  std::unique_ptr<Plural> plural = util::make_unique<Plural>();
-  plural->values[Plural::One] = util::make_unique<String>(table->string_pool.MakeRef("one"));
-  ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("com.app.a:plurals/hey"),
-                                 ConfigDescription{}, {}, std::move(plural),
-                                 context->GetDiagnostics()));
-
-  // Make a styled string.
-  StyleString style_string;
-  style_string.str = "hello";
-  style_string.spans.push_back(Span{"b", 0u, 4u});
-  ASSERT_TRUE(
-      table->AddResource(test::ParseNameOrDie("com.app.a:string/styled"), ConfigDescription{}, {},
-                         util::make_unique<StyledString>(table->string_pool.MakeRef(style_string)),
-                         context->GetDiagnostics()));
-
-  // Make a resource with different products.
-  ASSERT_TRUE(table->AddResource(
-      test::ParseNameOrDie("com.app.a:integer/one"),
-      test::ParseConfigOrDie("land"), {},
-      test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 123u),
-      context->GetDiagnostics()));
-  ASSERT_TRUE(table->AddResource(
-      test::ParseNameOrDie("com.app.a:integer/one"),
-      test::ParseConfigOrDie("land"), "tablet",
-      test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 321u),
-      context->GetDiagnostics()));
-
-  // Make a reference with both resource name and resource ID.
-  // The reference should point to a resource outside of this table to test that both name and id
-  // get serialized.
-  Reference expected_ref;
-  expected_ref.name = test::ParseNameOrDie("android:layout/main");
-  expected_ref.id = ResourceId(0x01020000);
-  ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("com.app.a:layout/abc"),
-                                 ConfigDescription::DefaultConfig(), {},
-                                 util::make_unique<Reference>(expected_ref),
-                                 context->GetDiagnostics()));
-
-  std::unique_ptr<pb::ResourceTable> pb_table = SerializeTableToPb(table.get());
-  ASSERT_THAT(pb_table, NotNull());
-
-  std::unique_ptr<ResourceTable> new_table = DeserializeTableFromPb(
-      *pb_table, Source{"test"}, context->GetDiagnostics());
-  ASSERT_THAT(new_table, NotNull());
-
-  Id* new_id = test::GetValue<Id>(new_table.get(), "com.app.a:id/foo");
-  ASSERT_THAT(new_id, NotNull());
-  EXPECT_THAT(new_id->IsWeak(), Eq(id->IsWeak()));
-
-  Maybe<ResourceTable::SearchResult> result =
-      new_table->FindResource(test::ParseNameOrDie("com.app.a:layout/main"));
-  ASSERT_TRUE(result);
-
-  EXPECT_THAT(result.value().type->symbol_status.state, Eq(SymbolState::kPublic));
-  EXPECT_THAT(result.value().entry->symbol_status.state, Eq(SymbolState::kPublic));
-
-  result = new_table->FindResource(test::ParseNameOrDie("com.app.a:bool/foo"));
-  ASSERT_TRUE(result);
-  EXPECT_THAT(result.value().entry->symbol_status.state, Eq(SymbolState::kUndefined));
-  EXPECT_TRUE(result.value().entry->symbol_status.allow_new);
-
-  // Find the product-dependent values
-  BinaryPrimitive* prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
-      new_table.get(), "com.app.a:integer/one", test::ParseConfigOrDie("land"), "");
-  ASSERT_THAT(prim, NotNull());
-  EXPECT_THAT(prim->value.data, Eq(123u));
-
-  prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
-      new_table.get(), "com.app.a:integer/one", test::ParseConfigOrDie("land"), "tablet");
-  ASSERT_THAT(prim, NotNull());
-  EXPECT_THAT(prim->value.data, Eq(321u));
-
-  Reference* actual_ref = test::GetValue<Reference>(new_table.get(), "com.app.a:layout/abc");
-  ASSERT_THAT(actual_ref, NotNull());
-  ASSERT_TRUE(actual_ref->name);
-  ASSERT_TRUE(actual_ref->id);
-  EXPECT_THAT(*actual_ref, Eq(expected_ref));
-
-  StyledString* actual_styled_str =
-      test::GetValue<StyledString>(new_table.get(), "com.app.a:string/styled");
-  ASSERT_THAT(actual_styled_str, NotNull());
-  EXPECT_THAT(actual_styled_str->value->value, Eq("hello"));
-  ASSERT_THAT(actual_styled_str->value->spans, SizeIs(1u));
-  EXPECT_THAT(*actual_styled_str->value->spans[0].name, Eq("b"));
-  EXPECT_THAT(actual_styled_str->value->spans[0].first_char, Eq(0u));
-  EXPECT_THAT(actual_styled_str->value->spans[0].last_char, Eq(4u));
-}
-
-TEST(TableProtoSerializer, SerializeFileHeader) {
-  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
-
-  ResourceFile f;
-  f.config = test::ParseConfigOrDie("hdpi-v9");
-  f.name = test::ParseNameOrDie("com.app.a:layout/main");
-  f.source.path = "res/layout-hdpi-v9/main.xml";
-  f.exported_symbols.push_back(
-      SourcedResourceName{test::ParseNameOrDie("id/unchecked"), 23u});
-
-  const std::string expected_data1 = "123";
-  const std::string expected_data2 = "1234";
-
-  std::string output_str;
-  {
-    std::unique_ptr<pb::internal::CompiledFile> pb_file1 = SerializeCompiledFileToPb(f);
-
-    f.name.entry = "__" + f.name.entry + "$0";
-    std::unique_ptr<pb::internal::CompiledFile> pb_file2 = SerializeCompiledFileToPb(f);
-
-    StringOutputStream out_stream(&output_str);
-    CompiledFileOutputStream out_file_stream(&out_stream);
-    out_file_stream.WriteLittleEndian32(2);
-    out_file_stream.WriteCompiledFile(pb_file1.get());
-    out_file_stream.WriteData(expected_data1.data(), expected_data1.size());
-    out_file_stream.WriteCompiledFile(pb_file2.get());
-    out_file_stream.WriteData(expected_data2.data(), expected_data2.size());
-    ASSERT_FALSE(out_file_stream.HadError());
-  }
-
-  CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
-  uint32_t num_files = 0;
-  ASSERT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
-  ASSERT_EQ(2u, num_files);
-
-  // Read the first compiled file.
-
-  pb::internal::CompiledFile new_pb_file;
-  ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_file));
-
-  std::unique_ptr<ResourceFile> file = DeserializeCompiledFileFromPb(
-      new_pb_file, Source("test"), context->GetDiagnostics());
-  ASSERT_THAT(file, NotNull());
-
-  uint64_t offset, len;
-  ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len));
-
-  std::string actual_data(output_str.data() + offset, len);
-  EXPECT_EQ(expected_data1, actual_data);
-
-  // Expect the data to be aligned.
-  EXPECT_EQ(0u, offset & 0x03);
-
-  ASSERT_EQ(1u, file->exported_symbols.size());
-  EXPECT_EQ(test::ParseNameOrDie("id/unchecked"), file->exported_symbols[0].name);
-
-  // Read the second compiled file.
-
-  ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_file));
-
-  file = DeserializeCompiledFileFromPb(new_pb_file, Source("test"), context->GetDiagnostics());
-  ASSERT_THAT(file, NotNull());
-
-  ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len));
-
-  actual_data = std::string(output_str.data() + offset, len);
-  EXPECT_EQ(expected_data2, actual_data);
-
-  // Expect the data to be aligned.
-  EXPECT_EQ(0u, offset & 0x03);
-}
-
-TEST(TableProtoSerializer, DeserializeCorruptHeaderSafely) {
-  ResourceFile f;
-  std::unique_ptr<pb::internal::CompiledFile> pb_file = SerializeCompiledFileToPb(f);
-
-  const std::string expected_data = "1234";
-
-  std::string output_str;
-  {
-    StringOutputStream out_stream(&output_str);
-    CompiledFileOutputStream out_file_stream(&out_stream);
-    out_file_stream.WriteLittleEndian32(1);
-    out_file_stream.WriteCompiledFile(pb_file.get());
-    out_file_stream.WriteData(expected_data.data(), expected_data.size());
-    ASSERT_FALSE(out_file_stream.HadError());
-  }
-
-  output_str[4] = 0xff;
-
-  CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
-
-  uint32_t num_files = 0;
-  EXPECT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
-  EXPECT_EQ(1u, num_files);
-
-  pb::internal::CompiledFile new_pb_file;
-  EXPECT_FALSE(in_file_stream.ReadCompiledFile(&new_pb_file));
-
-  uint64_t offset, len;
-  EXPECT_FALSE(in_file_stream.ReadDataMetaData(&offset, &len));
-}
-
-static void ExpectConfigSerializes(const StringPiece& config_str) {
-  const ConfigDescription expected_config = test::ParseConfigOrDie(config_str);
-  pb::Configuration pb_config;
-  SerializeConfig(expected_config, &pb_config);
-
-  ConfigDescription actual_config;
-  ASSERT_TRUE(DeserializeConfigDescriptionFromPb(pb_config, &actual_config));
-  EXPECT_EQ(expected_config, actual_config);
-}
-
-TEST(TableProtoSerializer, SerializeDeserializeConfiguration) {
-  ExpectConfigSerializes("");
-
-  ExpectConfigSerializes("mcc123");
-
-  ExpectConfigSerializes("mnc123");
-
-  ExpectConfigSerializes("en");
-  ExpectConfigSerializes("en-rGB");
-  ExpectConfigSerializes("b+en+GB");
-
-  ExpectConfigSerializes("ldltr");
-  ExpectConfigSerializes("ldrtl");
-
-  ExpectConfigSerializes("sw3600dp");
-
-  ExpectConfigSerializes("w300dp");
-
-  ExpectConfigSerializes("h400dp");
-
-  ExpectConfigSerializes("small");
-  ExpectConfigSerializes("normal");
-  ExpectConfigSerializes("large");
-  ExpectConfigSerializes("xlarge");
-
-  ExpectConfigSerializes("long");
-  ExpectConfigSerializes("notlong");
-
-  ExpectConfigSerializes("round");
-  ExpectConfigSerializes("notround");
-
-  ExpectConfigSerializes("widecg");
-  ExpectConfigSerializes("nowidecg");
-
-  ExpectConfigSerializes("highdr");
-  ExpectConfigSerializes("lowdr");
-
-  ExpectConfigSerializes("port");
-  ExpectConfigSerializes("land");
-  ExpectConfigSerializes("square");
-
-  ExpectConfigSerializes("desk");
-  ExpectConfigSerializes("car");
-  ExpectConfigSerializes("television");
-  ExpectConfigSerializes("appliance");
-  ExpectConfigSerializes("watch");
-  ExpectConfigSerializes("vrheadset");
-
-  ExpectConfigSerializes("night");
-  ExpectConfigSerializes("notnight");
-
-  ExpectConfigSerializes("300dpi");
-  ExpectConfigSerializes("hdpi");
-
-  ExpectConfigSerializes("notouch");
-  ExpectConfigSerializes("stylus");
-  ExpectConfigSerializes("finger");
-
-  ExpectConfigSerializes("keysexposed");
-  ExpectConfigSerializes("keyshidden");
-  ExpectConfigSerializes("keyssoft");
-
-  ExpectConfigSerializes("nokeys");
-  ExpectConfigSerializes("qwerty");
-  ExpectConfigSerializes("12key");
-
-  ExpectConfigSerializes("navhidden");
-  ExpectConfigSerializes("navexposed");
-
-  ExpectConfigSerializes("nonav");
-  ExpectConfigSerializes("dpad");
-  ExpectConfigSerializes("trackball");
-  ExpectConfigSerializes("wheel");
-
-  ExpectConfigSerializes("300x200");
-
-  ExpectConfigSerializes("v8");
-
-  ExpectConfigSerializes(
-      "mcc123-mnc456-b+en+GB-ldltr-sw300dp-w300dp-h400dp-large-long-round-widecg-highdr-land-car-"
-      "night-xhdpi-stylus-keysexposed-qwerty-navhidden-dpad-300x200-v23");
-}
-
-}  // namespace aapt