• 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 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> &param)
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