BinaryStreamWriter.h 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- BinaryStreamWriter.h - Writes objects to a BinaryStream ---*- 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_BINARYSTREAMWRITER_H
  14. #define LLVM_SUPPORT_BINARYSTREAMWRITER_H
  15. #include "llvm/ADT/ArrayRef.h"
  16. #include "llvm/ADT/StringRef.h"
  17. #include "llvm/Support/BinaryStreamArray.h"
  18. #include "llvm/Support/BinaryStreamError.h"
  19. #include "llvm/Support/BinaryStreamRef.h"
  20. #include "llvm/Support/Endian.h"
  21. #include "llvm/Support/Error.h"
  22. #include <cstdint>
  23. #include <type_traits>
  24. #include <utility>
  25. namespace llvm {
  26. /// Provides write only access to a subclass of `WritableBinaryStream`.
  27. /// Provides bounds checking and helpers for writing certain common data types
  28. /// such as null-terminated strings, integers in various flavors of endianness,
  29. /// etc. Can be subclassed to provide reading and writing of custom datatypes,
  30. /// although no methods are overridable.
  31. class BinaryStreamWriter {
  32. public:
  33. BinaryStreamWriter() = default;
  34. explicit BinaryStreamWriter(WritableBinaryStreamRef Ref);
  35. explicit BinaryStreamWriter(WritableBinaryStream &Stream);
  36. explicit BinaryStreamWriter(MutableArrayRef<uint8_t> Data,
  37. llvm::support::endianness Endian);
  38. BinaryStreamWriter(const BinaryStreamWriter &Other) = default;
  39. BinaryStreamWriter &operator=(const BinaryStreamWriter &Other) = default;
  40. virtual ~BinaryStreamWriter() = default;
  41. /// Write the bytes specified in \p Buffer to the underlying stream.
  42. /// On success, updates the offset so that subsequent writes will occur
  43. /// at the next unwritten position.
  44. ///
  45. /// \returns a success error code if the data was successfully written,
  46. /// otherwise returns an appropriate error code.
  47. Error writeBytes(ArrayRef<uint8_t> Buffer);
  48. /// Write the integer \p Value to the underlying stream in the
  49. /// specified endianness. On success, updates the offset so that
  50. /// subsequent writes occur at the next unwritten position.
  51. ///
  52. /// \returns a success error code if the data was successfully written,
  53. /// otherwise returns an appropriate error code.
  54. template <typename T> Error writeInteger(T Value) {
  55. static_assert(std::is_integral<T>::value,
  56. "Cannot call writeInteger with non-integral value!");
  57. uint8_t Buffer[sizeof(T)];
  58. llvm::support::endian::write<T, llvm::support::unaligned>(
  59. Buffer, Value, Stream.getEndian());
  60. return writeBytes(Buffer);
  61. }
  62. /// Similar to writeInteger
  63. template <typename T> Error writeEnum(T Num) {
  64. static_assert(std::is_enum<T>::value,
  65. "Cannot call writeEnum with non-Enum type");
  66. using U = std::underlying_type_t<T>;
  67. return writeInteger<U>(static_cast<U>(Num));
  68. }
  69. /// Write the unsigned integer Value to the underlying stream using ULEB128
  70. /// encoding.
  71. ///
  72. /// \returns a success error code if the data was successfully written,
  73. /// otherwise returns an appropriate error code.
  74. Error writeULEB128(uint64_t Value);
  75. /// Write the unsigned integer Value to the underlying stream using ULEB128
  76. /// encoding.
  77. ///
  78. /// \returns a success error code if the data was successfully written,
  79. /// otherwise returns an appropriate error code.
  80. Error writeSLEB128(int64_t Value);
  81. /// Write the string \p Str to the underlying stream followed by a null
  82. /// terminator. On success, updates the offset so that subsequent writes
  83. /// occur at the next unwritten position. \p Str need not be null terminated
  84. /// on input.
  85. ///
  86. /// \returns a success error code if the data was successfully written,
  87. /// otherwise returns an appropriate error code.
  88. Error writeCString(StringRef Str);
  89. /// Write the string \p Str to the underlying stream without a null
  90. /// terminator. On success, updates the offset so that subsequent writes
  91. /// occur at the next unwritten position.
  92. ///
  93. /// \returns a success error code if the data was successfully written,
  94. /// otherwise returns an appropriate error code.
  95. Error writeFixedString(StringRef Str);
  96. /// Efficiently reads all data from \p Ref, and writes it to this stream.
  97. /// This operation will not invoke any copies of the source data, regardless
  98. /// of the source stream's implementation.
  99. ///
  100. /// \returns a success error code if the data was successfully written,
  101. /// otherwise returns an appropriate error code.
  102. Error writeStreamRef(BinaryStreamRef Ref);
  103. /// Efficiently reads \p Size bytes from \p Ref, and writes it to this stream.
  104. /// This operation will not invoke any copies of the source data, regardless
  105. /// of the source stream's implementation.
  106. ///
  107. /// \returns a success error code if the data was successfully written,
  108. /// otherwise returns an appropriate error code.
  109. Error writeStreamRef(BinaryStreamRef Ref, uint64_t Size);
  110. /// Writes the object \p Obj to the underlying stream, as if by using memcpy.
  111. /// It is up to the caller to ensure that type of \p Obj can be safely copied
  112. /// in this fashion, as no checks are made to ensure that this is safe.
  113. ///
  114. /// \returns a success error code if the data was successfully written,
  115. /// otherwise returns an appropriate error code.
  116. template <typename T> Error writeObject(const T &Obj) {
  117. static_assert(!std::is_pointer<T>::value,
  118. "writeObject should not be used with pointers, to write "
  119. "the pointed-to value dereference the pointer before calling "
  120. "writeObject");
  121. return writeBytes(
  122. ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&Obj), sizeof(T)));
  123. }
  124. /// Writes an array of objects of type T to the underlying stream, as if by
  125. /// using memcpy. It is up to the caller to ensure that type of \p Obj can
  126. /// be safely copied in this fashion, as no checks are made to ensure that
  127. /// this is safe.
  128. ///
  129. /// \returns a success error code if the data was successfully written,
  130. /// otherwise returns an appropriate error code.
  131. template <typename T> Error writeArray(ArrayRef<T> Array) {
  132. if (Array.empty())
  133. return Error::success();
  134. if (Array.size() > UINT32_MAX / sizeof(T))
  135. return make_error<BinaryStreamError>(
  136. stream_error_code::invalid_array_size);
  137. return writeBytes(
  138. ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Array.data()),
  139. Array.size() * sizeof(T)));
  140. }
  141. /// Writes all data from the array \p Array to the underlying stream.
  142. ///
  143. /// \returns a success error code if the data was successfully written,
  144. /// otherwise returns an appropriate error code.
  145. template <typename T, typename U>
  146. Error writeArray(VarStreamArray<T, U> Array) {
  147. return writeStreamRef(Array.getUnderlyingStream());
  148. }
  149. /// Writes all elements from the array \p Array to the underlying stream.
  150. ///
  151. /// \returns a success error code if the data was successfully written,
  152. /// otherwise returns an appropriate error code.
  153. template <typename T> Error writeArray(FixedStreamArray<T> Array) {
  154. return writeStreamRef(Array.getUnderlyingStream());
  155. }
  156. /// Splits the Writer into two Writers at a given offset.
  157. std::pair<BinaryStreamWriter, BinaryStreamWriter> split(uint64_t Off) const;
  158. void setOffset(uint64_t Off) { Offset = Off; }
  159. uint64_t getOffset() const { return Offset; }
  160. uint64_t getLength() const { return Stream.getLength(); }
  161. uint64_t bytesRemaining() const { return getLength() - getOffset(); }
  162. Error padToAlignment(uint32_t Align);
  163. protected:
  164. WritableBinaryStreamRef Stream;
  165. uint64_t Offset = 0;
  166. };
  167. } // end namespace llvm
  168. #endif // LLVM_SUPPORT_BINARYSTREAMWRITER_H
  169. #ifdef __GNUC__
  170. #pragma GCC diagnostic pop
  171. #endif