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/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;