First kinda/sorta working version of the Archive library. Reading is not
authorReid Spencer <rspencer@reidspencer.com>
Sat, 6 Nov 2004 08:51:45 +0000 (08:51 +0000)
committerReid Spencer <rspencer@reidspencer.com>
Sat, 6 Nov 2004 08:51:45 +0000 (08:51 +0000)
yet supported but writing works. Way too early to review this. More to come

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17499 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Archive/Archive.cpp [new file with mode: 0644]
lib/Archive/ArchiveInternals.h [new file with mode: 0644]
lib/Archive/ArchiveWriter.cpp [new file with mode: 0644]
lib/Bytecode/Archive/Archive.cpp [new file with mode: 0644]
lib/Bytecode/Archive/ArchiveInternals.h [new file with mode: 0644]
lib/Bytecode/Archive/ArchiveWriter.cpp [new file with mode: 0644]

diff --git a/lib/Archive/Archive.cpp b/lib/Archive/Archive.cpp
new file mode 100644 (file)
index 0000000..e9fcd2e
--- /dev/null
@@ -0,0 +1,24 @@
+//===-- Archive.cpp - Generic LLVM archive functions ------------*- C++ -*-===//
+// 
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by Reid Spencer and is distributed under the 
+// University of Illinois Open Source License. See LICENSE.TXT for details.
+// 
+//===----------------------------------------------------------------------===//
+//
+// Builds up standard unix archive files (.a) containing LLVM bytecode.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchiveInternals.h"
+
+using namespace llvm;
+
+Archive::Archive() {
+}
+
+Archive::~Archive() {
+}
+
+// vim: sw=2 ai
diff --git a/lib/Archive/ArchiveInternals.h b/lib/Archive/ArchiveInternals.h
new file mode 100644 (file)
index 0000000..dde8358
--- /dev/null
@@ -0,0 +1,158 @@
+//===-- lib/Bytecode/ArchiveInternals.h -------------------------*- C++ -*-===//
+// 
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by Reid Spencer and is distributed under the 
+// University of Illinois Open Source License. See LICENSE.TXT for details.
+// 
+//===----------------------------------------------------------------------===//
+//
+// Internal implementation header for LLVM Archive files.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LIB_BYTECODE_ARCHIVEINTERNALS_H
+#define LIB_BYTECODE_ARCHIVEINTERNALS_H
+
+#include "llvm/Bytecode/Archive.h"
+#include "llvm/System/TimeValue.h"
+
+#define ARFILE_MAGIC "!<arch>\n"                   ///< magic string 
+#define ARFILE_MAGIC_LEN (sizeof(ARFILE_MAGIC)-1)  ///< length of magic string 
+#define ARFILE_SYMTAB_NAME "/"                     ///< name of symtab entry
+#define ARFILE_STRTAB_NAME "//"                    ///< name of strtab entry
+#define ARFILE_PAD '\n'                            ///< inter-file align padding
+
+namespace llvm {
+
+  /// The ArchiveMemberHeader structure is used internally for bytecode archives. 
+  /// The header precedes each file member in the archive. This structure is 
+  /// defined using character arrays for direct and correct interpretation
+  /// regardless of the endianess of the machine that produced it.
+  /// @brief Archive File Member Header
+  class ArchiveMemberHeader {
+    public:
+    void init() {
+      memset(name,' ',16);
+      memset(date,' ',12);
+      memset(uid,' ',6);
+      memset(gid,' ',6);
+      memset(mode,' ',8);
+      memset(size,' ',10);
+      fmag[0] = '`';
+      fmag[1] = '\n';
+    }
+    void setDate( int secondsSinceEpoch = 0 ) {
+      if (secondsSinceEpoch == 0) {
+        sys::TimeValue tv = sys::TimeValue::now();
+        uint64_t secs; uint32_t nanos;
+        tv.GetTimespecTime(secs,nanos);
+        secondsSinceEpoch = (int) secs;
+      }
+      char buffer[20];
+      sprintf(buffer,"%d", secondsSinceEpoch);
+      memcpy(date,buffer,strlen(buffer));
+    }
+
+    void setSize(size_t sz) {
+      char buffer[20];
+      sprintf(buffer, "%u", (unsigned)sz);
+      memcpy(size,buffer,strlen(buffer));
+    }
+
+    void setMode(int m) {
+      char buffer[20];
+      sprintf(buffer, "%o", m);
+      memcpy(mode,buffer,strlen(buffer));
+    }
+
+    void setUid(unsigned u) {
+      char buffer[20];
+      sprintf(buffer, "%u", u);
+      memcpy(uid,buffer,strlen(buffer));
+    }
+
+    void setGid(unsigned g) {
+      char buffer[20];
+      sprintf(buffer, "%u", g);
+      memcpy(gid,buffer,strlen(buffer));
+    }
+
+    bool setName(const std::string& nm) {
+      if (nm.length() > 0 && nm.length() <= 16) {
+        memcpy(name,nm.c_str(),nm.length());
+        for (int i = nm.length()+1; i < 16; i++ ) name[i] = ' ';
+        return true;
+      }
+      return false;
+    }
+
+    private:
+    char name[16];  ///< Name of the file member. The filename is terminated with '/'
+                    ///< and blanks. The empty name (/ and 15 blanks) is for the 
+                    ///< symbol table. The special name "//" and 15 blanks is for
+                    ///< the string table, used for long file names. It must be
+                    ///< first in the archive.
+    char date[12];  ///< File date, decimal seconds since Epoch
+    char uid[6];    ///< user id in ASCII decimal
+    char gid[6];    ///< group id in ASCII decimal
+    char mode[8];   ///< file mode in ASCII octal
+    char size[10];  ///< file size in ASCII decimal
+    char fmag[2];   ///< Always contains ARFILE_MAGIC_TERMINATOR
+
+  };
+
+  /// The ArchiveInternals class is used to hold the content of the archive
+  /// while it is in memory. It also provides the bulk of the implementation for
+  /// the llvm:Archive class's interface.
+  class Archive::ArchiveInternals {
+    /// @name Types
+    /// @{
+    public:
+      typedef std::vector<std::string> StrTab;
+
+      /// This structure holds information for one member in the archive. It is
+      /// used temporarily while the contents of the archive are being
+      /// determined.
+      struct MemberInfo {
+        MemberInfo() {}
+        sys::Path path;
+        std::string name;
+        sys::Path::StatusInfo status;
+        StrTab symbols;
+        unsigned offset;
+      };
+
+    /// @}
+    /// @name Methods
+    /// @{
+    public:
+      /// @brief Add a file member to the archive.
+      void addFileMember(
+        const sys::Path& path,         ///< The path to the file to be added
+        const std::string& name,       ///< The name for the member
+        const StrTab* syms = 0         ///< The symbol table of the member
+      );
+
+      /// @brief Write the accumulated archive information to an archive file
+      void writeArchive();
+      void writeMember(const MemberInfo& member,std::ofstream& ARFile);
+      void writeSymbolTable(std::ofstream& ARFile);
+      void writeInteger(int num, std::ofstream& ARFile);
+
+    /// @}
+    /// @name  Data
+    /// @{
+    private:
+      friend class Archive;            ///< Parent class is a friend
+      sys::Path       fname;           ///< Path to the archive file
+      std::vector<MemberInfo> members; ///< Info about member files
+      Archive::SymTab* symtab;         ///< User's symbol table
+
+    /// @}
+  };
+}
+
+#endif
+
+// vim: sw=2 ai
diff --git a/lib/Archive/ArchiveWriter.cpp b/lib/Archive/ArchiveWriter.cpp
new file mode 100644 (file)
index 0000000..e3e2df4
--- /dev/null
@@ -0,0 +1,284 @@
+//===-- ArchiveWriter.cpp - LLVM archive writing --------------------------===//
+// 
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by Reid Spencerand is distributed under the 
+// University of Illinois Open Source License. See LICENSE.TXT for details.
+// 
+//===----------------------------------------------------------------------===//
+//
+// Builds up standard unix archive files (.a) containing LLVM bytecode.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchiveInternals.h"
+#include "llvm/Module.h"
+#include "llvm/Bytecode/Reader.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/System/MappedFile.h"
+#include <fstream>
+#include <iostream>
+
+using namespace llvm;
+
+Archive* 
+Archive::CreateEmpty(const sys::Path& Filename) {
+  Archive* result = new Archive;
+  Archive::ArchiveInternals* impl = result->impl = new Archive::ArchiveInternals;
+  impl->fname = Filename;
+  return result;
+}
+
+Archive*
+Archive::CreateFromFiles(
+  const sys::Path& Filename,
+  const PathList& Files,
+  const std::string& StripName
+) {
+  Archive* result = new Archive;
+  Archive::ArchiveInternals* impl = result->impl = new Archive::ArchiveInternals;
+  impl->fname = Filename;
+
+  try {
+    size_t strip_len = StripName.length();
+    for (PathList::const_iterator P = Files.begin(), E = Files.end(); P != E ;++P)
+    {
+      if (P->readable()) {
+        std::string name(P->get());
+        if (strip_len > 0 && StripName == name.substr(0,strip_len)) {
+          name.erase(0,strip_len);
+        }
+        if (P->isBytecodeFile()) {
+          std::vector<std::string> syms;
+          if (!GetBytecodeSymbols(*P, syms))
+            throw std::string("Can not get symbols from: ") + P->get();
+          impl->addFileMember(*P, name, &syms);
+        } else {
+          impl->addFileMember(*P, name);
+        }
+      }
+      else
+        throw std::string("Can not read: ") + P->get();
+    }
+
+    // Now that we've collected everything, write the archive
+    impl->writeArchive();
+
+  } catch(...) {
+    delete impl;
+    result->impl = 0;
+    delete result;
+    throw;
+  }
+
+  return result;
+}
+
+void
+Archive::ArchiveInternals::addFileMember(
+  const sys::Path& filePath,
+  const std::string& memberName,
+  const StrTab* symbols
+) {
+  MemberInfo info;
+  info.path = filePath;
+  info.name = memberName;
+  filePath.getStatusInfo(info.status);
+  if (symbols)
+    info.symbols = *symbols;
+  info.offset = 0;
+  members.push_back(info);
+}
+
+void
+Archive::ArchiveInternals::writeInteger(int num, std::ofstream& ARFile) {
+  char buff[4];
+  buff[0] = (num >> 24) & 255;
+  buff[1] = (num >> 16) & 255;
+  buff[2] = (num >> 8) & 255;
+  buff[3] = num & 255;
+  ARFile.write(buff, sizeof(buff));
+}
+
+void
+Archive::ArchiveInternals::writeSymbolTable( std::ofstream& ARFile ) {
+  // Compute the number of symbols in the symbol table and the
+  // total byte size of the string pool. While we're traversing,
+  // build the string pool for supporting long file names. Also,
+  // build the table of file offsets for the symbol table and 
+  // the 
+  typedef std::map<std::string,unsigned> SymbolMap;
+  StrTab stringPool;
+  SymbolMap symbolTable;
+  std::vector<unsigned> fileOffsets;
+  std::string symTabStrings;
+  unsigned fileOffset = 0;
+  unsigned spOffset = 0;
+  unsigned numSymbols = 0;
+  unsigned numSymBytes = 0;
+  for (unsigned i = 0; i < members.size(); i++ ) {
+    MemberInfo& mi = members[i];
+    StrTab& syms = mi.symbols;
+    size_t numSym = syms.size();
+    numSymbols += numSym;
+    for (unsigned j = 0; j < numSym; j++ ) {
+      numSymBytes += syms[j].size() + 1;
+      symbolTable[syms[i]] = i;
+    }
+    if (mi.name.length() > 15 || std::string::npos != mi.name.find('/')) {
+      stringPool.push_back(mi.name + "/\n");
+      mi.name = std::string("/") + utostr(spOffset);
+      spOffset += mi.name.length() + 2;
+    } else if (mi.name[mi.name.length()-1] != '/') {
+      mi.name += "/";
+    }
+    fileOffsets.push_back(fileOffset);
+    fileOffset += sizeof(ArchiveMemberHeader) + mi.status.fileSize;
+  }
+
+
+  // Compute the size of the symbol table file member
+  unsigned symTabSize = 0;
+  if (numSymbols != 0) 
+    symTabSize = 
+      sizeof(ArchiveMemberHeader) + // Size of the file header
+      4 +                           // Size of "number of entries"
+      (4 * numSymbols) +            // Size of member file indices
+      numSymBytes;                  // Size of the string table
+
+  // Compute the size of the string pool
+  unsigned strPoolSize = 0;
+  if (spOffset != 0 )
+    strPoolSize = 
+      sizeof(ArchiveMemberHeader) + // Size of the file header
+      spOffset;                     // Number of bytes in the string pool
+
+  // Compute the byte index offset created by symbol table and string pool
+  unsigned firstFileOffset = symTabSize + strPoolSize;
+
+  // Create header for symbol table. This must be first if there is
+  // a symbol table and must have a special name.
+  if ( symTabSize > 0 ) {
+    ArchiveMemberHeader Hdr;
+    Hdr.init();
+
+    // Name of symbol table is '/               ' but "" is passed in
+    // because the setName method always terminates with a /
+    Hdr.setName(ARFILE_SYMTAB_NAME);
+    Hdr.setDate();
+    Hdr.setSize(symTabSize - sizeof(ArchiveMemberHeader));
+    Hdr.setMode(0);
+    Hdr.setUid(0);
+    Hdr.setGid(0);
+    
+    // Write header to archive file
+    ARFile.write((char*)&Hdr, sizeof(Hdr));
+    
+    // Write the number of entries in the symbol table
+    this->writeInteger(numSymbols, ARFile);
+
+    // Write the file offset indices for each symbol and build the
+    // symbol table string pool
+    std::string symTabStrPool;
+    symTabStrPool.reserve(256 * 1024); // Reserve 256KBytes for symbols
+    for (SymbolMap::iterator I = symbolTable.begin(), E = symbolTable.end();
+         I != E; ++I ) {
+      this->writeInteger(firstFileOffset + fileOffsets[I->second], ARFile);
+      symTabStrPool += I->first;
+      symTabStrPool += "\0";
+    }
+
+    // Write the symbol table's string pool
+    ARFile.write(symTabStrPool.data(), symTabStrPool.size());
+  }
+
+  //============== DONE WITH SYMBOL TABLE 
+
+  if (strPoolSize > 0) {
+    // Initialize the header for the string pool
+    ArchiveMemberHeader Hdr;
+    Hdr.init();
+    Hdr.setName(ARFILE_STRTAB_NAME); 
+    Hdr.setDate();
+    Hdr.setSize(spOffset);
+    Hdr.setMode(0);
+    Hdr.setUid(0);
+    Hdr.setGid(0);
+
+    // Write the string pool header
+    ARFile.write((char*)&Hdr, sizeof(Hdr));
+
+    // Write the string pool
+    for (unsigned i = 0; i < stringPool.size(); i++) {
+      ARFile.write(stringPool[i].data(), stringPool[i].size());
+    }
+  }
+}
+
+void
+Archive::ArchiveInternals::writeMember(
+  const MemberInfo& member,
+  std::ofstream& ARFile
+) {
+
+  // Map the file into memory. We do this early for two reasons. First,
+  // if there's any kind of error, we want to know about it. Second, we
+  // want to ensure we're using the most recent size for this file.
+  sys::MappedFile mFile(member.path);
+  mFile.map();
+
+  // Header for the archive member
+  ArchiveMemberHeader Hdr;
+  Hdr.init();
+
+  // Set the name. If its longer than 15 chars, it will have already
+  // been reduced by the writeSymbolTable.
+  Hdr.setName(member.name);
+
+  // Set the other header members
+  Hdr.setSize( mFile.size() );
+  Hdr.setMode( member.status.mode);
+  Hdr.setUid ( member.status.user);
+  Hdr.setGid ( member.status.group);
+  Hdr.setDate( member.status.modTime.ToPosixTime() );
+
+  // Write header to archive file
+  ARFile.write((char*)&Hdr, sizeof(Hdr));
+  
+  //write to archive file
+  ARFile.write(mFile.charBase(),mFile.size());
+
+  mFile.unmap();
+}
+
+void
+Archive::ArchiveInternals::writeArchive() {
+  
+  // Create archive file for output.
+  std::ofstream ArchiveFile(fname.get().c_str());
+  
+  // Check for errors opening or creating archive file.
+  if ( !ArchiveFile.is_open() || ArchiveFile.bad() ) {
+    throw std::string("Error opening archive file: ") + fname.get();
+  }
+
+  // Write magic string to archive.
+  ArchiveFile << ARFILE_MAGIC;
+
+  // Write the symbol table and string pool
+  writeSymbolTable(ArchiveFile);
+
+  //Loop over all member files, and add to the archive.
+  for ( unsigned i = 0; i < members.size(); ++i) {
+    if(ArchiveFile.tellp() % 2 != 0)
+      ArchiveFile << ARFILE_PAD;
+    writeMember(members[i],ArchiveFile);
+  }
+
+  //Close archive file.
+  ArchiveFile.close();
+}
+
+// vim: sw=2 ai
diff --git a/lib/Bytecode/Archive/Archive.cpp b/lib/Bytecode/Archive/Archive.cpp
new file mode 100644 (file)
index 0000000..e9fcd2e
--- /dev/null
@@ -0,0 +1,24 @@
+//===-- Archive.cpp - Generic LLVM archive functions ------------*- C++ -*-===//
+// 
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by Reid Spencer and is distributed under the 
+// University of Illinois Open Source License. See LICENSE.TXT for details.
+// 
+//===----------------------------------------------------------------------===//
+//
+// Builds up standard unix archive files (.a) containing LLVM bytecode.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchiveInternals.h"
+
+using namespace llvm;
+
+Archive::Archive() {
+}
+
+Archive::~Archive() {
+}
+
+// vim: sw=2 ai
diff --git a/lib/Bytecode/Archive/ArchiveInternals.h b/lib/Bytecode/Archive/ArchiveInternals.h
new file mode 100644 (file)
index 0000000..dde8358
--- /dev/null
@@ -0,0 +1,158 @@
+//===-- lib/Bytecode/ArchiveInternals.h -------------------------*- C++ -*-===//
+// 
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by Reid Spencer and is distributed under the 
+// University of Illinois Open Source License. See LICENSE.TXT for details.
+// 
+//===----------------------------------------------------------------------===//
+//
+// Internal implementation header for LLVM Archive files.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LIB_BYTECODE_ARCHIVEINTERNALS_H
+#define LIB_BYTECODE_ARCHIVEINTERNALS_H
+
+#include "llvm/Bytecode/Archive.h"
+#include "llvm/System/TimeValue.h"
+
+#define ARFILE_MAGIC "!<arch>\n"                   ///< magic string 
+#define ARFILE_MAGIC_LEN (sizeof(ARFILE_MAGIC)-1)  ///< length of magic string 
+#define ARFILE_SYMTAB_NAME "/"                     ///< name of symtab entry
+#define ARFILE_STRTAB_NAME "//"                    ///< name of strtab entry
+#define ARFILE_PAD '\n'                            ///< inter-file align padding
+
+namespace llvm {
+
+  /// The ArchiveMemberHeader structure is used internally for bytecode archives. 
+  /// The header precedes each file member in the archive. This structure is 
+  /// defined using character arrays for direct and correct interpretation
+  /// regardless of the endianess of the machine that produced it.
+  /// @brief Archive File Member Header
+  class ArchiveMemberHeader {
+    public:
+    void init() {
+      memset(name,' ',16);
+      memset(date,' ',12);
+      memset(uid,' ',6);
+      memset(gid,' ',6);
+      memset(mode,' ',8);
+      memset(size,' ',10);
+      fmag[0] = '`';
+      fmag[1] = '\n';
+    }
+    void setDate( int secondsSinceEpoch = 0 ) {
+      if (secondsSinceEpoch == 0) {
+        sys::TimeValue tv = sys::TimeValue::now();
+        uint64_t secs; uint32_t nanos;
+        tv.GetTimespecTime(secs,nanos);
+        secondsSinceEpoch = (int) secs;
+      }
+      char buffer[20];
+      sprintf(buffer,"%d", secondsSinceEpoch);
+      memcpy(date,buffer,strlen(buffer));
+    }
+
+    void setSize(size_t sz) {
+      char buffer[20];
+      sprintf(buffer, "%u", (unsigned)sz);
+      memcpy(size,buffer,strlen(buffer));
+    }
+
+    void setMode(int m) {
+      char buffer[20];
+      sprintf(buffer, "%o", m);
+      memcpy(mode,buffer,strlen(buffer));
+    }
+
+    void setUid(unsigned u) {
+      char buffer[20];
+      sprintf(buffer, "%u", u);
+      memcpy(uid,buffer,strlen(buffer));
+    }
+
+    void setGid(unsigned g) {
+      char buffer[20];
+      sprintf(buffer, "%u", g);
+      memcpy(gid,buffer,strlen(buffer));
+    }
+
+    bool setName(const std::string& nm) {
+      if (nm.length() > 0 && nm.length() <= 16) {
+        memcpy(name,nm.c_str(),nm.length());
+        for (int i = nm.length()+1; i < 16; i++ ) name[i] = ' ';
+        return true;
+      }
+      return false;
+    }
+
+    private:
+    char name[16];  ///< Name of the file member. The filename is terminated with '/'
+                    ///< and blanks. The empty name (/ and 15 blanks) is for the 
+                    ///< symbol table. The special name "//" and 15 blanks is for
+                    ///< the string table, used for long file names. It must be
+                    ///< first in the archive.
+    char date[12];  ///< File date, decimal seconds since Epoch
+    char uid[6];    ///< user id in ASCII decimal
+    char gid[6];    ///< group id in ASCII decimal
+    char mode[8];   ///< file mode in ASCII octal
+    char size[10];  ///< file size in ASCII decimal
+    char fmag[2];   ///< Always contains ARFILE_MAGIC_TERMINATOR
+
+  };
+
+  /// The ArchiveInternals class is used to hold the content of the archive
+  /// while it is in memory. It also provides the bulk of the implementation for
+  /// the llvm:Archive class's interface.
+  class Archive::ArchiveInternals {
+    /// @name Types
+    /// @{
+    public:
+      typedef std::vector<std::string> StrTab;
+
+      /// This structure holds information for one member in the archive. It is
+      /// used temporarily while the contents of the archive are being
+      /// determined.
+      struct MemberInfo {
+        MemberInfo() {}
+        sys::Path path;
+        std::string name;
+        sys::Path::StatusInfo status;
+        StrTab symbols;
+        unsigned offset;
+      };
+
+    /// @}
+    /// @name Methods
+    /// @{
+    public:
+      /// @brief Add a file member to the archive.
+      void addFileMember(
+        const sys::Path& path,         ///< The path to the file to be added
+        const std::string& name,       ///< The name for the member
+        const StrTab* syms = 0         ///< The symbol table of the member
+      );
+
+      /// @brief Write the accumulated archive information to an archive file
+      void writeArchive();
+      void writeMember(const MemberInfo& member,std::ofstream& ARFile);
+      void writeSymbolTable(std::ofstream& ARFile);
+      void writeInteger(int num, std::ofstream& ARFile);
+
+    /// @}
+    /// @name  Data
+    /// @{
+    private:
+      friend class Archive;            ///< Parent class is a friend
+      sys::Path       fname;           ///< Path to the archive file
+      std::vector<MemberInfo> members; ///< Info about member files
+      Archive::SymTab* symtab;         ///< User's symbol table
+
+    /// @}
+  };
+}
+
+#endif
+
+// vim: sw=2 ai
diff --git a/lib/Bytecode/Archive/ArchiveWriter.cpp b/lib/Bytecode/Archive/ArchiveWriter.cpp
new file mode 100644 (file)
index 0000000..e3e2df4
--- /dev/null
@@ -0,0 +1,284 @@
+//===-- ArchiveWriter.cpp - LLVM archive writing --------------------------===//
+// 
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by Reid Spencerand is distributed under the 
+// University of Illinois Open Source License. See LICENSE.TXT for details.
+// 
+//===----------------------------------------------------------------------===//
+//
+// Builds up standard unix archive files (.a) containing LLVM bytecode.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchiveInternals.h"
+#include "llvm/Module.h"
+#include "llvm/Bytecode/Reader.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/System/MappedFile.h"
+#include <fstream>
+#include <iostream>
+
+using namespace llvm;
+
+Archive* 
+Archive::CreateEmpty(const sys::Path& Filename) {
+  Archive* result = new Archive;
+  Archive::ArchiveInternals* impl = result->impl = new Archive::ArchiveInternals;
+  impl->fname = Filename;
+  return result;
+}
+
+Archive*
+Archive::CreateFromFiles(
+  const sys::Path& Filename,
+  const PathList& Files,
+  const std::string& StripName
+) {
+  Archive* result = new Archive;
+  Archive::ArchiveInternals* impl = result->impl = new Archive::ArchiveInternals;
+  impl->fname = Filename;
+
+  try {
+    size_t strip_len = StripName.length();
+    for (PathList::const_iterator P = Files.begin(), E = Files.end(); P != E ;++P)
+    {
+      if (P->readable()) {
+        std::string name(P->get());
+        if (strip_len > 0 && StripName == name.substr(0,strip_len)) {
+          name.erase(0,strip_len);
+        }
+        if (P->isBytecodeFile()) {
+          std::vector<std::string> syms;
+          if (!GetBytecodeSymbols(*P, syms))
+            throw std::string("Can not get symbols from: ") + P->get();
+          impl->addFileMember(*P, name, &syms);
+        } else {
+          impl->addFileMember(*P, name);
+        }
+      }
+      else
+        throw std::string("Can not read: ") + P->get();
+    }
+
+    // Now that we've collected everything, write the archive
+    impl->writeArchive();
+
+  } catch(...) {
+    delete impl;
+    result->impl = 0;
+    delete result;
+    throw;
+  }
+
+  return result;
+}
+
+void
+Archive::ArchiveInternals::addFileMember(
+  const sys::Path& filePath,
+  const std::string& memberName,
+  const StrTab* symbols
+) {
+  MemberInfo info;
+  info.path = filePath;
+  info.name = memberName;
+  filePath.getStatusInfo(info.status);
+  if (symbols)
+    info.symbols = *symbols;
+  info.offset = 0;
+  members.push_back(info);
+}
+
+void
+Archive::ArchiveInternals::writeInteger(int num, std::ofstream& ARFile) {
+  char buff[4];
+  buff[0] = (num >> 24) & 255;
+  buff[1] = (num >> 16) & 255;
+  buff[2] = (num >> 8) & 255;
+  buff[3] = num & 255;
+  ARFile.write(buff, sizeof(buff));
+}
+
+void
+Archive::ArchiveInternals::writeSymbolTable( std::ofstream& ARFile ) {
+  // Compute the number of symbols in the symbol table and the
+  // total byte size of the string pool. While we're traversing,
+  // build the string pool for supporting long file names. Also,
+  // build the table of file offsets for the symbol table and 
+  // the 
+  typedef std::map<std::string,unsigned> SymbolMap;
+  StrTab stringPool;
+  SymbolMap symbolTable;
+  std::vector<unsigned> fileOffsets;
+  std::string symTabStrings;
+  unsigned fileOffset = 0;
+  unsigned spOffset = 0;
+  unsigned numSymbols = 0;
+  unsigned numSymBytes = 0;
+  for (unsigned i = 0; i < members.size(); i++ ) {
+    MemberInfo& mi = members[i];
+    StrTab& syms = mi.symbols;
+    size_t numSym = syms.size();
+    numSymbols += numSym;
+    for (unsigned j = 0; j < numSym; j++ ) {
+      numSymBytes += syms[j].size() + 1;
+      symbolTable[syms[i]] = i;
+    }
+    if (mi.name.length() > 15 || std::string::npos != mi.name.find('/')) {
+      stringPool.push_back(mi.name + "/\n");
+      mi.name = std::string("/") + utostr(spOffset);
+      spOffset += mi.name.length() + 2;
+    } else if (mi.name[mi.name.length()-1] != '/') {
+      mi.name += "/";
+    }
+    fileOffsets.push_back(fileOffset);
+    fileOffset += sizeof(ArchiveMemberHeader) + mi.status.fileSize;
+  }
+
+
+  // Compute the size of the symbol table file member
+  unsigned symTabSize = 0;
+  if (numSymbols != 0) 
+    symTabSize = 
+      sizeof(ArchiveMemberHeader) + // Size of the file header
+      4 +                           // Size of "number of entries"
+      (4 * numSymbols) +            // Size of member file indices
+      numSymBytes;                  // Size of the string table
+
+  // Compute the size of the string pool
+  unsigned strPoolSize = 0;
+  if (spOffset != 0 )
+    strPoolSize = 
+      sizeof(ArchiveMemberHeader) + // Size of the file header
+      spOffset;                     // Number of bytes in the string pool
+
+  // Compute the byte index offset created by symbol table and string pool
+  unsigned firstFileOffset = symTabSize + strPoolSize;
+
+  // Create header for symbol table. This must be first if there is
+  // a symbol table and must have a special name.
+  if ( symTabSize > 0 ) {
+    ArchiveMemberHeader Hdr;
+    Hdr.init();
+
+    // Name of symbol table is '/               ' but "" is passed in
+    // because the setName method always terminates with a /
+    Hdr.setName(ARFILE_SYMTAB_NAME);
+    Hdr.setDate();
+    Hdr.setSize(symTabSize - sizeof(ArchiveMemberHeader));
+    Hdr.setMode(0);
+    Hdr.setUid(0);
+    Hdr.setGid(0);
+    
+    // Write header to archive file
+    ARFile.write((char*)&Hdr, sizeof(Hdr));
+    
+    // Write the number of entries in the symbol table
+    this->writeInteger(numSymbols, ARFile);
+
+    // Write the file offset indices for each symbol and build the
+    // symbol table string pool
+    std::string symTabStrPool;
+    symTabStrPool.reserve(256 * 1024); // Reserve 256KBytes for symbols
+    for (SymbolMap::iterator I = symbolTable.begin(), E = symbolTable.end();
+         I != E; ++I ) {
+      this->writeInteger(firstFileOffset + fileOffsets[I->second], ARFile);
+      symTabStrPool += I->first;
+      symTabStrPool += "\0";
+    }
+
+    // Write the symbol table's string pool
+    ARFile.write(symTabStrPool.data(), symTabStrPool.size());
+  }
+
+  //============== DONE WITH SYMBOL TABLE 
+
+  if (strPoolSize > 0) {
+    // Initialize the header for the string pool
+    ArchiveMemberHeader Hdr;
+    Hdr.init();
+    Hdr.setName(ARFILE_STRTAB_NAME); 
+    Hdr.setDate();
+    Hdr.setSize(spOffset);
+    Hdr.setMode(0);
+    Hdr.setUid(0);
+    Hdr.setGid(0);
+
+    // Write the string pool header
+    ARFile.write((char*)&Hdr, sizeof(Hdr));
+
+    // Write the string pool
+    for (unsigned i = 0; i < stringPool.size(); i++) {
+      ARFile.write(stringPool[i].data(), stringPool[i].size());
+    }
+  }
+}
+
+void
+Archive::ArchiveInternals::writeMember(
+  const MemberInfo& member,
+  std::ofstream& ARFile
+) {
+
+  // Map the file into memory. We do this early for two reasons. First,
+  // if there's any kind of error, we want to know about it. Second, we
+  // want to ensure we're using the most recent size for this file.
+  sys::MappedFile mFile(member.path);
+  mFile.map();
+
+  // Header for the archive member
+  ArchiveMemberHeader Hdr;
+  Hdr.init();
+
+  // Set the name. If its longer than 15 chars, it will have already
+  // been reduced by the writeSymbolTable.
+  Hdr.setName(member.name);
+
+  // Set the other header members
+  Hdr.setSize( mFile.size() );
+  Hdr.setMode( member.status.mode);
+  Hdr.setUid ( member.status.user);
+  Hdr.setGid ( member.status.group);
+  Hdr.setDate( member.status.modTime.ToPosixTime() );
+
+  // Write header to archive file
+  ARFile.write((char*)&Hdr, sizeof(Hdr));
+  
+  //write to archive file
+  ARFile.write(mFile.charBase(),mFile.size());
+
+  mFile.unmap();
+}
+
+void
+Archive::ArchiveInternals::writeArchive() {
+  
+  // Create archive file for output.
+  std::ofstream ArchiveFile(fname.get().c_str());
+  
+  // Check for errors opening or creating archive file.
+  if ( !ArchiveFile.is_open() || ArchiveFile.bad() ) {
+    throw std::string("Error opening archive file: ") + fname.get();
+  }
+
+  // Write magic string to archive.
+  ArchiveFile << ARFILE_MAGIC;
+
+  // Write the symbol table and string pool
+  writeSymbolTable(ArchiveFile);
+
+  //Loop over all member files, and add to the archive.
+  for ( unsigned i = 0; i < members.size(); ++i) {
+    if(ArchiveFile.tellp() % 2 != 0)
+      ArchiveFile << ARFILE_PAD;
+    writeMember(members[i],ArchiveFile);
+  }
+
+  //Close archive file.
+  ArchiveFile.close();
+}
+
+// vim: sw=2 ai