|  | /* | 
|  | *  Copyright (c) 2013 The WebRTC 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 in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | #ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_BYTE_IO_H_ | 
|  | #define WEBRTC_MODULES_RTP_RTCP_SOURCE_BYTE_IO_H_ | 
|  |  | 
|  |  | 
|  | // This file contains classes for reading and writing integer types from/to | 
|  | // byte array representations. Signed/unsigned, partial (whole byte) sizes, | 
|  | // and big/little endian byte order is all supported. | 
|  | // | 
|  | // Usage examples: | 
|  | // | 
|  | // uint8_t* buffer = ...; | 
|  | // | 
|  | // // Read an unsigned 4 byte integer in big endian format | 
|  | // uint32_t val = ByteReader<uint32_t>::ReadBigEndian(buffer); | 
|  | // | 
|  | // // Read a signed 24-bit (3 byte) integer in little endian format | 
|  | // int32_t val = ByteReader<int32_t, 3>::ReadLittle(buffer); | 
|  | // | 
|  | // // Write an unsigned 8 byte integer in little endian format | 
|  | // ByteWriter<uint64_t>::WriteLittleEndian(buffer, val); | 
|  | // | 
|  | // Write an unsigned 40-bit (5 byte) integer in big endian format | 
|  | // ByteWriter<uint64_t, 5>::WriteBigEndian(buffer, val); | 
|  | // | 
|  | // These classes are implemented as recursive templetizations, inteded to make | 
|  | // it easy for the compiler to completely inline the reading/writing. | 
|  |  | 
|  |  | 
|  | #include <limits> | 
|  |  | 
|  | #include "webrtc/typedefs.h" | 
|  |  | 
|  | namespace webrtc { | 
|  |  | 
|  | // According to ISO C standard ISO/IEC 9899, section 6.2.6.2 (2), the three | 
|  | // representations of signed integers allowed are two's complement, one's | 
|  | // complement and sign/magnitude. We can detect which is used by looking at | 
|  | // the two last bits of -1, which will be 11 in two's complement, 10 in one's | 
|  | // complement and 01 in sign/magnitude. | 
|  | // TODO(sprang): In the unlikely event that we actually need to support a | 
|  | // platform that doesn't use two's complement, implement conversion to/from | 
|  | // wire format. | 
|  |  | 
|  | namespace { | 
|  | inline void AssertTwosComplement() { | 
|  | // Assume the if any one signed integer type is two's complement, then all | 
|  | // other will be too. | 
|  | static_assert( | 
|  | (-1 & 0x03) == 0x03, | 
|  | "Only two's complement representation of signed integers supported."); | 
|  | } | 
|  | // Plain const char* won't work for static_assert, use #define instead. | 
|  | #define kSizeErrorMsg "Byte size must be less than or equal to data type size." | 
|  | } | 
|  |  | 
|  | // Utility class for getting the unsigned equivalent of a signed type. | 
|  | template <typename T> | 
|  | struct UnsignedOf; | 
|  |  | 
|  | // Class for reading integers from a sequence of bytes. | 
|  | // T = type of integer, B = bytes to read, is_signed = true if signed integer. | 
|  | // If is_signed is true and B < sizeof(T), sign extension might be needed. | 
|  | template <typename T, | 
|  | unsigned int B = sizeof(T), | 
|  | bool is_signed = std::numeric_limits<T>::is_signed> | 
|  | class ByteReader; | 
|  |  | 
|  | // Specialization of ByteReader for unsigned types. | 
|  | template <typename T, unsigned int B> | 
|  | class ByteReader<T, B, false> { | 
|  | public: | 
|  | static T ReadBigEndian(const uint8_t* data) { | 
|  | static_assert(B <= sizeof(T), kSizeErrorMsg); | 
|  | return InternalReadBigEndian(data); | 
|  | } | 
|  |  | 
|  | static T ReadLittleEndian(const uint8_t* data) { | 
|  | static_assert(B <= sizeof(T), kSizeErrorMsg); | 
|  | return InternalReadLittleEndian(data); | 
|  | } | 
|  |  | 
|  | private: | 
|  | static T InternalReadBigEndian(const uint8_t* data) { | 
|  | T val(0); | 
|  | for (unsigned int i = 0; i < B; ++i) | 
|  | val |= static_cast<T>(data[i]) << ((B - 1 - i) * 8); | 
|  | return val; | 
|  | } | 
|  |  | 
|  | static T InternalReadLittleEndian(const uint8_t* data) { | 
|  | T val(0); | 
|  | for (unsigned int i = 0; i < B; ++i) | 
|  | val |= static_cast<T>(data[i]) << (i * 8); | 
|  | return val; | 
|  | } | 
|  | }; | 
|  |  | 
|  | // Specialization of ByteReader for signed types. | 
|  | template <typename T, unsigned int B> | 
|  | class ByteReader<T, B, true> { | 
|  | public: | 
|  | typedef typename UnsignedOf<T>::Type U; | 
|  |  | 
|  | static T ReadBigEndian(const uint8_t* data) { | 
|  | U unsigned_val = ByteReader<T, B, false>::ReadBigEndian(data); | 
|  | if (B < sizeof(T)) | 
|  | unsigned_val = SignExtend(unsigned_val); | 
|  | return ReinterpretAsSigned(unsigned_val); | 
|  | } | 
|  |  | 
|  | static T ReadLittleEndian(const uint8_t* data) { | 
|  | U unsigned_val = ByteReader<T, B, false>::ReadLittleEndian(data); | 
|  | if (B < sizeof(T)) | 
|  | unsigned_val = SignExtend(unsigned_val); | 
|  | return ReinterpretAsSigned(unsigned_val); | 
|  | } | 
|  |  | 
|  | private: | 
|  | // As a hack to avoid implementation-specific or undefined behavior when | 
|  | // bit-shifting or casting signed integers, read as a signed equivalent | 
|  | // instead and convert to signed. This is safe since we have asserted that | 
|  | // two's complement for is used. | 
|  | static T ReinterpretAsSigned(U unsigned_val) { | 
|  | // An unsigned value with only the highest order bit set (ex 0x80). | 
|  | const U kUnsignedHighestBitMask = | 
|  | static_cast<U>(1) << ((sizeof(U) * 8) - 1); | 
|  | // A signed value with only the highest bit set. Since this is two's | 
|  | // complement form, we can use the min value from std::numeric_limits. | 
|  | const T kSignedHighestBitMask = std::numeric_limits<T>::min(); | 
|  |  | 
|  | T val; | 
|  | if ((unsigned_val & kUnsignedHighestBitMask) != 0) { | 
|  | // Casting is only safe when unsigned value can be represented in the | 
|  | // signed target type, so mask out highest bit and mask it back manually. | 
|  | val = static_cast<T>(unsigned_val & ~kUnsignedHighestBitMask); | 
|  | val |= kSignedHighestBitMask; | 
|  | } else { | 
|  | val = static_cast<T>(unsigned_val); | 
|  | } | 
|  | return val; | 
|  | } | 
|  |  | 
|  | // If number of bytes is less than native data type (eg 24 bit, in int32_t), | 
|  | // and the most significant bit of the actual data is set, we must sign | 
|  | // extend the remaining byte(s) with ones so that the correct negative | 
|  | // number is retained. | 
|  | // Ex: 0x810A0B -> 0xFF810A0B, but 0x710A0B -> 0x00710A0B | 
|  | static U SignExtend(const U val) { | 
|  | const uint8_t kMsb = static_cast<uint8_t>(val >> ((B - 1) * 8)); | 
|  | if ((kMsb & 0x80) != 0) { | 
|  | // Create a mask where all bits used by the B bytes are set to one, | 
|  | // for instance 0x00FFFFFF for B = 3. Bit-wise invert that mask (to | 
|  | // (0xFF000000 in the example above) and add it to the input value. | 
|  | // The "B % sizeof(T)" is a workaround to undefined values warnings for | 
|  | // B == sizeof(T), in which case this code won't be called anyway. | 
|  | const U kUsedBitsMask = (1 << ((B % sizeof(T)) * 8)) - 1; | 
|  | return ~kUsedBitsMask | val; | 
|  | } | 
|  | return val; | 
|  | } | 
|  | }; | 
|  |  | 
|  | // Class for writing integers to a sequence of bytes | 
|  | // T = type of integer, B = bytes to write | 
|  | template <typename T, | 
|  | unsigned int B = sizeof(T), | 
|  | bool is_signed = std::numeric_limits<T>::is_signed> | 
|  | class ByteWriter; | 
|  |  | 
|  | // Specialization of ByteWriter for unsigned types. | 
|  | template <typename T, unsigned int B> | 
|  | class ByteWriter<T, B, false> { | 
|  | public: | 
|  | static void WriteBigEndian(uint8_t* data, T val) { | 
|  | static_assert(B <= sizeof(T), kSizeErrorMsg); | 
|  | for (unsigned int i = 0; i < B; ++i) { | 
|  | data[i] = val >> ((B - 1 - i) * 8); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void WriteLittleEndian(uint8_t* data, T val) { | 
|  | static_assert(B <= sizeof(T), kSizeErrorMsg); | 
|  | for (unsigned int i = 0; i < B; ++i) { | 
|  | data[i] = val >> (i * 8); | 
|  | } | 
|  | } | 
|  | }; | 
|  |  | 
|  | // Specialization of ByteWriter for signed types. | 
|  | template <typename T, unsigned int B> | 
|  | class ByteWriter<T, B, true> { | 
|  | public: | 
|  | typedef typename UnsignedOf<T>::Type U; | 
|  |  | 
|  | static void WriteBigEndian(uint8_t* data, T val) { | 
|  | ByteWriter<U, B, false>::WriteBigEndian(data, ReinterpretAsUnsigned(val)); | 
|  | } | 
|  |  | 
|  | static void WriteLittleEndian(uint8_t* data, T val) { | 
|  | ByteWriter<U, B, false>::WriteLittleEndian(data, | 
|  | ReinterpretAsUnsigned(val)); | 
|  | } | 
|  |  | 
|  | private: | 
|  | static U ReinterpretAsUnsigned(T val) { | 
|  | // According to ISO C standard ISO/IEC 9899, section 6.3.1.3 (1, 2) a | 
|  | // conversion from signed to unsigned keeps the value if the new type can | 
|  | // represent it, and otherwise adds one more than the max value of T until | 
|  | // the value is in range. For two's complement, this fortunately means | 
|  | // that the bit-wise value will be intact. Thus, since we have asserted that | 
|  | // two's complement form is actually used, a simple cast is sufficient. | 
|  | return static_cast<U>(val); | 
|  | } | 
|  | }; | 
|  |  | 
|  | // ----- Below follows specializations of UnsignedOf utility class ----- | 
|  |  | 
|  | template <> | 
|  | struct UnsignedOf<int8_t> { | 
|  | typedef uint8_t Type; | 
|  | }; | 
|  | template <> | 
|  | struct UnsignedOf<int16_t> { | 
|  | typedef uint16_t Type; | 
|  | }; | 
|  | template <> | 
|  | struct UnsignedOf<int32_t> { | 
|  | typedef uint32_t Type; | 
|  | }; | 
|  | template <> | 
|  | struct UnsignedOf<int64_t> { | 
|  | typedef uint64_t Type; | 
|  | }; | 
|  |  | 
|  | // ----- Below follows specializations for unsigned, B in { 1, 2, 4, 8 } ----- | 
|  |  | 
|  | // TODO(sprang): Check if these actually help or if generic cases will be | 
|  | // unrolled to and optimized to similar performance. | 
|  |  | 
|  | // Specializations for single bytes | 
|  | template <typename T> | 
|  | class ByteReader<T, 1, false> { | 
|  | public: | 
|  | static T ReadBigEndian(const uint8_t* data) { | 
|  | static_assert(sizeof(T) == 1, kSizeErrorMsg); | 
|  | return data[0]; | 
|  | } | 
|  |  | 
|  | static T ReadLittleEndian(const uint8_t* data) { | 
|  | static_assert(sizeof(T) == 1, kSizeErrorMsg); | 
|  | return data[0]; | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <typename T> | 
|  | class ByteWriter<T, 1, false> { | 
|  | public: | 
|  | static void WriteBigEndian(uint8_t* data, T val) { | 
|  | static_assert(sizeof(T) == 1, kSizeErrorMsg); | 
|  | data[0] = val; | 
|  | } | 
|  |  | 
|  | static void WriteLittleEndian(uint8_t* data, T val) { | 
|  | static_assert(sizeof(T) == 1, kSizeErrorMsg); | 
|  | data[0] = val; | 
|  | } | 
|  | }; | 
|  |  | 
|  | // Specializations for two byte words | 
|  | template <typename T> | 
|  | class ByteReader<T, 2, false> { | 
|  | public: | 
|  | static T ReadBigEndian(const uint8_t* data) { | 
|  | static_assert(sizeof(T) >= 2, kSizeErrorMsg); | 
|  | return (data[0] << 8) | data[1]; | 
|  | } | 
|  |  | 
|  | static T ReadLittleEndian(const uint8_t* data) { | 
|  | static_assert(sizeof(T) >= 2, kSizeErrorMsg); | 
|  | return data[0] | (data[1] << 8); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <typename T> | 
|  | class ByteWriter<T, 2, false> { | 
|  | public: | 
|  | static void WriteBigEndian(uint8_t* data, T val) { | 
|  | static_assert(sizeof(T) >= 2, kSizeErrorMsg); | 
|  | data[0] = val >> 8; | 
|  | data[1] = val; | 
|  | } | 
|  |  | 
|  | static void WriteLittleEndian(uint8_t* data, T val) { | 
|  | static_assert(sizeof(T) >= 2, kSizeErrorMsg); | 
|  | data[0] = val; | 
|  | data[1] = val >> 8; | 
|  | } | 
|  | }; | 
|  |  | 
|  | // Specializations for four byte words. | 
|  | template <typename T> | 
|  | class ByteReader<T, 4, false> { | 
|  | public: | 
|  | static T ReadBigEndian(const uint8_t* data) { | 
|  | static_assert(sizeof(T) >= 4, kSizeErrorMsg); | 
|  | return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; | 
|  | } | 
|  |  | 
|  | static T ReadLittleEndian(const uint8_t* data) { | 
|  | static_assert(sizeof(T) >= 4, kSizeErrorMsg); | 
|  | return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); | 
|  | } | 
|  | }; | 
|  |  | 
|  | // Specializations for four byte words. | 
|  | template <typename T> | 
|  | class ByteWriter<T, 4, false> { | 
|  | public: | 
|  | static void WriteBigEndian(uint8_t* data, T val) { | 
|  | static_assert(sizeof(T) >= 4, kSizeErrorMsg); | 
|  | data[0] = val >> 24; | 
|  | data[1] = val >> 16; | 
|  | data[2] = val >> 8; | 
|  | data[3] = val; | 
|  | } | 
|  |  | 
|  | static void WriteLittleEndian(uint8_t* data, T val) { | 
|  | static_assert(sizeof(T) >= 4, kSizeErrorMsg); | 
|  | data[0] = val; | 
|  | data[1] = val >> 8; | 
|  | data[2] = val >> 16; | 
|  | data[3] = val >> 24; | 
|  | } | 
|  | }; | 
|  |  | 
|  | // Specializations for eight byte words. | 
|  | template <typename T> | 
|  | class ByteReader<T, 8, false> { | 
|  | public: | 
|  | static T ReadBigEndian(const uint8_t* data) { | 
|  | static_assert(sizeof(T) >= 8, kSizeErrorMsg); | 
|  | return | 
|  | (Get(data, 0) << 56) | (Get(data, 1) << 48) | | 
|  | (Get(data, 2) << 40) | (Get(data, 3) << 32) | | 
|  | (Get(data, 4) << 24) | (Get(data, 5) << 16) | | 
|  | (Get(data, 6) << 8)  |  Get(data, 7); | 
|  | } | 
|  |  | 
|  | static T ReadLittleEndian(const uint8_t* data) { | 
|  | static_assert(sizeof(T) >= 8, kSizeErrorMsg); | 
|  | return | 
|  | Get(data, 0)        | (Get(data, 1) << 8)  | | 
|  | (Get(data, 2) << 16) | (Get(data, 3) << 24) | | 
|  | (Get(data, 4) << 32) | (Get(data, 5) << 40) | | 
|  | (Get(data, 6) << 48) | (Get(data, 7) << 56); | 
|  | } | 
|  |  | 
|  | private: | 
|  | inline static T Get(const uint8_t* data, unsigned int index) { | 
|  | return static_cast<T>(data[index]); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <typename T> | 
|  | class ByteWriter<T, 8, false> { | 
|  | public: | 
|  | static void WriteBigEndian(uint8_t* data, T val) { | 
|  | static_assert(sizeof(T) >= 8, kSizeErrorMsg); | 
|  | data[0] = val >> 56; | 
|  | data[1] = val >> 48; | 
|  | data[2] = val >> 40; | 
|  | data[3] = val >> 32; | 
|  | data[4] = val >> 24; | 
|  | data[5] = val >> 16; | 
|  | data[6] = val >> 8; | 
|  | data[7] = val; | 
|  | } | 
|  |  | 
|  | static void WriteLittleEndian(uint8_t* data, T val) { | 
|  | static_assert(sizeof(T) >= 8, kSizeErrorMsg); | 
|  | data[0] = val; | 
|  | data[1] = val >> 8; | 
|  | data[2] = val >> 16; | 
|  | data[3] = val >> 24; | 
|  | data[4] = val >> 32; | 
|  | data[5] = val >> 40; | 
|  | data[6] = val >> 48; | 
|  | data[7] = val >> 56; | 
|  | } | 
|  | }; | 
|  |  | 
|  | }  // namespace webrtc | 
|  |  | 
|  | #endif  // WEBRTC_MODULES_RTP_RTCP_SOURCE_BYTE_IO_H_ |