BinaryStreamReader.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- BinaryStreamReader.h - Reads objects from a binary stream *- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #ifndef LLVM_SUPPORT_BINARYSTREAMREADER_H
  14. #define LLVM_SUPPORT_BINARYSTREAMREADER_H
  15. #include "llvm/ADT/ArrayRef.h"
  16. #include "llvm/ADT/StringRef.h"
  17. #include "llvm/Support/Alignment.h"
  18. #include "llvm/Support/BinaryStreamArray.h"
  19. #include "llvm/Support/BinaryStreamRef.h"
  20. #include "llvm/Support/ConvertUTF.h"
  21. #include "llvm/Support/Endian.h"
  22. #include "llvm/Support/Error.h"
  23. #include <type_traits>
  24. namespace llvm {
  25. /// Provides read only access to a subclass of `BinaryStream`. Provides
  26. /// bounds checking and helpers for writing certain common data types such as
  27. /// null-terminated strings, integers in various flavors of endianness, etc.
  28. /// Can be subclassed to provide reading of custom datatypes, although no
  29. /// are overridable.
  30. class BinaryStreamReader {
  31. public:
  32. BinaryStreamReader() = default;
  33. explicit BinaryStreamReader(BinaryStreamRef Ref);
  34. explicit BinaryStreamReader(BinaryStream &Stream);
  35. explicit BinaryStreamReader(ArrayRef<uint8_t> Data,
  36. llvm::support::endianness Endian);
  37. explicit BinaryStreamReader(StringRef Data, llvm::support::endianness Endian);
  38. BinaryStreamReader(const BinaryStreamReader &Other) = default;
  39. BinaryStreamReader &operator=(const BinaryStreamReader &Other) = default;
  40. virtual ~BinaryStreamReader() = default;
  41. /// Read as much as possible from the underlying string at the current offset
  42. /// without invoking a copy, and set \p Buffer to the resulting data slice.
  43. /// Updates the stream's offset to point after the newly read data.
  44. ///
  45. /// \returns a success error code if the data was successfully read, otherwise
  46. /// returns an appropriate error code.
  47. Error readLongestContiguousChunk(ArrayRef<uint8_t> &Buffer);
  48. /// Read \p Size bytes from the underlying stream at the current offset and
  49. /// and set \p Buffer to the resulting data slice. Whether a copy occurs
  50. /// depends on the implementation of the underlying stream. Updates the
  51. /// stream's offset to point after the newly read data.
  52. ///
  53. /// \returns a success error code if the data was successfully read, otherwise
  54. /// returns an appropriate error code.
  55. Error readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size);
  56. /// Read an integer of the specified endianness into \p Dest and update the
  57. /// stream's offset. The data is always copied from the stream's underlying
  58. /// buffer into \p Dest. Updates the stream's offset to point after the newly
  59. /// read data.
  60. ///
  61. /// \returns a success error code if the data was successfully read, otherwise
  62. /// returns an appropriate error code.
  63. template <typename T> Error readInteger(T &Dest) {
  64. static_assert(std::is_integral_v<T>,
  65. "Cannot call readInteger with non-integral value!");
  66. ArrayRef<uint8_t> Bytes;
  67. if (auto EC = readBytes(Bytes, sizeof(T)))
  68. return EC;
  69. Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
  70. Bytes.data(), Stream.getEndian());
  71. return Error::success();
  72. }
  73. /// Similar to readInteger.
  74. template <typename T> Error readEnum(T &Dest) {
  75. static_assert(std::is_enum<T>::value,
  76. "Cannot call readEnum with non-enum value!");
  77. std::underlying_type_t<T> N;
  78. if (auto EC = readInteger(N))
  79. return EC;
  80. Dest = static_cast<T>(N);
  81. return Error::success();
  82. }
  83. /// Read an unsigned LEB128 encoded value.
  84. ///
  85. /// \returns a success error code if the data was successfully read, otherwise
  86. /// returns an appropriate error code.
  87. Error readULEB128(uint64_t &Dest);
  88. /// Read a signed LEB128 encoded value.
  89. ///
  90. /// \returns a success error code if the data was successfully read, otherwise
  91. /// returns an appropriate error code.
  92. Error readSLEB128(int64_t &Dest);
  93. /// Read a null terminated string from \p Dest. Whether a copy occurs depends
  94. /// on the implementation of the underlying stream. Updates the stream's
  95. /// offset to point after the newly read data.
  96. ///
  97. /// \returns a success error code if the data was successfully read, otherwise
  98. /// returns an appropriate error code.
  99. Error readCString(StringRef &Dest);
  100. /// Similar to readCString, however read a null-terminated UTF16 string
  101. /// instead.
  102. ///
  103. /// \returns a success error code if the data was successfully read, otherwise
  104. /// returns an appropriate error code.
  105. Error readWideString(ArrayRef<UTF16> &Dest);
  106. /// Read a \p Length byte string into \p Dest. Whether a copy occurs depends
  107. /// on the implementation of the underlying stream. Updates the stream's
  108. /// offset to point after the newly read data.
  109. ///
  110. /// \returns a success error code if the data was successfully read, otherwise
  111. /// returns an appropriate error code.
  112. Error readFixedString(StringRef &Dest, uint32_t Length);
  113. /// Read the entire remainder of the underlying stream into \p Ref. This is
  114. /// equivalent to calling getUnderlyingStream().slice(Offset). Updates the
  115. /// stream's offset to point to the end of the stream. Never causes a copy.
  116. ///
  117. /// \returns a success error code if the data was successfully read, otherwise
  118. /// returns an appropriate error code.
  119. Error readStreamRef(BinaryStreamRef &Ref);
  120. /// Read \p Length bytes from the underlying stream into \p Ref. This is
  121. /// equivalent to calling getUnderlyingStream().slice(Offset, Length).
  122. /// Updates the stream's offset to point after the newly read object. Never
  123. /// causes a copy.
  124. ///
  125. /// \returns a success error code if the data was successfully read, otherwise
  126. /// returns an appropriate error code.
  127. Error readStreamRef(BinaryStreamRef &Ref, uint32_t Length);
  128. /// Read \p Length bytes from the underlying stream into \p Ref. This is
  129. /// equivalent to calling getUnderlyingStream().slice(Offset, Length).
  130. /// Updates the stream's offset to point after the newly read object. Never
  131. /// causes a copy.
  132. ///
  133. /// \returns a success error code if the data was successfully read, otherwise
  134. /// returns an appropriate error code.
  135. Error readSubstream(BinarySubstreamRef &Ref, uint32_t Length);
  136. /// Get a pointer to an object of type T from the underlying stream, as if by
  137. /// memcpy, and store the result into \p Dest. It is up to the caller to
  138. /// ensure that objects of type T can be safely treated in this manner.
  139. /// Updates the stream's offset to point after the newly read object. Whether
  140. /// a copy occurs depends upon the implementation of the underlying
  141. /// stream.
  142. ///
  143. /// \returns a success error code if the data was successfully read, otherwise
  144. /// returns an appropriate error code.
  145. template <typename T> Error readObject(const T *&Dest) {
  146. ArrayRef<uint8_t> Buffer;
  147. if (auto EC = readBytes(Buffer, sizeof(T)))
  148. return EC;
  149. Dest = reinterpret_cast<const T *>(Buffer.data());
  150. return Error::success();
  151. }
  152. /// Get a reference to a \p NumElements element array of objects of type T
  153. /// from the underlying stream as if by memcpy, and store the resulting array
  154. /// slice into \p array. It is up to the caller to ensure that objects of
  155. /// type T can be safely treated in this manner. Updates the stream's offset
  156. /// to point after the newly read object. Whether a copy occurs depends upon
  157. /// the implementation of the underlying stream.
  158. ///
  159. /// \returns a success error code if the data was successfully read, otherwise
  160. /// returns an appropriate error code.
  161. template <typename T>
  162. Error readArray(ArrayRef<T> &Array, uint32_t NumElements) {
  163. ArrayRef<uint8_t> Bytes;
  164. if (NumElements == 0) {
  165. Array = ArrayRef<T>();
  166. return Error::success();
  167. }
  168. if (NumElements > UINT32_MAX / sizeof(T))
  169. return make_error<BinaryStreamError>(
  170. stream_error_code::invalid_array_size);
  171. if (auto EC = readBytes(Bytes, NumElements * sizeof(T)))
  172. return EC;
  173. assert(isAddrAligned(Align::Of<T>(), Bytes.data()) &&
  174. "Reading at invalid alignment!");
  175. Array = ArrayRef<T>(reinterpret_cast<const T *>(Bytes.data()), NumElements);
  176. return Error::success();
  177. }
  178. /// Read a VarStreamArray of size \p Size bytes and store the result into
  179. /// \p Array. Updates the stream's offset to point after the newly read
  180. /// array. Never causes a copy (although iterating the elements of the
  181. /// VarStreamArray may, depending upon the implementation of the underlying
  182. /// stream).
  183. ///
  184. /// \returns a success error code if the data was successfully read, otherwise
  185. /// returns an appropriate error code.
  186. template <typename T, typename U>
  187. Error readArray(VarStreamArray<T, U> &Array, uint32_t Size,
  188. uint32_t Skew = 0) {
  189. BinaryStreamRef S;
  190. if (auto EC = readStreamRef(S, Size))
  191. return EC;
  192. Array.setUnderlyingStream(S, Skew);
  193. return Error::success();
  194. }
  195. /// Read a FixedStreamArray of \p NumItems elements and store the result into
  196. /// \p Array. Updates the stream's offset to point after the newly read
  197. /// array. Never causes a copy (although iterating the elements of the
  198. /// FixedStreamArray may, depending upon the implementation of the underlying
  199. /// stream).
  200. ///
  201. /// \returns a success error code if the data was successfully read, otherwise
  202. /// returns an appropriate error code.
  203. template <typename T>
  204. Error readArray(FixedStreamArray<T> &Array, uint32_t NumItems) {
  205. if (NumItems == 0) {
  206. Array = FixedStreamArray<T>();
  207. return Error::success();
  208. }
  209. if (NumItems > UINT32_MAX / sizeof(T))
  210. return make_error<BinaryStreamError>(
  211. stream_error_code::invalid_array_size);
  212. BinaryStreamRef View;
  213. if (auto EC = readStreamRef(View, NumItems * sizeof(T)))
  214. return EC;
  215. Array = FixedStreamArray<T>(View);
  216. return Error::success();
  217. }
  218. bool empty() const { return bytesRemaining() == 0; }
  219. void setOffset(uint64_t Off) { Offset = Off; }
  220. uint64_t getOffset() const { return Offset; }
  221. uint64_t getLength() const { return Stream.getLength(); }
  222. uint64_t bytesRemaining() const { return getLength() - getOffset(); }
  223. /// Advance the stream's offset by \p Amount bytes.
  224. ///
  225. /// \returns a success error code if at least \p Amount bytes remain in the
  226. /// stream, otherwise returns an appropriate error code.
  227. Error skip(uint64_t Amount);
  228. /// Examine the next byte of the underlying stream without advancing the
  229. /// stream's offset. If the stream is empty the behavior is undefined.
  230. ///
  231. /// \returns the next byte in the stream.
  232. uint8_t peek() const;
  233. Error padToAlignment(uint32_t Align);
  234. std::pair<BinaryStreamReader, BinaryStreamReader>
  235. split(uint64_t Offset) const;
  236. private:
  237. BinaryStreamRef Stream;
  238. uint64_t Offset = 0;
  239. };
  240. } // namespace llvm
  241. #endif // LLVM_SUPPORT_BINARYSTREAMREADER_H
  242. #ifdef __GNUC__
  243. #pragma GCC diagnostic pop
  244. #endif