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