Home | History | Annotate | Download | only in Object
      1 //===- Archive.h - ar archive file format -----------------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file declares the ar archive file format class.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #ifndef LLVM_OBJECT_ARCHIVE_H
     15 #define LLVM_OBJECT_ARCHIVE_H
     16 
     17 #include "llvm/ADT/SmallString.h"
     18 #include "llvm/ADT/StringRef.h"
     19 #include "llvm/ADT/Twine.h"
     20 #include "llvm/Object/Binary.h"
     21 #include "llvm/Support/DataTypes.h"
     22 #include "llvm/Support/ErrorHandling.h"
     23 #include "llvm/Support/MemoryBuffer.h"
     24 
     25 namespace llvm {
     26 namespace object {
     27 struct ArchiveMemberHeader {
     28   char Name[16];
     29   char LastModified[12];
     30   char UID[6];
     31   char GID[6];
     32   char AccessMode[8];
     33   char Size[10]; ///< Size of data, not including header or padding.
     34   char Terminator[2];
     35 
     36   ///! Get the name without looking up long names.
     37   llvm::StringRef getName() const {
     38     char EndCond;
     39     if (Name[0] == '/' || Name[0] == '#')
     40       EndCond = ' ';
     41     else
     42       EndCond = '/';
     43     llvm::StringRef::size_type end =
     44         llvm::StringRef(Name, sizeof(Name)).find(EndCond);
     45     if (end == llvm::StringRef::npos)
     46       end = sizeof(Name);
     47     assert(end <= sizeof(Name) && end > 0);
     48     // Don't include the EndCond if there is one.
     49     return llvm::StringRef(Name, end);
     50   }
     51 
     52   uint64_t getSize() const {
     53     uint64_t ret;
     54     if (llvm::StringRef(Size, sizeof(Size)).rtrim(" ").getAsInteger(10, ret))
     55       llvm_unreachable("Size is not an integer.");
     56     return ret;
     57   }
     58 };
     59 
     60 static const ArchiveMemberHeader *ToHeader(const char *base) {
     61   return reinterpret_cast<const ArchiveMemberHeader *>(base);
     62 }
     63 
     64 class Archive : public Binary {
     65   virtual void anchor();
     66 public:
     67   class Child {
     68     const Archive *Parent;
     69     /// \brief Includes header but not padding byte.
     70     StringRef Data;
     71     /// \brief Offset from Data to the start of the file.
     72     uint16_t StartOfFile;
     73 
     74   public:
     75     Child(const Archive *p, StringRef d) : Parent(p), Data(d) {
     76       if (!p || d.empty())
     77         return;
     78       // Setup StartOfFile and PaddingBytes.
     79       StartOfFile = sizeof(ArchiveMemberHeader);
     80       // Don't include attached name.
     81       StringRef Name = ToHeader(Data.data())->getName();
     82       if (Name.startswith("#1/")) {
     83         uint64_t NameSize;
     84         if (Name.substr(3).rtrim(" ").getAsInteger(10, NameSize))
     85           llvm_unreachable("Long name length is not an integer");
     86         StartOfFile += NameSize;
     87       }
     88     }
     89 
     90     bool operator ==(const Child &other) const {
     91       return (Parent == other.Parent) && (Data.begin() == other.Data.begin());
     92     }
     93 
     94     bool operator <(const Child &other) const {
     95       return Data.begin() < other.Data.begin();
     96     }
     97 
     98     Child getNext() const {
     99       size_t SpaceToSkip = Data.size();
    100       // If it's odd, add 1 to make it even.
    101       if (SpaceToSkip & 1)
    102         ++SpaceToSkip;
    103 
    104       const char *NextLoc = Data.data() + SpaceToSkip;
    105 
    106       // Check to see if this is past the end of the archive.
    107       if (NextLoc >= Parent->Data->getBufferEnd())
    108         return Child(Parent, StringRef(0, 0));
    109 
    110       size_t NextSize =
    111           sizeof(ArchiveMemberHeader) + ToHeader(NextLoc)->getSize();
    112 
    113       return Child(Parent, StringRef(NextLoc, NextSize));
    114     }
    115 
    116     error_code getName(StringRef &Result) const;
    117     int getLastModified() const;
    118     int getUID() const;
    119     int getGID() const;
    120     int getAccessMode() const;
    121     /// \return the size of the archive member without the header or padding.
    122     uint64_t getSize() const { return Data.size() - StartOfFile; }
    123 
    124     StringRef getBuffer() const {
    125       return StringRef(Data.data() + StartOfFile, getSize());
    126     }
    127 
    128     error_code getMemoryBuffer(OwningPtr<MemoryBuffer> &Result,
    129                                bool FullPath = false) const {
    130       StringRef Name;
    131       if (error_code ec = getName(Name))
    132         return ec;
    133       SmallString<128> Path;
    134       Result.reset(MemoryBuffer::getMemBuffer(
    135           getBuffer(), FullPath ? (Twine(Parent->getFileName()) + "(" + Name +
    136                                    ")").toStringRef(Path) : Name, false));
    137       return error_code::success();
    138     }
    139 
    140     error_code getAsBinary(OwningPtr<Binary> &Result) const;
    141   };
    142 
    143   class child_iterator {
    144     Child child;
    145   public:
    146     child_iterator() : child(Child(0, StringRef())) {}
    147     child_iterator(const Child &c) : child(c) {}
    148     const Child* operator->() const {
    149       return &child;
    150     }
    151 
    152     bool operator==(const child_iterator &other) const {
    153       return child == other.child;
    154     }
    155 
    156     bool operator!=(const child_iterator &other) const {
    157       return !(*this == other);
    158     }
    159 
    160     bool operator <(const child_iterator &other) const {
    161       return child < other.child;
    162     }
    163 
    164     child_iterator& operator++() {  // Preincrement
    165       child = child.getNext();
    166       return *this;
    167     }
    168   };
    169 
    170   class Symbol {
    171     const Archive *Parent;
    172     uint32_t SymbolIndex;
    173     uint32_t StringIndex; // Extra index to the string.
    174 
    175   public:
    176     bool operator ==(const Symbol &other) const {
    177       return (Parent == other.Parent) && (SymbolIndex == other.SymbolIndex);
    178     }
    179 
    180     Symbol(const Archive *p, uint32_t symi, uint32_t stri)
    181       : Parent(p)
    182       , SymbolIndex(symi)
    183       , StringIndex(stri) {}
    184     error_code getName(StringRef &Result) const;
    185     error_code getMember(child_iterator &Result) const;
    186     Symbol getNext() const;
    187   };
    188 
    189   class symbol_iterator {
    190     Symbol symbol;
    191   public:
    192     symbol_iterator(const Symbol &s) : symbol(s) {}
    193     const Symbol *operator->() const {
    194       return &symbol;
    195     }
    196 
    197     bool operator==(const symbol_iterator &other) const {
    198       return symbol == other.symbol;
    199     }
    200 
    201     bool operator!=(const symbol_iterator &other) const {
    202       return !(*this == other);
    203     }
    204 
    205     symbol_iterator& operator++() {  // Preincrement
    206       symbol = symbol.getNext();
    207       return *this;
    208     }
    209   };
    210 
    211   Archive(MemoryBuffer *source, error_code &ec);
    212 
    213   enum Kind {
    214     K_GNU,
    215     K_BSD,
    216     K_COFF
    217   };
    218 
    219   Kind kind() const {
    220     return Format;
    221   }
    222 
    223   child_iterator begin_children(bool skip_internal = true) const;
    224   child_iterator end_children() const;
    225 
    226   symbol_iterator begin_symbols() const;
    227   symbol_iterator end_symbols() const;
    228 
    229   // Cast methods.
    230   static inline bool classof(Binary const *v) {
    231     return v->isArchive();
    232   }
    233 
    234   // check if a symbol is in the archive
    235   child_iterator findSym(StringRef name) const;
    236 
    237 private:
    238   child_iterator SymbolTable;
    239   child_iterator StringTable;
    240   Kind Format;
    241 };
    242 
    243 }
    244 }
    245 
    246 #endif
    247