1 //===- Archive.h - ar archive file format -----------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file declares the ar archive file format class.
11 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_OBJECT_ARCHIVE_H
14 #define LLVM_OBJECT_ARCHIVE_H
16 #include "llvm/ADT/Optional.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/ADT/fallible_iterator.h"
19 #include "llvm/ADT/iterator_range.h"
20 #include "llvm/Object/Binary.h"
21 #include "llvm/Support/Chrono.h"
22 #include "llvm/Support/Error.h"
23 #include "llvm/Support/FileSystem.h"
24 #include "llvm/Support/MemoryBuffer.h"
37 class ArchiveMemberHeader
{
41 ArchiveMemberHeader(Archive
const *Parent
, const char *RawHeaderPtr
,
42 uint64_t Size
, Error
*Err
);
43 // ArchiveMemberHeader() = default;
45 /// Get the name without looking up long names.
46 Expected
<StringRef
> getRawName() const;
48 /// Get the name looking up long names.
49 Expected
<StringRef
> getName(uint64_t Size
) const;
51 Expected
<uint64_t> getSize() const;
53 Expected
<sys::fs::perms
> getAccessMode() const;
54 Expected
<sys::TimePoint
<std::chrono::seconds
>> getLastModified() const;
56 StringRef
getRawLastModified() const {
57 return StringRef(ArMemHdr
->LastModified
,
58 sizeof(ArMemHdr
->LastModified
)).rtrim(' ');
61 Expected
<unsigned> getUID() const;
62 Expected
<unsigned> getGID() const;
64 // This returns the size of the private struct ArMemHdrType
65 uint64_t getSizeOf() const {
66 return sizeof(ArMemHdrType
);
72 char LastModified
[12];
76 char Size
[10]; ///< Size of data, not including header or padding.
79 Archive
const *Parent
;
80 ArMemHdrType
const *ArMemHdr
;
83 class Archive
: public Binary
{
84 virtual void anchor();
89 friend ArchiveMemberHeader
;
91 const Archive
*Parent
;
92 ArchiveMemberHeader Header
;
93 /// Includes header but not padding byte.
95 /// Offset from Data to the start of the file.
98 Expected
<bool> isThinMember() const;
101 Child(const Archive
*Parent
, const char *Start
, Error
*Err
);
102 Child(const Archive
*Parent
, StringRef Data
, uint16_t StartOfFile
);
104 bool operator ==(const Child
&other
) const {
105 assert(!Parent
|| !other
.Parent
|| Parent
== other
.Parent
);
106 return Data
.begin() == other
.Data
.begin();
109 const Archive
*getParent() const { return Parent
; }
110 Expected
<Child
> getNext() const;
112 Expected
<StringRef
> getName() const;
113 Expected
<std::string
> getFullName() const;
114 Expected
<StringRef
> getRawName() const { return Header
.getRawName(); }
116 Expected
<sys::TimePoint
<std::chrono::seconds
>> getLastModified() const {
117 return Header
.getLastModified();
120 StringRef
getRawLastModified() const {
121 return Header
.getRawLastModified();
124 Expected
<unsigned> getUID() const { return Header
.getUID(); }
125 Expected
<unsigned> getGID() const { return Header
.getGID(); }
127 Expected
<sys::fs::perms
> getAccessMode() const {
128 return Header
.getAccessMode();
131 /// \return the size of the archive member without the header or padding.
132 Expected
<uint64_t> getSize() const;
133 /// \return the size in the archive header for this member.
134 Expected
<uint64_t> getRawSize() const;
136 Expected
<StringRef
> getBuffer() const;
137 uint64_t getChildOffset() const;
139 Expected
<MemoryBufferRef
> getMemoryBufferRef() const;
141 Expected
<std::unique_ptr
<Binary
>>
142 getAsBinary(LLVMContext
*Context
= nullptr) const;
145 class ChildFallibleIterator
{
149 ChildFallibleIterator() : C(Child(nullptr, nullptr, nullptr)) {}
150 ChildFallibleIterator(const Child
&C
) : C(C
) {}
152 const Child
*operator->() const { return &C
; }
153 const Child
&operator*() const { return C
; }
155 bool operator==(const ChildFallibleIterator
&other
) const {
156 // Ignore errors here: If an error occurred during increment then getNext
157 // will have been set to child_end(), and the following comparison should
158 // do the right thing.
162 bool operator!=(const ChildFallibleIterator
&other
) const {
163 return !(*this == other
);
167 auto NextChild
= C
.getNext();
169 return NextChild
.takeError();
170 C
= std::move(*NextChild
);
171 return Error::success();
175 using child_iterator
= fallible_iterator
<ChildFallibleIterator
>;
178 const Archive
*Parent
;
179 uint32_t SymbolIndex
;
180 uint32_t StringIndex
; // Extra index to the string.
183 Symbol(const Archive
*p
, uint32_t symi
, uint32_t stri
)
186 , StringIndex(stri
) {}
188 bool operator ==(const Symbol
&other
) const {
189 return (Parent
== other
.Parent
) && (SymbolIndex
== other
.SymbolIndex
);
192 StringRef
getName() const;
193 Expected
<Child
> getMember() const;
194 Symbol
getNext() const;
197 class symbol_iterator
{
201 symbol_iterator(const Symbol
&s
) : symbol(s
) {}
203 const Symbol
*operator->() const { return &symbol
; }
204 const Symbol
&operator*() const { return symbol
; }
206 bool operator==(const symbol_iterator
&other
) const {
207 return symbol
== other
.symbol
;
210 bool operator!=(const symbol_iterator
&other
) const {
211 return !(*this == other
);
214 symbol_iterator
& operator++() { // Preincrement
215 symbol
= symbol
.getNext();
220 Archive(MemoryBufferRef Source
, Error
&Err
);
221 static Expected
<std::unique_ptr
<Archive
>> create(MemoryBufferRef Source
);
223 /// Size field is 10 decimal digits long
224 static const uint64_t MaxMemberSize
= 9999999999;
235 Kind
kind() const { return (Kind
)Format
; }
236 bool isThin() const { return IsThin
; }
238 child_iterator
child_begin(Error
&Err
, bool SkipInternal
= true) const;
239 child_iterator
child_end() const;
240 iterator_range
<child_iterator
> children(Error
&Err
,
241 bool SkipInternal
= true) const {
242 return make_range(child_begin(Err
, SkipInternal
), child_end());
245 symbol_iterator
symbol_begin() const;
246 symbol_iterator
symbol_end() const;
247 iterator_range
<symbol_iterator
> symbols() const {
248 return make_range(symbol_begin(), symbol_end());
252 static bool classof(Binary
const *v
) {
253 return v
->isArchive();
256 // check if a symbol is in the archive
257 Expected
<Optional
<Child
>> findSym(StringRef name
) const;
259 bool isEmpty() const;
260 bool hasSymbolTable() const;
261 StringRef
getSymbolTable() const { return SymbolTable
; }
262 StringRef
getStringTable() const { return StringTable
; }
263 uint32_t getNumberOfSymbols() const;
265 std::vector
<std::unique_ptr
<MemoryBuffer
>> takeThinBuffers() {
266 return std::move(ThinBuffers
);
270 StringRef SymbolTable
;
271 StringRef StringTable
;
273 StringRef FirstRegularData
;
274 uint16_t FirstRegularStartOfFile
= -1;
275 void setFirstRegular(const Child
&C
);
279 mutable std::vector
<std::unique_ptr
<MemoryBuffer
>> ThinBuffers
;
282 } // end namespace object
283 } // end namespace llvm
285 #endif // LLVM_OBJECT_ARCHIVE_H