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 ASSERT(angle::IsValueInRangeForNumericType<int>(param));
190 int intValue = static_cast<int>(param);
191 write(&intValue, 1);
192 }
193
194 // Specialized writeInt for values that can also be exactly -1.
195 template <class UintT>
writeIntOrNegOne(UintT param)196 void writeIntOrNegOne(UintT param)
197 {
198 if (param == static_cast<UintT>(-1))
199 {
200 writeInt(-1);
201 }
202 else
203 {
204 writeInt(param);
205 }
206 }
207
208 template <class IntT>
writeIntVector(std::vector<IntT> param)209 void writeIntVector(std::vector<IntT> param)
210 {
211 writeInt(param.size());
212 for (IntT element : param)
213 {
214 writeIntOrNegOne(element);
215 }
216 }
217
218 template <class EnumT>
writeEnum(EnumT param)219 void writeEnum(EnumT param)
220 {
221 using UnderlyingType = typename std::underlying_type<EnumT>::type;
222 writeInt<UnderlyingType>(static_cast<UnderlyingType>(param));
223 }
224
writeString(const std::string & v)225 void writeString(const std::string &v)
226 {
227 writeInt(v.length());
228 write(v.c_str(), v.length());
229 }
230
writeBytes(const unsigned char * bytes,size_t count)231 void writeBytes(const unsigned char *bytes, size_t count) { write(bytes, count); }
232
length()233 size_t length() const { return mData.size(); }
234
data()235 const void *data() const { return mData.size() ? &mData[0] : nullptr; }
236
237 private:
238 std::vector<char> mData;
239
240 template <typename T>
write(const T * v,size_t num)241 void write(const T *v, size_t num)
242 {
243 static_assert(std::is_fundamental<T>::value, "T must be a fundamental type.");
244 const char *asBytes = reinterpret_cast<const char *>(v);
245 mData.insert(mData.end(), asBytes, asBytes + num * sizeof(T));
246 }
247 };
248
BinaryOutputStream()249 inline BinaryOutputStream::BinaryOutputStream() {}
250
251 inline BinaryOutputStream::~BinaryOutputStream() = default;
252
253 } // namespace gl
254
255 #endif // LIBANGLE_BINARYSTREAM_H_
256