resolved conflicts for merge of 6ec896af to master

Change-Id: I2b179d8b637df5e71c3018df50b7a3cc1fd2367f
diff --git a/bcinfo/Android.mk b/bcinfo/Android.mk
index f813e77..5a53e07 100644
--- a/bcinfo/Android.mk
+++ b/bcinfo/Android.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2011 The Android Open Source Project
+# Copyright (C) 2011-2012 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.
@@ -38,6 +38,7 @@
 
 libbcinfo_C_INCLUDES := $(LOCAL_PATH)/../include
 libbcinfo_STATIC_LIBRARIES := \
+  libLLVMWrap \
   libLLVMBitReader \
   libLLVMBitWriter \
   libLLVMCore \
diff --git a/bcinfo/BitcodeTranslator.cpp b/bcinfo/BitcodeTranslator.cpp
index 3dcddfc..bd4cd4b 100644
--- a/bcinfo/BitcodeTranslator.cpp
+++ b/bcinfo/BitcodeTranslator.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2011, The Android Open Source Project
+ * Copyright 2011-2012, 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.
@@ -16,6 +16,8 @@
 
 #include "bcinfo/BitcodeTranslator.h"
 
+#include "bcinfo/BitcodeWrapper.h"
+
 #include "BitReader_2_7/BitReader_2_7.h"
 #include "BitReader_3_0/BitReader_3_0.h"
 
@@ -88,6 +90,12 @@
     return false;
   }
 
+  BitcodeWrapper BCWrapper(mBitcode, mBitcodeSize);
+  if (BCWrapper.getTargetAPI() != mVersion) {
+    ALOGE("Bitcode wrapper (%u) and translator (%u) disagree about target API",
+          BCWrapper.getTargetAPI(), mVersion);
+  }
+
   if ((mVersion != kCurrentAPIVersion) &&
       ((mVersion < kMinimumAPIVersion) ||
        (mVersion > kMaximumAPIVersion))) {
@@ -136,11 +144,21 @@
   llvm::WriteBitcodeToFile(module, OS);
   OS.flush();
 
-  char *c = new char[Buffer.size()];
-  memcpy(c, Buffer.c_str(), Buffer.size());
+  AndroidBitcodeWrapper wrapper;
+  size_t actualWrapperLen = writeAndroidBitcodeWrapper(
+      &wrapper, Buffer.size(), BCWrapper.getTargetAPI(),
+      BCWrapper.getCompilerVersion(), BCWrapper.getOptimizationLevel());
+  if (!actualWrapperLen) {
+    ALOGE("Couldn't produce bitcode wrapper!");
+    return false;
+  }
+
+  mTranslatedBitcodeSize = actualWrapperLen + Buffer.size();
+  char *c = new char[mTranslatedBitcodeSize];
+  memcpy(c, &wrapper, actualWrapperLen);
+  memcpy(c + actualWrapperLen, Buffer.c_str(), Buffer.size());
 
   mTranslatedBitcode = c;
-  mTranslatedBitcodeSize = Buffer.size();
 
   return true;
 }
diff --git a/bcinfo/BitcodeWrapper.cpp b/bcinfo/BitcodeWrapper.cpp
index c6f9c04..67f95b8 100644
--- a/bcinfo/BitcodeWrapper.cpp
+++ b/bcinfo/BitcodeWrapper.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2011, The Android Open Source Project
+ * Copyright 2011-2012, 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.
@@ -15,6 +15,8 @@
  */
 
 #include "bcinfo/BitcodeWrapper.h"
+#include "bcinfo/Wrap/bitcode_wrapperer.h"
+#include "bcinfo/Wrap/in_memory_wrapper_input.h"
 
 #define LOG_TAG "bcinfo"
 #include <cutils/log.h>
@@ -28,8 +30,19 @@
 
 BitcodeWrapper::BitcodeWrapper(const char *bitcode, size_t bitcodeSize)
     : mFileType(BC_NOT_BC), mBitcode(bitcode),
-      mBitcodeEnd(bitcode + bitcodeSize - 1), mBitcodeSize(bitcodeSize) {
-  memset(&mBCHeader, 0, sizeof(mBCHeader));
+      mBitcodeEnd(bitcode + bitcodeSize - 1), mBitcodeSize(bitcodeSize),
+      mHeaderVersion(0), mTargetAPI(0) {
+  InMemoryWrapperInput inMem(mBitcode, mBitcodeSize);
+  BitcodeWrapperer wrapperer(&inMem, NULL);
+  if (wrapperer.IsInputBitcodeWrapper()) {
+    mFileType = BC_WRAPPER;
+    mHeaderVersion = wrapperer.getAndroidHeaderVersion();
+    mTargetAPI = wrapperer.getAndroidTargetAPI();
+    mCompilerVersion = wrapperer.getAndroidCompilerVersion();
+    mOptimizationLevel = wrapperer.getAndroidOptimizationLevel();
+  } else if (wrapperer.IsInputBitcodeFile()) {
+    mFileType = BC_RAW;
+  }
 }
 
 
@@ -39,30 +52,7 @@
 
 
 bool BitcodeWrapper::unwrap() {
-  if (!mBitcode || !mBitcodeSize) {
-    ALOGE("Invalid/empty bitcode");
-    return false;
-  }
-
-  if (llvm::isBitcodeWrapper((const unsigned char*) mBitcode,
-                             (const unsigned char*) mBitcodeEnd)) {
-    if (mBitcodeSize < sizeof(mBCHeader)) {
-      ALOGE("Invalid bitcode size");
-      return false;
-    }
-
-    mFileType = BC_WRAPPER;
-    memcpy(&mBCHeader, mBitcode, sizeof(mBCHeader));
-    return true;
-  } else if (llvm::isRawBitcode((const unsigned char*) mBitcode,
-                                (const unsigned char*) mBitcodeEnd)) {
-    mFileType = BC_RAW;
-    return true;
-  } else {
-    ALOGE("Not bitcode");
-    mFileType = BC_NOT_BC;
-    return false;
-  }
+  return mFileType != BC_NOT_BC;
 }
 
 }  // namespace bcinfo
diff --git a/bcinfo/Wrap/Android.mk b/bcinfo/Wrap/Android.mk
new file mode 100644
index 0000000..adc306a
--- /dev/null
+++ b/bcinfo/Wrap/Android.mk
@@ -0,0 +1,58 @@
+#
+# Copyright (C) 2012 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+LLVM_ROOT_PATH := $(LOCAL_PATH)/../../../../../external/llvm
+include $(LLVM_ROOT_PATH)/llvm.mk
+
+llvm_wrap_SRC_FILES := \
+  bitcode_wrapperer.cpp \
+  file_wrapper_input.cpp \
+  file_wrapper_output.cpp \
+  in_memory_wrapper_input.cpp \
+  wrapper_output.cpp
+
+llvm_wrap_C_INCLUDES := $(LOCAL_PATH)/../../include
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libLLVMWrap
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(llvm_wrap_SRC_FILES)
+LOCAL_CFLAGS += -D__HOST__
+LOCAL_C_INCLUDES := $(llvm_wrap_C_INCLUDES)
+
+include $(LLVM_HOST_BUILD_MK)
+include $(LLVM_GEN_INTRINSICS_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libLLVMWrap
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(llvm_wrap_SRC_FILES)
+LOCAL_C_INCLUDES := $(llvm_wrap_C_INCLUDES)
+
+include $(LLVM_DEVICE_BUILD_MK)
+include $(LLVM_GEN_INTRINSICS_MK)
+include $(BUILD_STATIC_LIBRARY)
diff --git a/bcinfo/Wrap/LLVMBuild.txt b/bcinfo/Wrap/LLVMBuild.txt
new file mode 100644
index 0000000..8750711
--- /dev/null
+++ b/bcinfo/Wrap/LLVMBuild.txt
@@ -0,0 +1,21 @@
+;===- ./lib/Wrap/LLVMBuild.txt ------------------------------*- Conf -*--===;
+;
+;                     The LLVM Compiler Infrastructure
+;
+; This file is distributed under the University of Illinois Open Source
+; License. See LICENSE.TXT for details.
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+;   http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = Library
+name = Wrap
+parent = Libraries
diff --git a/bcinfo/Wrap/Makefile b/bcinfo/Wrap/Makefile
new file mode 100644
index 0000000..79aa2b3
--- /dev/null
+++ b/bcinfo/Wrap/Makefile
@@ -0,0 +1,14 @@
+##===- lib/Linker/Makefile ---------------------------------*- Makefile -*-===##
+#
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../..
+LIBRARYNAME = LLVMWrap
+BUILD_ARCHIVE := 1
+
+include $(LEVEL)/Makefile.common
diff --git a/bcinfo/Wrap/bitcode_wrapperer.cpp b/bcinfo/Wrap/bitcode_wrapperer.cpp
new file mode 100644
index 0000000..c8b7d26
--- /dev/null
+++ b/bcinfo/Wrap/bitcode_wrapperer.cpp
@@ -0,0 +1,380 @@
+/*
+ * Copyright 2012, 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 "bcinfo/Wrap/bitcode_wrapperer.h"
+
+#define LOG_TAG "bcinfo"
+#include <cutils/log.h>
+
+#include <stdio.h>
+#include <sys/stat.h>
+
+using std::vector;
+
+// The number of bytes in a 32 bit integer.
+static const uint32_t kWordSize = 4;
+
+// Number of LLVM-defined fixed fields in the header.
+static const uint32_t kLLVMFields = 4;
+
+// Total number of fixed fields in the header.
+static const uint32_t kFixedFields = 7;
+
+// The magic number that must exist for bitcode wrappers.
+static const uint32_t kWrapperMagicNumber = 0x0B17C0DE;
+
+// The version number associated with a wrapper file.
+// Note: llvm currently only allows the value 0. When this changes,
+// we should consider making this a command line option.
+static const uint32_t kLLVMVersionNumber = 0;
+
+// Fields defined by Android bitcode header.
+static const uint32_t kAndroidHeaderVersion = 0;
+static const uint32_t kAndroidTargetAPI = 0;
+static const uint32_t kAndroidDefaultCompilerVersion = 0;
+static const uint32_t kAndroidDefaultOptimizationLevel = 3;
+
+// PNaCl bitcode version number.
+static const uint32_t kPnaclBitcodeVersion = 0;
+
+// Max size for variable fields. Currently only used for writing them
+// out to files (the parsing works for arbitrary sizes).
+static const size_t kMaxVariableFieldSize = 256;
+
+BitcodeWrapperer::BitcodeWrapperer(WrapperInput* infile, WrapperOutput* outfile)
+    : infile_(infile),
+      outfile_(outfile),
+      buffer_size_(0),
+      cursor_(0),
+      infile_at_eof_(false),
+      infile_bc_offset_(0),
+      wrapper_bc_offset_(0),
+      wrapper_bc_size_(0),
+      android_header_version_(kAndroidHeaderVersion),
+      android_target_api_(kAndroidTargetAPI),
+      android_compiler_version_(kAndroidDefaultCompilerVersion),
+      android_optimization_level_(kAndroidDefaultOptimizationLevel),
+      pnacl_bc_version_(0),
+      error_(false) {
+  buffer_.resize(kBitcodeWrappererBufferSize);
+  if (IsInputBitcodeWrapper()) {
+    ParseWrapperHeader();
+  } else if (IsInputBitcodeFile()) {
+    wrapper_bc_offset_ = kWordSize * kFixedFields;
+    wrapper_bc_size_ = GetInFileSize();
+  } else {
+    ALOGE("Error: input file is not a bitcode file.\n");
+    error_ = true;
+  }
+}
+
+BitcodeWrapperer::~BitcodeWrapperer() {
+  for(size_t i = 0; i < variable_field_data_.size(); i++) {
+    delete [] variable_field_data_[i];
+  }
+}
+
+
+void BitcodeWrapperer::ClearBuffer() {
+  buffer_size_ = 0;
+  cursor_ = 0;
+  infile_at_eof_ = false;
+}
+
+bool BitcodeWrapperer::Seek(uint32_t pos) {
+  if (infile_->Seek(pos)) {
+    ClearBuffer();
+    return true;
+  }
+  return false;
+}
+
+bool BitcodeWrapperer::CanReadWord() {
+  if (GetBufferUnreadBytes() < kWordSize) {
+    FillBuffer();
+    return GetBufferUnreadBytes() >= kWordSize;
+  } else {
+    return true;
+  }
+}
+
+void BitcodeWrapperer::FillBuffer() {
+  if (cursor_ > 0) {
+    // Before filling, move any remaining bytes to the
+    // front of the buffer. This allows us to assume
+    // that after the call to FillBuffer, readable
+    // text is contiguous.
+    if (cursor_ < buffer_size_) {
+      size_t i = 0;
+      while (cursor_ < buffer_size_) {
+        buffer_[i++] = buffer_[cursor_++];
+      }
+      cursor_ = 0;
+      buffer_size_ = i;
+    }
+  } else {
+    // Assume the buffer contents have been used,
+    // and we want to completely refill it.
+    buffer_size_ = 0;
+  }
+
+  // Now fill in remaining space.
+  size_t needed = buffer_.size() - buffer_size_;
+
+  while (buffer_.size() > buffer_size_) {
+    int actually_read = infile_->Read(&buffer_[buffer_size_], needed);
+    if (infile_->AtEof()) {
+      infile_at_eof_ = true;
+    }
+    if (actually_read) {
+      buffer_size_ += actually_read;
+      needed -= actually_read;
+    } else if (infile_at_eof_) {
+      break;
+    }
+  }
+}
+
+bool BitcodeWrapperer::ReadWord(uint32_t& word) {
+  if (!CanReadWord()) return false;
+  word = (((uint32_t) BufferLookahead(0)) << 0)
+      | (((uint32_t) BufferLookahead(1)) << 8)
+      | (((uint32_t) BufferLookahead(2)) << 16)
+      | (((uint32_t) BufferLookahead(3)) << 24);
+  cursor_ += kWordSize;
+  return true;
+}
+
+bool BitcodeWrapperer::WriteWord(uint32_t value) {
+  uint8_t buffer[kWordSize];
+  buffer[3] = (value >> 24) & 0xFF;
+  buffer[2] = (value >> 16) & 0xFF;
+  buffer[1] = (value >> 8)  & 0xFF;
+  buffer[0] = (value >> 0)  & 0xFF;
+  return outfile_->Write(buffer, kWordSize);
+}
+
+bool BitcodeWrapperer::WriteVariableFields() {
+  // This buffer may have to be bigger if we start using the fields
+  // for larger things.
+  uint8_t buffer[kMaxVariableFieldSize];
+  for (vector<BCHeaderField>::iterator it = header_fields_.begin();
+       it != header_fields_.end(); ++it) {
+    if (!it->Write(buffer, kMaxVariableFieldSize) ||
+        !outfile_->Write(buffer, it->GetTotalSize())) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool BitcodeWrapperer::ParseWrapperHeader() {
+  // Make sure LLVM-defined fields have been parsed
+  if (!IsInputBitcodeWrapper()) return false;
+  // Check the android/pnacl fields
+  if (!ReadWord(android_header_version_) ||
+      !ReadWord(android_target_api_) || !ReadWord(pnacl_bc_version_)) {
+    ALOGW("Error: file not long enough to contain header\n");
+    return false;
+  }
+  if (pnacl_bc_version_ != kPnaclBitcodeVersion) {
+    ALOGW("Error: bad PNaCl Bitcode version\n");
+    return false;
+  }
+  int field_data_total = wrapper_bc_offset_ - kWordSize * kFixedFields;
+  if (field_data_total > 0) {
+    // Read in the variable fields. We need to allocate space for the data.
+    int field_data_read = 0;
+
+    while (field_data_read < field_data_total) {
+      FillBuffer();
+      size_t buffer_needed = BCHeaderField::GetDataSizeFromSerialized(
+          &buffer_[cursor_]);
+      if (buffer_needed > buffer_.size()) {
+        buffer_.resize(buffer_needed +
+                       sizeof(BCHeaderField::FixedSubfield) * 2);
+        FillBuffer();
+      }
+      variable_field_data_.push_back(new uint8_t[buffer_needed]);
+
+      BCHeaderField field(BCHeaderField::kInvalid, 0,
+                          variable_field_data_.back());
+      field.Read(&buffer_[cursor_], buffer_size_);
+      header_fields_.push_back(field);
+      size_t field_size = field.GetTotalSize();
+      cursor_ += field_size;
+      field_data_read += field_size;
+      if (field_data_read > field_data_total) {
+        // We read too much data, the header is corrupted
+        ALOGE("Error: raw bitcode offset inconsistent with "
+              "variable field data\n");
+        return false;
+      }
+
+      struct IntFieldHelper {
+        BCHeaderField::FixedSubfield tag;
+        uint16_t len;
+        uint32_t val;
+      };
+      IntFieldHelper tempIntField;
+
+      switch (field.getID()) {
+        case BCHeaderField::kAndroidCompilerVersion:
+          if (field.Write((uint8_t*)&tempIntField,
+                          sizeof(tempIntField))) {
+            android_compiler_version_ = tempIntField.val;
+          }
+          break;
+        case BCHeaderField::kAndroidOptimizationLevel:
+          if (field.Write((uint8_t*)&tempIntField,
+                          sizeof(tempIntField))) {
+            android_optimization_level_ = tempIntField.val;
+          }
+          break;
+        default:
+          // Ignore other field types for now
+          break;
+      }
+    }
+    Seek(0);
+  }
+  return true;
+}
+
+bool BitcodeWrapperer::IsInputBitcodeWrapper() {
+  ResetCursor();
+  // First make sure that there are enough words (LLVM header)
+  // to peek at.
+  if (GetBufferUnreadBytes() < kLLVMFields * kWordSize) {
+    FillBuffer();
+    if (GetBufferUnreadBytes() < kLLVMFields * kWordSize) return false;
+  }
+
+  // Now make sure the magic number is right.
+  uint32_t first_word;
+  if ((!ReadWord(first_word)) ||
+      (kWrapperMagicNumber != first_word)) return false;
+
+  // Make sure the version is right.
+  uint32_t second_word;
+  if ((!ReadWord(second_word)) ||
+      (kLLVMVersionNumber != second_word)) return false;
+
+  // Make sure that the offset and size (for llvm) is defined.
+  uint32_t bc_offset;
+  uint32_t bc_size;
+  if (ReadWord(bc_offset) &&
+      ReadWord(bc_size)) {
+    // Before returning, save the extracted values.
+    wrapper_bc_offset_ = bc_offset;
+    infile_bc_offset_ = bc_offset;
+    wrapper_bc_size_ = bc_size;
+    return true;
+  }
+  // If reached, unable to read wrapped header.
+  return false;
+}
+
+bool BitcodeWrapperer::IsInputBitcodeFile() {
+  ResetCursor();
+  // First make sure that there are four bytes to peek at.
+  if (GetBufferUnreadBytes() < kWordSize) {
+    FillBuffer();
+    if (GetBufferUnreadBytes() < kWordSize) return false;
+  }
+  // If reached, Check if first 4 bytes match bitcode
+  // file magic number.
+  return (BufferLookahead(0) == 'B') &&
+      (BufferLookahead(1) == 'C') &&
+      (BufferLookahead(2) == 0xc0) &&
+      (BufferLookahead(3) == 0xde);
+}
+
+bool BitcodeWrapperer::BufferCopyInToOut(uint32_t size) {
+  while (size > 0) {
+    // Be sure buffer is non-empty before writing.
+    if (0 == buffer_size_) {
+      FillBuffer();
+      if (0 == buffer_size_) {
+        return false;
+      }
+    }
+    // copy the buffer to the output file.
+    size_t block = (buffer_size_ < size) ? buffer_size_ : size;
+    if (!outfile_->Write(&buffer_[cursor_], block)) return false;
+    size -= block;
+    buffer_size_ = 0;
+  }
+  // Be sure that there isn't more bytes on the input stream.
+  FillBuffer();
+  return buffer_size_ == 0;
+}
+
+void BitcodeWrapperer::AddHeaderField(BCHeaderField* field) {
+  header_fields_.push_back(*field);
+  wrapper_bc_offset_ += field->GetTotalSize();
+}
+
+bool BitcodeWrapperer::WriteBitcodeWrapperHeader() {
+  return
+      // Note: This writes out the 4 word header required by llvm wrapped
+      // bitcode.
+      WriteWord(kWrapperMagicNumber) &&
+      WriteWord(kLLVMVersionNumber) &&
+      WriteWord(wrapper_bc_offset_) &&
+      WriteWord(wrapper_bc_size_) &&
+      // 2 fixed fields defined by Android
+      WriteWord(android_header_version_) &&
+      WriteWord(android_target_api_) &&
+      // PNaClBitcode version
+      WriteWord(kPnaclBitcodeVersion) &&
+      // Common variable-length fields
+      WriteVariableFields();
+}
+
+void BitcodeWrapperer::PrintWrapperHeader() {
+  if (error_) {
+    fprintf(stderr, "Error condition exists: the following"
+            "data may not be reliable\n");
+  }
+  fprintf(stderr, "Wrapper magic:\t\t%x\n", kWrapperMagicNumber);
+  fprintf(stderr, "LLVM Bitcode version:\t%d\n", kLLVMVersionNumber);
+  fprintf(stderr, "Raw bitcode offset:\t%d\n", wrapper_bc_offset_);
+  fprintf(stderr, "Raw bitcode size:\t%d\n", wrapper_bc_size_);
+  fprintf(stderr, "Android header version:\t%d\n", android_header_version_);
+  fprintf(stderr, "Android target API:\t%d\n", android_target_api_);
+  fprintf(stderr, "PNaCl bitcode version:\t%d\n", kPnaclBitcodeVersion);
+  for (size_t i = 0; i < header_fields_.size(); i++) header_fields_[i].Print();
+}
+
+bool BitcodeWrapperer::GenerateWrappedBitcodeFile() {
+  if (!error_ &&
+      WriteBitcodeWrapperHeader() &&
+      Seek(infile_bc_offset_) &&
+      BufferCopyInToOut(wrapper_bc_size_)) {
+    off_t dangling = wrapper_bc_size_ & 3;
+    if (dangling) {
+      return outfile_->Write((const uint8_t*) "\0\0\0\0", 4 - dangling);
+    }
+    return true;
+  }
+  return false;
+}
+
+bool BitcodeWrapperer::GenerateRawBitcodeFile() {
+  return !error_ && Seek(infile_bc_offset_) &&
+      BufferCopyInToOut(wrapper_bc_size_);
+}
diff --git a/bcinfo/Wrap/file_wrapper_input.cpp b/bcinfo/Wrap/file_wrapper_input.cpp
new file mode 100644
index 0000000..08212c2
--- /dev/null
+++ b/bcinfo/Wrap/file_wrapper_input.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2012, 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 <sys/stat.h>
+#include <stdlib.h>
+
+#include "bcinfo/Wrap/file_wrapper_input.h"
+
+FileWrapperInput::FileWrapperInput(const char* name) :
+    _name(name), _at_eof(false), _size_found(false), _size(0) {
+  _file = fopen(name, "rb");
+  if (NULL == _file) {
+    fprintf(stderr, "Unable to open: %s\n", name);
+    exit(1);
+  }
+}
+
+FileWrapperInput::~FileWrapperInput() {
+  fclose(_file);
+}
+
+size_t FileWrapperInput::Read(uint8_t* buffer, size_t wanted) {
+  size_t found = fread((char*) buffer, 1, wanted, _file);
+  if (feof(_file) || ferror(_file)) {
+    _at_eof = true;
+  }
+  return found;
+}
+
+bool FileWrapperInput::AtEof() {
+  return _at_eof;
+}
+
+off_t FileWrapperInput::Size() {
+  if (_size_found) return _size;
+  struct stat st;
+  if (0 == stat(_name, &st)) {
+    _size_found = true;
+    _size = st.st_size;
+    return _size;
+  } else {
+    fprintf(stderr, "Unable to compute file size: %s\n", _name);
+    exit(1);
+  }
+  // NOT REACHABLE.
+  return 0;
+}
+
+bool FileWrapperInput::Seek(uint32_t pos) {
+  return 0 == fseek(_file, (long) pos, SEEK_SET);
+}
diff --git a/bcinfo/Wrap/file_wrapper_output.cpp b/bcinfo/Wrap/file_wrapper_output.cpp
new file mode 100644
index 0000000..4cdc54e
--- /dev/null
+++ b/bcinfo/Wrap/file_wrapper_output.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012, 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 <stdlib.h>
+
+#include "bcinfo/Wrap/file_wrapper_output.h"
+
+FileWrapperOutput::FileWrapperOutput(const char* name)
+    : _name(name) {
+  _file = fopen(name, "wb");
+  if (NULL == _file) {
+    fprintf(stderr, "Unable to open: %s\n", name);
+    exit(1);
+  }
+}
+
+FileWrapperOutput::~FileWrapperOutput() {
+  fclose(_file);
+}
+
+bool FileWrapperOutput::Write(uint8_t byte) {
+  return EOF != fputc(byte, _file);
+}
+
+bool FileWrapperOutput::Write(const uint8_t* buffer, size_t buffer_size) {
+  if (buffer_size > 0) {
+    return buffer_size == fwrite(buffer, 1, buffer_size, _file);
+  } else {
+    return true;
+  }
+}
diff --git a/bcinfo/Wrap/in_memory_wrapper_input.cpp b/bcinfo/Wrap/in_memory_wrapper_input.cpp
new file mode 100644
index 0000000..3f91f01
--- /dev/null
+++ b/bcinfo/Wrap/in_memory_wrapper_input.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2012, 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 <sys/stat.h>
+#include <stdlib.h>
+
+#include "bcinfo/Wrap/in_memory_wrapper_input.h"
+
+InMemoryWrapperInput::InMemoryWrapperInput(const char* buffer, size_t size) :
+    _buffer(buffer), _pos(0), _size(size) {
+}
+
+InMemoryWrapperInput::~InMemoryWrapperInput() {
+}
+
+size_t InMemoryWrapperInput::Read(uint8_t* buffer, size_t wanted) {
+  size_t found = 0;
+  while (found < wanted) {
+    if (_pos >= _size) {
+      return found;
+    }
+    buffer[found++] = _buffer[_pos++];
+  }
+  return found;
+}
+
+bool InMemoryWrapperInput::AtEof() {
+  return (_pos >= _size);
+}
+
+off_t InMemoryWrapperInput::Size() {
+  return _size;
+}
+
+bool InMemoryWrapperInput::Seek(uint32_t pos) {
+  if (pos < _size) {
+    _pos = pos;
+    return true;
+  } else {
+    return false;
+  }
+}
diff --git a/bcinfo/Wrap/wrapper_output.cpp b/bcinfo/Wrap/wrapper_output.cpp
new file mode 100644
index 0000000..3c72422
--- /dev/null
+++ b/bcinfo/Wrap/wrapper_output.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2012, 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 "bcinfo/Wrap/wrapper_output.h"
+
+bool WrapperOutput::Write(const uint8_t* buffer, size_t buffer_size) {
+  // Default implementation that uses the byte write routine.
+  for (size_t i = 0; i < buffer_size; ++i) {
+    if (!Write(buffer[i])) return false;
+  }
+  return true;
+}
diff --git a/bcinfo/tools/main.cpp b/bcinfo/tools/main.cpp
index 6ecded0..bed24aa 100644
--- a/bcinfo/tools/main.cpp
+++ b/bcinfo/tools/main.cpp
@@ -120,8 +120,6 @@
   }
   printf("\n");
 
-  printf("optimizationLevel: %u\n", ME->getOptimizationLevel());
-
   return;
 }
 
@@ -184,11 +182,6 @@
   unsigned int version = 0;
 
   bcinfo::BitcodeWrapper bcWrapper((const char *)bitcode, bitcodeSize);
-  if (!bcWrapper.unwrap()) {
-    fprintf(stderr, "failed to unwrap bitcode wrapper\n");
-    return 2;
-  }
-
   if (bcWrapper.getBCFileType() == bcinfo::BC_WRAPPER) {
     version = bcWrapper.getTargetAPI();
     printf("Found bitcodeWrapper\n");
@@ -196,7 +189,9 @@
     version = 12;
   }
 
-  printf("bitcodeVersion: %u\n", version);
+  printf("targetAPI: %u\n", version);
+  printf("compilerVersion: %u\n", bcWrapper.getCompilerVersion());
+  printf("optimizationLevel: %u\n\n", bcWrapper.getOptimizationLevel());
 
   bcinfo::BitcodeTranslator *BT =
       new bcinfo::BitcodeTranslator(bitcode, bitcodeSize, version);
diff --git a/include/bcinfo/BitcodeWrapper.h b/include/bcinfo/BitcodeWrapper.h
index cde0a91..3e9ed52 100644
--- a/include/bcinfo/BitcodeWrapper.h
+++ b/include/bcinfo/BitcodeWrapper.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2011, The Android Open Source Project
+ * Copyright 2011-2012, 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.
@@ -17,18 +17,27 @@
 #ifndef __ANDROID_BCINFO_BITCODEWRAPPER_H__
 #define __ANDROID_BCINFO_BITCODEWRAPPER_H__
 
+#include "bcinfo/Wrap/BCHeaderField.h"
+
 #include <cstddef>
 #include <stdint.h>
 
 namespace bcinfo {
 
-struct BCWrapperHeader {
+struct AndroidBitcodeWrapper {
   uint32_t Magic;
   uint32_t Version;
   uint32_t BitcodeOffset;
   uint32_t BitcodeSize;
   uint32_t HeaderVersion;
   uint32_t TargetAPI;
+  uint32_t PNaClVersion;
+  uint16_t CompilerVersionTag;
+  uint16_t CompilerVersionLen;
+  uint32_t CompilerVersion;
+  uint16_t OptimizationLevelTag;
+  uint16_t OptimizationLevelLen;
+  uint32_t OptimizationLevel;
 };
 
 enum BCFileType {
@@ -44,7 +53,10 @@
   const char *mBitcodeEnd;
   size_t mBitcodeSize;
 
-  struct BCWrapperHeader mBCHeader;
+  uint32_t mHeaderVersion;
+  uint32_t mTargetAPI;
+  uint32_t mCompilerVersion;
+  uint32_t mOptimizationLevel;
 
  public:
   /**
@@ -58,7 +70,7 @@
   ~BitcodeWrapper();
 
   /**
-   * Attempt to unwrap the target bitcode.
+   * Attempt to unwrap the target bitcode. This function is \deprecated.
    *
    * \return true on success and false if an error occurred.
    */
@@ -72,20 +84,71 @@
   }
 
   /**
-   * \return header version of bitcode wrapper. This can only be 0 currently.
+   * \return header version of bitcode wrapper.
    */
   uint32_t getHeaderVersion() const {
-    return mBCHeader.HeaderVersion;
+    return mHeaderVersion;
   }
 
   /**
-   * \return target API version of this script.
+   * \return target API version for this bitcode.
    */
   uint32_t getTargetAPI() const {
-    return mBCHeader.TargetAPI;
+    return mTargetAPI;
   }
+
+  /**
+   * \return compiler version that generated this bitcode.
+   */
+  uint32_t getCompilerVersion() const {
+    return mCompilerVersion;
+  }
+
+  /**
+   * \return compiler optimization level for this bitcode.
+   */
+  uint32_t getOptimizationLevel() const {
+    return mOptimizationLevel;
+  }
+
 };
 
+/**
+ * Helper function to emit just the bitcode wrapper returning the number of
+ * bytes that were written.
+ *
+ * \param wrapper - where to write header information into.
+ * \param bitcodeSize - size of bitcode in bytes.
+ * \param targetAPI - target API version for this bitcode.
+ * \param compilerVersion - compiler version that generated this bitcode.
+ * \param optimizationLevel - compiler optimization level for this bitcode.
+ *
+ * \return number of wrapper bytes written into the \p buffer.
+ */
+static inline size_t writeAndroidBitcodeWrapper(AndroidBitcodeWrapper *wrapper,
+    size_t bitcodeSize, uint32_t targetAPI, uint32_t compilerVersion,
+    uint32_t optimizationLevel) {
+  if (!wrapper) {
+    return 0;
+  }
+
+  wrapper->Magic = 0x0B17C0DE;
+  wrapper->Version = 0;
+  wrapper->BitcodeOffset = sizeof(*wrapper);
+  wrapper->BitcodeSize = bitcodeSize;
+  wrapper->HeaderVersion = 0;
+  wrapper->TargetAPI = targetAPI;
+  wrapper->PNaClVersion = 0;
+  wrapper->CompilerVersionTag = BCHeaderField::kAndroidCompilerVersion;
+  wrapper->CompilerVersionLen = 4;
+  wrapper->CompilerVersion = compilerVersion;
+  wrapper->OptimizationLevelTag = BCHeaderField::kAndroidOptimizationLevel;
+  wrapper->OptimizationLevelLen = 4;
+  wrapper->OptimizationLevel = optimizationLevel;
+
+  return sizeof(*wrapper);
+}
+
 }  // namespace bcinfo
 
 #endif  // __ANDROID_BCINFO_BITCODEWRAPPER_H__
diff --git a/include/bcinfo/Wrap/BCHeaderField.h b/include/bcinfo/Wrap/BCHeaderField.h
new file mode 100644
index 0000000..8652d78
--- /dev/null
+++ b/include/bcinfo/Wrap/BCHeaderField.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2012, 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 LLVM_WRAP_BCHEADER_FIELD_H__
+#define LLVM_WRAP_BCHEADER_FIELD_H__
+
+#include <limits>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+// Class representing a variable-size metadata field in the bitcode header.
+// Also contains the list of known Tag IDs.
+// Contains a pointer to the data but does not own the data, so it can be
+// copied with the trivial copy constructor/assignment operator.
+
+// The serialized format has 2 fixed subfields (ID and length) and the
+// variable-length data subfield
+class BCHeaderField {
+ public:
+  typedef enum {
+    kInvalid = 0,
+    kBitcodeHash = 1,
+    kAndroidCompilerVersion = 0x4001,
+    kAndroidOptimizationLevel = 0x4002
+  } Tag;
+  typedef uint16_t FixedSubfield;
+
+  BCHeaderField(Tag ID, size_t len, uint8_t* data) :
+      ID_(ID), len_(len), data_(data) {}
+  size_t GetTotalSize() {
+    // Round up to 4 byte alignment
+    return (kTagLenSize + len_ + 3) & ~3;
+  }
+
+  bool Write(uint8_t* buf, size_t buf_len) {
+    size_t fields_len = kTagLenSize + len_;
+    size_t pad_len = (4 - (fields_len & 3)) & 3;
+    // Ensure buffer is large enough and that length can be represented
+    // in 16 bits
+    if (buf_len < fields_len + pad_len ||
+        len_ > std::numeric_limits<FixedSubfield>::max()) return false;
+
+    WriteFixedSubfield(static_cast<FixedSubfield>(ID_), buf);
+    WriteFixedSubfield(static_cast<FixedSubfield>(len_),
+                       buf + sizeof(FixedSubfield));
+    memcpy(buf + kTagLenSize, data_, len_);
+    // Pad out to 4 byte alignment
+    if (pad_len) {
+      memset(buf + fields_len, 0, pad_len);
+    }
+    return true;
+  }
+
+  bool Read(const uint8_t* buf, size_t buf_len) {
+    if (buf_len < kTagLenSize) return false;
+    FixedSubfield field;
+    ReadFixedSubfield(&field, buf);
+    ID_ = static_cast<Tag>(field);
+    ReadFixedSubfield(&field, buf + sizeof(FixedSubfield));
+    len_ = static_cast<size_t>(field);
+    if (buf_len < kTagLenSize + len_) return false;
+    memcpy(data_, buf + kTagLenSize, len_);
+    return true;
+  }
+
+  void Print() {
+    fprintf(stderr, "Field ID: %d, data length %d, total length %d\n",
+            ID_, static_cast<int>(len_), static_cast<int>(GetTotalSize()));
+    fprintf(stderr, "Data:");
+    for (size_t i = 0; i < len_; i++) fprintf(stderr, "0x%x ", data_[i]);
+    fprintf(stderr, "\n");
+  }
+
+  // Get the data size from a serialized field to allow allocation
+  static size_t GetDataSizeFromSerialized(const uint8_t* buf) {
+    FixedSubfield len;
+    ReadFixedSubfield(&len, buf + sizeof(FixedSubfield));
+    return len;
+  }
+
+  Tag getID() const {
+    return ID_;
+  }
+
+  size_t getLen() const {
+    return len_;
+  }
+
+ private:
+ // Combined size of the fixed subfields
+ const static size_t kTagLenSize = 2 * sizeof(FixedSubfield);
+  static void WriteFixedSubfield(FixedSubfield value, uint8_t* buf) {
+    buf[0] = value & 0xFF;
+    buf[1] = (value >> 8) & 0xFF;
+  }
+  static void ReadFixedSubfield(FixedSubfield* value, const uint8_t* buf) {
+    *value = buf[0] | buf[1] << 8;
+  }
+  Tag ID_;
+  size_t len_;
+  uint8_t *data_;
+};
+
+#endif  // LLVM_WRAP_BCHEADER_FIELD_H__
diff --git a/include/bcinfo/Wrap/bitcode_wrapperer.h b/include/bcinfo/Wrap/bitcode_wrapperer.h
new file mode 100644
index 0000000..2fbce21
--- /dev/null
+++ b/include/bcinfo/Wrap/bitcode_wrapperer.h
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2012, 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.
+ */
+
+// Define utility class to wrap/unwrap bitcode files. Does wrapping/unwrapping
+// in such a way that the wrappered bitcode file is still a bitcode file.
+
+#ifndef LLVM_WRAP_BITCODE_WRAPPERER_H__
+#define LLVM_WRAP_BITCODE_WRAPPERER_H__
+
+#include <stdint.h>
+#include <stddef.h>
+#include <vector>
+
+#include "bcinfo/Wrap/support_macros.h"
+#include "bcinfo/Wrap/BCHeaderField.h"
+#include "bcinfo/Wrap/wrapper_input.h"
+#include "bcinfo/Wrap/wrapper_output.h"
+
+// The bitcode wrapper header is the following 7 fixed 4-byte fields:
+//      1) 0B17C0DE - The magic number expected by llvm for wrapped bitcodes
+//      2) Version # 0 - The current version of wrapped bitcode files
+//      3) (raw) bitcode offset
+//      4) (raw) bitcode size
+//      5) Android header version
+//      6) Android target API
+//      7) PNaCl Bitcode version
+//      plus 0 or more variable-length fields (consisting of ID, length, data)
+
+// Initial buffer size. It is expanded if needed to hold large variable-size
+// fields.
+static const size_t kBitcodeWrappererBufferSize = 1024;
+
+// Support class for outputting a wrapped bitcode file from a raw bitcode
+// file (and optionally additional header fields), or for outputting a raw
+// bitcode file from a wrapped one.
+class BitcodeWrapperer {
+ public:
+  // Create a bitcode wrapperer using the following
+  // input and output files.
+  BitcodeWrapperer(WrapperInput* infile, WrapperOutput* outfile);
+
+  // Returns true if the input file begins with a bitcode
+  // wrapper magic number. As a side effect, _wrapper_ fields are set.
+  bool IsInputBitcodeWrapper();
+
+  // Returns true if the input file begins with a bitcode
+  // file magic number.
+  bool IsInputBitcodeFile();
+
+  // Add a variable-length field to the header. The caller is responsible
+  // for freeing the data pointed to by the BCHeaderField.
+  void AddHeaderField(BCHeaderField* field);
+
+  // Generate a wrapped bitcode file from the input bitcode file
+  // and the current header data. Return true on success.
+  bool GenerateWrappedBitcodeFile();
+
+  // Unwrap the wrapped bitcode file, to the corresponding
+  // outfile. Return true on success.
+  bool GenerateRawBitcodeFile();
+
+  // Print current wrapper header fields to stderr for debugging.
+  void PrintWrapperHeader();
+
+  uint32_t getAndroidHeaderVersion() {
+    return android_header_version_;
+  }
+
+  uint32_t getAndroidTargetAPI() {
+    return android_target_api_;
+  }
+
+  uint32_t getAndroidCompilerVersion() {
+    return android_compiler_version_;
+  }
+
+  uint32_t getAndroidOptimizationLevel() {
+    return android_optimization_level_;
+  }
+
+  ~BitcodeWrapperer();
+
+ private:
+  DISALLOW_CLASS_COPY_AND_ASSIGN(BitcodeWrapperer);
+
+  // Refills the buffer with more bytes. Does this in a way
+  // such that it is maximally filled.
+  void FillBuffer();
+
+  // Returns the number of bytes in infile.
+  off_t GetInFileSize() { return infile_->Size(); }
+
+  // Returns the offset of bitcode (i.e. the size of the wrapper header)
+  // if the output file were to be written now.
+  size_t BitcodeOffset();
+
+  // Returns true if we can read a word. If necessary, fills the buffer
+  // with enough characters so that there are at least a 32-bit value
+  // in the buffer. Returns false if there isn't a 32-bit value
+  // to read from the input file.
+  bool CanReadWord();
+
+  // Read a (32-bit) word from the input. Return true
+  // if able to read the word.
+  bool ReadWord(uint32_t& word);
+
+  // Write a (32-bit) word to the output. Return true if successful
+  bool WriteWord(uint32_t word);
+
+  // Write all variable-sized header fields to the output. Return true
+  // if successful.
+  bool WriteVariableFields();
+
+  // Parse the bitcode wrapper header in the infile, if any. Return true
+  // if successful.
+  bool ParseWrapperHeader();
+
+  // Returns the i-th character in front of the cursor in the buffer.
+  uint8_t BufferLookahead(int i) { return buffer_[cursor_ + i]; }
+
+  // Returns how many unread bytes are in the buffer.
+  size_t GetBufferUnreadBytes() { return buffer_size_ - cursor_; }
+
+
+  // Backs up the read cursor to the beginning of the input buffer.
+  void ResetCursor() {
+    cursor_ = 0;
+  }
+
+  // Generates the header sequence for the wrapped bitcode being
+  // generated.
+  bool WriteBitcodeWrapperHeader();
+
+  // Copies size bytes of infile to outfile, using the buffer.
+  bool BufferCopyInToOut(uint32_t size);
+
+  // Discards the old infile and replaces it with the given file.
+  void ReplaceInFile(WrapperInput* new_infile);
+
+  // Discards the old outfile and replaces it with the given file.
+  void ReplaceOutFile(WrapperOutput* new_outfile);
+
+  // Moves to the given position in the input file. Returns false
+  // if unsuccessful.
+  bool Seek(uint32_t pos);
+
+  // Clear the buffer of all contents.
+  void ClearBuffer();
+
+  // The input file being processed. Can be either
+  // a bitcode file, a wrappered bitcode file, or a secondary
+  // file to be wrapped.
+  WrapperInput* infile_;
+
+  // The output file being generated. Can be either
+  // a bitcode file, a wrappered bitcode file, or a secondary
+  // unwrapped file.
+  WrapperOutput* outfile_;
+
+  // A buffer of bytes read from the input file.
+  std::vector<uint8_t> buffer_;
+
+  // The number of bytes that were read from the input file
+  // into the buffer.
+  size_t buffer_size_;
+
+  // The index to the current read point within the buffer.
+  size_t cursor_;
+
+  // True when eof of input is reached.
+  bool infile_at_eof_;
+
+  // The 32-bit value defining the offset of the raw bitcode in the input file.
+  uint32_t infile_bc_offset_;
+
+  // The 32-bit value defining the generated offset of the wrapped bitcode.
+  // This value changes as new fields are added with AddHeaderField
+  uint32_t wrapper_bc_offset_;
+
+  // The 32-bit value defining the size of the raw wrapped bitcode.
+  uint32_t wrapper_bc_size_;
+
+  // Android header version and target API
+  uint32_t android_header_version_;
+  uint32_t android_target_api_;
+  uint32_t android_compiler_version_;
+  uint32_t android_optimization_level_;
+
+  // PNaCl bitcode version
+  uint32_t pnacl_bc_version_;
+
+  // Vector of variable header fields
+  std::vector<BCHeaderField> header_fields_;
+  // If any bufferdata from header fields is owned, it is stored here and
+  // freed on destruction.
+  std::vector<uint8_t*> variable_field_data_;
+
+  // True if there was an error condition (e.g. the file is not bitcode)
+  bool error_;
+};
+
+#endif  // LLVM_WRAP_BITCODE_WRAPPERER_H__
diff --git a/include/bcinfo/Wrap/file_wrapper_input.h b/include/bcinfo/Wrap/file_wrapper_input.h
new file mode 100644
index 0000000..2ff955f
--- /dev/null
+++ b/include/bcinfo/Wrap/file_wrapper_input.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2012, 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.
+ */
+
+// Defines utility allowing files for bitcode input wrapping.
+
+#ifndef FILE_WRAPPER_INPUT_H__
+#define FILE_WRAPPER_INPUT_H__
+
+#include <stdio.h>
+
+#include "bcinfo/Wrap/support_macros.h"
+#include "bcinfo/Wrap/wrapper_input.h"
+
+// Define a class to wrap named files.
+class FileWrapperInput : public WrapperInput {
+ public:
+  FileWrapperInput(const char* _name);
+  ~FileWrapperInput();
+  // Tries to read the requested number of bytes into the buffer. Returns the
+  // actual number of bytes read.
+  virtual size_t Read(uint8_t* buffer, size_t wanted);
+  // Returns true if at end of file. Note: May return false
+  // until Read is called, and returns 0.
+  virtual bool AtEof();
+  // Returns the size of the file (in bytes).
+  virtual off_t Size();
+  // Moves to the given offset within the file. Returns
+  // false if unable to move to that position.
+  virtual bool Seek(uint32_t pos);
+ private:
+  // The name of the file.
+  const char* _name;
+  // True once eof has been encountered.
+  bool _at_eof;
+  // True if size has been computed.
+  bool _size_found;
+  // The size of the file.
+  off_t _size;
+  // The corresponding (opened) file.
+  FILE* _file;
+ private:
+  DISALLOW_CLASS_COPY_AND_ASSIGN(FileWrapperInput);
+};
+
+#endif // FILE_WRAPPER_INPUT_H__
diff --git a/include/bcinfo/Wrap/file_wrapper_output.h b/include/bcinfo/Wrap/file_wrapper_output.h
new file mode 100644
index 0000000..fa01c93
--- /dev/null
+++ b/include/bcinfo/Wrap/file_wrapper_output.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2012, 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.
+ */
+
+// Defines utility allowing files for bitcode output wrapping.
+
+#ifndef FILE_WRAPPER_OUTPUT_H__
+#define FILE_WRAPPER_OUTPUT_H__
+
+#include <stdio.h>
+
+#include "bcinfo/Wrap/support_macros.h"
+#include "bcinfo/Wrap/wrapper_output.h"
+
+// Define a class to wrap named files. */
+class FileWrapperOutput : public WrapperOutput {
+ public:
+  FileWrapperOutput(const char* name);
+  ~FileWrapperOutput();
+  // Writes a single byte, returning false if unable to write.
+  virtual bool Write(uint8_t byte);
+  // Writes the specified number of bytes in the buffer to
+  // output. Returns false if unable to write.
+  virtual bool Write(const uint8_t* buffer, size_t buffer_size);
+ private:
+  // The name of the file
+  const char* _name;
+  // The corresponding (opened) file.
+  FILE* _file;
+ private:
+  DISALLOW_CLASS_COPY_AND_ASSIGN(FileWrapperOutput);
+};
+#endif  // FILE_WRAPPER_OUTPUT_H__
diff --git a/include/bcinfo/Wrap/in_memory_wrapper_input.h b/include/bcinfo/Wrap/in_memory_wrapper_input.h
new file mode 100644
index 0000000..634dd40
--- /dev/null
+++ b/include/bcinfo/Wrap/in_memory_wrapper_input.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012, 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.
+ */
+
+// Defines utility allowing in-memory buffers for bitcode input wrapping.
+
+#ifndef IN_MEMORY_WRAPPER_INPUT_H__
+#define IN_MEMORY_WRAPPER_INPUT_H__
+
+#include <stdio.h>
+
+#include "bcinfo/Wrap/support_macros.h"
+#include "bcinfo/Wrap/wrapper_input.h"
+
+// Define a class to wrap named files.
+class InMemoryWrapperInput : public WrapperInput {
+ public:
+  InMemoryWrapperInput(const char* buffer, size_t size);
+  ~InMemoryWrapperInput();
+  // Tries to read the requested number of bytes into the buffer. Returns the
+  // actual number of bytes read.
+  virtual size_t Read(uint8_t* buffer, size_t wanted);
+  // Returns true if at end of buffer. Note: May return false
+  // until Read is called, and returns 0.
+  virtual bool AtEof();
+  // Returns the size of the buffer (in bytes).
+  virtual off_t Size();
+  // Moves to the given offset within the buffer. Returns
+  // false if unable to move to that position.
+  virtual bool Seek(uint32_t pos);
+ private:
+  // The actual in-memory buffer
+  const char* _buffer;
+  // The position in the buffer
+  size_t _pos;
+  // True once eof has been encountered.
+  bool _at_eof;
+  // The size of the buffer.
+  size_t _size;
+ private:
+  DISALLOW_CLASS_COPY_AND_ASSIGN(InMemoryWrapperInput);
+};
+
+#endif // IN_MEMORY_WRAPPER_INPUT_H__
diff --git a/include/bcinfo/Wrap/support_macros.h b/include/bcinfo/Wrap/support_macros.h
new file mode 100644
index 0000000..5d3b8ce
--- /dev/null
+++ b/include/bcinfo/Wrap/support_macros.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2012, 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.
+ */
+
+// Define support macros for defining classes, etc.
+
+#ifndef LLVM_SUPPORT_SUPPORT_MACROS_H__
+#define LLVM_SUPPORT_SUPPORT_MACROS_H__
+
+// Define macro, to use within a class declaration,  to disallow constructor
+// copy. Defines copy constructor declaration under the assumption that it
+// is never defined.
+#define DISALLOW_CLASS_COPY(class_name) \
+  class_name(class_name& arg)  // Do not implement
+
+// Define macro, to use within a class declaration,  to disallow assignment.
+// Defines assignment operation declaration under the assumption that it
+// is never defined.
+#define DISALLOW_CLASS_ASSIGN(class_name) \
+  void operator=(class_name& arg)  // Do not implement
+
+// Define macro to add copy and assignment declarations to a class file,
+// for which no bodies will be defined, effectively disallowing these from
+// being defined in the class.
+#define DISALLOW_CLASS_COPY_AND_ASSIGN(class_name) \
+  DISALLOW_CLASS_COPY(class_name); \
+  DISALLOW_CLASS_ASSIGN(class_name)
+
+#endif  // LLVM_SUPPORT_SUPPORT_MACROS_H__
diff --git a/include/bcinfo/Wrap/wrapper_input.h b/include/bcinfo/Wrap/wrapper_input.h
new file mode 100644
index 0000000..d3330df
--- /dev/null
+++ b/include/bcinfo/Wrap/wrapper_input.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2012, 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.
+ */
+
+// Define a generic interface to a file/memory region that contains
+// a bitcode file, a wrapped bitcode file, or a data file to wrap.
+
+#ifndef LLVM_WRAP_WRAPPER_INPUT_H__
+#define LLVM_WRAP_WRAPPER_INPUT_H__
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "support_macros.h"
+
+// The following is a generic interface to a file/memory region that contains
+// a bitcode file, a wrapped bitcode file, or data file to wrap.
+class WrapperInput {
+ public:
+  WrapperInput() {}
+  virtual ~WrapperInput() {}
+  // Tries to read the requested number of bytes into the buffer. Returns the
+  // actual number of bytes read.
+  virtual size_t Read(uint8_t* buffer, size_t wanted) = 0;
+  // Returns true if at end of input. Note: May return false until
+  // Read is called, and returns 0.
+  virtual bool AtEof() = 0;
+  // Returns the size of the input (in bytes).
+  virtual off_t Size() = 0;
+  // Moves to the given offset within the input region. Returns false
+  // if unable to move to that position.
+  virtual bool Seek(uint32_t pos) = 0;
+ private:
+  DISALLOW_CLASS_COPY_AND_ASSIGN(WrapperInput);
+};
+
+#endif  // LLVM_WRAP_WRAPPER_INPUT_H__
diff --git a/include/bcinfo/Wrap/wrapper_output.h b/include/bcinfo/Wrap/wrapper_output.h
new file mode 100644
index 0000000..6498805
--- /dev/null
+++ b/include/bcinfo/Wrap/wrapper_output.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2012, 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.
+ */
+
+// Defines a generic interface to a file/memory region that
+// contains a generated wrapped bitcode file, bitcode file,
+// or data file.
+
+#ifndef LLVM_WRAP_WRAPPER_OUTPUT_H__
+#define LLVM_WRAP_WRAPPER_OUTPUT_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "bcinfo/Wrap/support_macros.h"
+
+// The following is a generic interface to a file/memory region
+// that contains a generated bitcode file, wrapped bitcode file,
+// or a data file.
+class WrapperOutput {
+ public:
+  WrapperOutput() {}
+  virtual ~WrapperOutput() {}
+  // Writes a single byte, returning false if unable to write.
+  virtual bool Write(uint8_t byte) = 0;
+  // Writes the specified number of bytes in the buffer to
+  // output. Returns false if unable to write.
+  virtual bool Write(const uint8_t* buffer, size_t buffer_size);
+ private:
+  DISALLOW_CLASS_COPY_AND_ASSIGN(WrapperOutput);
+};
+
+#endif  // LLVM_WRAP_WRAPPER_OUTPUT_H__