Merge "Refactor compact dex writing"
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index 3c71770..fabe6e7 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -17,6 +17,7 @@
     defaults: ["art_defaults"],
     host_supported: true,
     srcs: [
+        "compact_dex_writer.cc",
         "dexlayout.cc",
         "dex_ir.cc",
         "dex_ir_builder.cc",
diff --git a/dexlayout/compact_dex_writer.cc b/dexlayout/compact_dex_writer.cc
new file mode 100644
index 0000000..b089c1d
--- /dev/null
+++ b/dexlayout/compact_dex_writer.cc
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#include "compact_dex_writer.h"
+
+#include "cdex/compact_dex_file.h"
+
+namespace art {
+
+void CompactDexWriter::WriteHeader() {
+  CompactDexFile::Header header;
+  CompactDexFile::WriteMagic(&header.magic_[0]);
+  CompactDexFile::WriteCurrentVersion(&header.magic_[0]);
+  header.checksum_ = header_->Checksum();
+  std::copy_n(header_->Signature(), DexFile::kSha1DigestSize, header.signature_);
+  header.file_size_ = header_->FileSize();
+  header.header_size_ = header_->GetSize();
+  header.endian_tag_ = header_->EndianTag();
+  header.link_size_ = header_->LinkSize();
+  header.link_off_ = header_->LinkOffset();
+  const dex_ir::Collections& collections = header_->GetCollections();
+  header.map_off_ = collections.MapListOffset();
+  header.string_ids_size_ = collections.StringIdsSize();
+  header.string_ids_off_ = collections.StringIdsOffset();
+  header.type_ids_size_ = collections.TypeIdsSize();
+  header.type_ids_off_ = collections.TypeIdsOffset();
+  header.proto_ids_size_ = collections.ProtoIdsSize();
+  header.proto_ids_off_ = collections.ProtoIdsOffset();
+  header.field_ids_size_ = collections.FieldIdsSize();
+  header.field_ids_off_ = collections.FieldIdsOffset();
+  header.method_ids_size_ = collections.MethodIdsSize();
+  header.method_ids_off_ = collections.MethodIdsOffset();
+  header.class_defs_size_ = collections.ClassDefsSize();
+  header.class_defs_off_ = collections.ClassDefsOffset();
+  header.data_size_ = header_->DataSize();
+  header.data_off_ = header_->DataOffset();
+  Write(reinterpret_cast<uint8_t*>(&header), sizeof(header), 0u);
+}
+
+}  // namespace art
diff --git a/dexlayout/compact_dex_writer.h b/dexlayout/compact_dex_writer.h
new file mode 100644
index 0000000..1c77202
--- /dev/null
+++ b/dexlayout/compact_dex_writer.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ *
+ * Header file of an in-memory representation of DEX files.
+ */
+
+#ifndef ART_DEXLAYOUT_COMPACT_DEX_WRITER_H_
+#define ART_DEXLAYOUT_COMPACT_DEX_WRITER_H_
+
+#include "dex_writer.h"
+
+namespace art {
+
+class CompactDexWriter : public DexWriter {
+ public:
+  CompactDexWriter(dex_ir::Header* header, MemMap* mem_map, CompactDexLevel compact_dex_level)
+      : DexWriter(header, mem_map),
+        compact_dex_level_(compact_dex_level) { }
+
+ protected:
+  void WriteHeader() OVERRIDE;
+
+  const CompactDexLevel compact_dex_level_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CompactDexWriter);
+};
+
+}  // namespace art
+
+#endif  // ART_DEXLAYOUT_COMPACT_DEX_WRITER_H_
diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc
index 8c82106..4895ab6 100644
--- a/dexlayout/dex_writer.cc
+++ b/dexlayout/dex_writer.cc
@@ -12,8 +12,6 @@
  * 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.
- *
- * Header file of an in-memory representation of DEX files.
  */
 
 #include "dex_writer.h"
@@ -24,6 +22,7 @@
 #include <vector>
 
 #include "cdex/compact_dex_file.h"
+#include "compact_dex_writer.h"
 #include "dex_file_types.h"
 #include "standard_dex_file.h"
 #include "utf.h"
@@ -629,48 +628,36 @@
 }
 
 void DexWriter::WriteHeader() {
-  uint32_t buffer[20];
-  dex_ir::Collections& collections = header_->GetCollections();
-  size_t offset = 0;
-  if (compact_dex_level_ != CompactDexLevel::kCompactDexLevelNone) {
-    static constexpr size_t kMagicAndVersionLen =
-        CompactDexFile::kDexMagicSize + CompactDexFile::kDexVersionLen;
-    uint8_t magic_and_version[kMagicAndVersionLen] = {};
-    CompactDexFile::WriteMagic(&magic_and_version[0]);
-    CompactDexFile::WriteCurrentVersion(&magic_and_version[0]);
-    offset += Write(magic_and_version, kMagicAndVersionLen * sizeof(uint8_t), offset);
-  } else {
-    static constexpr size_t kMagicAndVersionLen =
-        StandardDexFile::kDexMagicSize + StandardDexFile::kDexVersionLen;
-    offset += Write(header_->Magic(), kMagicAndVersionLen * sizeof(uint8_t), offset);
-  }
-  buffer[0] = header_->Checksum();
-  offset += Write(buffer, sizeof(uint32_t), offset);
-  offset += Write(header_->Signature(), 20 * sizeof(uint8_t), offset);
-  uint32_t file_size = header_->FileSize();
-  buffer[0] = file_size;
-  buffer[1] = header_->GetSize();
-  buffer[2] = header_->EndianTag();
-  buffer[3] = header_->LinkSize();
-  buffer[4] = header_->LinkOffset();
-  buffer[5] = collections.MapListOffset();
-  buffer[6] = collections.StringIdsSize();
-  buffer[7] = collections.StringIdsOffset();
-  buffer[8] = collections.TypeIdsSize();
-  buffer[9] = collections.TypeIdsOffset();
-  buffer[10] = collections.ProtoIdsSize();
-  buffer[11] = collections.ProtoIdsOffset();
-  buffer[12] = collections.FieldIdsSize();
-  buffer[13] = collections.FieldIdsOffset();
-  buffer[14] = collections.MethodIdsSize();
-  buffer[15] = collections.MethodIdsOffset();
-  uint32_t class_defs_size = collections.ClassDefsSize();
-  uint32_t class_defs_off = collections.ClassDefsOffset();
-  buffer[16] = class_defs_size;
-  buffer[17] = class_defs_off;
-  buffer[18] = header_->DataSize();
-  buffer[19] = header_->DataOffset();
-  Write(buffer, 20 * sizeof(uint32_t), offset);
+  StandardDexFile::Header header;
+  static constexpr size_t kMagicAndVersionLen =
+      StandardDexFile::kDexMagicSize + StandardDexFile::kDexVersionLen;
+  std::copy_n(header_->Magic(), kMagicAndVersionLen, header.magic_);
+  header.checksum_ = header_->Checksum();
+  std::copy_n(header_->Signature(), DexFile::kSha1DigestSize, header.signature_);
+  header.file_size_ = header_->FileSize();
+  header.header_size_ = header_->GetSize();
+  header.endian_tag_ = header_->EndianTag();
+  header.link_size_ = header_->LinkSize();
+  header.link_off_ = header_->LinkOffset();
+  const dex_ir::Collections& collections = header_->GetCollections();
+  header.map_off_ = collections.MapListOffset();
+  header.string_ids_size_ = collections.StringIdsSize();
+  header.string_ids_off_ = collections.StringIdsOffset();
+  header.type_ids_size_ = collections.TypeIdsSize();
+  header.type_ids_off_ = collections.TypeIdsOffset();
+  header.proto_ids_size_ = collections.ProtoIdsSize();
+  header.proto_ids_off_ = collections.ProtoIdsOffset();
+  header.field_ids_size_ = collections.FieldIdsSize();
+  header.field_ids_off_ = collections.FieldIdsOffset();
+  header.method_ids_size_ = collections.MethodIdsSize();
+  header.method_ids_off_ = collections.MethodIdsOffset();
+  header.class_defs_size_ = collections.ClassDefsSize();
+  header.class_defs_off_ = collections.ClassDefsOffset();
+  header.data_size_ = header_->DataSize();
+  header.data_off_ = header_->DataOffset();
+
+  static_assert(sizeof(header) == 0x70, "Size doesn't match dex spec");
+  Write(reinterpret_cast<uint8_t*>(&header), sizeof(header), 0u);
 }
 
 void DexWriter::WriteMemMap() {
@@ -695,8 +682,13 @@
 }
 
 void DexWriter::Output(dex_ir::Header* header, MemMap* mem_map, CompactDexLevel compact_dex_level) {
-  DexWriter dex_writer(header, mem_map, compact_dex_level);
-  dex_writer.WriteMemMap();
+  std::unique_ptr<DexWriter> writer;
+  if (compact_dex_level != CompactDexLevel::kCompactDexLevelNone) {
+    writer.reset(new CompactDexWriter(header, mem_map, compact_dex_level));
+  } else {
+    writer.reset(new DexWriter(header, mem_map));
+  }
+  writer->WriteMemMap();
 }
 
 }  // namespace art
diff --git a/dexlayout/dex_writer.h b/dexlayout/dex_writer.h
index d932b9f..85d3e7e 100644
--- a/dexlayout/dex_writer.h
+++ b/dexlayout/dex_writer.h
@@ -29,16 +29,13 @@
 
 class DexWriter {
  public:
-  DexWriter(dex_ir::Header* header,
-            MemMap* mem_map,
-            CompactDexLevel compact_dex_level)
-      : header_(header),
-        mem_map_(mem_map),
-        compact_dex_level_(compact_dex_level) { }
+  DexWriter(dex_ir::Header* header, MemMap* mem_map) : header_(header), mem_map_(mem_map) {}
 
   static void Output(dex_ir::Header* header, MemMap* mem_map, CompactDexLevel compact_dex_level);
 
- private:
+  virtual ~DexWriter() {}
+
+ protected:
   void WriteMemMap();
 
   size_t Write(const void* buffer, size_t length, size_t offset);
@@ -68,12 +65,12 @@
   void WriteCallSites();
   void WriteMethodHandles();
   void WriteMapItem();
-  void WriteHeader();
+  virtual void WriteHeader();
 
   dex_ir::Header* const header_;
   MemMap* const mem_map_;
-  const CompactDexLevel compact_dex_level_;
 
+ private:
   DISALLOW_COPY_AND_ASSIGN(DexWriter);
 };
 
diff --git a/runtime/cdex/compact_dex_file.h b/runtime/cdex/compact_dex_file.h
index 3c1b638..8ab9247 100644
--- a/runtime/cdex/compact_dex_file.h
+++ b/runtime/cdex/compact_dex_file.h
@@ -24,6 +24,9 @@
 // CompactDex is a currently ART internal dex file format that aims to reduce storage/RAM usage.
 class CompactDexFile : public DexFile {
  public:
+  class Header : public DexFile::Header {
+    // Same for now.
+  };
   static constexpr uint8_t kDexMagic[kDexMagicSize] = { 'c', 'd', 'e', 'x' };
   static constexpr uint8_t kDexMagicVersion[] = {'0', '0', '1', '\0'};
 
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index c0e0fbc..f239edc 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -78,35 +78,32 @@
 
   // Raw header_item.
   struct Header {
-    uint8_t magic_[8];
-    uint32_t checksum_;  // See also location_checksum_
-    uint8_t signature_[kSha1DigestSize];
-    uint32_t file_size_;  // size of entire file
-    uint32_t header_size_;  // offset to start of next section
-    uint32_t endian_tag_;
-    uint32_t link_size_;  // unused
-    uint32_t link_off_;  // unused
-    uint32_t map_off_;  // unused
-    uint32_t string_ids_size_;  // number of StringIds
-    uint32_t string_ids_off_;  // file offset of StringIds array
-    uint32_t type_ids_size_;  // number of TypeIds, we don't support more than 65535
-    uint32_t type_ids_off_;  // file offset of TypeIds array
-    uint32_t proto_ids_size_;  // number of ProtoIds, we don't support more than 65535
-    uint32_t proto_ids_off_;  // file offset of ProtoIds array
-    uint32_t field_ids_size_;  // number of FieldIds
-    uint32_t field_ids_off_;  // file offset of FieldIds array
-    uint32_t method_ids_size_;  // number of MethodIds
-    uint32_t method_ids_off_;  // file offset of MethodIds array
-    uint32_t class_defs_size_;  // number of ClassDefs
-    uint32_t class_defs_off_;  // file offset of ClassDef array
-    uint32_t data_size_;  // size of data section
-    uint32_t data_off_;  // file offset of data section
+    uint8_t magic_[8] = {};
+    uint32_t checksum_ = 0;  // See also location_checksum_
+    uint8_t signature_[kSha1DigestSize] = {};
+    uint32_t file_size_ = 0;  // size of entire file
+    uint32_t header_size_ = 0;  // offset to start of next section
+    uint32_t endian_tag_ = 0;
+    uint32_t link_size_ = 0;  // unused
+    uint32_t link_off_ = 0;  // unused
+    uint32_t map_off_ = 0;  // unused
+    uint32_t string_ids_size_ = 0;  // number of StringIds
+    uint32_t string_ids_off_ = 0;  // file offset of StringIds array
+    uint32_t type_ids_size_ = 0;  // number of TypeIds, we don't support more than 65535
+    uint32_t type_ids_off_ = 0;  // file offset of TypeIds array
+    uint32_t proto_ids_size_ = 0;  // number of ProtoIds, we don't support more than 65535
+    uint32_t proto_ids_off_ = 0;  // file offset of ProtoIds array
+    uint32_t field_ids_size_ = 0;  // number of FieldIds
+    uint32_t field_ids_off_ = 0;  // file offset of FieldIds array
+    uint32_t method_ids_size_ = 0;  // number of MethodIds
+    uint32_t method_ids_off_ = 0;  // file offset of MethodIds array
+    uint32_t class_defs_size_ = 0;  // number of ClassDefs
+    uint32_t class_defs_off_ = 0;  // file offset of ClassDef array
+    uint32_t data_size_ = 0;  // size of data section
+    uint32_t data_off_ = 0;  // file offset of data section
 
     // Decode the dex magic version
     uint32_t GetVersion() const;
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(Header);
   };
 
   // Map item type codes.
diff --git a/runtime/standard_dex_file.h b/runtime/standard_dex_file.h
index 906b0b7..784ab31 100644
--- a/runtime/standard_dex_file.h
+++ b/runtime/standard_dex_file.h
@@ -28,6 +28,10 @@
 // Standard dex file. This is the format that is packaged in APKs and produced by tools.
 class StandardDexFile : public DexFile {
  public:
+  class Header : public DexFile::Header {
+    // Same for now.
+  };
+
   static const uint8_t kDexMagic[kDexMagicSize];
   static constexpr size_t kNumDexVersions = 4;
   static const uint8_t kDexMagicVersions[kNumDexVersions][kDexVersionLen];