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