// // Copyright 2012 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // BinaryStream.h: Provides binary serialization of simple types. #ifndef LIBANGLE_BINARYSTREAM_H_ #define LIBANGLE_BINARYSTREAM_H_ #include #include #include #include #include "common/angleutils.h" #include "common/mathutil.h" namespace gl { template struct PromotedIntegerType { using type = typename std::conditional< std::is_signed::value, typename std::conditional::type, typename std::conditional::type>::type; }; class BinaryInputStream : angle::NonCopyable { public: BinaryInputStream(const void *data, size_t length) { mError = false; mOffset = 0; mData = static_cast(data); mLength = length; } // readInt will generate an error for bool types template IntT readInt() { static_assert(!std::is_same()>(), "Use readBool"); using PromotedIntT = typename PromotedIntegerType::type; PromotedIntT value = 0; read(&value); ASSERT(angle::IsValueInRangeForNumericType(value)); return static_cast(value); } template void readInt(IntT *outValue) { *outValue = readInt(); } template void readIntVector(std::vector *param) { size_t size = readInt(); for (size_t index = 0; index < size; ++index) { param->push_back(readInt()); } } template EnumT readEnum() { using UnderlyingType = typename std::underlying_type::type; return static_cast(readInt()); } template void readEnum(EnumT *outValue) { *outValue = readEnum(); } bool readBool() { int value = 0; read(&value); return (value > 0); } void readBool(bool *outValue) { *outValue = readBool(); } void readBytes(unsigned char outArray[], size_t count) { read(outArray, count); } std::string readString() { std::string outString; readString(&outString); return outString; } void readString(std::string *v) { size_t length; readInt(&length); if (mError) { return; } angle::CheckedNumeric checkedOffset(mOffset); checkedOffset += length; if (!checkedOffset.IsValid() || mOffset + length > mLength) { mError = true; return; } v->assign(reinterpret_cast(mData) + mOffset, length); mOffset = checkedOffset.ValueOrDie(); } float readFloat() { float f; read(&f, 1); return f; } void skip(size_t length) { angle::CheckedNumeric checkedOffset(mOffset); checkedOffset += length; if (!checkedOffset.IsValid() || mOffset + length > mLength) { mError = true; return; } mOffset = checkedOffset.ValueOrDie(); } size_t offset() const { return mOffset; } size_t remainingSize() const { ASSERT(mLength >= mOffset); return mLength - mOffset; } bool error() const { return mError; } bool endOfStream() const { return mOffset == mLength; } const uint8_t *data() { return mData; } private: bool mError; size_t mOffset; const uint8_t *mData; size_t mLength; template void read(T *v, size_t num) { static_assert(std::is_fundamental::value, "T must be a fundamental type."); angle::CheckedNumeric checkedLength(num); checkedLength *= sizeof(T); if (!checkedLength.IsValid()) { mError = true; return; } angle::CheckedNumeric checkedOffset(mOffset); checkedOffset += checkedLength; if (!checkedOffset.IsValid() || checkedOffset.ValueOrDie() > mLength) { mError = true; return; } memcpy(v, mData + mOffset, checkedLength.ValueOrDie()); mOffset = checkedOffset.ValueOrDie(); } template void read(T *v) { read(v, 1); } }; class BinaryOutputStream : angle::NonCopyable { public: BinaryOutputStream(); ~BinaryOutputStream(); // writeInt also handles bool types template void writeInt(IntT param) { static_assert(std::is_integral::value, "Not an integral type"); static_assert(!std::is_same()>(), "Use writeBool"); using PromotedIntT = typename PromotedIntegerType::type; ASSERT(angle::IsValueInRangeForNumericType(param)); PromotedIntT intValue = static_cast(param); write(&intValue, 1); } // Specialized writeInt for values that can also be exactly -1. template void writeIntOrNegOne(UintT param) { if (param == static_cast(-1)) { writeInt(-1); } else { writeInt(param); } } template void writeIntVector(const std::vector ¶m) { writeInt(param.size()); for (IntT element : param) { writeIntOrNegOne(element); } } template void writeEnum(EnumT param) { using UnderlyingType = typename std::underlying_type::type; writeInt(static_cast(param)); } void writeString(const std::string &v) { writeInt(v.length()); write(v.c_str(), v.length()); } void writeBytes(const unsigned char *bytes, size_t count) { write(bytes, count); } void writeBool(bool value) { int intValue = value ? 1 : 0; write(&intValue, 1); } void writeFloat(float value) { write(&value, 1); } size_t length() const { return mData.size(); } const void *data() const { return mData.size() ? &mData[0] : nullptr; } const std::vector &getData() const { return mData; } private: template void write(const T *v, size_t num) { static_assert(std::is_fundamental::value, "T must be a fundamental type."); const char *asBytes = reinterpret_cast(v); mData.insert(mData.end(), asBytes, asBytes + num * sizeof(T)); } std::vector mData; }; inline BinaryOutputStream::BinaryOutputStream() {} inline BinaryOutputStream::~BinaryOutputStream() = default; } // namespace gl #endif // LIBANGLE_BINARYSTREAM_H_