tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

byte_io.h (12916B)


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