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 StringRef getRawName() const { return ToHeader(Data.data())->getName(); }
118 int getLastModified() const;
121 int getAccessMode() const;
122 /// \return the size of the archive member without the header or padding.
123 uint64_t getSize() const { return Data.size() - StartOfFile; }
125 StringRef getBuffer() const {
126 return StringRef(Data.data() + StartOfFile, getSize());
129 error_code getMemoryBuffer(OwningPtr<MemoryBuffer> &Result,
130 bool FullPath = false) const {
132 if (error_code ec = getName(Name))
134 SmallString<128> Path;
135 Result.reset(MemoryBuffer::getMemBuffer(
136 getBuffer(), FullPath ? (Twine(Parent->getFileName()) + "(" + Name +
137 ")").toStringRef(Path) : Name, false));
138 return error_code::success();
141 error_code getAsBinary(OwningPtr<Binary> &Result) const;
144 class child_iterator {
147 child_iterator() : child(Child(0, StringRef())) {}
148 child_iterator(const Child &c) : child(c) {}
149 const Child* operator->() const {
153 bool operator==(const child_iterator &other) const {
154 return child == other.child;
157 bool operator!=(const child_iterator &other) const {
158 return !(*this == other);
161 bool operator <(const child_iterator &other) const {
162 return child < other.child;
165 child_iterator& operator++() { // Preincrement
166 child = child.getNext();
172 const Archive *Parent;
173 uint32_t SymbolIndex;
174 uint32_t StringIndex; // Extra index to the string.
177 bool operator ==(const Symbol &other) const {
178 return (Parent == other.Parent) && (SymbolIndex == other.SymbolIndex);
181 Symbol(const Archive *p, uint32_t symi, uint32_t stri)
184 , StringIndex(stri) {}
185 error_code getName(StringRef &Result) const;
186 error_code getMember(child_iterator &Result) const;
187 Symbol getNext() const;
190 class symbol_iterator {
193 symbol_iterator(const Symbol &s) : symbol(s) {}
194 const Symbol *operator->() const {
198 bool operator==(const symbol_iterator &other) const {
199 return symbol == other.symbol;
202 bool operator!=(const symbol_iterator &other) const {
203 return !(*this == other);
206 symbol_iterator& operator++() { // Preincrement
207 symbol = symbol.getNext();
212 Archive(MemoryBuffer *source, error_code &ec);
224 child_iterator begin_children(bool skip_internal = true) const;
225 child_iterator end_children() const;
227 symbol_iterator begin_symbols() const;
228 symbol_iterator end_symbols() const;
231 static inline bool classof(Binary const *v) {
232 return v->isArchive();
235 // check if a symbol is in the archive
236 child_iterator findSym(StringRef name) const;
239 child_iterator SymbolTable;
240 child_iterator StringTable;