Support for loading classes from DEX files stored in a ByteBuffer.

Bug: http://b/26878838
Test: test-art-target-gtest-dex_file_test

Change-Id: I68845c35784386bde6270102f0079d4f07bc4d03
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 2704d8a..2328e3d 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -22,6 +22,7 @@
 #include "base/unix_file/fd_file.h"
 #include "common_runtime_test.h"
 #include "dex_file-inl.h"
+#include "mem_map.h"
 #include "os.h"
 #include "scoped_thread_state_change.h"
 #include "thread-inl.h"
@@ -61,7 +62,7 @@
   255, 255, 255, 255
 };
 
-static inline uint8_t* DecodeBase64(const char* src, size_t* dst_size) {
+static inline std::vector<uint8_t> DecodeBase64(const char* src) {
   std::vector<uint8_t> tmp;
   uint32_t t = 0, y = 0;
   int g = 3;
@@ -73,13 +74,11 @@
       c = 0;
       // prevent g < 0 which would potentially allow an overflow later
       if (--g < 0) {
-        *dst_size = 0;
-        return nullptr;
+        return std::vector<uint8_t>();
       }
     } else if (g != 3) {
       // we only allow = to be at the end
-      *dst_size = 0;
-      return nullptr;
+        return std::vector<uint8_t>();
     }
     t = (t << 6) | c;
     if (++y == 4) {
@@ -94,17 +93,9 @@
     }
   }
   if (y != 0) {
-    *dst_size = 0;
-    return nullptr;
+    return std::vector<uint8_t>();
   }
-  std::unique_ptr<uint8_t[]> dst(new uint8_t[tmp.size()]);
-  if (dst_size != nullptr) {
-    *dst_size = tmp.size();
-  } else {
-    *dst_size = 0;
-  }
-  std::copy(tmp.begin(), tmp.end(), dst.get());
-  return dst.release();
+  return tmp;
 }
 
 // Although this is the same content logically as the Nested test dex,
@@ -175,14 +166,13 @@
 static void DecodeAndWriteDexFile(const char* base64, const char* location) {
   // decode base64
   CHECK(base64 != nullptr);
-  size_t length;
-  std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(base64, &length));
-  CHECK(dex_bytes.get() != nullptr);
+  std::vector<uint8_t> dex_bytes = DecodeBase64(base64);
+  CHECK_NE(dex_bytes.size(), 0u);
 
   // write to provided file
   std::unique_ptr<File> file(OS::CreateEmptyFile(location));
   CHECK(file.get() != nullptr);
-  if (!file->WriteFully(dex_bytes.get(), length)) {
+  if (!file->WriteFully(dex_bytes.data(), dex_bytes.size())) {
     PLOG(FATAL) << "Failed to write base64 as dex file";
   }
   if (file->FlushCloseOrErase() != 0) {
@@ -208,9 +198,67 @@
   return dex_file;
 }
 
+static std::unique_ptr<const DexFile> OpenDexFileInMemoryBase64(const char* base64,
+                                                                const char* location,
+                                                                uint32_t location_checksum) {
+  CHECK(base64 != nullptr);
+  std::vector<uint8_t> dex_bytes = DecodeBase64(base64);
+  CHECK_NE(dex_bytes.size(), 0u);
+
+  std::string error_message;
+  std::unique_ptr<MemMap> region(MemMap::MapAnonymous("test-region",
+                                                      nullptr,
+                                                      dex_bytes.size(),
+                                                      PROT_READ | PROT_WRITE,
+                                                      /* low_4gb */ false,
+                                                      /* reuse */ false,
+                                                      &error_message));
+  memcpy(region->Begin(), dex_bytes.data(), dex_bytes.size());
+  std::unique_ptr<const DexFile> dex_file(DexFile::Open(location,
+                                                        location_checksum,
+                                                        std::move(region),
+                                                        /* verify */ true,
+                                                        /* verify_checksum */ true,
+                                                        &error_message));
+  CHECK(dex_file != nullptr) << error_message;
+  return dex_file;
+}
+
 TEST_F(DexFileTest, Header) {
   ScratchFile tmp;
   std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kRawDex, tmp.GetFilename().c_str()));
+  ASSERT_TRUE(raw != nullptr);
+
+  const DexFile::Header& header = raw->GetHeader();
+  // TODO: header.magic_
+  EXPECT_EQ(0x00d87910U, header.checksum_);
+  // TODO: header.signature_
+  EXPECT_EQ(904U, header.file_size_);
+  EXPECT_EQ(112U, header.header_size_);
+  EXPECT_EQ(0U, header.link_size_);
+  EXPECT_EQ(0U, header.link_off_);
+  EXPECT_EQ(15U, header.string_ids_size_);
+  EXPECT_EQ(112U, header.string_ids_off_);
+  EXPECT_EQ(7U, header.type_ids_size_);
+  EXPECT_EQ(172U, header.type_ids_off_);
+  EXPECT_EQ(2U, header.proto_ids_size_);
+  EXPECT_EQ(200U, header.proto_ids_off_);
+  EXPECT_EQ(1U, header.field_ids_size_);
+  EXPECT_EQ(224U, header.field_ids_off_);
+  EXPECT_EQ(3U, header.method_ids_size_);
+  EXPECT_EQ(232U, header.method_ids_off_);
+  EXPECT_EQ(2U, header.class_defs_size_);
+  EXPECT_EQ(256U, header.class_defs_off_);
+  EXPECT_EQ(584U, header.data_size_);
+  EXPECT_EQ(320U, header.data_off_);
+
+  EXPECT_EQ(header.checksum_, raw->GetLocationChecksum());
+}
+
+TEST_F(DexFileTest, HeaderInMemory) {
+  ScratchFile tmp;
+  std::unique_ptr<const DexFile> raw =
+      OpenDexFileInMemoryBase64(kRawDex, tmp.GetFilename().c_str(), 0x00d87910U);
   ASSERT_TRUE(raw.get() != nullptr);
 
   const DexFile::Header& header = raw->GetHeader();