// // Copyright (c) 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 "common/angleutils.h" #include "common/mathutil.h" #include #include #include #include template void StaticAssertIsFundamental() { // c++11 STL is not available on OSX or Android #if !defined(ANGLE_PLATFORM_APPLE) && !defined(ANGLE_PLATFORM_ANDROID) static_assert(std::is_fundamental::value, "T must be a fundamental type."); #else union { T dummy; } dummy; static_cast(dummy); #endif } namespace gl { 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() { int value = 0; read(&value); return static_cast(value); } template void readInt(IntT *outValue) { *outValue = readInt(); } 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; } if (!rx::IsUnsignedAdditionSafe(mOffset, length) || mOffset + length > mLength) { mError = true; return; } v->assign(reinterpret_cast(mData) + mOffset, length); mOffset += length; } void skip(size_t length) { if (!rx::IsUnsignedAdditionSafe(mOffset, length) || mOffset + length > mLength) { mError = true; return; } mOffset += length; } size_t offset() const { return 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) { StaticAssertIsFundamental(); if (!rx::IsUnsignedMultiplicationSafe(num, sizeof(T))) { mError = true; return; } size_t length = num * sizeof(T); if (!rx::IsUnsignedAdditionSafe(mOffset, length) || mOffset + length > mLength) { mError = true; return; } memcpy(v, mData + mOffset, length); mOffset += length; } template void read(T *v) { read(v, 1); } }; class BinaryOutputStream : angle::NonCopyable { public: BinaryOutputStream() { } // writeInt also handles bool types template void writeInt(IntT param) { ASSERT(rx::IsIntegerCastSafe(param)); int intValue = static_cast(param); write(&intValue, 1); } 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); } size_t length() const { return mData.size(); } const void* data() const { return mData.size() ? &mData[0] : NULL; } private: std::vector mData; template void write(const T *v, size_t num) { StaticAssertIsFundamental(); const char *asBytes = reinterpret_cast(v); mData.insert(mData.end(), asBytes, asBytes + num * sizeof(T)); } }; } #endif // LIBANGLE_BINARYSTREAM_H_