BinaryStreamRef.h 10 KB

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