Create OutputStream abstraction
Allows data to be sent to file or memory transparently.
Standard C++ streams don't allow to create a stream from a file descriptor.
Change-Id: I820a864172e756949c61f29ef1517d1ebb253a0b
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index e434c29..82815d6 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -29,6 +29,7 @@
#include "class_linker.h"
#include "class_loader.h"
#include "compiler.h"
+#include "file_output_stream.h"
#include "image_writer.h"
#include "leb128.h"
#include "oat_writer.h"
@@ -268,7 +269,8 @@
}
}
- if (!OatWriter::Create(oat_file,
+ FileOutputStream file_output_stream(oat_file);
+ if (!OatWriter::Create(file_output_stream,
dex_files,
image_file_location_oat_checksum,
image_file_location_oat_begin,
diff --git a/src/file_output_stream.cc b/src/file_output_stream.cc
new file mode 100644
index 0000000..8b967af
--- /dev/null
+++ b/src/file_output_stream.cc
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2013 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 "file_output_stream.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/unix_file/fd_file.h"
+
+namespace art {
+
+FileOutputStream::FileOutputStream(File* file) : OutputStream(file->GetPath()), file_(file) {};
+
+bool FileOutputStream::WriteFully(const void* buffer, int64_t byte_count) {
+ return file_->WriteFully(buffer, byte_count);
+}
+
+off_t FileOutputStream::lseek(off_t offset, int whence) {
+ return ::lseek(file_->Fd(), offset, whence);
+}
+
+} // namespace art
diff --git a/src/file_output_stream.h b/src/file_output_stream.h
new file mode 100644
index 0000000..4106744
--- /dev/null
+++ b/src/file_output_stream.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2013 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 ART_SRC_FILE_OUTPUT_STREAM_H_
+#define ART_SRC_FILE_OUTPUT_STREAM_H_
+
+#include "output_stream.h"
+
+#include "os.h"
+
+namespace art {
+
+class FileOutputStream : public OutputStream {
+
+ public:
+ FileOutputStream(File* file);
+
+ virtual ~FileOutputStream() {};
+
+ virtual bool WriteFully(const void* buffer, int64_t byte_count);
+
+ virtual off_t lseek(off_t offset, int whence);
+
+ private:
+ File* file_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileOutputStream);
+};
+
+} // namespace art
+
+#endif // ART_SRC_FILE_OUTPUT_STREAM_H_
diff --git a/src/image_test.cc b/src/image_test.cc
index dc81587..502e1a0 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -20,6 +20,7 @@
#include "common_test.h"
#include "image.h"
#include "image_writer.h"
+#include "file_output_stream.h"
#include "oat_writer.h"
#include "signal_catcher.h"
#include "gc/space.h"
@@ -48,7 +49,8 @@
ScopedObjectAccess soa(Thread::Current());
std::vector<const DexFile*> dex_files;
dex_files.push_back(java_lang_dex_file_);
- bool success_oat = OatWriter::Create(tmp_oat.GetFile(), dex_files, 0, 0, "", *compiler_.get());
+ FileOutputStream file_output_stream(tmp_oat.GetFile());
+ bool success_oat = OatWriter::Create(file_output_stream, dex_files, 0, 0, "", *compiler_.get());
ASSERT_TRUE(success_oat);
// Force all system classes into memory
diff --git a/src/oat_test.cc b/src/oat_test.cc
index ae30c7e..6f0e7b6 100644
--- a/src/oat_test.cc
+++ b/src/oat_test.cc
@@ -16,6 +16,7 @@
#include "oat_file.h"
#include "oat_writer.h"
+#include "file_output_stream.h"
#include "common_test.h"
@@ -79,7 +80,8 @@
ScopedObjectAccess soa(Thread::Current());
ScratchFile tmp;
- bool success = OatWriter::Create(tmp.GetFile(),
+ FileOutputStream file_output_stream(tmp.GetFile());
+ bool success = OatWriter::Create(file_output_stream,
class_linker->GetBootClassPath(),
42U,
4096U,
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index 284578b..c5b698c 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -23,6 +23,7 @@
#include "class_linker.h"
#include "class_loader.h"
#include "os.h"
+#include "output_stream.h"
#include "safe_map.h"
#include "scoped_thread_state_change.h"
#include "gc/space.h"
@@ -30,7 +31,7 @@
namespace art {
-bool OatWriter::Create(File* file,
+bool OatWriter::Create(OutputStream& output_stream,
const std::vector<const DexFile*>& dex_files,
uint32_t image_file_location_oat_checksum,
uint32_t image_file_location_oat_begin,
@@ -41,7 +42,7 @@
image_file_location_oat_begin,
image_file_location,
compiler);
- return oat_writer.Write(file);
+ return oat_writer.Write(output_stream);
}
OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
@@ -421,50 +422,49 @@
}
#define DCHECK_CODE_OFFSET() \
- DCHECK_EQ(static_cast<off_t>(code_offset), lseek(file->Fd(), 0, SEEK_CUR))
+ DCHECK_EQ(static_cast<off_t>(code_offset), out.lseek(0, SEEK_CUR))
-bool OatWriter::Write(File* file) {
- if (!file->WriteFully(oat_header_, sizeof(*oat_header_))) {
- PLOG(ERROR) << "Failed to write oat header to " << file->GetPath();
+bool OatWriter::Write(OutputStream& out) {
+ if (!out.WriteFully(oat_header_, sizeof(*oat_header_))) {
+ PLOG(ERROR) << "Failed to write oat header to " << out.GetLocation();
return false;
}
- if (!file->WriteFully(image_file_location_.data(),
- image_file_location_.size())) {
- PLOG(ERROR) << "Failed to write oat header image file location to " << file->GetPath();
+ if (!out.WriteFully(image_file_location_.data(), image_file_location_.size())) {
+ PLOG(ERROR) << "Failed to write oat header image file location to " << out.GetLocation();
return false;
}
- if (!WriteTables(file)) {
- LOG(ERROR) << "Failed to write oat tables to " << file->GetPath();
+ if (!WriteTables(out)) {
+ LOG(ERROR) << "Failed to write oat tables to " << out.GetLocation();
return false;
}
- size_t code_offset = WriteCode(file);
+ size_t code_offset = WriteCode(out);
if (code_offset == 0) {
- LOG(ERROR) << "Failed to write oat code to " << file->GetPath();
+ LOG(ERROR) << "Failed to write oat code to " << out.GetLocation();
return false;
}
- code_offset = WriteCodeDexFiles(file, code_offset);
+ code_offset = WriteCodeDexFiles(out, code_offset);
if (code_offset == 0) {
- LOG(ERROR) << "Failed to write oat code for dex files to " << file->GetPath();
+ LOG(ERROR) << "Failed to write oat code for dex files to " << out.GetLocation();
return false;
}
return true;
}
-bool OatWriter::WriteTables(File* file) {
+bool OatWriter::WriteTables(OutputStream& out) {
for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
- if (!oat_dex_files_[i]->Write(file)) {
- PLOG(ERROR) << "Failed to write oat dex information to " << file->GetPath();
+ if (!oat_dex_files_[i]->Write(out)) {
+ PLOG(ERROR) << "Failed to write oat dex information to " << out.GetLocation();
return false;
}
}
for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
uint32_t expected_offset = oat_dex_files_[i]->dex_file_offset_;
- off_t actual_offset = lseek(file->Fd(), expected_offset, SEEK_SET);
+ off_t actual_offset = out.lseek(expected_offset, SEEK_SET);
if (static_cast<uint32_t>(actual_offset) != expected_offset) {
const DexFile* dex_file = (*dex_files_)[i];
PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset
@@ -472,38 +472,38 @@
return false;
}
const DexFile* dex_file = (*dex_files_)[i];
- if (!file->WriteFully(&dex_file->GetHeader(), dex_file->GetHeader().file_size_)) {
- PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation() << " to " << file->GetPath();
+ if (!out.WriteFully(&dex_file->GetHeader(), dex_file->GetHeader().file_size_)) {
+ PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation() << " to " << out.GetLocation();
return false;
}
}
for (size_t i = 0; i != oat_classes_.size(); ++i) {
- if (!oat_classes_[i]->Write(file)) {
- PLOG(ERROR) << "Failed to write oat methods information to " << file->GetPath();
+ if (!oat_classes_[i]->Write(out)) {
+ PLOG(ERROR) << "Failed to write oat methods information to " << out.GetLocation();
return false;
}
}
return true;
}
-size_t OatWriter::WriteCode(File* file) {
+size_t OatWriter::WriteCode(OutputStream& out) {
uint32_t code_offset = oat_header_->GetExecutableOffset();
- off_t new_offset = lseek(file->Fd(), executable_offset_padding_length_, SEEK_CUR);
+ off_t new_offset = out.lseek(executable_offset_padding_length_, SEEK_CUR);
if (static_cast<uint32_t>(new_offset) != code_offset) {
PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
- << " Expected: " << code_offset << " File: " << file->GetPath();
+ << " Expected: " << code_offset << " File: " << out.GetLocation();
return 0;
}
DCHECK_CODE_OFFSET();
return code_offset;
}
-size_t OatWriter::WriteCodeDexFiles(File* file, size_t code_offset) {
+size_t OatWriter::WriteCodeDexFiles(OutputStream& out, size_t code_offset) {
size_t oat_class_index = 0;
for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
const DexFile* dex_file = (*dex_files_)[i];
CHECK(dex_file != NULL);
- code_offset = WriteCodeDexFile(file, code_offset, oat_class_index, *dex_file);
+ code_offset = WriteCodeDexFile(out, code_offset, oat_class_index, *dex_file);
if (code_offset == 0) {
return 0;
}
@@ -511,12 +511,12 @@
return code_offset;
}
-size_t OatWriter::WriteCodeDexFile(File* file, size_t code_offset, size_t& oat_class_index,
+size_t OatWriter::WriteCodeDexFile(OutputStream& out, size_t code_offset, size_t& oat_class_index,
const DexFile& dex_file) {
for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs();
class_def_index++, oat_class_index++) {
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
- code_offset = WriteCodeClassDef(file, code_offset, oat_class_index, dex_file, class_def);
+ code_offset = WriteCodeClassDef(out, code_offset, oat_class_index, dex_file, class_def);
if (code_offset == 0) {
return 0;
}
@@ -525,12 +525,12 @@
}
void OatWriter::ReportWriteFailure(const char* what, uint32_t method_idx,
- const DexFile& dex_file, File* f) const {
+ const DexFile& dex_file, OutputStream& out) const {
PLOG(ERROR) << "Failed to write " << what << " for " << PrettyMethod(method_idx, dex_file)
- << " to " << f->GetPath();
+ << " to " << out.GetLocation();
}
-size_t OatWriter::WriteCodeClassDef(File* file,
+size_t OatWriter::WriteCodeClassDef(OutputStream& out,
size_t code_offset, size_t oat_class_index,
const DexFile& dex_file,
const DexFile::ClassDef& class_def) {
@@ -551,7 +551,7 @@
size_t class_def_method_index = 0;
while (it.HasNextDirectMethod()) {
bool is_static = (it.GetMemberAccessFlags() & kAccStatic) != 0;
- code_offset = WriteCodeMethod(file, code_offset, oat_class_index, class_def_method_index,
+ code_offset = WriteCodeMethod(out, code_offset, oat_class_index, class_def_method_index,
is_static, it.GetMemberIndex(), dex_file);
if (code_offset == 0) {
return 0;
@@ -560,7 +560,7 @@
it.Next();
}
while (it.HasNextVirtualMethod()) {
- code_offset = WriteCodeMethod(file, code_offset, oat_class_index, class_def_method_index,
+ code_offset = WriteCodeMethod(out, code_offset, oat_class_index, class_def_method_index,
false, it.GetMemberIndex(), dex_file);
if (code_offset == 0) {
return 0;
@@ -571,7 +571,7 @@
return code_offset;
}
-size_t OatWriter::WriteCodeMethod(File* file, size_t code_offset, size_t oat_class_index,
+size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t code_offset, size_t oat_class_index,
size_t class_def_method_index, bool is_static,
uint32_t method_idx, const DexFile& dex_file) {
const CompiledMethod* compiled_method =
@@ -585,10 +585,10 @@
uint32_t aligned_code_offset = compiled_method->AlignCode(code_offset);
uint32_t aligned_code_delta = aligned_code_offset - code_offset;
if (aligned_code_delta != 0) {
- off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR);
+ off_t new_offset = out.lseek(aligned_code_delta, SEEK_CUR);
if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
- << " Expected: " << aligned_code_offset << " File: " << file->GetPath();
+ << " Expected: " << aligned_code_offset << " File: " << out.GetLocation();
return 0;
}
code_offset += aligned_code_delta;
@@ -606,14 +606,14 @@
DCHECK(code_iter->second == method_offsets.code_offset_) << PrettyMethod(method_idx, dex_file);
} else {
DCHECK(offset == method_offsets.code_offset_) << PrettyMethod(method_idx, dex_file);
- if (!file->WriteFully(&code_size, sizeof(code_size))) {
- ReportWriteFailure("method code size", method_idx, dex_file, file);
+ if (!out.WriteFully(&code_size, sizeof(code_size))) {
+ ReportWriteFailure("method code size", method_idx, dex_file, out);
return 0;
}
code_offset += sizeof(code_size);
DCHECK_CODE_OFFSET();
- if (!file->WriteFully(&code[0], code_size)) {
- ReportWriteFailure("method code", method_idx, dex_file, file);
+ if (!out.WriteFully(&code[0], code_size)) {
+ ReportWriteFailure("method code", method_idx, dex_file, out);
return 0;
}
code_offset += code_size;
@@ -635,8 +635,8 @@
DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
|| code_offset == method_offsets.mapping_table_offset_)
<< PrettyMethod(method_idx, dex_file);
- if (!file->WriteFully(&mapping_table[0], mapping_table_size)) {
- ReportWriteFailure("mapping table", method_idx, dex_file, file);
+ if (!out.WriteFully(&mapping_table[0], mapping_table_size)) {
+ ReportWriteFailure("mapping table", method_idx, dex_file, out);
return 0;
}
code_offset += mapping_table_size;
@@ -658,8 +658,8 @@
DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
|| code_offset == method_offsets.vmap_table_offset_)
<< PrettyMethod(method_idx, dex_file);
- if (!file->WriteFully(&vmap_table[0], vmap_table_size)) {
- ReportWriteFailure("vmap table", method_idx, dex_file, file);
+ if (!out.WriteFully(&vmap_table[0], vmap_table_size)) {
+ ReportWriteFailure("vmap table", method_idx, dex_file, out);
return 0;
}
code_offset += vmap_table_size;
@@ -681,8 +681,8 @@
DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
|| code_offset == method_offsets.gc_map_offset_)
<< PrettyMethod(method_idx, dex_file);
- if (!file->WriteFully(&gc_map[0], gc_map_size)) {
- ReportWriteFailure("GC map", method_idx, dex_file, file);
+ if (!out.WriteFully(&gc_map[0], gc_map_size)) {
+ ReportWriteFailure("GC map", method_idx, dex_file, out);
return 0;
}
code_offset += gc_map_size;
@@ -696,7 +696,7 @@
compiler_->GetInstructionSet());
uint32_t aligned_code_delta = aligned_code_offset - code_offset;
if (aligned_code_delta != 0) {
- off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR);
+ off_t new_offset = out.lseek(aligned_code_delta, SEEK_CUR);
if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
PLOG(ERROR) << "Failed to seek to align invoke stub code. Actual: " << new_offset
<< " Expected: " << aligned_code_offset;
@@ -718,14 +718,14 @@
DCHECK(stub_iter->second == method_offsets.invoke_stub_offset_) << PrettyMethod(method_idx, dex_file);
} else {
DCHECK(offset == method_offsets.invoke_stub_offset_) << PrettyMethod(method_idx, dex_file);
- if (!file->WriteFully(&invoke_stub_size, sizeof(invoke_stub_size))) {
- ReportWriteFailure("invoke stub code size", method_idx, dex_file, file);
+ if (!out.WriteFully(&invoke_stub_size, sizeof(invoke_stub_size))) {
+ ReportWriteFailure("invoke stub code size", method_idx, dex_file, out);
return 0;
}
code_offset += sizeof(invoke_stub_size);
DCHECK_CODE_OFFSET();
- if (!file->WriteFully(&invoke_stub[0], invoke_stub_size)) {
- ReportWriteFailure("invoke stub code", method_idx, dex_file, file);
+ if (!out.WriteFully(&invoke_stub[0], invoke_stub_size)) {
+ ReportWriteFailure("invoke stub code", method_idx, dex_file, out);
return 0;
}
code_offset += invoke_stub_size;
@@ -742,7 +742,7 @@
uint32_t aligned_code_delta = aligned_code_offset - code_offset;
CHECK(aligned_code_delta < 48u);
if (aligned_code_delta != 0) {
- off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR);
+ off_t new_offset = out.lseek(aligned_code_delta, SEEK_CUR);
if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
PLOG(ERROR) << "Failed to seek to align proxy stub code. Actual: " << new_offset
<< " Expected: " << aligned_code_offset;
@@ -764,14 +764,14 @@
DCHECK(stub_iter->second == method_offsets.proxy_stub_offset_) << PrettyMethod(method_idx, dex_file);
} else {
DCHECK(offset == method_offsets.proxy_stub_offset_) << PrettyMethod(method_idx, dex_file);
- if (!file->WriteFully(&proxy_stub_size, sizeof(proxy_stub_size))) {
- ReportWriteFailure("proxy stub code size", method_idx, dex_file, file);
+ if (!out.WriteFully(&proxy_stub_size, sizeof(proxy_stub_size))) {
+ ReportWriteFailure("proxy stub code size", method_idx, dex_file, out);
return 0;
}
code_offset += sizeof(proxy_stub_size);
DCHECK_CODE_OFFSET();
- if (!file->WriteFully(&proxy_stub[0], proxy_stub_size)) {
- ReportWriteFailure("proxy stub code", method_idx, dex_file, file);
+ if (!out.WriteFully(&proxy_stub[0], proxy_stub_size)) {
+ ReportWriteFailure("proxy stub code", method_idx, dex_file, out);
return 0;
}
code_offset += proxy_stub_size;
@@ -811,26 +811,26 @@
sizeof(methods_offsets_[0]) * methods_offsets_.size());
}
-bool OatWriter::OatDexFile::Write(File* file) const {
- if (!file->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
- PLOG(ERROR) << "Failed to write dex file location length to " << file->GetPath();
+bool OatWriter::OatDexFile::Write(OutputStream& out) const {
+ if (!out.WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
+ PLOG(ERROR) << "Failed to write dex file location length to " << out.GetLocation();
return false;
}
- if (!file->WriteFully(dex_file_location_data_, dex_file_location_size_)) {
- PLOG(ERROR) << "Failed to write dex file location data to " << file->GetPath();
+ if (!out.WriteFully(dex_file_location_data_, dex_file_location_size_)) {
+ PLOG(ERROR) << "Failed to write dex file location data to " << out.GetLocation();
return false;
}
- if (!file->WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
- PLOG(ERROR) << "Failed to write dex file location checksum to " << file->GetPath();
+ if (!out.WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
+ PLOG(ERROR) << "Failed to write dex file location checksum to " << out.GetLocation();
return false;
}
- if (!file->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
- PLOG(ERROR) << "Failed to write dex file offset to " << file->GetPath();
+ if (!out.WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
+ PLOG(ERROR) << "Failed to write dex file offset to " << out.GetLocation();
return false;
}
- if (!file->WriteFully(&methods_offsets_[0],
- sizeof(methods_offsets_[0]) * methods_offsets_.size())) {
- PLOG(ERROR) << "Failed to write methods offsets to " << file->GetPath();
+ if (!out.WriteFully(&methods_offsets_[0],
+ sizeof(methods_offsets_[0]) * methods_offsets_.size())) {
+ PLOG(ERROR) << "Failed to write methods offsets to " << out.GetLocation();
return false;
}
return true;
@@ -852,14 +852,14 @@
sizeof(method_offsets_[0]) * method_offsets_.size());
}
-bool OatWriter::OatClass::Write(File* file) const {
- if (!file->WriteFully(&status_, sizeof(status_))) {
- PLOG(ERROR) << "Failed to write class status to " << file->GetPath();
+bool OatWriter::OatClass::Write(OutputStream& out) const {
+ if (!out.WriteFully(&status_, sizeof(status_))) {
+ PLOG(ERROR) << "Failed to write class status to " << out.GetLocation();
return false;
}
- if (!file->WriteFully(&method_offsets_[0],
- sizeof(method_offsets_[0]) * method_offsets_.size())) {
- PLOG(ERROR) << "Failed to write method offsets to " << file->GetPath();
+ if (!out.WriteFully(&method_offsets_[0],
+ sizeof(method_offsets_[0]) * method_offsets_.size())) {
+ PLOG(ERROR) << "Failed to write method offsets to " << out.GetLocation();
return false;
}
return true;
diff --git a/src/oat_writer.h b/src/oat_writer.h
index c5114fc..2bcbbc5 100644
--- a/src/oat_writer.h
+++ b/src/oat_writer.h
@@ -26,12 +26,13 @@
#include "mem_map.h"
#include "oat.h"
#include "object.h"
-#include "os.h"
#include "safe_map.h"
#include "UniquePtr.h"
namespace art {
+class OutputStream;
+
// OatHeader variable length with count of D OatDexFiles
//
// OatDexFile[0] one variable sized OatDexFile with offsets to Dex and OatClasses
@@ -63,7 +64,7 @@
class OatWriter {
public:
// Write an oat file. Returns true on success, false on failure.
- static bool Create(File* file,
+ static bool Create(OutputStream& out,
const std::vector<const DexFile*>& dex_files,
uint32_t image_file_location_oat_checksum,
uint32_t image_file_location_oat_begin,
@@ -100,27 +101,27 @@
uint32_t method_idx, const DexFile*)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool Write(File* file);
- bool WriteTables(File* file);
- size_t WriteCode(File* file);
- size_t WriteCodeDexFiles(File* file, size_t offset);
- size_t WriteCodeDexFile(File* file, size_t offset, size_t& oat_class_index,
+ bool Write(OutputStream& out);
+ bool WriteTables(OutputStream& out);
+ size_t WriteCode(OutputStream& out);
+ size_t WriteCodeDexFiles(OutputStream& out, size_t offset);
+ size_t WriteCodeDexFile(OutputStream& out, size_t offset, size_t& oat_class_index,
const DexFile& dex_file);
- size_t WriteCodeClassDef(File* file, size_t offset, size_t oat_class_index,
+ size_t WriteCodeClassDef(OutputStream& out, size_t offset, size_t oat_class_index,
const DexFile& dex_file, const DexFile::ClassDef& class_def);
- size_t WriteCodeMethod(File* file, size_t offset, size_t oat_class_index,
+ size_t WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_class_index,
size_t class_def_method_index, bool is_static, uint32_t method_idx,
const DexFile& dex_file);
void ReportWriteFailure(const char* what, uint32_t method_idx, const DexFile& dex_file,
- File* f) const;
+ OutputStream& out) const;
class OatDexFile {
public:
explicit OatDexFile(const DexFile& dex_file);
size_t SizeOf() const;
void UpdateChecksum(OatHeader& oat_header) const;
- bool Write(File* file) const;
+ bool Write(OutputStream& out) const;
// data to write
uint32_t dex_file_location_size_;
@@ -138,7 +139,7 @@
explicit OatClass(Class::Status status, uint32_t methods_count);
size_t SizeOf() const;
void UpdateChecksum(OatHeader& oat_header) const;
- bool Write(File* file) const;
+ bool Write(OutputStream& out) const;
// data to write
Class::Status status_;
diff --git a/src/output_stream.h b/src/output_stream.h
new file mode 100644
index 0000000..c35fe25
--- /dev/null
+++ b/src/output_stream.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2013 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 ART_SRC_OUTPUT_STREAM_H_
+#define ART_SRC_OUTPUT_STREAM_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/macros.h"
+
+namespace art {
+
+class OutputStream {
+ public:
+ OutputStream(const std::string& location) : location_(location) {};
+
+ virtual ~OutputStream() {};
+
+ const std::string& GetLocation() const {
+ return location_;
+ }
+
+ virtual bool WriteFully(const void* buffer, int64_t byte_count) = 0;
+
+ virtual off_t lseek(off_t offset, int whence) = 0;
+
+ private:
+ const std::string location_;
+
+ DISALLOW_COPY_AND_ASSIGN(OutputStream);
+};
+
+} // namespace art
+
+#endif // ART_SRC_OUTPUT_STREAM_H_
diff --git a/src/output_stream_test.cc b/src/output_stream_test.cc
new file mode 100644
index 0000000..8415d9f
--- /dev/null
+++ b/src/output_stream_test.cc
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2013 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 "base/logging.h"
+#include "common_test.h"
+#include "file_output_stream.h"
+#include "vector_output_stream.h"
+
+namespace art {
+
+class OutputStreamTest : public CommonTest {
+ protected:
+ void CheckOffset(off_t expected) {
+ off_t actual = output_stream_->lseek(0, SEEK_CUR);
+ CHECK_EQ(expected, actual);
+ }
+
+ void SetOutputStream(OutputStream& output_stream) {
+ output_stream_ = &output_stream;
+ }
+
+ void GenerateTestOutput() {
+ CHECK_EQ(3, output_stream_->lseek(3, SEEK_CUR));
+ CheckOffset(3);
+ CHECK_EQ(2, output_stream_->lseek(2, SEEK_SET));
+ CheckOffset(2);
+ uint8_t buf[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ CHECK(output_stream_->WriteFully(buf, 2));
+ CheckOffset(4);
+ CHECK_EQ(6, output_stream_->lseek(2, SEEK_END));
+ CheckOffset(6);
+ CHECK(output_stream_->WriteFully(buf, 4));
+ CheckOffset(10);
+ }
+
+ void CheckTestOutput(const std::vector<uint8_t>& actual) {
+ uint8_t expected[] = {
+ 0, 0, 1, 2, 0, 0, 1, 2, 3, 4
+ };
+ CHECK_EQ(sizeof(expected), actual.size());
+ CHECK_EQ(0, memcmp(expected, &actual[0], actual.size()));
+ }
+
+ OutputStream* output_stream_;
+};
+
+TEST_F(OutputStreamTest, File) {
+ ScratchFile tmp;
+ FileOutputStream output_stream(tmp.GetFile());
+ SetOutputStream(output_stream);
+ GenerateTestOutput();
+ UniquePtr<File> in(OS::OpenFile(tmp.GetFilename().c_str(), false));
+ CHECK(in.get() != NULL);
+ std::vector<uint8_t> actual(in->GetLength());
+ bool readSuccess = in->ReadFully(&actual[0], actual.size());
+ CHECK(readSuccess);
+ CheckTestOutput(actual);
+}
+
+TEST_F(OutputStreamTest, Vector) {
+ std::vector<uint8_t> output;
+ VectorOutputStream output_stream("test vector output", output);
+ SetOutputStream(output_stream);
+ GenerateTestOutput();
+ CheckTestOutput(output);
+}
+
+} // namespace std
diff --git a/src/vector_output_stream.cc b/src/vector_output_stream.cc
new file mode 100644
index 0000000..73bc209
--- /dev/null
+++ b/src/vector_output_stream.cc
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2013 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 "vector_output_stream.h"
+
+#include <string.h>
+
+#include "base/logging.h"
+
+namespace art {
+
+VectorOutputStream::VectorOutputStream(const std::string& location, std::vector<uint8_t>& vector)
+ : OutputStream(location), offset_(vector.size()), vector_(vector) {};
+
+bool VectorOutputStream::WriteFully(const void* buffer, int64_t byte_count) {
+ off_t new_offset = offset_ + byte_count;
+ EnsureCapacity(new_offset);
+ memcpy(&vector_[offset_], buffer, byte_count);
+ offset_ = new_offset;
+ return true;
+}
+
+off_t VectorOutputStream::lseek(off_t offset, int whence) {
+ CHECK(whence == SEEK_SET || whence == SEEK_CUR || whence == SEEK_END) << whence;
+ off_t new_offset;
+ switch (whence) {
+ case SEEK_SET: {
+ new_offset = offset;
+ break;
+ }
+ case SEEK_CUR: {
+ new_offset = offset_ + offset;
+ break;
+ }
+ case SEEK_END: {
+ new_offset = vector_.size() + offset;
+ break;
+ }
+ default: {
+ LOG(FATAL) << whence;
+ new_offset = -1;
+ }
+ }
+ EnsureCapacity(new_offset);
+ offset_ = new_offset;
+ return offset_;
+}
+
+void VectorOutputStream::EnsureCapacity(off_t new_offset) {
+ if (new_offset > static_cast<off_t>(vector_.size())) {
+ vector_.resize(new_offset);
+ }
+}
+
+} // namespace art
diff --git a/src/vector_output_stream.h b/src/vector_output_stream.h
new file mode 100644
index 0000000..a11c82b
--- /dev/null
+++ b/src/vector_output_stream.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 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 ART_SRC_VECTOR_OUTPUT_STREAM_H_
+#define ART_SRC_VECTOR_OUTPUT_STREAM_H_
+
+#include "output_stream.h"
+
+#include <string>
+#include <vector>
+
+namespace art {
+
+class VectorOutputStream : public OutputStream {
+
+ public:
+ VectorOutputStream(const std::string& location, std::vector<uint8_t>& vector);
+
+ virtual ~VectorOutputStream() {};
+
+ virtual bool WriteFully(const void* buffer, int64_t byte_count);
+
+ virtual off_t lseek(off_t offset, int whence);
+
+ private:
+ void EnsureCapacity(off_t new_offset);
+
+ off_t offset_;
+ std::vector<uint8_t>& vector_;
+
+ DISALLOW_COPY_AND_ASSIGN(VectorOutputStream);
+};
+
+} // namespace art
+
+#endif // ART_SRC_VECTOR_OUTPUT_STREAM_H_