1 //===- Archive.h - ar archive file format -----------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file declares the ar archive file format class.
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_OBJECT_ARCHIVE_H
15 #define LLVM_OBJECT_ARCHIVE_H
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"
27 struct ArchiveMemberHeader {
29 char LastModified[12];
33 char Size[10]; ///< Size of data, not including header or padding.
36 ///! Get the name without looking up long names.
37 llvm::StringRef getName() const {
39 if (Name[0] == '/' || Name[0] == '#')
43 llvm::StringRef::size_type end =
44 llvm::StringRef(Name, sizeof(Name)).find(EndCond);
45 if (end == llvm::StringRef::npos)
47 assert(end <= sizeof(Name) && end > 0);
48 // Don't include the EndCond if there is one.
49 return llvm::StringRef(Name, end);
52 uint64_t getSize() const {
54 if (llvm::StringRef(Size, sizeof(Size)).rtrim(" ").getAsInteger(10, ret))
55 llvm_unreachable("Size is not an integer.");
60 static const ArchiveMemberHeader *ToHeader(const char *base) {
61 return reinterpret_cast<const ArchiveMemberHeader *>(base);
64 class Archive : public Binary {
65 virtual void anchor();
68 const Archive *Parent;
69 /// \brief Includes header but not padding byte.
71 /// \brief Offset from Data to the start of the file.
75 Child(const Archive *p, StringRef d) : Parent(p), Data(d) {
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/")) {
84 if (Name.substr(3).rtrim(" ").getAsInteger(10, NameSize))
85 llvm_unreachable("Long name length is not an integer");
86 StartOfFile += NameSize;
90 bool operator ==(const Child &other) const {
91 return (Parent == other.Parent) && (Data.begin() == other.Data.begin());
94 bool operator <(const Child &other) const {
95 return Data.begin() < other.Data.begin();
98 Child getNext() const {
99 size_t SpaceToSkip = Data.size();
100 // If it's odd, add 1 to make it even.
104 const char *NextLoc = Data.data() + SpaceToSkip;
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));
111 sizeof(ArchiveMemberHeader) + ToHeader(NextLoc)->getSize();
113 return Child(Parent, StringRef(NextLoc, NextSize));
116 error_code getName(StringRef &Result) const;
117 int getLastModified() 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; }
124 StringRef getBuffer() const {
125 return StringRef(Data.data() + StartOfFile, getSize());
128 error_code getMemoryBuffer(OwningPtr<MemoryBuffer> &Result,
129 bool FullPath = false) const {
131 if (error_code ec = getName(Name))
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();
140 error_code getAsBinary(OwningPtr<Binary> &Result) const;
143 class child_iterator {
146 child_iterator() : child(Child(0, StringRef())) {}
147 child_iterator(const Child &c) : child(c) {}
148 const Child* operator->() const {
152 bool operator==(const child_iterator &other) const {
153 return child == other.child;
156 bool operator!=(const child_iterator &other) const {
157 return !(*this == other);
160 bool operator <(const child_iterator &other) const {
161 return child < other.child;
164 child_iterator& operator++() { // Preincrement
165 child = child.getNext();
171 const Archive *Parent;
172 uint32_t SymbolIndex;
173 uint32_t StringIndex; // Extra index to the string.
176 bool operator ==(const Symbol &other) const {
177 return (Parent == other.Parent) && (SymbolIndex == other.SymbolIndex);
180 Symbol(const Archive *p, uint32_t symi, uint32_t stri)
183 , StringIndex(stri) {}
184 error_code getName(StringRef &Result) const;
185 error_code getMember(child_iterator &Result) const;
186 Symbol getNext() const;
189 class symbol_iterator {
192 symbol_iterator(const Symbol &s) : symbol(s) {}
193 const Symbol *operator->() const {
197 bool operator==(const symbol_iterator &other) const {
198 return symbol == other.symbol;
201 bool operator!=(const symbol_iterator &other) const {
202 return !(*this == other);
205 symbol_iterator& operator++() { // Preincrement
206 symbol = symbol.getNext();
211 Archive(MemoryBuffer *source, error_code &ec);
223 child_iterator begin_children(bool skip_internal = true) const;
224 child_iterator end_children() const;
226 symbol_iterator begin_symbols() const;
227 symbol_iterator end_symbols() const;
230 static inline bool classof(Binary const *v) {
231 return v->isArchive();
234 // check if a symbol is in the archive
235 child_iterator findSym(StringRef name) const;
238 child_iterator SymbolTable;
239 child_iterator StringTable;