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; 16using endianness = llvm::support::endianness; 17 18BinaryStreamReader::BinaryStreamReader(BinaryStreamRef Ref) : Stream(Ref) {} 19 20BinaryStreamReader::BinaryStreamReader(BinaryStream &Stream) : Stream(Stream) {} 21 22BinaryStreamReader::BinaryStreamReader(ArrayRef<uint8_t> Data, 23 endianness Endian) 24 : Stream(Data, Endian) {} 25 26BinaryStreamReader::BinaryStreamReader(StringRef Data, endianness Endian) 27 : Stream(Data, Endian) {} 28 29Error 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 37Error 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 44Error 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 59Error 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 74Error BinaryStreamReader::readCString(StringRef &Dest) { 75 uint64_t OriginalOffset = getOffset(); 76 uint64_t FoundOffset = 0; 77 while (true) { 78 uint64_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 102Error BinaryStreamReader::readWideString(ArrayRef<UTF16> &Dest) { 103 uint64_t Length = 0; 104 uint64_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 uint64_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 122Error 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 130Error BinaryStreamReader::readStreamRef(BinaryStreamRef &Ref) { 131 return readStreamRef(Ref, bytesRemaining()); 132} 133 134Error 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 142Error BinaryStreamReader::readSubstream(BinarySubstreamRef &Ref, 143 uint32_t Length) { 144 Ref.Offset = getOffset(); 145 return readStreamRef(Ref.StreamData, Length); 146} 147 148Error BinaryStreamReader::skip(uint64_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 155Error BinaryStreamReader::padToAlignment(uint32_t Align) { 156 uint32_t NewOffset = alignTo(Offset, Align); 157 return skip(NewOffset - Offset); 158} 159 160uint8_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 168std::pair<BinaryStreamReader, BinaryStreamReader> 169BinaryStreamReader::split(uint64_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