BinaryStreamReader.h 11 KB

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