xref: /aosp_15_r20/external/angle/src/common/BinaryStream.h (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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/PackedEnums.h"
18 #include "common/angleutils.h"
19 #include "common/mathutil.h"
20 
21 namespace gl
22 {
23 template <typename IntT>
24 struct PromotedIntegerType
25 {
26     using type = typename std::conditional<
27         std::is_signed<IntT>::value,
28         typename std::conditional<sizeof(IntT) <= 4, int32_t, int64_t>::type,
29         typename std::conditional<sizeof(IntT) <= 4, uint32_t, uint64_t>::type>::type;
30 };
31 
32 class BinaryInputStream : angle::NonCopyable
33 {
34   public:
BinaryInputStream(const void * data,size_t length)35     BinaryInputStream(const void *data, size_t length)
36     {
37         mError  = false;
38         mOffset = 0;
39         mData   = static_cast<const uint8_t *>(data);
40         mLength = length;
41     }
42 
43     // readInt will generate an error for bool types
44     template <class IntT>
readInt()45     IntT readInt()
46     {
47         static_assert(!std::is_same<bool, std::remove_cv<IntT>()>(), "Use readBool");
48         using PromotedIntT = typename PromotedIntegerType<IntT>::type;
49         PromotedIntT value = 0;
50         read(&value);
51         ASSERT(angle::IsValueInRangeForNumericType<IntT>(value));
52         return static_cast<IntT>(value);
53     }
54 
55     template <class IntT>
readInt(IntT * outValue)56     void readInt(IntT *outValue)
57     {
58         *outValue = readInt<IntT>();
59     }
60 
61     template <class T>
readVector(std::vector<T> * param)62     void readVector(std::vector<T> *param)
63     {
64         static_assert(std::is_trivially_copyable<T>(), "must be memcpy-able");
65         ASSERT(param->empty());
66         size_t size = readInt<size_t>();
67         if (size > 0)
68         {
69             param->resize(size);
70             readBytes(reinterpret_cast<uint8_t *>(param->data()), param->size() * sizeof(T));
71         }
72     }
73 
74     template <typename E, typename T>
readPackedEnumMap(angle::PackedEnumMap<E,T> * param)75     void readPackedEnumMap(angle::PackedEnumMap<E, T> *param)
76     {
77         static_assert(std::is_trivially_copyable<T>(), "must be memcpy-able");
78         readBytes(reinterpret_cast<uint8_t *>(param->data()), param->size() * sizeof(T));
79     }
80 
81     template <class T>
readStruct(T * param)82     void readStruct(T *param)
83     {
84         static_assert(std::is_trivially_copyable<T>(), "must be memcpy-able");
85         readBytes(reinterpret_cast<uint8_t *>(param), sizeof(T));
86     }
87 
88     template <class EnumT>
readEnum()89     EnumT readEnum()
90     {
91         using UnderlyingType = typename std::underlying_type<EnumT>::type;
92         return static_cast<EnumT>(readInt<UnderlyingType>());
93     }
94 
95     template <class EnumT>
readEnum(EnumT * outValue)96     void readEnum(EnumT *outValue)
97     {
98         *outValue = readEnum<EnumT>();
99     }
100 
readBool()101     bool readBool()
102     {
103         int value = 0;
104         read(&value);
105         return (value > 0);
106     }
107 
readBool(bool * outValue)108     void readBool(bool *outValue) { *outValue = readBool(); }
109 
readBytes(unsigned char outArray[],size_t count)110     void readBytes(unsigned char outArray[], size_t count) { read<unsigned char>(outArray, count); }
getBytes(size_t count)111     const unsigned char *getBytes(size_t count) { return read<unsigned char>(nullptr, count); }
112 
readString()113     std::string readString()
114     {
115         std::string outString;
116         readString(&outString);
117         return outString;
118     }
119 
readString(std::string * v)120     void readString(std::string *v)
121     {
122         size_t length;
123         readInt(&length);
124 
125         if (mError)
126         {
127             return;
128         }
129 
130         angle::CheckedNumeric<size_t> checkedOffset(mOffset);
131         checkedOffset += length;
132 
133         if (!checkedOffset.IsValid() || mOffset + length > mLength)
134         {
135             mError = true;
136             return;
137         }
138 
139         v->assign(reinterpret_cast<const char *>(mData) + mOffset, length);
140         mOffset = checkedOffset.ValueOrDie();
141     }
142 
readFloat()143     float readFloat()
144     {
145         float f;
146         read(&f, 1);
147         return f;
148     }
149 
skip(size_t length)150     void skip(size_t length)
151     {
152         angle::CheckedNumeric<size_t> checkedOffset(mOffset);
153         checkedOffset += length;
154 
155         if (!checkedOffset.IsValid() || mOffset + length > mLength)
156         {
157             mError = true;
158             return;
159         }
160 
161         mOffset = checkedOffset.ValueOrDie();
162     }
163 
offset()164     size_t offset() const { return mOffset; }
remainingSize()165     size_t remainingSize() const
166     {
167         ASSERT(mLength >= mOffset);
168         return mLength - mOffset;
169     }
170 
error()171     bool error() const { return mError; }
172 
endOfStream()173     bool endOfStream() const { return mOffset == mLength; }
174 
data()175     const uint8_t *data() { return mData; }
176 
177   private:
178     bool mError;
179     size_t mOffset;
180     const uint8_t *mData;
181     size_t mLength;
182 
183     template <typename T>
read(T * v,size_t num)184     const uint8_t *read(T *v, size_t num)
185     {
186         static_assert(std::is_fundamental<T>::value, "T must be a fundamental type.");
187 
188         angle::CheckedNumeric<size_t> checkedLength(num);
189         checkedLength *= sizeof(T);
190         if (!checkedLength.IsValid())
191         {
192             mError = true;
193             return nullptr;
194         }
195 
196         angle::CheckedNumeric<size_t> checkedOffset(mOffset);
197         checkedOffset += checkedLength;
198 
199         if (!checkedOffset.IsValid() || checkedOffset.ValueOrDie() > mLength)
200         {
201             mError = true;
202             return nullptr;
203         }
204 
205         const uint8_t *srcBytes = mData + mOffset;
206         if (v != nullptr)
207         {
208             memcpy(v, srcBytes, checkedLength.ValueOrDie());
209         }
210         mOffset = checkedOffset.ValueOrDie();
211 
212         return srcBytes;
213     }
214 
215     template <typename T>
read(T * v)216     void read(T *v)
217     {
218         read(v, 1);
219     }
220 };
221 
222 class BinaryOutputStream : angle::NonCopyable
223 {
224   public:
225     BinaryOutputStream();
226     ~BinaryOutputStream();
227 
228     // writeInt also handles bool types
229     template <class IntT>
writeInt(IntT param)230     void writeInt(IntT param)
231     {
232         static_assert(std::is_integral<IntT>::value, "Not an integral type");
233         static_assert(!std::is_same<bool, std::remove_cv<IntT>()>(), "Use writeBool");
234         using PromotedIntT = typename PromotedIntegerType<IntT>::type;
235         ASSERT(angle::IsValueInRangeForNumericType<PromotedIntT>(param));
236         PromotedIntT intValue = static_cast<PromotedIntT>(param);
237         write(&intValue, 1);
238     }
239 
240     // Specialized writeInt for values that can also be exactly -1.
241     template <class UintT>
writeIntOrNegOne(UintT param)242     void writeIntOrNegOne(UintT param)
243     {
244         if (param == static_cast<UintT>(-1))
245         {
246             writeInt(-1);
247         }
248         else
249         {
250             writeInt(param);
251         }
252     }
253 
254     template <class T>
writeVector(const std::vector<T> & param)255     void writeVector(const std::vector<T> &param)
256     {
257         static_assert(std::is_trivially_copyable<T>(), "must be memcpy-able");
258         writeInt(param.size());
259         if (param.size() > 0)
260         {
261             writeBytes(reinterpret_cast<const uint8_t *>(param.data()), param.size() * sizeof(T));
262         }
263     }
264 
265     template <typename E, typename T>
writePackedEnumMap(const angle::PackedEnumMap<E,T> & param)266     void writePackedEnumMap(const angle::PackedEnumMap<E, T> &param)
267     {
268         static_assert(std::is_trivially_copyable<T>(), "must be memcpy-able");
269         writeBytes(reinterpret_cast<const uint8_t *>(param.data()), param.size() * sizeof(T));
270     }
271 
272     template <class T>
writeStruct(const T & param)273     void writeStruct(const T &param)
274     {
275         static_assert(!std::is_pointer<T>::value,
276                       "Must pass in a struct, not the pointer to struct");
277         static_assert(std::is_trivially_copyable<T>(), "must be memcpy-able");
278         writeBytes(reinterpret_cast<const uint8_t *>(&param), sizeof(T));
279     }
280 
281     template <class EnumT>
writeEnum(EnumT param)282     void writeEnum(EnumT param)
283     {
284         using UnderlyingType = typename std::underlying_type<EnumT>::type;
285         writeInt<UnderlyingType>(static_cast<UnderlyingType>(param));
286     }
287 
writeString(const std::string & v)288     void writeString(const std::string &v)
289     {
290         writeInt(v.length());
291         write(v.c_str(), v.length());
292     }
293 
writeString(const char * v)294     void writeString(const char *v)
295     {
296         size_t len = strlen(v);
297         writeInt(len);
298         write(v, len);
299     }
300 
writeBytes(const unsigned char * bytes,size_t count)301     void writeBytes(const unsigned char *bytes, size_t count) { write(bytes, count); }
302 
writeBool(bool value)303     void writeBool(bool value)
304     {
305         int intValue = value ? 1 : 0;
306         write(&intValue, 1);
307     }
308 
writeFloat(float value)309     void writeFloat(float value) { write(&value, 1); }
310 
length()311     size_t length() const { return mData.size(); }
312 
data()313     const void *data() const { return mData.size() ? &mData[0] : nullptr; }
314 
getData()315     const std::vector<uint8_t> &getData() const { return mData; }
316 
317   private:
318     template <typename T>
write(const T * v,size_t num)319     void write(const T *v, size_t num)
320     {
321         static_assert(std::is_fundamental<T>::value, "T must be a fundamental type.");
322         const char *asBytes = reinterpret_cast<const char *>(v);
323         mData.insert(mData.end(), asBytes, asBytes + num * sizeof(T));
324     }
325 
326     std::vector<uint8_t> mData;
327 };
328 
BinaryOutputStream()329 inline BinaryOutputStream::BinaryOutputStream() {}
330 
331 inline BinaryOutputStream::~BinaryOutputStream() = default;
332 
333 }  // namespace gl
334 
335 #endif  // COMMON_BINARYSTREAM_H_
336