Home | History | Annotate | Line # | Download | only in Support
      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   uint32_t OriginalOffset = getOffset();
     76   uint32_t FoundOffset = 0;
     77   while (true) {
     78     uint32_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   uint32_t Length = 0;
    104   uint32_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   uint32_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(uint32_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(uint32_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