Allow raw dex files to be read from arrays of base64 encoded bytes.
This allows tests to be run without opening files on local disk.
Change-Id: I05296bfba584d76ae272d4905b5c45ae10687bc6
diff --git a/Android.common.mk b/Android.common.mk
index 5bb20fa..9f7fa43 100644
--- a/Android.common.mk
+++ b/Android.common.mk
@@ -41,6 +41,7 @@
LIBART_LOCAL_SRC_FILES := \
src/assembler.cc \
+ src/base64.cc \
src/dex_file.cc \
src/dex_instruction.cc \
src/memory_region.cc \
diff --git a/src/base64.cc b/src/base64.cc
new file mode 100644
index 0000000..e745a62
--- /dev/null
+++ b/src/base64.cc
@@ -0,0 +1,76 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include "src/globals.h"
+#include "src/scoped_ptr.h"
+
+#include <vector>
+
+namespace art {
+
+static const byte kMap[256] = {
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
+ 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
+ 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255
+};
+
+byte* DecodeBase64(const char* src, size_t size, size_t* dst_size) {
+ std::vector<byte> tmp;
+ unsigned long t = 0, y = 0;
+ int g = 3;
+ for (size_t i = 0; i < size; ++i) {
+ byte c = kMap[src[i] & 0xFF];
+ if (c == 255) continue;
+ // the final = symbols are read and used to trim the remaining bytes
+ if (c == 254) {
+ c = 0;
+ // prevent g < 0 which would potentially allow an overflow later
+ if (--g < 0) {
+ return NULL;
+ }
+ } else if (g != 3) {
+ // we only allow = to be at the end
+ return NULL;
+ }
+ t = (t << 6) | c;
+ if (++y == 4) {
+ tmp.push_back((t >> 16) & 255);
+ if (g > 1) {
+ tmp.push_back((t >> 8) & 255);
+ }
+ if (g > 2) {
+ tmp.push_back(t & 255);
+ }
+ y = t = 0;
+ }
+ }
+ if (y != 0) {
+ return NULL;
+ }
+ scoped_ptr<byte> dst(new byte[tmp.size()]);
+ if (dst_size != NULL) {
+ *dst_size = tmp.size();
+ }
+ std::copy(tmp.begin(), tmp.end(), dst.get());
+ return dst.release();
+}
+
+};
diff --git a/src/base64.h b/src/base64.h
new file mode 100644
index 0000000..320148d
--- /dev/null
+++ b/src/base64.h
@@ -0,0 +1,14 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_BASE64_H_
+#define ART_SRC_BASE64_H_
+
+#include "src/globals.h"
+
+namespace art {
+
+byte* DecodeBase64(const char* src, size_t size, size_t* dst_size);
+
+} // namespace art
+
+#endif // ART_SRC_BASE64_H_
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 1951af5..1331ac7 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -9,8 +9,17 @@
namespace art {
-DexFile* DexFile::Open(const char* filename) {
- RawDexFile* raw = RawDexFile::Open(filename);
+DexFile* DexFile::OpenFile(const char* filename) {
+ RawDexFile* raw = RawDexFile::OpenFile(filename);
+ return Open(raw);
+}
+
+DexFile* DexFile::OpenBase64(const char* base64) {
+ RawDexFile* raw = RawDexFile::OpenBase64(base64);
+ return Open(raw);
+}
+
+DexFile* DexFile::Open(RawDexFile* raw) {
if (raw == NULL) {
return NULL;
}
diff --git a/src/dex_file.h b/src/dex_file.h
index 94ba33d..51c0a5a 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -12,8 +12,16 @@
class DexFile {
public:
- // Opens a dex file. Returns NULL on failure.
- static DexFile* Open(const char* filename);
+ // Opens a .dex file from the file system. Returns NULL on failure.
+ static DexFile* OpenFile(const char* filename);
+
+ // Opens a .dex file from a base64 encoded array. Returns NULL on
+ // failure.
+ static DexFile* OpenBase64(const char* base64);
+
+ // Opens a .dex file from a RawDexFile. Takes ownership of the
+ // RawDexFile.
+ static DexFile* Open(RawDexFile* raw);
// Close and deallocate.
~DexFile();
diff --git a/src/dex_file_test.cc b/src/dex_file_test.cc
index 74adca3..b46cbb5 100644
--- a/src/dex_file_test.cc
+++ b/src/dex_file_test.cc
@@ -8,16 +8,37 @@
namespace art {
-static const char* filename =
- "/usr/local/google/work/dalvik-dev-git/Nested.dex";
+// Nested.java
+//
+// class Nested {
+// class Inner {
+// }
+// }
+static const char kNestedDex[] =
+ "ZGV4CjAzNQAQedgAe7gM1B/WHsWJ6L7lGAISGC7yjD2IAwAAcAAAAHhWNBIAAAAAAAAAAMQCAAAP"
+ "AAAAcAAAAAcAAACsAAAAAgAAAMgAAAABAAAA4AAAAAMAAADoAAAAAgAAAAABAABIAgAAQAEAAK4B"
+ "AAC2AQAAvQEAAM0BAADXAQAA+wEAABsCAAA+AgAAUgIAAF8CAABiAgAAZgIAAHMCAAB5AgAAgQIA"
+ "AAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAkAAAAJAAAABgAAAAAAAAAKAAAABgAAAKgBAAAAAAEA"
+ "DQAAAAAAAQAAAAAAAQAAAAAAAAAFAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAIAAAAiAEAAKsCAAAA"
+ "AAAAAQAAAAAAAAAFAAAAAAAAAAgAAACYAQAAuAIAAAAAAAACAAAAlAIAAJoCAAABAAAAowIAAAIA"
+ "AgABAAAAiAIAAAYAAABbAQAAcBACAAAADgABAAEAAQAAAI4CAAAEAAAAcBACAAAADgBAAQAAAAAA"
+ "AAAAAAAAAAAATAEAAAAAAAAAAAAAAAAAAAEAAAABAAY8aW5pdD4ABUlubmVyAA5MTmVzdGVkJElu"
+ "bmVyOwAITE5lc3RlZDsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2"
+ "aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAhTGRhbHZpay9hbm5vdGF0aW9uL01lbWJlckNsYXNz"
+ "ZXM7ABJMamF2YS9sYW5nL09iamVjdDsAC05lc3RlZC5qYXZhAAFWAAJWTAALYWNjZXNzRmxhZ3MA"
+ "BG5hbWUABnRoaXMkMAAFdmFsdWUAAgEABw4AAQAHDjwAAgIBDhgBAgMCCwQADBcBAgQBDhwBGAAA"
+ "AQEAAJAgAICABNQCAAABAAGAgATwAgAAEAAAAAAAAAABAAAAAAAAAAEAAAAPAAAAcAAAAAIAAAAH"
+ "AAAArAAAAAMAAAACAAAAyAAAAAQAAAABAAAA4AAAAAUAAAADAAAA6AAAAAYAAAACAAAAAAEAAAMQ"
+ "AAACAAAAQAEAAAEgAAACAAAAVAEAAAYgAAACAAAAiAEAAAEQAAABAAAAqAEAAAIgAAAPAAAArgEA"
+ "AAMgAAACAAAAiAIAAAQgAAADAAAAlAIAAAAgAAACAAAAqwIAAAAQAAABAAAAxAIAAA==";
TEST(DexFile, Open) {
- scoped_ptr<DexFile> dex(DexFile::Open(filename));
+ scoped_ptr<DexFile> dex(DexFile::OpenBase64(kNestedDex));
ASSERT_TRUE(dex != NULL);
}
TEST(DexFile, LoadNonexistent) {
- scoped_ptr<DexFile> dex(DexFile::Open(filename));
+ scoped_ptr<DexFile> dex(DexFile::OpenBase64(kNestedDex));
ASSERT_TRUE(dex != NULL);
Class* klass = dex->LoadClass("NoSuchClass");
@@ -25,7 +46,7 @@
}
TEST(DexFile, Load) {
- scoped_ptr<DexFile> dex(DexFile::Open(filename));
+ scoped_ptr<DexFile> dex(DexFile::OpenBase64(kNestedDex));
ASSERT_TRUE(dex != NULL);
Class* klass = dex->LoadClass("LNested;");
diff --git a/src/raw_dex_file.cc b/src/raw_dex_file.cc
index 9f09177..6f1703f 100644
--- a/src/raw_dex_file.cc
+++ b/src/raw_dex_file.cc
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
-#include "src/raw_dex_file.h"
+#include "src/base64.h"
#include "src/globals.h"
#include "src/logging.h"
+#include "src/raw_dex_file.h"
+#include "src/scoped_ptr.h"
#include <errno.h>
#include <fcntl.h>
@@ -17,7 +19,33 @@
const byte RawDexFile::kDexMagic[] = { 'd', 'e', 'x', '\n' };
const byte RawDexFile::kDexMagicVersion[] = { '0', '3', '5', '\0' };
-RawDexFile* RawDexFile::Open(const char* filename) {
+// Helper class to deallocate mmap-backed .dex files.
+class MmapCloser : public RawDexFile::Closer {
+ public:
+ MmapCloser(void* addr, size_t length) : addr_(addr), length_(length) {};
+ virtual ~MmapCloser() {
+ CHECK(addr_ != NULL);
+ if (munmap(addr_, length_) == -1) {
+ LG << "munmap: " << strerror(errno); // TODO: PLOG
+ }
+ }
+ private:
+ void* addr_;
+ size_t length_;
+};
+
+// Helper class for deallocating new/delete-backed .dex files.
+class PtrCloser : public RawDexFile::Closer {
+ public:
+ PtrCloser(byte* addr) : addr_(addr) {};
+ virtual ~PtrCloser() { delete[] addr_; }
+ private:
+ byte* addr_;
+};
+
+RawDexFile::Closer::~Closer() {}
+
+RawDexFile* RawDexFile::OpenFile(const char* filename) {
CHECK(filename != NULL);
int fd = open(filename, O_RDONLY);
if (fd == -1) {
@@ -39,19 +67,33 @@
return NULL;
}
close(fd);
- RawDexFile* raw = new RawDexFile(reinterpret_cast<byte*>(addr), length);
- raw->Init();
- return raw;
+ byte* dex_file = reinterpret_cast<byte*>(addr);
+ Closer* closer = new MmapCloser(addr, length);
+ return Open(dex_file, closer);
}
-RawDexFile::~RawDexFile() {
- CHECK(base_ != NULL);
- const void* addr = reinterpret_cast<const void*>(base_);
- if (munmap(const_cast<void*>(addr), length_) == -1) {
- LG << "munmap: " << strerror(errno); // TODO: PLOG
+RawDexFile* RawDexFile::OpenBase64(const char* base64) {
+ CHECK(base64 != NULL);
+ size_t size = strlen(base64);
+ byte* dex_file = DecodeBase64(base64, size, NULL);
+ if (dex_file == NULL) {
+ return NULL;
+ }
+ RawDexFile::Closer* closer = new PtrCloser(dex_file);
+ return Open(dex_file, closer);
+}
+
+RawDexFile* RawDexFile::Open(const byte* dex_file, Closer* closer) {
+ scoped_ptr<RawDexFile> raw(new RawDexFile(dex_file, closer));
+ if (!raw->Init()) {
+ return NULL;
+ } else {
+ return raw.release();
}
}
+RawDexFile::~RawDexFile() {}
+
bool RawDexFile::Init() {
InitMembers();
if (!IsMagicValid()) {
@@ -74,7 +116,7 @@
}
bool RawDexFile::IsMagicValid() {
- return CheckMagic(header_->magic);
+ return CheckMagic(header_->magic_);
}
bool RawDexFile::CheckMagic(const byte* magic) {
diff --git a/src/raw_dex_file.h b/src/raw_dex_file.h
index ca01486..ea2ac4d 100644
--- a/src/raw_dex_file.h
+++ b/src/raw_dex_file.h
@@ -6,6 +6,7 @@
#include "src/globals.h"
#include "src/leb128.h"
#include "src/logging.h"
+#include "src/scoped_ptr.h"
#include "src/strutil.h"
#include <map>
@@ -20,9 +21,9 @@
// Raw header_item.
struct Header {
- uint8_t magic[8];
- uint32_t checksum;
- uint8_t signature[kSha1DigestSize];
+ uint8_t magic_[8];
+ uint32_t checksum_;
+ uint8_t signature_[kSha1DigestSize];
uint32_t file_size_; // length of entire file
uint32_t header_size_; // offset to start of next section
uint32_t endian_tag_;
@@ -142,11 +143,23 @@
uint32_t code_off_;
};
- // Opens a .dex file.
- static RawDexFile* Open(const char* filename);
+ // Helper class to deallocate underlying storage.
+ class Closer {
+ public:
+ virtual ~Closer();
+ };
+
+ // Opens a .dex file from the file system.
+ static RawDexFile* OpenFile(const char* filename);
+
+ // Opens a .dex file from a base64 encoded array.
+ static RawDexFile* OpenBase64(const char* base64);
+
+ // Opens a .dex file at a the given address.
+ static RawDexFile* Open(const byte* dex_file, Closer* closer);
// Closes a .dex file.
- ~RawDexFile();
+ virtual ~RawDexFile();
const Header& GetHeader() {
CHECK(header_ != NULL);
@@ -335,9 +348,9 @@
}
private:
- RawDexFile(const byte* addr, size_t length)
+ RawDexFile(const byte* addr, Closer* closer)
: base_(addr),
- length_(length),
+ closer_(closer),
header_(0),
string_ids_(0),
type_ids_(0),
@@ -368,8 +381,8 @@
// The base address of the memory mapping.
const byte* base_;
- // The length of the memory mapping in bytes.
- const size_t length_;
+ // Helper object to free the underlying allocation.
+ scoped_ptr<Closer> closer_;
// Points to the header section.
const Header* header_;
diff --git a/src/raw_dex_file_test.cc b/src/raw_dex_file_test.cc
index 6347c44..6bfd82a 100644
--- a/src/raw_dex_file_test.cc
+++ b/src/raw_dex_file_test.cc
@@ -1,23 +1,73 @@
// Copyright 2011 Google Inc. All Rights Reserved.
#include "src/raw_dex_file.h"
+#include "src/scoped_ptr.h"
#include <stdio.h>
#include "gtest/gtest.h"
namespace art {
-static const char* filename =
- "/usr/local/google/work/dalvik-dev-git/Nested.dex";
+// Nested.java
+//
+// class Nested {
+// class Inner {
+// }
+// }
+static const char kNestedDex[] =
+ "ZGV4CjAzNQAQedgAe7gM1B/WHsWJ6L7lGAISGC7yjD2IAwAAcAAAAHhWNBIAAAAAAAAAAMQCAAAP"
+ "AAAAcAAAAAcAAACsAAAAAgAAAMgAAAABAAAA4AAAAAMAAADoAAAAAgAAAAABAABIAgAAQAEAAK4B"
+ "AAC2AQAAvQEAAM0BAADXAQAA+wEAABsCAAA+AgAAUgIAAF8CAABiAgAAZgIAAHMCAAB5AgAAgQIA"
+ "AAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAkAAAAJAAAABgAAAAAAAAAKAAAABgAAAKgBAAAAAAEA"
+ "DQAAAAAAAQAAAAAAAQAAAAAAAAAFAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAIAAAAiAEAAKsCAAAA"
+ "AAAAAQAAAAAAAAAFAAAAAAAAAAgAAACYAQAAuAIAAAAAAAACAAAAlAIAAJoCAAABAAAAowIAAAIA"
+ "AgABAAAAiAIAAAYAAABbAQAAcBACAAAADgABAAEAAQAAAI4CAAAEAAAAcBACAAAADgBAAQAAAAAA"
+ "AAAAAAAAAAAATAEAAAAAAAAAAAAAAAAAAAEAAAABAAY8aW5pdD4ABUlubmVyAA5MTmVzdGVkJElu"
+ "bmVyOwAITE5lc3RlZDsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2"
+ "aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAhTGRhbHZpay9hbm5vdGF0aW9uL01lbWJlckNsYXNz"
+ "ZXM7ABJMamF2YS9sYW5nL09iamVjdDsAC05lc3RlZC5qYXZhAAFWAAJWTAALYWNjZXNzRmxhZ3MA"
+ "BG5hbWUABnRoaXMkMAAFdmFsdWUAAgEABw4AAQAHDjwAAgIBDhgBAgMCCwQADBcBAgQBDhwBGAAA"
+ "AQEAAJAgAICABNQCAAABAAGAgATwAgAAEAAAAAAAAAABAAAAAAAAAAEAAAAPAAAAcAAAAAIAAAAH"
+ "AAAArAAAAAMAAAACAAAAyAAAAAQAAAABAAAA4AAAAAUAAAADAAAA6AAAAAYAAAACAAAAAAEAAAMQ"
+ "AAACAAAAQAEAAAEgAAACAAAAVAEAAAYgAAACAAAAiAEAAAEQAAABAAAAqAEAAAIgAAAPAAAArgEA"
+ "AAMgAAACAAAAiAIAAAQgAAADAAAAlAIAAAAgAAACAAAAqwIAAAAQAAABAAAAxAIAAA==";
+
TEST(RawDexFile, Open) {
- RawDexFile* raw = RawDexFile::Open(filename);
+ scoped_ptr<RawDexFile> raw(RawDexFile::OpenBase64(kNestedDex));
ASSERT_TRUE(raw != NULL);
- delete raw;
+}
+
+TEST(RawDexFile, Header) {
+ scoped_ptr<RawDexFile> raw(RawDexFile::OpenBase64(kNestedDex));
+ ASSERT_TRUE(raw != NULL);
+
+ const RawDexFile::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_);
}
TEST(RawDexFile, ClassDefs) {
- RawDexFile* raw = RawDexFile::Open(filename);
+ scoped_ptr<RawDexFile> raw(RawDexFile::OpenBase64(kNestedDex));
ASSERT_TRUE(raw != NULL);
EXPECT_EQ(2U, raw->NumClassDefs());
@@ -26,8 +76,6 @@
const RawDexFile::ClassDef& c1 = raw->GetClassDef(1);
EXPECT_STREQ("LNested;", raw->GetClassDescriptor(c1));
-
- delete raw;
}
} // namespace art
diff --git a/src/scoped_ptr.h b/src/scoped_ptr.h
index 19c8166..ce21cc5 100644
--- a/src/scoped_ptr.h
+++ b/src/scoped_ptr.h
@@ -18,6 +18,8 @@
// implementation of the scoped_ptr class, and its closely-related brethren,
// scoped_array, scoped_ptr_malloc, and make_scoped_ptr.
+#include "src/macros.h"
+
#include <assert.h>
#include <stdlib.h>