Home | History | Annotate | Download | only in source
      1 /*
      2  *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_BYTE_IO_H_
     12 #define WEBRTC_MODULES_RTP_RTCP_SOURCE_BYTE_IO_H_
     13 
     14 
     15 // This file contains classes for reading and writing integer types from/to
     16 // byte array representations. Signed/unsigned, partial (whole byte) sizes,
     17 // and big/little endian byte order is all supported.
     18 //
     19 // Usage examples:
     20 //
     21 // uint8_t* buffer = ...;
     22 //
     23 // // Read an unsigned 4 byte integer in big endian format
     24 // uint32_t val = ByteReader<uint32_t>::ReadBigEndian(buffer);
     25 //
     26 // // Read a signed 24-bit (3 byte) integer in little endian format
     27 // int32_t val = ByteReader<int32_t, 3>::ReadLittle(buffer);
     28 //
     29 // // Write an unsigned 8 byte integer in little endian format
     30 // ByteWriter<uint64_t>::WriteLittleEndian(buffer, val);
     31 //
     32 // Write an unsigned 40-bit (5 byte) integer in big endian format
     33 // ByteWriter<uint64_t, 5>::WriteBigEndian(buffer, val);
     34 //
     35 // These classes are implemented as recursive templetizations, inteded to make
     36 // it easy for the compiler to completely inline the reading/writing.
     37 
     38 
     39 #include <limits>
     40 
     41 #include "webrtc/typedefs.h"
     42 
     43 namespace webrtc {
     44 
     45 // According to ISO C standard ISO/IEC 9899, section 6.2.6.2 (2), the three
     46 // representations of signed integers allowed are two's complement, one's
     47 // complement and sign/magnitude. We can detect which is used by looking at
     48 // the two last bits of -1, which will be 11 in two's complement, 10 in one's
     49 // complement and 01 in sign/magnitude.
     50 // TODO(sprang): In the unlikely event that we actually need to support a
     51 // platform that doesn't use two's complement, implement conversion to/from
     52 // wire format.
     53 
     54 // Assume the if any one signed integer type is two's complement, then all
     55 // other will be too.
     56 static_assert(
     57     (-1 & 0x03) == 0x03,
     58     "Only two's complement representation of signed integers supported.");
     59 
     60 // Plain const char* won't work for static_assert, use #define instead.
     61 #define kSizeErrorMsg "Byte size must be less than or equal to data type size."
     62 
     63 // Utility class for getting the unsigned equivalent of a signed type.
     64 template <typename T>
     65 struct UnsignedOf;
     66 
     67 // Class for reading integers from a sequence of bytes.
     68 // T = type of integer, B = bytes to read, is_signed = true if signed integer.
     69 // If is_signed is true and B < sizeof(T), sign extension might be needed.
     70 template <typename T,
     71           unsigned int B = sizeof(T),
     72           bool is_signed = std::numeric_limits<T>::is_signed>
     73 class ByteReader;
     74 
     75 // Specialization of ByteReader for unsigned types.
     76 template <typename T, unsigned int B>
     77 class ByteReader<T, B, false> {
     78  public:
     79   static T ReadBigEndian(const uint8_t* data) {
     80     static_assert(B <= sizeof(T), kSizeErrorMsg);
     81     return InternalReadBigEndian(data);
     82   }
     83 
     84   static T ReadLittleEndian(const uint8_t* data) {
     85     static_assert(B <= sizeof(T), kSizeErrorMsg);
     86     return InternalReadLittleEndian(data);
     87   }
     88 
     89  private:
     90   static T InternalReadBigEndian(const uint8_t* data) {
     91     T val(0);
     92     for (unsigned int i = 0; i < B; ++i)
     93       val |= static_cast<T>(data[i]) << ((B - 1 - i) * 8);
     94     return val;
     95   }
     96 
     97   static T InternalReadLittleEndian(const uint8_t* data) {
     98     T val(0);
     99     for (unsigned int i = 0; i < B; ++i)
    100       val |= static_cast<T>(data[i]) << (i * 8);
    101     return val;
    102   }
    103 };
    104 
    105 // Specialization of ByteReader for signed types.
    106 template <typename T, unsigned int B>
    107 class ByteReader<T, B, true> {
    108  public:
    109   typedef typename UnsignedOf<T>::Type U;
    110 
    111   static T ReadBigEndian(const uint8_t* data) {
    112     U unsigned_val = ByteReader<T, B, false>::ReadBigEndian(data);
    113     if (B < sizeof(T))
    114       unsigned_val = SignExtend(unsigned_val);
    115     return ReinterpretAsSigned(unsigned_val);
    116   }
    117 
    118   static T ReadLittleEndian(const uint8_t* data) {
    119     U unsigned_val = ByteReader<T, B, false>::ReadLittleEndian(data);
    120     if (B < sizeof(T))
    121       unsigned_val = SignExtend(unsigned_val);
    122     return ReinterpretAsSigned(unsigned_val);
    123   }
    124 
    125  private:
    126   // As a hack to avoid implementation-specific or undefined behavior when
    127   // bit-shifting or casting signed integers, read as a signed equivalent
    128   // instead and convert to signed. This is safe since we have asserted that
    129   // two's complement for is used.
    130   static T ReinterpretAsSigned(U unsigned_val) {
    131     // An unsigned value with only the highest order bit set (ex 0x80).
    132     const U kUnsignedHighestBitMask =
    133         static_cast<U>(1) << ((sizeof(U) * 8) - 1);
    134     // A signed value with only the highest bit set. Since this is two's
    135     // complement form, we can use the min value from std::numeric_limits.
    136     const T kSignedHighestBitMask = std::numeric_limits<T>::min();
    137 
    138     T val;
    139     if ((unsigned_val & kUnsignedHighestBitMask) != 0) {
    140       // Casting is only safe when unsigned value can be represented in the
    141       // signed target type, so mask out highest bit and mask it back manually.
    142       val = static_cast<T>(unsigned_val & ~kUnsignedHighestBitMask);
    143       val |= kSignedHighestBitMask;
    144     } else {
    145       val = static_cast<T>(unsigned_val);
    146     }
    147     return val;
    148   }
    149 
    150   // If number of bytes is less than native data type (eg 24 bit, in int32_t),
    151   // and the most significant bit of the actual data is set, we must sign
    152   // extend the remaining byte(s) with ones so that the correct negative
    153   // number is retained.
    154   // Ex: 0x810A0B -> 0xFF810A0B, but 0x710A0B -> 0x00710A0B
    155   static U SignExtend(const U val) {
    156     const uint8_t kMsb = static_cast<uint8_t>(val >> ((B - 1) * 8));
    157     if ((kMsb & 0x80) != 0) {
    158       // Create a mask where all bits used by the B bytes are set to one,
    159       // for instance 0x00FFFFFF for B = 3. Bit-wise invert that mask (to
    160       // (0xFF000000 in the example above) and add it to the input value.
    161       // The "B % sizeof(T)" is a workaround to undefined values warnings for
    162       // B == sizeof(T), in which case this code won't be called anyway.
    163       const U kUsedBitsMask = (1 << ((B % sizeof(T)) * 8)) - 1;
    164       return ~kUsedBitsMask | val;
    165     }
    166     return val;
    167   }
    168 };
    169 
    170 // Class for writing integers to a sequence of bytes
    171 // T = type of integer, B = bytes to write
    172 template <typename T,
    173           unsigned int B = sizeof(T),
    174           bool is_signed = std::numeric_limits<T>::is_signed>
    175 class ByteWriter;
    176 
    177 // Specialization of ByteWriter for unsigned types.
    178 template <typename T, unsigned int B>
    179 class ByteWriter<T, B, false> {
    180  public:
    181   static void WriteBigEndian(uint8_t* data, T val) {
    182     static_assert(B <= sizeof(T), kSizeErrorMsg);
    183     for (unsigned int i = 0; i < B; ++i) {
    184       data[i] = val >> ((B - 1 - i) * 8);
    185     }
    186   }
    187 
    188   static void WriteLittleEndian(uint8_t* data, T val) {
    189     static_assert(B <= sizeof(T), kSizeErrorMsg);
    190     for (unsigned int i = 0; i < B; ++i) {
    191       data[i] = val >> (i * 8);
    192     }
    193   }
    194 };
    195 
    196 // Specialization of ByteWriter for signed types.
    197 template <typename T, unsigned int B>
    198 class ByteWriter<T, B, true> {
    199  public:
    200   typedef typename UnsignedOf<T>::Type U;
    201 
    202   static void WriteBigEndian(uint8_t* data, T val) {
    203     ByteWriter<U, B, false>::WriteBigEndian(data, ReinterpretAsUnsigned(val));
    204   }
    205 
    206   static void WriteLittleEndian(uint8_t* data, T val) {
    207     ByteWriter<U, B, false>::WriteLittleEndian(data,
    208                                                ReinterpretAsUnsigned(val));
    209   }
    210 
    211  private:
    212   static U ReinterpretAsUnsigned(T val) {
    213     // According to ISO C standard ISO/IEC 9899, section 6.3.1.3 (1, 2) a
    214     // conversion from signed to unsigned keeps the value if the new type can
    215     // represent it, and otherwise adds one more than the max value of T until
    216     // the value is in range. For two's complement, this fortunately means
    217     // that the bit-wise value will be intact. Thus, since we have asserted that
    218     // two's complement form is actually used, a simple cast is sufficient.
    219     return static_cast<U>(val);
    220   }
    221 };
    222 
    223 // ----- Below follows specializations of UnsignedOf utility class -----
    224 
    225 template <>
    226 struct UnsignedOf<int8_t> {
    227   typedef uint8_t Type;
    228 };
    229 template <>
    230 struct UnsignedOf<int16_t> {
    231   typedef uint16_t Type;
    232 };
    233 template <>
    234 struct UnsignedOf<int32_t> {
    235   typedef uint32_t Type;
    236 };
    237 template <>
    238 struct UnsignedOf<int64_t> {
    239   typedef uint64_t Type;
    240 };
    241 
    242 // ----- Below follows specializations for unsigned, B in { 1, 2, 4, 8 } -----
    243 
    244 // TODO(sprang): Check if these actually help or if generic cases will be
    245 // unrolled to and optimized to similar performance.
    246 
    247 // Specializations for single bytes
    248 template <typename T>
    249 class ByteReader<T, 1, false> {
    250  public:
    251   static T ReadBigEndian(const uint8_t* data) {
    252     static_assert(sizeof(T) == 1, kSizeErrorMsg);
    253     return data[0];
    254   }
    255 
    256   static T ReadLittleEndian(const uint8_t* data) {
    257     static_assert(sizeof(T) == 1, kSizeErrorMsg);
    258     return data[0];
    259   }
    260 };
    261 
    262 template <typename T>
    263 class ByteWriter<T, 1, false> {
    264  public:
    265   static void WriteBigEndian(uint8_t* data, T val) {
    266     static_assert(sizeof(T) == 1, kSizeErrorMsg);
    267     data[0] = val;
    268   }
    269 
    270   static void WriteLittleEndian(uint8_t* data, T val) {
    271     static_assert(sizeof(T) == 1, kSizeErrorMsg);
    272     data[0] = val;
    273   }
    274 };
    275 
    276 // Specializations for two byte words
    277 template <typename T>
    278 class ByteReader<T, 2, false> {
    279  public:
    280   static T ReadBigEndian(const uint8_t* data) {
    281     static_assert(sizeof(T) >= 2, kSizeErrorMsg);
    282     return (data[0] << 8) | data[1];
    283   }
    284 
    285   static T ReadLittleEndian(const uint8_t* data) {
    286     static_assert(sizeof(T) >= 2, kSizeErrorMsg);
    287     return data[0] | (data[1] << 8);
    288   }
    289 };
    290 
    291 template <typename T>
    292 class ByteWriter<T, 2, false> {
    293  public:
    294   static void WriteBigEndian(uint8_t* data, T val) {
    295     static_assert(sizeof(T) >= 2, kSizeErrorMsg);
    296     data[0] = val >> 8;
    297     data[1] = val;
    298   }
    299 
    300   static void WriteLittleEndian(uint8_t* data, T val) {
    301     static_assert(sizeof(T) >= 2, kSizeErrorMsg);
    302     data[0] = val;
    303     data[1] = val >> 8;
    304   }
    305 };
    306 
    307 // Specializations for four byte words.
    308 template <typename T>
    309 class ByteReader<T, 4, false> {
    310  public:
    311   static T ReadBigEndian(const uint8_t* data) {
    312     static_assert(sizeof(T) >= 4, kSizeErrorMsg);
    313     return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
    314   }
    315 
    316   static T ReadLittleEndian(const uint8_t* data) {
    317     static_assert(sizeof(T) >= 4, kSizeErrorMsg);
    318     return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
    319   }
    320 };
    321 
    322 // Specializations for four byte words.
    323 template <typename T>
    324 class ByteWriter<T, 4, false> {
    325  public:
    326   static void WriteBigEndian(uint8_t* data, T val) {
    327     static_assert(sizeof(T) >= 4, kSizeErrorMsg);
    328     data[0] = val >> 24;
    329     data[1] = val >> 16;
    330     data[2] = val >> 8;
    331     data[3] = val;
    332   }
    333 
    334   static void WriteLittleEndian(uint8_t* data, T val) {
    335     static_assert(sizeof(T) >= 4, kSizeErrorMsg);
    336     data[0] = val;
    337     data[1] = val >> 8;
    338     data[2] = val >> 16;
    339     data[3] = val >> 24;
    340   }
    341 };
    342 
    343 // Specializations for eight byte words.
    344 template <typename T>
    345 class ByteReader<T, 8, false> {
    346  public:
    347   static T ReadBigEndian(const uint8_t* data) {
    348     static_assert(sizeof(T) >= 8, kSizeErrorMsg);
    349     return
    350         (Get(data, 0) << 56) | (Get(data, 1) << 48) |
    351         (Get(data, 2) << 40) | (Get(data, 3) << 32) |
    352         (Get(data, 4) << 24) | (Get(data, 5) << 16) |
    353         (Get(data, 6) << 8)  |  Get(data, 7);
    354   }
    355 
    356   static T ReadLittleEndian(const uint8_t* data) {
    357     static_assert(sizeof(T) >= 8, kSizeErrorMsg);
    358     return
    359          Get(data, 0)        | (Get(data, 1) << 8)  |
    360         (Get(data, 2) << 16) | (Get(data, 3) << 24) |
    361         (Get(data, 4) << 32) | (Get(data, 5) << 40) |
    362         (Get(data, 6) << 48) | (Get(data, 7) << 56);
    363   }
    364 
    365  private:
    366   inline static T Get(const uint8_t* data, unsigned int index) {
    367     return static_cast<T>(data[index]);
    368   }
    369 };
    370 
    371 template <typename T>
    372 class ByteWriter<T, 8, false> {
    373  public:
    374   static void WriteBigEndian(uint8_t* data, T val) {
    375     static_assert(sizeof(T) >= 8, kSizeErrorMsg);
    376     data[0] = val >> 56;
    377     data[1] = val >> 48;
    378     data[2] = val >> 40;
    379     data[3] = val >> 32;
    380     data[4] = val >> 24;
    381     data[5] = val >> 16;
    382     data[6] = val >> 8;
    383     data[7] = val;
    384   }
    385 
    386   static void WriteLittleEndian(uint8_t* data, T val) {
    387     static_assert(sizeof(T) >= 8, kSizeErrorMsg);
    388     data[0] = val;
    389     data[1] = val >> 8;
    390     data[2] = val >> 16;
    391     data[3] = val >> 24;
    392     data[4] = val >> 32;
    393     data[5] = val >> 40;
    394     data[6] = val >> 48;
    395     data[7] = val >> 56;
    396   }
    397 };
    398 
    399 }  // namespace webrtc
    400 
    401 #endif  // WEBRTC_MODULES_RTP_RTCP_SOURCE_BYTE_IO_H_
    402