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