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