| //===- BinaryStreamRef.h - A copyable reference to a stream -----*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_SUPPORT_BINARYSTREAMREF_H |
| #define LLVM_SUPPORT_BINARYSTREAMREF_H |
| |
| #include "llvm/ADT/ArrayRef.h" |
| #include "llvm/Support/BinaryStream.h" |
| #include "llvm/Support/BinaryStreamError.h" |
| #include "llvm/Support/Error.h" |
| #include <algorithm> |
| #include <cstdint> |
| |
| namespace llvm { |
| |
| /// Common stuff for mutable and immutable StreamRefs. |
| template <class StreamType, class RefType> class BinaryStreamRefBase { |
| public: |
| BinaryStreamRefBase() : Stream(nullptr), ViewOffset(0), Length(0) {} |
| BinaryStreamRefBase(StreamType &Stream, uint32_t Offset, uint32_t Length) |
| : Stream(&Stream), ViewOffset(Offset), Length(Length) {} |
| |
| llvm::support::endianness getEndian() const { return Stream->getEndian(); } |
| |
| uint32_t getLength() const { return Length; } |
| const StreamType *getStream() const { return Stream; } |
| |
| /// Return a new BinaryStreamRef with the first \p N elements removed. |
| RefType drop_front(uint32_t N) const { |
| if (!Stream) |
| return RefType(); |
| |
| N = std::min(N, Length); |
| return RefType(*Stream, ViewOffset + N, Length - N); |
| } |
| |
| /// Return a new BinaryStreamRef with only the first \p N elements remaining. |
| RefType keep_front(uint32_t N) const { |
| if (!Stream) |
| return RefType(); |
| N = std::min(N, Length); |
| return RefType(*Stream, ViewOffset, N); |
| } |
| |
| /// Return a new BinaryStreamRef with the first \p Offset elements removed, |
| /// and retaining exactly \p Len elements. |
| RefType slice(uint32_t Offset, uint32_t Len) const { |
| return drop_front(Offset).keep_front(Len); |
| } |
| |
| bool operator==(const RefType &Other) const { |
| if (Stream != Other.Stream) |
| return false; |
| if (ViewOffset != Other.ViewOffset) |
| return false; |
| if (Length != Other.Length) |
| return false; |
| return true; |
| } |
| |
| protected: |
| Error checkOffset(uint32_t Offset, uint32_t DataSize) const { |
| if (Offset > getLength()) |
| return make_error<BinaryStreamError>(stream_error_code::invalid_offset); |
| if (getLength() < DataSize + Offset) |
| return make_error<BinaryStreamError>(stream_error_code::stream_too_short); |
| return Error::success(); |
| } |
| |
| StreamType *Stream; |
| uint32_t ViewOffset; |
| uint32_t Length; |
| }; |
| |
| /// \brief BinaryStreamRef is to BinaryStream what ArrayRef is to an Array. It |
| /// provides copy-semantics and read only access to a "window" of the underlying |
| /// BinaryStream. Note that BinaryStreamRef is *not* a BinaryStream. That is to |
| /// say, it does not inherit and override the methods of BinaryStream. In |
| /// general, you should not pass around pointers or references to BinaryStreams |
| /// and use inheritance to achieve polymorphism. Instead, you should pass |
| /// around BinaryStreamRefs by value and achieve polymorphism that way. |
| class BinaryStreamRef |
| : public BinaryStreamRefBase<BinaryStream, BinaryStreamRef> { |
| public: |
| BinaryStreamRef() = default; |
| BinaryStreamRef(BinaryStream &Stream) |
| : BinaryStreamRefBase(Stream, 0, Stream.getLength()) {} |
| BinaryStreamRef(BinaryStream &Stream, uint32_t Offset, uint32_t Length) |
| : BinaryStreamRefBase(Stream, Offset, Length) {} |
| |
| // Use BinaryStreamRef.slice() instead. |
| BinaryStreamRef(BinaryStreamRef &S, uint32_t Offset, |
| uint32_t Length) = delete; |
| |
| /// Given an Offset into this StreamRef and a Size, return a reference to a |
| /// buffer owned by the stream. |
| /// |
| /// \returns a success error code if the entire range of data is within the |
| /// bounds of this BinaryStreamRef's view and the implementation could read |
| /// the data, and an appropriate error code otherwise. |
| Error readBytes(uint32_t Offset, uint32_t Size, |
| ArrayRef<uint8_t> &Buffer) const { |
| if (auto EC = checkOffset(Offset, Size)) |
| return EC; |
| |
| return Stream->readBytes(ViewOffset + Offset, Size, Buffer); |
| } |
| |
| /// Given an Offset into this BinaryStreamRef, return a reference to the |
| /// largest buffer the stream could support without necessitating a copy. |
| /// |
| /// \returns a success error code if implementation could read the data, |
| /// and an appropriate error code otherwise. |
| Error readLongestContiguousChunk(uint32_t Offset, |
| ArrayRef<uint8_t> &Buffer) const { |
| if (auto EC = checkOffset(Offset, 1)) |
| return EC; |
| |
| if (auto EC = |
| Stream->readLongestContiguousChunk(ViewOffset + Offset, Buffer)) |
| return EC; |
| // This StreamRef might refer to a smaller window over a larger stream. In |
| // that case we will have read out more bytes than we should return, because |
| // we should not read past the end of the current view. |
| uint32_t MaxLength = Length - Offset; |
| if (Buffer.size() > MaxLength) |
| Buffer = Buffer.slice(0, MaxLength); |
| return Error::success(); |
| } |
| }; |
| |
| class WritableBinaryStreamRef |
| : public BinaryStreamRefBase<WritableBinaryStream, |
| WritableBinaryStreamRef> { |
| public: |
| WritableBinaryStreamRef() = default; |
| WritableBinaryStreamRef(WritableBinaryStream &Stream) |
| : BinaryStreamRefBase(Stream, 0, Stream.getLength()) {} |
| WritableBinaryStreamRef(WritableBinaryStream &Stream, uint32_t Offset, |
| uint32_t Length) |
| : BinaryStreamRefBase(Stream, Offset, Length) {} |
| |
| // Use WritableBinaryStreamRef.slice() instead. |
| WritableBinaryStreamRef(WritableBinaryStreamRef &S, uint32_t Offset, |
| uint32_t Length) = delete; |
| |
| /// Given an Offset into this WritableBinaryStreamRef and some input data, |
| /// writes the data to the underlying stream. |
| /// |
| /// \returns a success error code if the data could fit within the underlying |
| /// stream at the specified location and the implementation could write the |
| /// data, and an appropriate error code otherwise. |
| Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) const { |
| if (auto EC = checkOffset(Offset, Data.size())) |
| return EC; |
| |
| return Stream->writeBytes(ViewOffset + Offset, Data); |
| } |
| |
| operator BinaryStreamRef() { return BinaryStreamRef(*Stream); } |
| |
| /// \brief For buffered streams, commits changes to the backing store. |
| Error commit() { return Stream->commit(); } |
| }; |
| |
| } // end namespace llvm |
| |
| #endif // LLVM_SUPPORT_BINARYSTREAMREF_H |