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 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 102 Error 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 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(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 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(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