xref: /freebsd/contrib/llvm-project/llvm/lib/Support/BinaryStreamReader.cpp (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
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 
15 using namespace llvm;
16 
17 BinaryStreamReader::BinaryStreamReader(BinaryStreamRef Ref) : Stream(Ref) {}
18 
19 BinaryStreamReader::BinaryStreamReader(BinaryStream &Stream) : Stream(Stream) {}
20 
21 BinaryStreamReader::BinaryStreamReader(ArrayRef<uint8_t> Data,
22                                        endianness Endian)
23     : Stream(Data, Endian) {}
24 
25 BinaryStreamReader::BinaryStreamReader(StringRef Data, endianness Endian)
26     : Stream(Data, Endian) {}
27 
28 Error 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 
36 Error 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 
43 Error 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(NextByte, 1))
50       return Err;
51     EncodedBytes.push_back(NextByte[0]);
52   } while (NextByte[0] & 0x80);
53 
54   Dest = decodeULEB128(EncodedBytes.begin(), nullptr, EncodedBytes.end());
55   return Error::success();
56 }
57 
58 Error 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(NextByte, 1))
65       return Err;
66     EncodedBytes.push_back(NextByte[0]);
67   } while (NextByte[0] & 0x80);
68 
69   Dest = decodeSLEB128(EncodedBytes.begin(), nullptr, EncodedBytes.end());
70   return Error::success();
71 }
72 
73 Error 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('\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 
101 Error 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(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(Dest, Length))
116     return EC;
117   setOffset(NewOffset);
118   return Error::success();
119 }
120 
121 Error BinaryStreamReader::readFixedString(StringRef &Dest, uint32_t Length) {
122   ArrayRef<uint8_t> Bytes;
123   if (auto EC = readBytes(Bytes, Length))
124     return EC;
125   Dest = StringRef(reinterpret_cast<const char *>(Bytes.begin()), Bytes.size());
126   return Error::success();
127 }
128 
129 Error BinaryStreamReader::readStreamRef(BinaryStreamRef &Ref) {
130   return readStreamRef(Ref, bytesRemaining());
131 }
132 
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);
137   Offset += Length;
138   return Error::success();
139 }
140 
141 Error BinaryStreamReader::readSubstream(BinarySubstreamRef &Ref,
142                                         uint32_t Length) {
143   Ref.Offset = getOffset();
144   return readStreamRef(Ref.StreamData, Length);
145 }
146 
147 Error BinaryStreamReader::skip(uint64_t Amount) {
148   if (Amount > bytesRemaining())
149     return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
150   Offset += Amount;
151   return Error::success();
152 }
153 
154 Error BinaryStreamReader::padToAlignment(uint32_t Align) {
155   uint32_t NewOffset = alignTo(Offset, Align);
156   return skip(NewOffset - Offset);
157 }
158 
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));
164   return Buffer[0];
165 }
166 
167 std::pair<BinaryStreamReader, BinaryStreamReader>
168 BinaryStreamReader::split(uint64_t Off) const {
169   assert(getLength() >= Off);
170 
171   BinaryStreamRef First = Stream.drop_front(Offset);
172 
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);
178 }
179