179 lines · cpp
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-exception6//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 {W1, W2};178}179