BinaryStream.h (7139B)
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: 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> 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> 55 void readInt(IntT *outValue) 56 { 57 *outValue = readInt<IntT>(); 58 } 59 60 template <class IntT, class VectorElementT> 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> 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> 78 void readEnum(EnumT *outValue) 79 { 80 *outValue = readEnum<EnumT>(); 81 } 82 83 bool readBool() 84 { 85 int value = 0; 86 read(&value); 87 return (value > 0); 88 } 89 90 void readBool(bool *outValue) { *outValue = readBool(); } 91 92 void readBytes(unsigned char outArray[], size_t count) { read<unsigned char>(outArray, count); } 93 94 std::string readString() 95 { 96 std::string outString; 97 readString(&outString); 98 return outString; 99 } 100 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 124 float readFloat() 125 { 126 float f; 127 read(&f, 1); 128 return f; 129 } 130 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 145 size_t offset() const { return mOffset; } 146 size_t remainingSize() const 147 { 148 ASSERT(mLength >= mOffset); 149 return mLength - mOffset; 150 } 151 152 bool error() const { return mError; } 153 154 bool endOfStream() const { return mOffset == mLength; } 155 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> 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> 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> 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> 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> 230 void writeIntVector(const std::vector<IntT> ¶m) 231 { 232 writeInt(param.size()); 233 for (IntT element : param) 234 { 235 writeIntOrNegOne(element); 236 } 237 } 238 239 template <class EnumT> 240 void writeEnum(EnumT param) 241 { 242 using UnderlyingType = typename std::underlying_type<EnumT>::type; 243 writeInt<UnderlyingType>(static_cast<UnderlyingType>(param)); 244 } 245 246 void writeString(const std::string &v) 247 { 248 writeInt(v.length()); 249 write(v.c_str(), v.length()); 250 } 251 252 void writeBytes(const unsigned char *bytes, size_t count) { write(bytes, count); } 253 254 void writeBool(bool value) 255 { 256 int intValue = value ? 1 : 0; 257 write(&intValue, 1); 258 } 259 260 void writeFloat(float value) { write(&value, 1); } 261 262 size_t length() const { return mData.size(); } 263 264 const void *data() const { return mData.size() ? &mData[0] : nullptr; } 265 266 const std::vector<uint8_t> &getData() const { return mData; } 267 268 private: 269 template <typename T> 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 280 inline BinaryOutputStream::BinaryOutputStream() {} 281 282 inline BinaryOutputStream::~BinaryOutputStream() = default; 283 284 } // namespace gl 285 286 #endif // LIBANGLE_BINARYSTREAM_H_