• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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> &param)
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