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