1 //===- BinaryStreamRef.h - A copyable reference to a stream -----*- C++ -*-===// 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 #ifndef LLVM_SUPPORT_BINARYSTREAMREF_H 11 #define LLVM_SUPPORT_BINARYSTREAMREF_H 12 13 #include "llvm/ADT/ArrayRef.h" 14 #include "llvm/Support/BinaryStream.h" 15 #include "llvm/Support/BinaryStreamError.h" 16 #include "llvm/Support/Error.h" 17 #include <algorithm> 18 #include <cstdint> 19 #include <memory> 20 21 namespace llvm { 22 23 /// Common stuff for mutable and immutable StreamRefs. 24 template <class RefType, class StreamType> class BinaryStreamRefBase { 25 protected: 26 BinaryStreamRefBase() = default; 27 BinaryStreamRefBase(std::shared_ptr<StreamType> SharedImpl, uint32_t Offset, 28 uint32_t Length) 29 : SharedImpl(SharedImpl), BorrowedImpl(SharedImpl.get()), 30 ViewOffset(Offset), Length(Length) {} 31 BinaryStreamRefBase(StreamType &BorrowedImpl, uint32_t Offset, 32 uint32_t Length) 33 : BorrowedImpl(&BorrowedImpl), ViewOffset(Offset), Length(Length) {} 34 BinaryStreamRefBase(const BinaryStreamRefBase &Other) = default; 35 BinaryStreamRefBase &operator=(const BinaryStreamRefBase &Other) = default; 36 37 BinaryStreamRefBase &operator=(BinaryStreamRefBase &&Other) = default; 38 BinaryStreamRefBase(BinaryStreamRefBase &&Other) = default; 39 40 public: 41 llvm::support::endianness getEndian() const { 42 return BorrowedImpl->getEndian(); 43 } 44 45 uint32_t getLength() const { return Length; } 46 47 /// Return a new BinaryStreamRef with the first \p N elements removed. 48 RefType drop_front(uint32_t N) const { 49 if (!BorrowedImpl) 50 return RefType(); 51 52 N = std::min(N, Length); 53 RefType Result(static_cast<const RefType &>(*this)); 54 Result.ViewOffset += N; 55 Result.Length -= N; 56 return Result; 57 } 58 59 /// Return a new BinaryStreamRef with the first \p N elements removed. 60 RefType drop_back(uint32_t N) const { 61 if (!BorrowedImpl) 62 return RefType(); 63 64 N = std::min(N, Length); 65 RefType Result(static_cast<const RefType &>(*this)); 66 Result.Length -= N; 67 return Result; 68 } 69 70 /// Return a new BinaryStreamRef with only the first \p N elements remaining. 71 RefType keep_front(uint32_t N) const { 72 assert(N <= getLength()); 73 return drop_back(getLength() - N); 74 } 75 76 /// Return a new BinaryStreamRef with only the last \p N elements remaining. 77 RefType keep_back(uint32_t N) const { 78 assert(N <= getLength()); 79 return drop_front(getLength() - N); 80 } 81 82 /// Return a new BinaryStreamRef with the first and last \p N elements 83 /// removed. 84 RefType drop_symmetric(uint32_t N) const { 85 return drop_front(N).drop_back(N); 86 } 87 88 /// Return a new BinaryStreamRef with the first \p Offset elements removed, 89 /// and retaining exactly \p Len elements. 90 RefType slice(uint32_t Offset, uint32_t Len) const { 91 return drop_front(Offset).keep_front(Len); 92 } 93 94 bool valid() const { return BorrowedImpl != nullptr; } 95 96 bool operator==(const RefType &Other) const { 97 if (BorrowedImpl != Other.BorrowedImpl) 98 return false; 99 if (ViewOffset != Other.ViewOffset) 100 return false; 101 if (Length != Other.Length) 102 return false; 103 return true; 104 } 105 106 protected: 107 Error checkOffset(uint32_t Offset, uint32_t DataSize) const { 108 if (Offset > getLength()) 109 return make_error<BinaryStreamError>(stream_error_code::invalid_offset); 110 if (getLength() < DataSize + Offset) 111 return make_error<BinaryStreamError>(stream_error_code::stream_too_short); 112 return Error::success(); 113 } 114 115 std::shared_ptr<StreamType> SharedImpl; 116 StreamType *BorrowedImpl = nullptr; 117 uint32_t ViewOffset = 0; 118 uint32_t Length = 0; 119 }; 120 121 /// \brief BinaryStreamRef is to BinaryStream what ArrayRef is to an Array. It 122 /// provides copy-semantics and read only access to a "window" of the underlying 123 /// BinaryStream. Note that BinaryStreamRef is *not* a BinaryStream. That is to 124 /// say, it does not inherit and override the methods of BinaryStream. In 125 /// general, you should not pass around pointers or references to BinaryStreams 126 /// and use inheritance to achieve polymorphism. Instead, you should pass 127 /// around BinaryStreamRefs by value and achieve polymorphism that way. 128 class BinaryStreamRef 129 : public BinaryStreamRefBase<BinaryStreamRef, BinaryStream> { 130 friend BinaryStreamRefBase<BinaryStreamRef, BinaryStream>; 131 friend class WritableBinaryStreamRef; 132 BinaryStreamRef(std::shared_ptr<BinaryStream> Impl, uint32_t ViewOffset, 133 uint32_t Length) 134 : BinaryStreamRefBase(Impl, ViewOffset, Length) {} 135 136 public: 137 BinaryStreamRef() = default; 138 BinaryStreamRef(BinaryStream &Stream); 139 BinaryStreamRef(BinaryStream &Stream, uint32_t Offset, uint32_t Length); 140 explicit BinaryStreamRef(ArrayRef<uint8_t> Data, 141 llvm::support::endianness Endian); 142 explicit BinaryStreamRef(StringRef Data, llvm::support::endianness Endian); 143 144 BinaryStreamRef(const BinaryStreamRef &Other) = default; 145 BinaryStreamRef &operator=(const BinaryStreamRef &Other) = default; 146 BinaryStreamRef(BinaryStreamRef &&Other) = default; 147 BinaryStreamRef &operator=(BinaryStreamRef &&Other) = default; 148 149 // Use BinaryStreamRef.slice() instead. 150 BinaryStreamRef(BinaryStreamRef &S, uint32_t Offset, 151 uint32_t Length) = delete; 152 153 /// Given an Offset into this StreamRef and a Size, return a reference to a 154 /// buffer owned by the stream. 155 /// 156 /// \returns a success error code if the entire range of data is within the 157 /// bounds of this BinaryStreamRef's view and the implementation could read 158 /// the data, and an appropriate error code otherwise. 159 Error readBytes(uint32_t Offset, uint32_t Size, 160 ArrayRef<uint8_t> &Buffer) const; 161 162 /// Given an Offset into this BinaryStreamRef, return a reference to the 163 /// largest buffer the stream could support without necessitating a copy. 164 /// 165 /// \returns a success error code if implementation could read the data, 166 /// and an appropriate error code otherwise. 167 Error readLongestContiguousChunk(uint32_t Offset, 168 ArrayRef<uint8_t> &Buffer) const; 169 }; 170 171 struct BinarySubstreamRef { 172 uint32_t Offset; // Offset in the parent stream 173 BinaryStreamRef StreamData; // Stream Data 174 175 BinarySubstreamRef slice(uint32_t Off, uint32_t Size) const { 176 BinaryStreamRef SubSub = StreamData.slice(Off, Size); 177 return {Off + Offset, SubSub}; 178 } 179 BinarySubstreamRef drop_front(uint32_t N) const { 180 return slice(N, size() - N); 181 } 182 BinarySubstreamRef keep_front(uint32_t N) const { return slice(0, N); } 183 184 std::pair<BinarySubstreamRef, BinarySubstreamRef> 185 split(uint32_t Offset) const { 186 return std::make_pair(keep_front(Offset), drop_front(Offset)); 187 } 188 189 uint32_t size() const { return StreamData.getLength(); } 190 bool empty() const { return size() == 0; } 191 }; 192 193 class WritableBinaryStreamRef 194 : public BinaryStreamRefBase<WritableBinaryStreamRef, 195 WritableBinaryStream> { 196 friend BinaryStreamRefBase<WritableBinaryStreamRef, WritableBinaryStream>; 197 WritableBinaryStreamRef(std::shared_ptr<WritableBinaryStream> Impl, 198 uint32_t ViewOffset, uint32_t Length) 199 : BinaryStreamRefBase(Impl, ViewOffset, Length) {} 200 201 public: 202 WritableBinaryStreamRef() = default; 203 WritableBinaryStreamRef(WritableBinaryStream &Stream); 204 WritableBinaryStreamRef(WritableBinaryStream &Stream, uint32_t Offset, 205 uint32_t Length); 206 explicit WritableBinaryStreamRef(MutableArrayRef<uint8_t> Data, 207 llvm::support::endianness Endian); 208 WritableBinaryStreamRef(const WritableBinaryStreamRef &Other) = default; 209 WritableBinaryStreamRef & 210 operator=(const WritableBinaryStreamRef &Other) = default; 211 212 WritableBinaryStreamRef(WritableBinaryStreamRef &&Other) = default; 213 WritableBinaryStreamRef &operator=(WritableBinaryStreamRef &&Other) = default; 214 215 // Use WritableBinaryStreamRef.slice() instead. 216 WritableBinaryStreamRef(WritableBinaryStreamRef &S, uint32_t Offset, 217 uint32_t Length) = delete; 218 219 /// Given an Offset into this WritableBinaryStreamRef and some input data, 220 /// writes the data to the underlying stream. 221 /// 222 /// \returns a success error code if the data could fit within the underlying 223 /// stream at the specified location and the implementation could write the 224 /// data, and an appropriate error code otherwise. 225 Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) const; 226 227 /// Conver this WritableBinaryStreamRef to a read-only BinaryStreamRef. 228 operator BinaryStreamRef() const; 229 230 /// \brief For buffered streams, commits changes to the backing store. 231 Error commit(); 232 }; 233 234 } // end namespace llvm 235 236 #endif // LLVM_SUPPORT_BINARYSTREAMREF_H 237