1//===- BinaryStreamReader.cpp - Reads objects from a binary stream --------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/Support/BinaryStreamReader.h"
10
11#include "llvm/Support/BinaryStreamError.h"
12#include "llvm/Support/BinaryStreamRef.h"
13#include "llvm/Support/LEB128.h"
14
15using namespace llvm;
16
17BinaryStreamReader::BinaryStreamReader(BinaryStreamRef Ref) : Stream(Ref) {}
18
19BinaryStreamReader::BinaryStreamReader(BinaryStream &Stream) : Stream(Stream) {}
20
21BinaryStreamReader::BinaryStreamReader(ArrayRef<uint8_t> Data,
22 endianness Endian)
23 : Stream(Data, Endian) {}
24
25BinaryStreamReader::BinaryStreamReader(StringRef Data, endianness Endian)
26 : Stream(Data, Endian) {}
27
28Error BinaryStreamReader::readLongestContiguousChunk(
29 ArrayRef<uint8_t> &Buffer) {
30 if (auto EC = Stream.readLongestContiguousChunk(Offset, Buffer))
31 return EC;
32 Offset += Buffer.size();
33 return Error::success();
34}
35
36Error BinaryStreamReader::readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size) {
37 if (auto EC = Stream.readBytes(Offset, Size, Buffer))
38 return EC;
39 Offset += Size;
40 return Error::success();
41}
42
43Error BinaryStreamReader::readULEB128(uint64_t &Dest) {
44 SmallVector<uint8_t, 10> EncodedBytes;
45 ArrayRef<uint8_t> NextByte;
46
47 // Copy the encoded ULEB into the buffer.
48 do {
49 if (auto Err = readBytes(Buffer&: NextByte, Size: 1))
50 return Err;
51 EncodedBytes.push_back(Elt: NextByte[0]);
52 } while (NextByte[0] & 0x80);
53
54 Dest = decodeULEB128(p: EncodedBytes.begin(), n: nullptr, end: EncodedBytes.end());
55 return Error::success();
56}
57
58Error BinaryStreamReader::readSLEB128(int64_t &Dest) {
59 SmallVector<uint8_t, 10> EncodedBytes;
60 ArrayRef<uint8_t> NextByte;
61
62 // Copy the encoded ULEB into the buffer.
63 do {
64 if (auto Err = readBytes(Buffer&: NextByte, Size: 1))
65 return Err;
66 EncodedBytes.push_back(Elt: NextByte[0]);
67 } while (NextByte[0] & 0x80);
68
69 Dest = decodeSLEB128(p: EncodedBytes.begin(), n: nullptr, end: EncodedBytes.end());
70 return Error::success();
71}
72
73Error BinaryStreamReader::readCString(StringRef &Dest) {
74 uint64_t OriginalOffset = getOffset();
75 uint64_t FoundOffset = 0;
76 while (true) {
77 uint64_t ThisOffset = getOffset();
78 ArrayRef<uint8_t> Buffer;
79 if (auto EC = readLongestContiguousChunk(Buffer))
80 return EC;
81 StringRef S(reinterpret_cast<const char *>(Buffer.begin()), Buffer.size());
82 size_t Pos = S.find_first_of(C: '\0');
83 if (LLVM_LIKELY(Pos != StringRef::npos)) {
84 FoundOffset = Pos + ThisOffset;
85 break;
86 }
87 }
88 assert(FoundOffset >= OriginalOffset);
89
90 setOffset(OriginalOffset);
91 size_t Length = FoundOffset - OriginalOffset;
92
93 if (auto EC = readFixedString(Dest, Length))
94 return EC;
95
96 // Now set the offset back to after the null terminator.
97 setOffset(FoundOffset + 1);
98 return Error::success();
99}
100
101Error BinaryStreamReader::readWideString(ArrayRef<UTF16> &Dest) {
102 uint64_t Length = 0;
103 uint64_t OriginalOffset = getOffset();
104 const UTF16 *C;
105 while (true) {
106 if (auto EC = readObject(Dest&: C))
107 return EC;
108 if (*C == 0x0000)
109 break;
110 ++Length;
111 }
112 uint64_t NewOffset = getOffset();
113 setOffset(OriginalOffset);
114
115 if (auto EC = readArray(Array&: Dest, NumElements: Length))
116 return EC;
117 setOffset(NewOffset);
118 return Error::success();
119}
120
121Error BinaryStreamReader::readFixedString(StringRef &Dest, uint32_t Length) {
122 ArrayRef<uint8_t> Bytes;
123 if (auto EC = readBytes(Buffer&: Bytes, Size: Length))
124 return EC;
125 Dest = StringRef(reinterpret_cast<const char *>(Bytes.begin()), Bytes.size());
126 return Error::success();
127}
128
129Error BinaryStreamReader::readStreamRef(BinaryStreamRef &Ref) {
130 return readStreamRef(Ref, Length: bytesRemaining());
131}
132
133Error BinaryStreamReader::readStreamRef(BinaryStreamRef &Ref, uint32_t Length) {
134 if (bytesRemaining() < Length)
135 return make_error<BinaryStreamError>(Args: stream_error_code::stream_too_short);
136 Ref = Stream.slice(Offset, Len: Length);
137 Offset += Length;
138 return Error::success();
139}
140
141Error BinaryStreamReader::readSubstream(BinarySubstreamRef &Ref,
142 uint32_t Length) {
143 Ref.Offset = getOffset();
144 return readStreamRef(Ref&: Ref.StreamData, Length);
145}
146
147Error BinaryStreamReader::skip(uint64_t Amount) {
148 if (Amount > bytesRemaining())
149 return make_error<BinaryStreamError>(Args: stream_error_code::stream_too_short);
150 Offset += Amount;
151 return Error::success();
152}
153
154Error BinaryStreamReader::padToAlignment(uint32_t Align) {
155 uint32_t NewOffset = alignTo(Value: Offset, Align);
156 return skip(Amount: NewOffset - Offset);
157}
158
159uint8_t BinaryStreamReader::peek() const {
160 ArrayRef<uint8_t> Buffer;
161 auto EC = Stream.readBytes(Offset, Size: 1, Buffer);
162 assert(!EC && "Cannot peek an empty buffer!");
163 llvm::consumeError(Err: std::move(EC));
164 return Buffer[0];
165}
166
167std::pair<BinaryStreamReader, BinaryStreamReader>
168BinaryStreamReader::split(uint64_t Off) const {
169 assert(getLength() >= Off);
170
171 BinaryStreamRef First = Stream.drop_front(N: Offset);
172
173 BinaryStreamRef Second = First.drop_front(N: Off);
174 First = First.keep_front(N: Off);
175 BinaryStreamReader W1{First};
176 BinaryStreamReader W2{Second};
177 return std::make_pair(x&: W1, y&: W2);
178}
179