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