1 //
2 // Copyright 2012 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // BinaryStream.h: Provides binary serialization of simple types.
8
9 #ifndef COMMON_BINARYSTREAM_H_
10 #define COMMON_BINARYSTREAM_H_
11
12 #include <stdint.h>
13 #include <cstddef>
14 #include <string>
15 #include <vector>
16
17 #include "common/PackedEnums.h"
18 #include "common/angleutils.h"
19 #include "common/mathutil.h"
20
21 namespace gl
22 {
23 template <typename IntT>
24 struct PromotedIntegerType
25 {
26 using type = typename std::conditional<
27 std::is_signed<IntT>::value,
28 typename std::conditional<sizeof(IntT) <= 4, int32_t, int64_t>::type,
29 typename std::conditional<sizeof(IntT) <= 4, uint32_t, uint64_t>::type>::type;
30 };
31
32 class BinaryInputStream : angle::NonCopyable
33 {
34 public:
BinaryInputStream(const void * data,size_t length)35 BinaryInputStream(const void *data, size_t length)
36 {
37 mError = false;
38 mOffset = 0;
39 mData = static_cast<const uint8_t *>(data);
40 mLength = length;
41 }
42
43 // readInt will generate an error for bool types
44 template <class IntT>
readInt()45 IntT readInt()
46 {
47 static_assert(!std::is_same<bool, std::remove_cv<IntT>()>(), "Use readBool");
48 using PromotedIntT = typename PromotedIntegerType<IntT>::type;
49 PromotedIntT value = 0;
50 read(&value);
51 ASSERT(angle::IsValueInRangeForNumericType<IntT>(value));
52 return static_cast<IntT>(value);
53 }
54
55 template <class IntT>
readInt(IntT * outValue)56 void readInt(IntT *outValue)
57 {
58 *outValue = readInt<IntT>();
59 }
60
61 template <class T>
readVector(std::vector<T> * param)62 void readVector(std::vector<T> *param)
63 {
64 static_assert(std::is_trivially_copyable<T>(), "must be memcpy-able");
65 ASSERT(param->empty());
66 size_t size = readInt<size_t>();
67 if (size > 0)
68 {
69 param->resize(size);
70 readBytes(reinterpret_cast<uint8_t *>(param->data()), param->size() * sizeof(T));
71 }
72 }
73
74 template <typename E, typename T>
readPackedEnumMap(angle::PackedEnumMap<E,T> * param)75 void readPackedEnumMap(angle::PackedEnumMap<E, T> *param)
76 {
77 static_assert(std::is_trivially_copyable<T>(), "must be memcpy-able");
78 readBytes(reinterpret_cast<uint8_t *>(param->data()), param->size() * sizeof(T));
79 }
80
81 template <class T>
readStruct(T * param)82 void readStruct(T *param)
83 {
84 static_assert(std::is_trivially_copyable<T>(), "must be memcpy-able");
85 readBytes(reinterpret_cast<uint8_t *>(param), sizeof(T));
86 }
87
88 template <class EnumT>
readEnum()89 EnumT readEnum()
90 {
91 using UnderlyingType = typename std::underlying_type<EnumT>::type;
92 return static_cast<EnumT>(readInt<UnderlyingType>());
93 }
94
95 template <class EnumT>
readEnum(EnumT * outValue)96 void readEnum(EnumT *outValue)
97 {
98 *outValue = readEnum<EnumT>();
99 }
100
readBool()101 bool readBool()
102 {
103 int value = 0;
104 read(&value);
105 return (value > 0);
106 }
107
readBool(bool * outValue)108 void readBool(bool *outValue) { *outValue = readBool(); }
109
readBytes(unsigned char outArray[],size_t count)110 void readBytes(unsigned char outArray[], size_t count) { read<unsigned char>(outArray, count); }
getBytes(size_t count)111 const unsigned char *getBytes(size_t count) { return read<unsigned char>(nullptr, count); }
112
readString()113 std::string readString()
114 {
115 std::string outString;
116 readString(&outString);
117 return outString;
118 }
119
readString(std::string * v)120 void readString(std::string *v)
121 {
122 size_t length;
123 readInt(&length);
124
125 if (mError)
126 {
127 return;
128 }
129
130 angle::CheckedNumeric<size_t> checkedOffset(mOffset);
131 checkedOffset += length;
132
133 if (!checkedOffset.IsValid() || mOffset + length > mLength)
134 {
135 mError = true;
136 return;
137 }
138
139 v->assign(reinterpret_cast<const char *>(mData) + mOffset, length);
140 mOffset = checkedOffset.ValueOrDie();
141 }
142
readFloat()143 float readFloat()
144 {
145 float f;
146 read(&f, 1);
147 return f;
148 }
149
skip(size_t length)150 void skip(size_t length)
151 {
152 angle::CheckedNumeric<size_t> checkedOffset(mOffset);
153 checkedOffset += length;
154
155 if (!checkedOffset.IsValid() || mOffset + length > mLength)
156 {
157 mError = true;
158 return;
159 }
160
161 mOffset = checkedOffset.ValueOrDie();
162 }
163
offset()164 size_t offset() const { return mOffset; }
remainingSize()165 size_t remainingSize() const
166 {
167 ASSERT(mLength >= mOffset);
168 return mLength - mOffset;
169 }
170
error()171 bool error() const { return mError; }
172
endOfStream()173 bool endOfStream() const { return mOffset == mLength; }
174
data()175 const uint8_t *data() { return mData; }
176
177 private:
178 bool mError;
179 size_t mOffset;
180 const uint8_t *mData;
181 size_t mLength;
182
183 template <typename T>
read(T * v,size_t num)184 const uint8_t *read(T *v, size_t num)
185 {
186 static_assert(std::is_fundamental<T>::value, "T must be a fundamental type.");
187
188 angle::CheckedNumeric<size_t> checkedLength(num);
189 checkedLength *= sizeof(T);
190 if (!checkedLength.IsValid())
191 {
192 mError = true;
193 return nullptr;
194 }
195
196 angle::CheckedNumeric<size_t> checkedOffset(mOffset);
197 checkedOffset += checkedLength;
198
199 if (!checkedOffset.IsValid() || checkedOffset.ValueOrDie() > mLength)
200 {
201 mError = true;
202 return nullptr;
203 }
204
205 const uint8_t *srcBytes = mData + mOffset;
206 if (v != nullptr)
207 {
208 memcpy(v, srcBytes, checkedLength.ValueOrDie());
209 }
210 mOffset = checkedOffset.ValueOrDie();
211
212 return srcBytes;
213 }
214
215 template <typename T>
read(T * v)216 void read(T *v)
217 {
218 read(v, 1);
219 }
220 };
221
222 class BinaryOutputStream : angle::NonCopyable
223 {
224 public:
225 BinaryOutputStream();
226 ~BinaryOutputStream();
227
228 // writeInt also handles bool types
229 template <class IntT>
writeInt(IntT param)230 void writeInt(IntT param)
231 {
232 static_assert(std::is_integral<IntT>::value, "Not an integral type");
233 static_assert(!std::is_same<bool, std::remove_cv<IntT>()>(), "Use writeBool");
234 using PromotedIntT = typename PromotedIntegerType<IntT>::type;
235 ASSERT(angle::IsValueInRangeForNumericType<PromotedIntT>(param));
236 PromotedIntT intValue = static_cast<PromotedIntT>(param);
237 write(&intValue, 1);
238 }
239
240 // Specialized writeInt for values that can also be exactly -1.
241 template <class UintT>
writeIntOrNegOne(UintT param)242 void writeIntOrNegOne(UintT param)
243 {
244 if (param == static_cast<UintT>(-1))
245 {
246 writeInt(-1);
247 }
248 else
249 {
250 writeInt(param);
251 }
252 }
253
254 template <class T>
writeVector(const std::vector<T> & param)255 void writeVector(const std::vector<T> ¶m)
256 {
257 static_assert(std::is_trivially_copyable<T>(), "must be memcpy-able");
258 writeInt(param.size());
259 if (param.size() > 0)
260 {
261 writeBytes(reinterpret_cast<const uint8_t *>(param.data()), param.size() * sizeof(T));
262 }
263 }
264
265 template <typename E, typename T>
writePackedEnumMap(const angle::PackedEnumMap<E,T> & param)266 void writePackedEnumMap(const angle::PackedEnumMap<E, T> ¶m)
267 {
268 static_assert(std::is_trivially_copyable<T>(), "must be memcpy-able");
269 writeBytes(reinterpret_cast<const uint8_t *>(param.data()), param.size() * sizeof(T));
270 }
271
272 template <class T>
writeStruct(const T & param)273 void writeStruct(const T ¶m)
274 {
275 static_assert(!std::is_pointer<T>::value,
276 "Must pass in a struct, not the pointer to struct");
277 static_assert(std::is_trivially_copyable<T>(), "must be memcpy-able");
278 writeBytes(reinterpret_cast<const uint8_t *>(¶m), sizeof(T));
279 }
280
281 template <class EnumT>
writeEnum(EnumT param)282 void writeEnum(EnumT param)
283 {
284 using UnderlyingType = typename std::underlying_type<EnumT>::type;
285 writeInt<UnderlyingType>(static_cast<UnderlyingType>(param));
286 }
287
writeString(const std::string & v)288 void writeString(const std::string &v)
289 {
290 writeInt(v.length());
291 write(v.c_str(), v.length());
292 }
293
writeString(const char * v)294 void writeString(const char *v)
295 {
296 size_t len = strlen(v);
297 writeInt(len);
298 write(v, len);
299 }
300
writeBytes(const unsigned char * bytes,size_t count)301 void writeBytes(const unsigned char *bytes, size_t count) { write(bytes, count); }
302
writeBool(bool value)303 void writeBool(bool value)
304 {
305 int intValue = value ? 1 : 0;
306 write(&intValue, 1);
307 }
308
writeFloat(float value)309 void writeFloat(float value) { write(&value, 1); }
310
length()311 size_t length() const { return mData.size(); }
312
data()313 const void *data() const { return mData.size() ? &mData[0] : nullptr; }
314
getData()315 const std::vector<uint8_t> &getData() const { return mData; }
316
317 private:
318 template <typename T>
write(const T * v,size_t num)319 void write(const T *v, size_t num)
320 {
321 static_assert(std::is_fundamental<T>::value, "T must be a fundamental type.");
322 const char *asBytes = reinterpret_cast<const char *>(v);
323 mData.insert(mData.end(), asBytes, asBytes + num * sizeof(T));
324 }
325
326 std::vector<uint8_t> mData;
327 };
328
BinaryOutputStream()329 inline BinaryOutputStream::BinaryOutputStream() {}
330
331 inline BinaryOutputStream::~BinaryOutputStream() = default;
332
333 } // namespace gl
334
335 #endif // COMMON_BINARYSTREAM_H_
336