brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.2 KiB · 26ddf3f Raw
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