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 /// Members are not larger than 4GB.
52 Expected
<uint32_t> getSize() const;
54 Expected
<sys::fs::perms
> getAccessMode() const;
55 Expected
<sys::TimePoint
<std::chrono::seconds
>> getLastModified() const;
57 StringRef
getRawLastModified() const {
58 return StringRef(ArMemHdr
->LastModified
,
59 sizeof(ArMemHdr
->LastModified
)).rtrim(' ');
62 Expected
<unsigned> getUID() const;
63 Expected
<unsigned> getGID() const;
65 // This returns the size of the private struct ArMemHdrType
66 uint64_t getSizeOf() const {
67 return sizeof(ArMemHdrType
);
73 char LastModified
[12];
77 char Size
[10]; ///< Size of data, not including header or padding.
80 Archive
const *Parent
;
81 ArMemHdrType
const *ArMemHdr
;
84 class Archive
: public Binary
{
85 virtual void anchor();
90 friend ArchiveMemberHeader
;
92 const Archive
*Parent
;
93 ArchiveMemberHeader Header
;
94 /// Includes header but not padding byte.
96 /// Offset from Data to the start of the file.
99 Expected
<bool> isThinMember() const;
102 Child(const Archive
*Parent
, const char *Start
, Error
*Err
);
103 Child(const Archive
*Parent
, StringRef Data
, uint16_t StartOfFile
);
105 bool operator ==(const Child
&other
) const {
106 assert(!Parent
|| !other
.Parent
|| Parent
== other
.Parent
);
107 return Data
.begin() == other
.Data
.begin();
110 const Archive
*getParent() const { return Parent
; }
111 Expected
<Child
> getNext() const;
113 Expected
<StringRef
> getName() const;
114 Expected
<std::string
> getFullName() const;
115 Expected
<StringRef
> getRawName() const { return Header
.getRawName(); }
117 Expected
<sys::TimePoint
<std::chrono::seconds
>> getLastModified() const {
118 return Header
.getLastModified();
121 StringRef
getRawLastModified() const {
122 return Header
.getRawLastModified();
125 Expected
<unsigned> getUID() const { return Header
.getUID(); }
126 Expected
<unsigned> getGID() const { return Header
.getGID(); }
128 Expected
<sys::fs::perms
> getAccessMode() const {
129 return Header
.getAccessMode();
132 /// \return the size of the archive member without the header or padding.
133 Expected
<uint64_t> getSize() const;
134 /// \return the size in the archive header for this member.
135 Expected
<uint64_t> getRawSize() const;
137 Expected
<StringRef
> getBuffer() const;
138 uint64_t getChildOffset() const;
140 Expected
<MemoryBufferRef
> getMemoryBufferRef() const;
142 Expected
<std::unique_ptr
<Binary
>>
143 getAsBinary(LLVMContext
*Context
= nullptr) const;
146 class ChildFallibleIterator
{
150 ChildFallibleIterator() : C(Child(nullptr, nullptr, nullptr)) {}
151 ChildFallibleIterator(const Child
&C
) : C(C
) {}
153 const Child
*operator->() const { return &C
; }
154 const Child
&operator*() const { return C
; }
156 bool operator==(const ChildFallibleIterator
&other
) const {
157 // Ignore errors here: If an error occurred during increment then getNext
158 // will have been set to child_end(), and the following comparison should
159 // do the right thing.
163 bool operator!=(const ChildFallibleIterator
&other
) const {
164 return !(*this == other
);
168 auto NextChild
= C
.getNext();
170 return NextChild
.takeError();
171 C
= std::move(*NextChild
);
172 return Error::success();
176 using child_iterator
= fallible_iterator
<ChildFallibleIterator
>;
179 const Archive
*Parent
;
180 uint32_t SymbolIndex
;
181 uint32_t StringIndex
; // Extra index to the string.
184 Symbol(const Archive
*p
, uint32_t symi
, uint32_t stri
)
187 , StringIndex(stri
) {}
189 bool operator ==(const Symbol
&other
) const {
190 return (Parent
== other
.Parent
) && (SymbolIndex
== other
.SymbolIndex
);
193 StringRef
getName() const;
194 Expected
<Child
> getMember() const;
195 Symbol
getNext() const;
198 class symbol_iterator
{
202 symbol_iterator(const Symbol
&s
) : symbol(s
) {}
204 const Symbol
*operator->() const { return &symbol
; }
205 const Symbol
&operator*() const { return symbol
; }
207 bool operator==(const symbol_iterator
&other
) const {
208 return symbol
== other
.symbol
;
211 bool operator!=(const symbol_iterator
&other
) const {
212 return !(*this == other
);
215 symbol_iterator
& operator++() { // Preincrement
216 symbol
= symbol
.getNext();
221 Archive(MemoryBufferRef Source
, Error
&Err
);
222 static Expected
<std::unique_ptr
<Archive
>> create(MemoryBufferRef Source
);
233 Kind
kind() const { return (Kind
)Format
; }
234 bool isThin() const { return IsThin
; }
236 child_iterator
child_begin(Error
&Err
, bool SkipInternal
= true) const;
237 child_iterator
child_end() const;
238 iterator_range
<child_iterator
> children(Error
&Err
,
239 bool SkipInternal
= true) const {
240 return make_range(child_begin(Err
, SkipInternal
), child_end());
243 symbol_iterator
symbol_begin() const;
244 symbol_iterator
symbol_end() const;
245 iterator_range
<symbol_iterator
> symbols() const {
246 return make_range(symbol_begin(), symbol_end());
250 static bool classof(Binary
const *v
) {
251 return v
->isArchive();
254 // check if a symbol is in the archive
255 Expected
<Optional
<Child
>> findSym(StringRef name
) const;
257 bool isEmpty() const;
258 bool hasSymbolTable() const;
259 StringRef
getSymbolTable() const { return SymbolTable
; }
260 StringRef
getStringTable() const { return StringTable
; }
261 uint32_t getNumberOfSymbols() const;
263 std::vector
<std::unique_ptr
<MemoryBuffer
>> takeThinBuffers() {
264 return std::move(ThinBuffers
);
268 StringRef SymbolTable
;
269 StringRef StringTable
;
271 StringRef FirstRegularData
;
272 uint16_t FirstRegularStartOfFile
= -1;
273 void setFirstRegular(const Child
&C
);
277 mutable std::vector
<std::unique_ptr
<MemoryBuffer
>> ThinBuffers
;
280 } // end namespace object
281 } // end namespace llvm
283 #endif // LLVM_OBJECT_ARCHIVE_H