]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/llvm/include/llvm/Object/Archive.h
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / llvm / include / llvm / Object / Archive.h
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