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/StringRef.h"
18#include "llvm/Object/Binary.h"
19#include "llvm/Support/ErrorHandling.h"
20#include "llvm/Support/ErrorOr.h"
21#include "llvm/Support/FileSystem.h"
22#include "llvm/Support/MemoryBuffer.h"
23
24namespace llvm {
25namespace object {
26struct ArchiveMemberHeader {
27  char Name[16];
28  char LastModified[12];
29  char UID[6];
30  char GID[6];
31  char AccessMode[8];
32  char Size[10]; ///< Size of data, not including header or padding.
33  char Terminator[2];
34
35  /// Get the name without looking up long names.
36  llvm::StringRef getName() const;
37
38  /// Members are not larger than 4GB.
39  uint32_t getSize() const;
40
41  sys::fs::perms getAccessMode() const;
42  sys::TimeValue getLastModified() const;
43  unsigned getUID() const;
44  unsigned getGID() const;
45};
46
47class Archive : public Binary {
48  virtual void anchor();
49public:
50  class Child {
51    const Archive *Parent;
52    /// \brief Includes header but not padding byte.
53    StringRef Data;
54    /// \brief Offset from Data to the start of the file.
55    uint16_t StartOfFile;
56
57    const ArchiveMemberHeader *getHeader() const {
58      return reinterpret_cast<const ArchiveMemberHeader *>(Data.data());
59    }
60
61  public:
62    Child(const Archive *Parent, const char *Start);
63
64    bool operator ==(const Child &other) const {
65      assert(Parent == other.Parent);
66      return Data.begin() == other.Data.begin();
67    }
68
69    bool operator <(const Child &other) const {
70      return Data.begin() < other.Data.begin();
71    }
72
73    Child getNext() const;
74
75    ErrorOr<StringRef> getName() const;
76    StringRef getRawName() const { return getHeader()->getName(); }
77    sys::TimeValue getLastModified() const {
78      return getHeader()->getLastModified();
79    }
80    unsigned getUID() const { return getHeader()->getUID(); }
81    unsigned getGID() const { return getHeader()->getGID(); }
82    sys::fs::perms getAccessMode() const {
83      return getHeader()->getAccessMode();
84    }
85    /// \return the size of the archive member without the header or padding.
86    uint64_t getSize() const { return Data.size() - StartOfFile; }
87
88    StringRef getBuffer() const {
89      return StringRef(Data.data() + StartOfFile, getSize());
90    }
91
92    ErrorOr<std::unique_ptr<MemoryBuffer>>
93    getMemoryBuffer(bool FullPath = false) const;
94
95    ErrorOr<std::unique_ptr<Binary>>
96    getAsBinary(LLVMContext *Context = nullptr) const;
97  };
98
99  class child_iterator {
100    Child child;
101  public:
102    child_iterator() : child(Child(nullptr, nullptr)) {}
103    child_iterator(const Child &c) : child(c) {}
104    const Child* operator->() const {
105      return &child;
106    }
107
108    bool operator==(const child_iterator &other) const {
109      return child == other.child;
110    }
111
112    bool operator!=(const child_iterator &other) const {
113      return !(*this == other);
114    }
115
116    bool operator <(const child_iterator &other) const {
117      return child < other.child;
118    }
119
120    child_iterator& operator++() {  // Preincrement
121      child = child.getNext();
122      return *this;
123    }
124  };
125
126  class Symbol {
127    const Archive *Parent;
128    uint32_t SymbolIndex;
129    uint32_t StringIndex; // Extra index to the string.
130
131  public:
132    bool operator ==(const Symbol &other) const {
133      return (Parent == other.Parent) && (SymbolIndex == other.SymbolIndex);
134    }
135
136    Symbol(const Archive *p, uint32_t symi, uint32_t stri)
137      : Parent(p)
138      , SymbolIndex(symi)
139      , StringIndex(stri) {}
140    StringRef getName() const;
141    ErrorOr<child_iterator> getMember() const;
142    Symbol getNext() const;
143  };
144
145  class symbol_iterator {
146    Symbol symbol;
147  public:
148    symbol_iterator(const Symbol &s) : symbol(s) {}
149    const Symbol *operator->() const {
150      return &symbol;
151    }
152
153    bool operator==(const symbol_iterator &other) const {
154      return symbol == other.symbol;
155    }
156
157    bool operator!=(const symbol_iterator &other) const {
158      return !(*this == other);
159    }
160
161    symbol_iterator& operator++() {  // Preincrement
162      symbol = symbol.getNext();
163      return *this;
164    }
165  };
166
167  Archive(std::unique_ptr<MemoryBuffer> Source, std::error_code &EC);
168  static ErrorOr<Archive *> create(std::unique_ptr<MemoryBuffer> Source);
169
170  enum Kind {
171    K_GNU,
172    K_BSD,
173    K_COFF
174  };
175
176  Kind kind() const {
177    return Format;
178  }
179
180  child_iterator child_begin(bool SkipInternal = true) const;
181  child_iterator child_end() const;
182
183  symbol_iterator symbol_begin() const;
184  symbol_iterator symbol_end() const;
185
186  // Cast methods.
187  static inline bool classof(Binary const *v) {
188    return v->isArchive();
189  }
190
191  // check if a symbol is in the archive
192  child_iterator findSym(StringRef name) const;
193
194  bool hasSymbolTable() const;
195
196private:
197  child_iterator SymbolTable;
198  child_iterator StringTable;
199  child_iterator FirstRegular;
200  Kind Format;
201};
202
203}
204}
205
206#endif
207