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/build/Android.common.mk b/build/Android.common.mk
index eb95285..2556fa2 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -155,6 +155,7 @@
 	src/disassembler_mips.cc \
 	src/disassembler_x86.cc \
 	src/dlmalloc.cc \
+	src/file_output_stream.cc \
 	src/gc/card_table.cc \
 	src/gc/garbage_collector.cc \
 	src/gc/heap_bitmap.cc \
@@ -235,6 +236,7 @@
 	src/trace.cc \
 	src/utf.cc \
 	src/utils.cc \
+	src/vector_output_stream.cc \
 	src/well_known_classes.cc \
 	src/zip_archive.cc \
 	src/verifier/dex_gc_map.cc \
@@ -387,6 +389,7 @@
 	src/oat/utils/x86/managed_register_x86_test.cc \
 	src/oat_test.cc \
 	src/object_test.cc \
+	src/output_stream_test.cc \
 	src/reference_table_test.cc \
 	src/runtime_support_test.cc \
 	src/runtime_test.cc \
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_