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 // Class for reading integers from a sequence of bytes.
     46 // T = type of integer, B = bytes to read, is_signed = true if signed integer
     47 // If is_signed is true and B < sizeof(T), sign extension might be needed
     48 template<typename T, unsigned int B = sizeof(T),
     49     bool is_signed = std::numeric_limits<T>::is_signed>
     50 class ByteReader {
     51  public:
     52   static T ReadBigEndian(uint8_t* data) {
     53     if (is_signed && B < sizeof(T)) {
     54       return SignExtend(InternalReadBigEndian(data));
     55     }
     56     return InternalReadBigEndian(data);
     57   }
     58 
     59   static T ReadLittleEndian(uint8_t* data) {
     60     if (is_signed && B < sizeof(T)) {
     61       return SignExtend(InternalReadLittleEndian(data));
     62     }
     63     return InternalReadLittleEndian(data);
     64   }
     65 
     66  private:
     67   static T InternalReadBigEndian(uint8_t* data) {
     68     T val(0);
     69     for (unsigned int i = 0; i < B; ++i) {
     70       val |= static_cast<T>(data[i]) << ((B - 1 - i) * 8);
     71     }
     72     return val;
     73   }
     74 
     75   static T InternalReadLittleEndian(uint8_t* data) {
     76     T val(0);
     77     for (unsigned int i = 0; i < B; ++i) {
     78       val |= static_cast<T>(data[i]) << (i * 8);
     79     }
     80     return val;
     81   }
     82 
     83   // If number of bytes is less than native data type (eg 24 bit, in int32_t),
     84   // and the most significant bit of the actual data is set, we must sign
     85   // extend the remaining byte(s) with ones so that the correct negative
     86   // number is retained.
     87   // Ex: 0x810A0B -> 0xFF810A0B, but 0x710A0B -> 0x00710A0B
     88   static T SignExtend(T val) {
     89     uint8_t msb = static_cast<uint8_t>(val >> ((B - 1) * 8));
     90     if (msb & 0x80) {
     91       // Sign extension is -1 (all ones) shifted left B bytes.
     92       // The "B % sizeof(T)"-part is there to avoid compiler warning for
     93       // shifting the whole size of the data type.
     94       T sign_extend = (sizeof(T) == B ? 0 :
     95           (static_cast<T>(-1L) << ((B % sizeof(T)) * 8)));
     96 
     97       return val | sign_extend;
     98     }
     99     return val;
    100   }
    101 };
    102 
    103 // Class for writing integers to a sequence of bytes
    104 // T = type of integer, B = bytes to write
    105 template<typename T, unsigned int B = sizeof(T)>
    106 class ByteWriter {
    107  public:
    108   static void WriteBigEndian(uint8_t* data, T val) {
    109     for (unsigned int i = 0; i < B; ++i) {
    110       data[i] = val >> ((B - 1 - i) * 8);
    111     }
    112   }
    113 
    114   static void WriteLittleEndian(uint8_t* data, T val) {
    115     for (unsigned int i = 0; i < B; ++i) {
    116       data[i] = val >> (i * 8);
    117     }
    118   }
    119 };
    120 
    121 
    122 // -------- Below follows specializations for B in { 2, 4, 8 } --------
    123 
    124 
    125 // Specializations for two byte words
    126 template<typename T, bool is_signed>
    127 class ByteReader<T, 2, is_signed> {
    128  public:
    129   static T ReadBigEndian(uint8_t* data) {
    130     return (data[0] << 8) | data[1];
    131   }
    132 
    133   static T ReadLittleEndian(uint8_t* data) {
    134     return data[0] | (data[1] << 8);
    135   }
    136 };
    137 
    138 template<typename T>
    139 class ByteWriter<T, 2> {
    140  public:
    141   static void WriteBigEndian(uint8_t* data, T val) {
    142     data[0] = val >> 8;
    143     data[1] = val;
    144   }
    145 
    146   static void WriteLittleEndian(uint8_t* data, T val) {
    147     data[0] = val;
    148     data[1] = val >> 8;
    149   }
    150 };
    151 
    152 // Specializations for four byte words.
    153 template<typename T, bool is_signed>
    154 class ByteReader<T, 4, is_signed> {
    155  public:
    156   static T ReadBigEndian(uint8_t* data) {
    157     return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
    158   }
    159 
    160   static T ReadLittleEndian(uint8_t* data) {
    161     return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
    162   }
    163 };
    164 
    165 // Specializations for four byte words.
    166 template<typename T>
    167 class ByteWriter<T, 4> {
    168  public:
    169   static void WriteBigEndian(uint8_t* data, T val) {
    170     data[0] = val >> 24;
    171     data[1] = val >> 16;
    172     data[2] = val >> 8;
    173     data[3] = val;
    174   }
    175 
    176   static void WriteLittleEndian(uint8_t* data, T val) {
    177     data[0] = val;
    178     data[1] = val >> 8;
    179     data[2] = val >> 16;
    180     data[3] = val >> 24;
    181   }
    182 };
    183 
    184 // Specializations for eight byte words.
    185 template<typename T, bool is_signed>
    186 class ByteReader<T, 8, is_signed> {
    187  public:
    188   static T ReadBigEndian(uint8_t* data) {
    189     return
    190         (Get(data, 0) << 56) | (Get(data, 1) << 48) |
    191         (Get(data, 2) << 40) | (Get(data, 3) << 32) |
    192         (Get(data, 4) << 24) | (Get(data, 5) << 16) |
    193         (Get(data, 6) << 8)  |  Get(data, 7);
    194   }
    195 
    196   static T ReadLittleEndian(uint8_t* data) {
    197     return
    198          Get(data, 0)        | (Get(data, 1) << 8)  |
    199         (Get(data, 2) << 16) | (Get(data, 3) << 24) |
    200         (Get(data, 4) << 32) | (Get(data, 5) << 40) |
    201         (Get(data, 6) << 48) | (Get(data, 7) << 56);
    202   }
    203 
    204  private:
    205   inline static T Get(uint8_t* data, unsigned int index) {
    206     return static_cast<T>(data[index]);
    207   }
    208 };
    209 
    210 template<typename T>
    211 class ByteWriter<T, 8> {
    212  public:
    213   static void WriteBigEndian(uint8_t* data, T val) {
    214     data[0] = val >> 56;
    215     data[1] = val >> 48;
    216     data[2] = val >> 40;
    217     data[3] = val >> 32;
    218     data[4] = val >> 24;
    219     data[5] = val >> 16;
    220     data[6] = val >> 8;
    221     data[7] = val;
    222   }
    223 
    224   static void WriteLittleEndian(uint8_t* data, T val) {
    225     data[0] = val;
    226     data[1] = val >> 8;
    227     data[2] = val >> 16;
    228     data[3] = val >> 24;
    229     data[4] = val >> 32;
    230     data[5] = val >> 40;
    231     data[6] = val >> 48;
    232     data[7] = val >> 56;
    233   }
    234 };
    235 
    236 }  // namespace webrtc
    237 
    238 #endif  // WEBRTC_MODULES_RTP_RTCP_SOURCE_BYTE_IO_H_
    239