LLVM API Documentation

Object/Archive.h
Go to the documentation of this file.
00001 //===- Archive.h - ar archive file format -----------------------*- C++ -*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file declares the ar archive file format class.
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #ifndef LLVM_OBJECT_ARCHIVE_H
00015 #define LLVM_OBJECT_ARCHIVE_H
00016 
00017 #include "llvm/ADT/SmallString.h"
00018 #include "llvm/ADT/StringRef.h"
00019 #include "llvm/ADT/Twine.h"
00020 #include "llvm/Object/Binary.h"
00021 #include "llvm/Support/DataTypes.h"
00022 #include "llvm/Support/ErrorHandling.h"
00023 #include "llvm/Support/MemoryBuffer.h"
00024 
00025 namespace llvm {
00026 namespace object {
00027 struct ArchiveMemberHeader {
00028   char Name[16];
00029   char LastModified[12];
00030   char UID[6];
00031   char GID[6];
00032   char AccessMode[8];
00033   char Size[10]; ///< Size of data, not including header or padding.
00034   char Terminator[2];
00035 
00036   ///! Get the name without looking up long names.
00037   llvm::StringRef getName() const {
00038     char EndCond;
00039     if (Name[0] == '/' || Name[0] == '#')
00040       EndCond = ' ';
00041     else
00042       EndCond = '/';
00043     llvm::StringRef::size_type end =
00044         llvm::StringRef(Name, sizeof(Name)).find(EndCond);
00045     if (end == llvm::StringRef::npos)
00046       end = sizeof(Name);
00047     assert(end <= sizeof(Name) && end > 0);
00048     // Don't include the EndCond if there is one.
00049     return llvm::StringRef(Name, end);
00050   }
00051 
00052   uint64_t getSize() const {
00053     uint64_t ret;
00054     if (llvm::StringRef(Size, sizeof(Size)).rtrim(" ").getAsInteger(10, ret))
00055       llvm_unreachable("Size is not an integer.");
00056     return ret;
00057   }
00058 };
00059 
00060 static const ArchiveMemberHeader *ToHeader(const char *base) {
00061   return reinterpret_cast<const ArchiveMemberHeader *>(base);
00062 }
00063 
00064 class Archive : public Binary {
00065   virtual void anchor();
00066 public:
00067   class Child {
00068     const Archive *Parent;
00069     /// \brief Includes header but not padding byte.
00070     StringRef Data;
00071     /// \brief Offset from Data to the start of the file.
00072     uint16_t StartOfFile;
00073 
00074   public:
00075     Child(const Archive *p, StringRef d) : Parent(p), Data(d) {
00076       if (!p || d.empty())
00077         return;
00078       // Setup StartOfFile and PaddingBytes.
00079       StartOfFile = sizeof(ArchiveMemberHeader);
00080       // Don't include attached name.
00081       StringRef Name = ToHeader(Data.data())->getName();
00082       if (Name.startswith("#1/")) {
00083         uint64_t NameSize;
00084         if (Name.substr(3).rtrim(" ").getAsInteger(10, NameSize))
00085           llvm_unreachable("Long name length is not an integer");
00086         StartOfFile += NameSize;
00087       }
00088     }
00089 
00090     bool operator ==(const Child &other) const {
00091       return (Parent == other.Parent) && (Data.begin() == other.Data.begin());
00092     }
00093 
00094     bool operator <(const Child &other) const {
00095       return Data.begin() < other.Data.begin();
00096     }
00097 
00098     Child getNext() const {
00099       size_t SpaceToSkip = Data.size();
00100       // If it's odd, add 1 to make it even.
00101       if (SpaceToSkip & 1)
00102         ++SpaceToSkip;
00103 
00104       const char *NextLoc = Data.data() + SpaceToSkip;
00105 
00106       // Check to see if this is past the end of the archive.
00107       if (NextLoc >= Parent->Data->getBufferEnd())
00108         return Child(Parent, StringRef(0, 0));
00109 
00110       size_t NextSize =
00111           sizeof(ArchiveMemberHeader) + ToHeader(NextLoc)->getSize();
00112 
00113       return Child(Parent, StringRef(NextLoc, NextSize));
00114     }
00115 
00116     error_code getName(StringRef &Result) const;
00117     int getLastModified() const;
00118     int getUID() const;
00119     int getGID() const;
00120     int getAccessMode() const;
00121     /// \return the size of the archive member without the header or padding.
00122     uint64_t getSize() const { return Data.size() - StartOfFile; }
00123 
00124     StringRef getBuffer() const {
00125       return StringRef(Data.data() + StartOfFile, getSize());
00126     }
00127 
00128     error_code getMemoryBuffer(OwningPtr<MemoryBuffer> &Result,
00129                                bool FullPath = false) const {
00130       StringRef Name;
00131       if (error_code ec = getName(Name))
00132         return ec;
00133       SmallString<128> Path;
00134       Result.reset(MemoryBuffer::getMemBuffer(
00135           getBuffer(), FullPath ? (Twine(Parent->getFileName()) + "(" + Name +
00136                                    ")").toStringRef(Path) : Name, false));
00137       return error_code::success();
00138     }
00139 
00140     error_code getAsBinary(OwningPtr<Binary> &Result) const;
00141   };
00142 
00143   class child_iterator {
00144     Child child;
00145   public:
00146     child_iterator() : child(Child(0, StringRef())) {}
00147     child_iterator(const Child &c) : child(c) {}
00148     const Child* operator->() const {
00149       return &child;
00150     }
00151 
00152     bool operator==(const child_iterator &other) const {
00153       return child == other.child;
00154     }
00155 
00156     bool operator!=(const child_iterator &other) const {
00157       return !(*this == other);
00158     }
00159 
00160     bool operator <(const child_iterator &other) const {
00161       return child < other.child;
00162     }
00163 
00164     child_iterator& operator++() {  // Preincrement
00165       child = child.getNext();
00166       return *this;
00167     }
00168   };
00169 
00170   class Symbol {
00171     const Archive *Parent;
00172     uint32_t SymbolIndex;
00173     uint32_t StringIndex; // Extra index to the string.
00174 
00175   public:
00176     bool operator ==(const Symbol &other) const {
00177       return (Parent == other.Parent) && (SymbolIndex == other.SymbolIndex);
00178     }
00179 
00180     Symbol(const Archive *p, uint32_t symi, uint32_t stri)
00181       : Parent(p)
00182       , SymbolIndex(symi)
00183       , StringIndex(stri) {}
00184     error_code getName(StringRef &Result) const;
00185     error_code getMember(child_iterator &Result) const;
00186     Symbol getNext() const;
00187   };
00188 
00189   class symbol_iterator {
00190     Symbol symbol;
00191   public:
00192     symbol_iterator(const Symbol &s) : symbol(s) {}
00193     const Symbol *operator->() const {
00194       return &symbol;
00195     }
00196 
00197     bool operator==(const symbol_iterator &other) const {
00198       return symbol == other.symbol;
00199     }
00200 
00201     bool operator!=(const symbol_iterator &other) const {
00202       return !(*this == other);
00203     }
00204 
00205     symbol_iterator& operator++() {  // Preincrement
00206       symbol = symbol.getNext();
00207       return *this;
00208     }
00209   };
00210 
00211   Archive(MemoryBuffer *source, error_code &ec);
00212 
00213   enum Kind {
00214     K_GNU,
00215     K_BSD,
00216     K_COFF
00217   };
00218 
00219   Kind kind() const { 
00220     return Format;
00221   }
00222 
00223   child_iterator begin_children(bool skip_internal = true) const;
00224   child_iterator end_children() const;
00225 
00226   symbol_iterator begin_symbols() const;
00227   symbol_iterator end_symbols() const;
00228 
00229   // Cast methods.
00230   static inline bool classof(Binary const *v) {
00231     return v->isArchive();
00232   }
00233 
00234   // check if a symbol is in the archive
00235   child_iterator findSym(StringRef name) const;
00236 
00237 private:
00238   child_iterator SymbolTable;
00239   child_iterator StringTable;
00240   Kind Format;
00241 };
00242 
00243 }
00244 }
00245 
00246 #endif