Home | History | Annotate | Download | only in Support
      1 //===- BinaryStreamReader.cpp - Reads objects from a binary stream --------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "llvm/Support/BinaryStreamReader.h"
     11 
     12 #include "llvm/Support/BinaryStreamError.h"
     13 #include "llvm/Support/BinaryStreamRef.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::readCString(StringRef &Dest) {
     45   uint32_t OriginalOffset = getOffset();
     46   uint32_t FoundOffset = 0;
     47   while (true) {
     48     uint32_t ThisOffset = getOffset();
     49     ArrayRef<uint8_t> Buffer;
     50     if (auto EC = readLongestContiguousChunk(Buffer))
     51       return EC;
     52     StringRef S(reinterpret_cast<const char *>(Buffer.begin()), Buffer.size());
     53     size_t Pos = S.find_first_of('\0');
     54     if (LLVM_LIKELY(Pos != StringRef::npos)) {
     55       FoundOffset = Pos + ThisOffset;
     56       break;
     57     }
     58   }
     59   assert(FoundOffset >= OriginalOffset);
     60 
     61   setOffset(OriginalOffset);
     62   size_t Length = FoundOffset - OriginalOffset;
     63 
     64   if (auto EC = readFixedString(Dest, Length))
     65     return EC;
     66 
     67   // Now set the offset back to after the null terminator.
     68   setOffset(FoundOffset + 1);
     69   return Error::success();
     70 }
     71 
     72 Error BinaryStreamReader::readWideString(ArrayRef<UTF16> &Dest) {
     73   uint32_t Length = 0;
     74   uint32_t OriginalOffset = getOffset();
     75   const UTF16 *C;
     76   while (true) {
     77     if (auto EC = readObject(C))
     78       return EC;
     79     if (*C == 0x0000)
     80       break;
     81     ++Length;
     82   }
     83   uint32_t NewOffset = getOffset();
     84   setOffset(OriginalOffset);
     85 
     86   if (auto EC = readArray(Dest, Length))
     87     return EC;
     88   setOffset(NewOffset);
     89   return Error::success();
     90 }
     91 
     92 Error BinaryStreamReader::readFixedString(StringRef &Dest, uint32_t Length) {
     93   ArrayRef<uint8_t> Bytes;
     94   if (auto EC = readBytes(Bytes, Length))
     95     return EC;
     96   Dest = StringRef(reinterpret_cast<const char *>(Bytes.begin()), Bytes.size());
     97   return Error::success();
     98 }
     99 
    100 Error BinaryStreamReader::readStreamRef(BinaryStreamRef &Ref) {
    101   return readStreamRef(Ref, bytesRemaining());
    102 }
    103 
    104 Error BinaryStreamReader::readStreamRef(BinaryStreamRef &Ref, uint32_t Length) {
    105   if (bytesRemaining() < Length)
    106     return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
    107   Ref = Stream.slice(Offset, Length);
    108   Offset += Length;
    109   return Error::success();
    110 }
    111 
    112 Error BinaryStreamReader::readSubstream(BinarySubstreamRef &Stream,
    113                                         uint32_t Size) {
    114   Stream.Offset = getOffset();
    115   return readStreamRef(Stream.StreamData, Size);
    116 }
    117 
    118 Error BinaryStreamReader::skip(uint32_t Amount) {
    119   if (Amount > bytesRemaining())
    120     return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
    121   Offset += Amount;
    122   return Error::success();
    123 }
    124 
    125 Error BinaryStreamReader::padToAlignment(uint32_t Align) {
    126   uint32_t NewOffset = alignTo(Offset, Align);
    127   return skip(NewOffset - Offset);
    128 }
    129 
    130 uint8_t BinaryStreamReader::peek() const {
    131   ArrayRef<uint8_t> Buffer;
    132   auto EC = Stream.readBytes(Offset, 1, Buffer);
    133   assert(!EC && "Cannot peek an empty buffer!");
    134   llvm::consumeError(std::move(EC));
    135   return Buffer[0];
    136 }
    137 
    138 std::pair<BinaryStreamReader, BinaryStreamReader>
    139 BinaryStreamReader::split(uint32_t Off) const {
    140   assert(getLength() >= Off);
    141 
    142   BinaryStreamRef First = Stream.drop_front(Offset);
    143 
    144   BinaryStreamRef Second = First.drop_front(Off);
    145   First = First.keep_front(Off);
    146   BinaryStreamReader W1{First};
    147   BinaryStreamReader W2{Second};
    148   return std::make_pair(W1, W2);
    149 }