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