1 //===- BinaryStreamReader.cpp - Reads objects from a binary stream --------===//
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 #include "llvm/Support/BinaryStreamReader.h"
11 #include "llvm/Support/BinaryStreamError.h"
12 #include "llvm/Support/BinaryStreamRef.h"
13 #include "llvm/Support/LEB128.h"
17 BinaryStreamReader::BinaryStreamReader(BinaryStreamRef Ref
) : Stream(Ref
) {}
19 BinaryStreamReader::BinaryStreamReader(BinaryStream
&Stream
) : Stream(Stream
) {}
21 BinaryStreamReader::BinaryStreamReader(ArrayRef
<uint8_t> Data
,
23 : Stream(Data
, Endian
) {}
25 BinaryStreamReader::BinaryStreamReader(StringRef Data
, endianness Endian
)
26 : Stream(Data
, Endian
) {}
28 Error
BinaryStreamReader::readLongestContiguousChunk(
29 ArrayRef
<uint8_t> &Buffer
) {
30 if (auto EC
= Stream
.readLongestContiguousChunk(Offset
, Buffer
))
32 Offset
+= Buffer
.size();
33 return Error::success();
36 Error
BinaryStreamReader::readBytes(ArrayRef
<uint8_t> &Buffer
, uint32_t Size
) {
37 if (auto EC
= Stream
.readBytes(Offset
, Size
, Buffer
))
40 return Error::success();
43 Error
BinaryStreamReader::readULEB128(uint64_t &Dest
) {
44 SmallVector
<uint8_t, 10> EncodedBytes
;
45 ArrayRef
<uint8_t> NextByte
;
47 // Copy the encoded ULEB into the buffer.
49 if (auto Err
= readBytes(NextByte
, 1))
51 EncodedBytes
.push_back(NextByte
[0]);
52 } while (NextByte
[0] & 0x80);
54 Dest
= decodeULEB128(EncodedBytes
.begin(), nullptr, EncodedBytes
.end());
55 return Error::success();
58 Error
BinaryStreamReader::readSLEB128(int64_t &Dest
) {
59 SmallVector
<uint8_t, 10> EncodedBytes
;
60 ArrayRef
<uint8_t> NextByte
;
62 // Copy the encoded ULEB into the buffer.
64 if (auto Err
= readBytes(NextByte
, 1))
66 EncodedBytes
.push_back(NextByte
[0]);
67 } while (NextByte
[0] & 0x80);
69 Dest
= decodeSLEB128(EncodedBytes
.begin(), nullptr, EncodedBytes
.end());
70 return Error::success();
73 Error
BinaryStreamReader::readCString(StringRef
&Dest
) {
74 uint64_t OriginalOffset
= getOffset();
75 uint64_t FoundOffset
= 0;
77 uint64_t ThisOffset
= getOffset();
78 ArrayRef
<uint8_t> Buffer
;
79 if (auto EC
= readLongestContiguousChunk(Buffer
))
81 StringRef
S(reinterpret_cast<const char *>(Buffer
.begin()), Buffer
.size());
82 size_t Pos
= S
.find_first_of('\0');
83 if (LLVM_LIKELY(Pos
!= StringRef::npos
)) {
84 FoundOffset
= Pos
+ ThisOffset
;
88 assert(FoundOffset
>= OriginalOffset
);
90 setOffset(OriginalOffset
);
91 size_t Length
= FoundOffset
- OriginalOffset
;
93 if (auto EC
= readFixedString(Dest
, Length
))
96 // Now set the offset back to after the null terminator.
97 setOffset(FoundOffset
+ 1);
98 return Error::success();
101 Error
BinaryStreamReader::readWideString(ArrayRef
<UTF16
> &Dest
) {
103 uint64_t OriginalOffset
= getOffset();
106 if (auto EC
= readObject(C
))
112 uint64_t NewOffset
= getOffset();
113 setOffset(OriginalOffset
);
115 if (auto EC
= readArray(Dest
, Length
))
117 setOffset(NewOffset
);
118 return Error::success();
121 Error
BinaryStreamReader::readFixedString(StringRef
&Dest
, uint32_t Length
) {
122 ArrayRef
<uint8_t> Bytes
;
123 if (auto EC
= readBytes(Bytes
, Length
))
125 Dest
= StringRef(reinterpret_cast<const char *>(Bytes
.begin()), Bytes
.size());
126 return Error::success();
129 Error
BinaryStreamReader::readStreamRef(BinaryStreamRef
&Ref
) {
130 return readStreamRef(Ref
, bytesRemaining());
133 Error
BinaryStreamReader::readStreamRef(BinaryStreamRef
&Ref
, uint32_t Length
) {
134 if (bytesRemaining() < Length
)
135 return make_error
<BinaryStreamError
>(stream_error_code::stream_too_short
);
136 Ref
= Stream
.slice(Offset
, Length
);
138 return Error::success();
141 Error
BinaryStreamReader::readSubstream(BinarySubstreamRef
&Ref
,
143 Ref
.Offset
= getOffset();
144 return readStreamRef(Ref
.StreamData
, Length
);
147 Error
BinaryStreamReader::skip(uint64_t Amount
) {
148 if (Amount
> bytesRemaining())
149 return make_error
<BinaryStreamError
>(stream_error_code::stream_too_short
);
151 return Error::success();
154 Error
BinaryStreamReader::padToAlignment(uint32_t Align
) {
155 uint32_t NewOffset
= alignTo(Offset
, Align
);
156 return skip(NewOffset
- Offset
);
159 uint8_t BinaryStreamReader::peek() const {
160 ArrayRef
<uint8_t> Buffer
;
161 auto EC
= Stream
.readBytes(Offset
, 1, Buffer
);
162 assert(!EC
&& "Cannot peek an empty buffer!");
163 llvm::consumeError(std::move(EC
));
167 std::pair
<BinaryStreamReader
, BinaryStreamReader
>
168 BinaryStreamReader::split(uint64_t Off
) const {
169 assert(getLength() >= Off
);
171 BinaryStreamRef First
= Stream
.drop_front(Offset
);
173 BinaryStreamRef Second
= First
.drop_front(Off
);
174 First
= First
.keep_front(Off
);
175 BinaryStreamReader W1
{First
};
176 BinaryStreamReader W2
{Second
};
177 return std::make_pair(W1
, W2
);