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 17 BinaryStreamReader::BinaryStreamReader(BinaryStreamRef S) 18 : Stream(S), Offset(0) {} 19 20 Error BinaryStreamReader::readLongestContiguousChunk( 21 ArrayRef<uint8_t> &Buffer) { 22 if (auto EC = Stream.readLongestContiguousChunk(Offset, Buffer)) 23 return EC; 24 Offset += Buffer.size(); 25 return Error::success(); 26 } 27 28 Error BinaryStreamReader::readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size) { 29 if (auto EC = Stream.readBytes(Offset, Size, Buffer)) 30 return EC; 31 Offset += Size; 32 return Error::success(); 33 } 34 35 Error BinaryStreamReader::readCString(StringRef &Dest) { 36 // TODO: This could be made more efficient by using readLongestContiguousChunk 37 // and searching for null terminators in the resulting buffer. 38 39 uint32_t Length = 0; 40 // First compute the length of the string by reading 1 byte at a time. 41 uint32_t OriginalOffset = getOffset(); 42 const char *C; 43 while (true) { 44 if (auto EC = readObject(C)) 45 return EC; 46 if (*C == '\0') 47 break; 48 ++Length; 49 } 50 // Now go back and request a reference for that many bytes. 51 uint32_t NewOffset = getOffset(); 52 setOffset(OriginalOffset); 53 54 if (auto EC = readFixedString(Dest, Length)) 55 return EC; 56 57 // Now set the offset back to where it was after we calculated the length. 58 setOffset(NewOffset); 59 return Error::success(); 60 } 61 62 Error BinaryStreamReader::readFixedString(StringRef &Dest, uint32_t Length) { 63 ArrayRef<uint8_t> Bytes; 64 if (auto EC = readBytes(Bytes, Length)) 65 return EC; 66 Dest = StringRef(reinterpret_cast<const char *>(Bytes.begin()), Bytes.size()); 67 return Error::success(); 68 } 69 70 Error BinaryStreamReader::readStreamRef(BinaryStreamRef &Ref) { 71 return readStreamRef(Ref, bytesRemaining()); 72 } 73 74 Error BinaryStreamReader::readStreamRef(BinaryStreamRef &Ref, uint32_t Length) { 75 if (bytesRemaining() < Length) 76 return make_error<BinaryStreamError>(stream_error_code::stream_too_short); 77 Ref = Stream.slice(Offset, Length); 78 Offset += Length; 79 return Error::success(); 80 } 81 82 Error BinaryStreamReader::skip(uint32_t Amount) { 83 if (Amount > bytesRemaining()) 84 return make_error<BinaryStreamError>(stream_error_code::stream_too_short); 85 Offset += Amount; 86 return Error::success(); 87 } 88 89 uint8_t BinaryStreamReader::peek() const { 90 ArrayRef<uint8_t> Buffer; 91 auto EC = Stream.readBytes(Offset, 1, Buffer); 92 assert(!EC && "Cannot peek an empty buffer!"); 93 llvm::consumeError(std::move(EC)); 94 return Buffer[0]; 95 } 96 97 std::pair<BinaryStreamReader, BinaryStreamReader> 98 BinaryStreamReader::split(uint32_t Off) const { 99 assert(getLength() >= Off); 100 101 BinaryStreamRef First = Stream.drop_front(Offset); 102 103 BinaryStreamRef Second = First.drop_front(Off); 104 First = First.keep_front(Off); 105 BinaryStreamReader W1{First}; 106 BinaryStreamReader W2{Second}; 107 return std::make_pair(W1, W2); 108 }