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/angleutils.h"
18 #include "common/mathutil.h"
19
20 namespace gl
21 {
22 template <typename IntT>
23 struct PromotedIntegerType
24 {
25 using type = typename std::conditional<
26 std::is_signed<IntT>::value,
27 typename std::conditional<sizeof(IntT) <= 4, int32_t, int64_t>::type,
28 typename std::conditional<sizeof(IntT) <= 4, uint32_t, uint64_t>::type>::type;
29 };
30
31 class BinaryInputStream : angle::NonCopyable
32 {
33 public:
BinaryInputStream(const void * data,size_t length)34 BinaryInputStream(const void *data, size_t length)
35 {
36 mError = false;
37 mOffset = 0;
38 mData = static_cast<const uint8_t *>(data);
39 mLength = length;
40 }
41
42 // readInt will generate an error for bool types
43 template <class IntT>
readInt()44 IntT readInt()
45 {
46 static_assert(!std::is_same<bool, std::remove_cv<IntT>()>(), "Use readBool");
47 using PromotedIntT = typename PromotedIntegerType<IntT>::type;
48 PromotedIntT value = 0;
49 read(&value);
50 ASSERT(angle::IsValueInRangeForNumericType<IntT>(value));
51 return static_cast<IntT>(value);
52 }
53
54 template <class IntT>
readInt(IntT * outValue)55 void readInt(IntT *outValue)
56 {
57 *outValue = readInt<IntT>();
58 }
59
60 template <class IntT, class VectorElementT>
readIntVector(std::vector<VectorElementT> * param)61 void readIntVector(std::vector<VectorElementT> *param)
62 {
63 size_t size = readInt<size_t>();
64 param->reserve(size);
65 for (size_t index = 0; index < size; ++index)
66 {
67 param->push_back(readInt<IntT>());
68 }
69 }
70
71 template <class EnumT>
readEnum()72 EnumT readEnum()
73 {
74 using UnderlyingType = typename std::underlying_type<EnumT>::type;
75 return static_cast<EnumT>(readInt<UnderlyingType>());
76 }
77
78 template <class EnumT>
readEnum(EnumT * outValue)79 void readEnum(EnumT *outValue)
80 {
81 *outValue = readEnum<EnumT>();
82 }
83
readBool()84 bool readBool()
85 {
86 int value = 0;
87 read(&value);
88 return (value > 0);
89 }
90
readBool(bool * outValue)91 void readBool(bool *outValue) { *outValue = readBool(); }
92
readBytes(unsigned char outArray[],size_t count)93 void readBytes(unsigned char outArray[], size_t count) { read<unsigned char>(outArray, count); }
94
readString()95 std::string readString()
96 {
97 std::string outString;
98 readString(&outString);
99 return outString;
100 }
101
readString(std::string * v)102 void readString(std::string *v)
103 {
104 size_t length;
105 readInt(&length);
106
107 if (mError)
108 {
109 return;
110 }
111
112 angle::CheckedNumeric<size_t> checkedOffset(mOffset);
113 checkedOffset += length;
114
115 if (!checkedOffset.IsValid() || mOffset + length > mLength)
116 {
117 mError = true;
118 return;
119 }
120
121 v->assign(reinterpret_cast<const char *>(mData) + mOffset, length);
122 mOffset = checkedOffset.ValueOrDie();
123 }
124
readFloat()125 float readFloat()
126 {
127 float f;
128 read(&f, 1);
129 return f;
130 }
131
skip(size_t length)132 void skip(size_t length)
133 {
134 angle::CheckedNumeric<size_t> checkedOffset(mOffset);
135 checkedOffset += length;
136
137 if (!checkedOffset.IsValid() || mOffset + length > mLength)
138 {
139 mError = true;
140 return;
141 }
142
143 mOffset = checkedOffset.ValueOrDie();
144 }
145
offset()146 size_t offset() const { return mOffset; }
remainingSize()147 size_t remainingSize() const
148 {
149 ASSERT(mLength >= mOffset);
150 return mLength - mOffset;
151 }
152
error()153 bool error() const { return mError; }
154
endOfStream()155 bool endOfStream() const { return mOffset == mLength; }
156
data()157 const uint8_t *data() { return mData; }
158
159 private:
160 bool mError;
161 size_t mOffset;
162 const uint8_t *mData;
163 size_t mLength;
164
165 template <typename T>
read(T * v,size_t num)166 void read(T *v, size_t num)
167 {
168 static_assert(std::is_fundamental<T>::value, "T must be a fundamental type.");
169
170 angle::CheckedNumeric<size_t> checkedLength(num);
171 checkedLength *= sizeof(T);
172 if (!checkedLength.IsValid())
173 {
174 mError = true;
175 return;
176 }
177
178 angle::CheckedNumeric<size_t> checkedOffset(mOffset);
179 checkedOffset += checkedLength;
180
181 if (!checkedOffset.IsValid() || checkedOffset.ValueOrDie() > mLength)
182 {
183 mError = true;
184 return;
185 }
186
187 memcpy(v, mData + mOffset, checkedLength.ValueOrDie());
188 mOffset = checkedOffset.ValueOrDie();
189 }
190
191 template <typename T>
read(T * v)192 void read(T *v)
193 {
194 read(v, 1);
195 }
196 };
197
198 class BinaryOutputStream : angle::NonCopyable
199 {
200 public:
201 BinaryOutputStream();
202 ~BinaryOutputStream();
203
204 // writeInt also handles bool types
205 template <class IntT>
writeInt(IntT param)206 void writeInt(IntT param)
207 {
208 static_assert(std::is_integral<IntT>::value, "Not an integral type");
209 static_assert(!std::is_same<bool, std::remove_cv<IntT>()>(), "Use writeBool");
210 using PromotedIntT = typename PromotedIntegerType<IntT>::type;
211 ASSERT(angle::IsValueInRangeForNumericType<PromotedIntT>(param));
212 PromotedIntT intValue = static_cast<PromotedIntT>(param);
213 write(&intValue, 1);
214 }
215
216 // Specialized writeInt for values that can also be exactly -1.
217 template <class UintT>
writeIntOrNegOne(UintT param)218 void writeIntOrNegOne(UintT param)
219 {
220 if (param == static_cast<UintT>(-1))
221 {
222 writeInt(-1);
223 }
224 else
225 {
226 writeInt(param);
227 }
228 }
229
230 template <class IntT>
writeIntVector(const std::vector<IntT> & param)231 void writeIntVector(const std::vector<IntT> ¶m)
232 {
233 writeInt(param.size());
234 for (IntT element : param)
235 {
236 writeIntOrNegOne(element);
237 }
238 }
239
240 template <class EnumT>
writeEnum(EnumT param)241 void writeEnum(EnumT param)
242 {
243 using UnderlyingType = typename std::underlying_type<EnumT>::type;
244 writeInt<UnderlyingType>(static_cast<UnderlyingType>(param));
245 }
246
writeString(const std::string & v)247 void writeString(const std::string &v)
248 {
249 writeInt(v.length());
250 write(v.c_str(), v.length());
251 }
252
writeString(const char * v)253 void writeString(const char *v)
254 {
255 size_t len = strlen(v);
256 writeInt(len);
257 write(v, len);
258 }
259
writeBytes(const unsigned char * bytes,size_t count)260 void writeBytes(const unsigned char *bytes, size_t count) { write(bytes, count); }
261
writeBool(bool value)262 void writeBool(bool value)
263 {
264 int intValue = value ? 1 : 0;
265 write(&intValue, 1);
266 }
267
writeFloat(float value)268 void writeFloat(float value) { write(&value, 1); }
269
length()270 size_t length() const { return mData.size(); }
271
data()272 const void *data() const { return mData.size() ? &mData[0] : nullptr; }
273
getData()274 const std::vector<uint8_t> &getData() const { return mData; }
275
276 private:
277 template <typename T>
write(const T * v,size_t num)278 void write(const T *v, size_t num)
279 {
280 static_assert(std::is_fundamental<T>::value, "T must be a fundamental type.");
281 const char *asBytes = reinterpret_cast<const char *>(v);
282 mData.insert(mData.end(), asBytes, asBytes + num * sizeof(T));
283 }
284
285 std::vector<uint8_t> mData;
286 };
287
BinaryOutputStream()288 inline BinaryOutputStream::BinaryOutputStream() {}
289
290 inline BinaryOutputStream::~BinaryOutputStream() = default;
291
292 } // namespace gl
293
294 #endif // COMMON_BINARYSTREAM_H_
295