Add ElfWriter::GetStream().

This will be used for writing the OatHeader which is
currently oddly written through the .text stream.

Also move the error delaying output stream out of the
ElfBuilder<> to its own file and move all output stream
files to compiler/linker/.

Change-Id: I00db4e33ed80ac4757ec459946c7b5ae014a3a2e
diff --git a/compiler/linker/arm/relative_patcher_arm_base.cc b/compiler/linker/arm/relative_patcher_arm_base.cc
index 13754fd..73b0fac 100644
--- a/compiler/linker/arm/relative_patcher_arm_base.cc
+++ b/compiler/linker/arm/relative_patcher_arm_base.cc
@@ -17,9 +17,9 @@
 #include "linker/arm/relative_patcher_arm_base.h"
 
 #include "compiled_method.h"
+#include "linker/output_stream.h"
 #include "oat.h"
 #include "oat_quick_method_header.h"
-#include "output_stream.h"
 
 namespace art {
 namespace linker {
diff --git a/compiler/linker/arm64/relative_patcher_arm64.cc b/compiler/linker/arm64/relative_patcher_arm64.cc
index 57018af..3d4c218 100644
--- a/compiler/linker/arm64/relative_patcher_arm64.cc
+++ b/compiler/linker/arm64/relative_patcher_arm64.cc
@@ -20,10 +20,10 @@
 #include "art_method.h"
 #include "compiled_method.h"
 #include "driver/compiler_driver.h"
-#include "utils/arm64/assembler_arm64.h"
+#include "linker/output_stream.h"
 #include "oat.h"
 #include "oat_quick_method_header.h"
-#include "output_stream.h"
+#include "utils/arm64/assembler_arm64.h"
 
 namespace art {
 namespace linker {
diff --git a/compiler/linker/buffered_output_stream.cc b/compiler/linker/buffered_output_stream.cc
new file mode 100644
index 0000000..4c66c76
--- /dev/null
+++ b/compiler/linker/buffered_output_stream.cc
@@ -0,0 +1,70 @@
+/*
+ * 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 "buffered_output_stream.h"
+
+#include <string.h>
+
+namespace art {
+
+BufferedOutputStream::BufferedOutputStream(std::unique_ptr<OutputStream> out)
+    : OutputStream(out->GetLocation()),  // Before out is moved to out_.
+      out_(std::move(out)),
+      used_(0) {}
+
+BufferedOutputStream::~BufferedOutputStream() {
+  FlushBuffer();
+}
+
+bool BufferedOutputStream::WriteFully(const void* buffer, size_t byte_count) {
+  if (byte_count > kBufferSize) {
+    if (!FlushBuffer()) {
+      return false;
+    }
+    return out_->WriteFully(buffer, byte_count);
+  }
+  if (used_ + byte_count > kBufferSize) {
+    if (!FlushBuffer()) {
+      return false;
+    }
+  }
+  const uint8_t* src = reinterpret_cast<const uint8_t*>(buffer);
+  memcpy(&buffer_[used_], src, byte_count);
+  used_ += byte_count;
+  return true;
+}
+
+bool BufferedOutputStream::Flush() {
+  return FlushBuffer() && out_->Flush();
+}
+
+bool BufferedOutputStream::FlushBuffer() {
+  bool success = true;
+  if (used_ > 0) {
+    success = out_->WriteFully(&buffer_[0], used_);
+    used_ = 0;
+  }
+  return success;
+}
+
+off_t BufferedOutputStream::Seek(off_t offset, Whence whence) {
+  if (!FlushBuffer()) {
+    return -1;
+  }
+  return out_->Seek(offset, whence);
+}
+
+}  // namespace art
diff --git a/compiler/linker/buffered_output_stream.h b/compiler/linker/buffered_output_stream.h
new file mode 100644
index 0000000..a2eefbb
--- /dev/null
+++ b/compiler/linker/buffered_output_stream.h
@@ -0,0 +1,54 @@
+/*
+ * 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_COMPILER_LINKER_BUFFERED_OUTPUT_STREAM_H_
+#define ART_COMPILER_LINKER_BUFFERED_OUTPUT_STREAM_H_
+
+#include <memory>
+
+#include "output_stream.h"
+
+#include "globals.h"
+
+namespace art {
+
+class BufferedOutputStream FINAL : public OutputStream {
+ public:
+  explicit BufferedOutputStream(std::unique_ptr<OutputStream> out);
+
+  ~BufferedOutputStream() OVERRIDE;
+
+  bool WriteFully(const void* buffer, size_t byte_count) OVERRIDE;
+
+  off_t Seek(off_t offset, Whence whence) OVERRIDE;
+
+  bool Flush() OVERRIDE;
+
+ private:
+  static const size_t kBufferSize = 8 * KB;
+
+  bool FlushBuffer();
+
+  std::unique_ptr<OutputStream> const out_;
+  uint8_t buffer_[kBufferSize];
+  size_t used_;
+
+  DISALLOW_COPY_AND_ASSIGN(BufferedOutputStream);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_LINKER_BUFFERED_OUTPUT_STREAM_H_
diff --git a/compiler/linker/error_delaying_output_stream.h b/compiler/linker/error_delaying_output_stream.h
new file mode 100644
index 0000000..99410e4
--- /dev/null
+++ b/compiler/linker/error_delaying_output_stream.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2015 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_COMPILER_LINKER_ERROR_DELAYING_OUTPUT_STREAM_H_
+#define ART_COMPILER_LINKER_ERROR_DELAYING_OUTPUT_STREAM_H_
+
+#include "output_stream.h"
+
+#include "base/logging.h"
+
+namespace art {
+
+// OutputStream wrapper that delays reporting an error until Flush().
+class ErrorDelayingOutputStream FINAL : public OutputStream {
+ public:
+  explicit ErrorDelayingOutputStream(OutputStream* output)
+      : OutputStream(output->GetLocation()),
+        output_(output),
+        output_good_(true),
+        output_offset_(0) { }
+
+  // This function always succeeds to simplify code.
+  // Use Good() to check the actual status of the output stream.
+  bool WriteFully(const void* buffer, size_t byte_count) OVERRIDE {
+    if (output_good_) {
+      if (!output_->WriteFully(buffer, byte_count)) {
+        PLOG(ERROR) << "Failed to write " << byte_count
+                    << " bytes to " << GetLocation() << " at offset " << output_offset_;
+        output_good_ = false;
+      }
+    }
+    output_offset_ += byte_count;
+    return true;
+  }
+
+  // This function always succeeds to simplify code.
+  // Use Good() to check the actual status of the output stream.
+  off_t Seek(off_t offset, Whence whence) OVERRIDE {
+    // We keep shadow copy of the offset so that we return
+    // the expected value even if the output stream failed.
+    off_t new_offset;
+    switch (whence) {
+      case kSeekSet:
+        new_offset = offset;
+        break;
+      case kSeekCurrent:
+        new_offset = output_offset_ + offset;
+        break;
+      default:
+        LOG(FATAL) << "Unsupported seek type: " << whence;
+        UNREACHABLE();
+    }
+    if (output_good_) {
+      off_t actual_offset = output_->Seek(offset, whence);
+      if (actual_offset == static_cast<off_t>(-1)) {
+        PLOG(ERROR) << "Failed to seek in " << GetLocation() << ". Offset=" << offset
+                    << " whence=" << whence << " new_offset=" << new_offset;
+        output_good_ = false;
+      }
+      DCHECK_EQ(actual_offset, new_offset);
+    }
+    output_offset_ = new_offset;
+    return new_offset;
+  }
+
+  // Flush the output and return whether all operations have succeeded.
+  // Do nothing if we already have a pending error.
+  bool Flush() OVERRIDE {
+    if (output_good_) {
+      output_good_ = output_->Flush();
+    }
+    return output_good_;
+  }
+
+  // Check (without flushing) whether all operations have succeeded so far.
+  bool Good() const {
+    return output_good_;
+  }
+
+ private:
+  OutputStream* output_;
+  bool output_good_;  // True if all writes to output succeeded.
+  off_t output_offset_;  // Keep track of the current position in the stream.
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_LINKER_ERROR_DELAYING_OUTPUT_STREAM_H_
diff --git a/compiler/linker/file_output_stream.cc b/compiler/linker/file_output_stream.cc
new file mode 100644
index 0000000..bbfbdfd
--- /dev/null
+++ b/compiler/linker/file_output_stream.cc
@@ -0,0 +1,40 @@
+/*
+ * 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, size_t byte_count) {
+  return file_->WriteFully(buffer, byte_count);
+}
+
+off_t FileOutputStream::Seek(off_t offset, Whence whence) {
+  return lseek(file_->Fd(), offset, static_cast<int>(whence));
+}
+
+bool FileOutputStream::Flush() {
+  return file_->Flush() == 0;
+}
+
+}  // namespace art
diff --git a/compiler/linker/file_output_stream.h b/compiler/linker/file_output_stream.h
new file mode 100644
index 0000000..f2d8453
--- /dev/null
+++ b/compiler/linker/file_output_stream.h
@@ -0,0 +1,46 @@
+/*
+ * 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_COMPILER_LINKER_FILE_OUTPUT_STREAM_H_
+#define ART_COMPILER_LINKER_FILE_OUTPUT_STREAM_H_
+
+#include "output_stream.h"
+
+#include "os.h"
+
+namespace art {
+
+class FileOutputStream FINAL : public OutputStream {
+ public:
+  explicit FileOutputStream(File* file);
+
+  ~FileOutputStream() OVERRIDE {}
+
+  bool WriteFully(const void* buffer, size_t byte_count) OVERRIDE;
+
+  off_t Seek(off_t offset, Whence whence) OVERRIDE;
+
+  bool Flush() OVERRIDE;
+
+ private:
+  File* const file_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileOutputStream);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_LINKER_FILE_OUTPUT_STREAM_H_
diff --git a/compiler/linker/output_stream.cc b/compiler/linker/output_stream.cc
new file mode 100644
index 0000000..a8b64ca
--- /dev/null
+++ b/compiler/linker/output_stream.cc
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 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 "output_stream.h"
+
+namespace art {
+
+std::ostream& operator<<(std::ostream& os, const Whence& rhs) {
+  switch (rhs) {
+    case kSeekSet:     os << "SEEK_SET"; break;
+    case kSeekCurrent: os << "SEEK_CUR"; break;
+    case kSeekEnd:     os << "SEEK_END"; break;
+    default: UNREACHABLE();
+  }
+  return os;
+}
+
+}  // namespace art
diff --git a/compiler/linker/output_stream.h b/compiler/linker/output_stream.h
new file mode 100644
index 0000000..96a5f48
--- /dev/null
+++ b/compiler/linker/output_stream.h
@@ -0,0 +1,64 @@
+/*
+ * 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_COMPILER_LINKER_OUTPUT_STREAM_H_
+#define ART_COMPILER_LINKER_OUTPUT_STREAM_H_
+
+#include <ostream>
+#include <string>
+
+#include "base/macros.h"
+
+namespace art {
+
+enum Whence {
+  kSeekSet = SEEK_SET,
+  kSeekCurrent = SEEK_CUR,
+  kSeekEnd = SEEK_END,
+};
+std::ostream& operator<<(std::ostream& os, const Whence& rhs);
+
+class OutputStream {
+ public:
+  explicit OutputStream(const std::string& location) : location_(location) {}
+
+  virtual ~OutputStream() {}
+
+  const std::string& GetLocation() const {
+    return location_;
+  }
+
+  virtual bool WriteFully(const void* buffer, size_t byte_count) = 0;
+
+  virtual off_t Seek(off_t offset, Whence whence) = 0;
+
+  /*
+   * Flushes the stream. Returns whether the operation was successful.
+   *
+   * An OutputStream may delay reporting errors from WriteFully() or
+   * Seek(). In that case, Flush() shall report any pending error.
+   */
+  virtual bool Flush() = 0;
+
+ private:
+  const std::string location_;
+
+  DISALLOW_COPY_AND_ASSIGN(OutputStream);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_LINKER_OUTPUT_STREAM_H_
diff --git a/compiler/linker/output_stream_test.cc b/compiler/linker/output_stream_test.cc
new file mode 100644
index 0000000..84c76f2
--- /dev/null
+++ b/compiler/linker/output_stream_test.cc
@@ -0,0 +1,137 @@
+/*
+ * 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 "vector_output_stream.h"
+
+#include "base/unix_file/fd_file.h"
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "buffered_output_stream.h"
+#include "common_runtime_test.h"
+
+namespace art {
+
+class OutputStreamTest : public CommonRuntimeTest {
+ protected:
+  void CheckOffset(off_t expected) {
+    off_t actual = output_stream_->Seek(0, kSeekCurrent);
+    EXPECT_EQ(expected, actual);
+  }
+
+  void SetOutputStream(OutputStream& output_stream) {
+    output_stream_ = &output_stream;
+  }
+
+  void GenerateTestOutput() {
+    EXPECT_EQ(3, output_stream_->Seek(3, kSeekCurrent));
+    CheckOffset(3);
+    EXPECT_EQ(2, output_stream_->Seek(2, kSeekSet));
+    CheckOffset(2);
+    uint8_t buf[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+    EXPECT_TRUE(output_stream_->WriteFully(buf, 2));
+    CheckOffset(4);
+    EXPECT_EQ(6, output_stream_->Seek(2, kSeekEnd));
+    CheckOffset(6);
+    EXPECT_TRUE(output_stream_->WriteFully(buf, 4));
+    CheckOffset(10);
+    EXPECT_TRUE(output_stream_->WriteFully(buf, 6));
+    EXPECT_TRUE(output_stream_->Flush());
+  }
+
+  void CheckTestOutput(const std::vector<uint8_t>& actual) {
+    uint8_t expected[] = {
+        0, 0, 1, 2, 0, 0, 1, 2, 3, 4, 1, 2, 3, 4, 5, 6
+    };
+    EXPECT_EQ(sizeof(expected), actual.size());
+    EXPECT_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();
+  std::unique_ptr<File> in(OS::OpenFileForReading(tmp.GetFilename().c_str()));
+  EXPECT_TRUE(in.get() != nullptr);
+  std::vector<uint8_t> actual(in->GetLength());
+  bool readSuccess = in->ReadFully(&actual[0], actual.size());
+  EXPECT_TRUE(readSuccess);
+  CheckTestOutput(actual);
+}
+
+TEST_F(OutputStreamTest, Buffered) {
+  ScratchFile tmp;
+  {
+    BufferedOutputStream buffered_output_stream(MakeUnique<FileOutputStream>(tmp.GetFile()));
+    SetOutputStream(buffered_output_stream);
+    GenerateTestOutput();
+  }
+  std::unique_ptr<File> in(OS::OpenFileForReading(tmp.GetFilename().c_str()));
+  EXPECT_TRUE(in.get() != nullptr);
+  std::vector<uint8_t> actual(in->GetLength());
+  bool readSuccess = in->ReadFully(&actual[0], actual.size());
+  EXPECT_TRUE(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);
+}
+
+TEST_F(OutputStreamTest, BufferedFlush) {
+  struct CheckingOutputStream : OutputStream {
+    CheckingOutputStream()
+        : OutputStream("dummy"),
+          flush_called(false) { }
+    ~CheckingOutputStream() OVERRIDE {}
+
+    bool WriteFully(const void* buffer ATTRIBUTE_UNUSED,
+                    size_t byte_count ATTRIBUTE_UNUSED) OVERRIDE {
+      LOG(FATAL) << "UNREACHABLE";
+      UNREACHABLE();
+    }
+
+    off_t Seek(off_t offset ATTRIBUTE_UNUSED, Whence whence ATTRIBUTE_UNUSED) OVERRIDE {
+      LOG(FATAL) << "UNREACHABLE";
+      UNREACHABLE();
+    }
+
+    bool Flush() OVERRIDE {
+      flush_called = true;
+      return true;
+    }
+
+    bool flush_called;
+  };
+
+  std::unique_ptr<CheckingOutputStream> cos = MakeUnique<CheckingOutputStream>();
+  CheckingOutputStream* checking_output_stream = cos.get();
+  BufferedOutputStream buffered(std::move(cos));
+  ASSERT_FALSE(checking_output_stream->flush_called);
+  bool flush_result = buffered.Flush();
+  ASSERT_TRUE(flush_result);
+  ASSERT_TRUE(checking_output_stream->flush_called);
+}
+
+}  // namespace art
diff --git a/compiler/linker/vector_output_stream.cc b/compiler/linker/vector_output_stream.cc
new file mode 100644
index 0000000..f758005
--- /dev/null
+++ b/compiler/linker/vector_output_stream.cc
@@ -0,0 +1,48 @@
+/*
+ * 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 "base/logging.h"
+
+namespace art {
+
+VectorOutputStream::VectorOutputStream(const std::string& location, std::vector<uint8_t>* vector)
+    : OutputStream(location), offset_(vector->size()), vector_(vector) {}
+
+off_t VectorOutputStream::Seek(off_t offset, Whence whence) {
+  CHECK(whence == kSeekSet || whence == kSeekCurrent || whence == kSeekEnd) << whence;
+  off_t new_offset = 0;
+  switch (whence) {
+    case kSeekSet: {
+      new_offset = offset;
+      break;
+    }
+    case kSeekCurrent: {
+      new_offset = offset_ + offset;
+      break;
+    }
+    case kSeekEnd: {
+      new_offset = vector_->size() + offset;
+      break;
+    }
+  }
+  EnsureCapacity(new_offset);
+  offset_ = new_offset;
+  return offset_;
+}
+
+}  // namespace art
diff --git a/compiler/linker/vector_output_stream.h b/compiler/linker/vector_output_stream.h
new file mode 100644
index 0000000..3210143
--- /dev/null
+++ b/compiler/linker/vector_output_stream.h
@@ -0,0 +1,69 @@
+/*
+ * 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_COMPILER_LINKER_VECTOR_OUTPUT_STREAM_H_
+#define ART_COMPILER_LINKER_VECTOR_OUTPUT_STREAM_H_
+
+#include "output_stream.h"
+
+#include <string>
+#include <string.h>
+#include <vector>
+
+namespace art {
+
+class VectorOutputStream FINAL : public OutputStream {
+ public:
+  VectorOutputStream(const std::string& location, std::vector<uint8_t>* vector);
+
+  ~VectorOutputStream() OVERRIDE {}
+
+  bool WriteFully(const void* buffer, size_t byte_count) OVERRIDE {
+    if (static_cast<size_t>(offset_) == vector_->size()) {
+      const uint8_t* start = reinterpret_cast<const uint8_t*>(buffer);
+      vector_->insert(vector_->end(), &start[0], &start[byte_count]);
+      offset_ += byte_count;
+    } else {
+      off_t new_offset = offset_ + byte_count;
+      EnsureCapacity(new_offset);
+      memcpy(&(*vector_)[offset_], buffer, byte_count);
+      offset_ = new_offset;
+    }
+    return true;
+  }
+
+  off_t Seek(off_t offset, Whence whence) OVERRIDE;
+
+  bool Flush() OVERRIDE {
+    return true;
+  }
+
+ private:
+  void EnsureCapacity(off_t new_offset) {
+    if (new_offset > static_cast<off_t>(vector_->size())) {
+      vector_->resize(new_offset);
+    }
+  }
+
+  off_t offset_;
+  std::vector<uint8_t>* const vector_;
+
+  DISALLOW_COPY_AND_ASSIGN(VectorOutputStream);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_LINKER_VECTOR_OUTPUT_STREAM_H_