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(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
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(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
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('\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(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
121Error 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
129Error BinaryStreamReader::readStreamRef(BinaryStreamRef &Ref) {
130  return readStreamRef(Ref, bytesRemaining());
131}
132
133Error 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
141Error BinaryStreamReader::readSubstream(BinarySubstreamRef &Ref,
142                                        uint32_t Length) {
143  Ref.Offset = getOffset();
144  return readStreamRef(Ref.StreamData, Length);
145}
146
147Error 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
154Error BinaryStreamReader::padToAlignment(uint32_t Align) {
155  uint32_t NewOffset = alignTo(Offset, Align);
156  return skip(NewOffset - Offset);
157}
158
159uint8_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
167std::pair<BinaryStreamReader, BinaryStreamReader>
168BinaryStreamReader::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