LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/rtp_rtcp/source - byte_io.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 93 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 28 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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           0 :   static T ReadBigEndian(const uint8_t* data) {
      80             :     static_assert(B <= sizeof(T), kSizeErrorMsg);
      81           0 :     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           0 :   static T InternalReadBigEndian(const uint8_t* data) {
      91           0 :     T val(0);
      92           0 :     for (unsigned int i = 0; i < B; ++i)
      93           0 :       val |= static_cast<T>(data[i]) << ((B - 1 - i) * 8);
      94           0 :     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           0 :   static T ReadBigEndian(const uint8_t* data) {
     112           0 :     U unsigned_val = ByteReader<T, B, false>::ReadBigEndian(data);
     113             :     if (B < sizeof(T))
     114           0 :       unsigned_val = SignExtend(unsigned_val);
     115           0 :     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           0 :   static T ReinterpretAsSigned(U unsigned_val) {
     131             :     // An unsigned value with only the highest order bit set (ex 0x80).
     132             :     const U kUnsignedHighestBitMask =
     133           0 :         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           0 :     const T kSignedHighestBitMask = std::numeric_limits<T>::min();
     137             : 
     138             :     T val;
     139           0 :     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           0 :       val = static_cast<T>(unsigned_val & ~kUnsignedHighestBitMask);
     143           0 :       val |= kSignedHighestBitMask;
     144             :     } else {
     145           0 :       val = static_cast<T>(unsigned_val);
     146             :     }
     147           0 :     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           0 :   static U SignExtend(const U val) {
     156           0 :     const uint8_t kMsb = static_cast<uint8_t>(val >> ((B - 1) * 8));
     157           0 :     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           0 :       const U kUsedBitsMask = (1 << ((B % sizeof(T)) * 8)) - 1;
     164           0 :       return ~kUsedBitsMask | val;
     165             :     }
     166           0 :     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           0 :   static void WriteBigEndian(uint8_t* data, T val) {
     182             :     static_assert(B <= sizeof(T), kSizeErrorMsg);
     183           0 :     for (unsigned int i = 0; i < B; ++i) {
     184           0 :       data[i] = val >> ((B - 1 - i) * 8);
     185             :     }
     186           0 :   }
     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           0 :   static void WriteBigEndian(uint8_t* data, T val) {
     203           0 :     ByteWriter<U, B, false>::WriteBigEndian(data, ReinterpretAsUnsigned(val));
     204           0 :   }
     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           0 :   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           0 :     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           0 :   static T ReadBigEndian(const uint8_t* data) {
     252             :     static_assert(sizeof(T) == 1, kSizeErrorMsg);
     253           0 :     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           0 :   static void WriteBigEndian(uint8_t* data, T val) {
     266             :     static_assert(sizeof(T) == 1, kSizeErrorMsg);
     267           0 :     data[0] = val;
     268           0 :   }
     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           0 :   static T ReadBigEndian(const uint8_t* data) {
     281             :     static_assert(sizeof(T) >= 2, kSizeErrorMsg);
     282           0 :     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           0 :   static void WriteBigEndian(uint8_t* data, T val) {
     295             :     static_assert(sizeof(T) >= 2, kSizeErrorMsg);
     296           0 :     data[0] = val >> 8;
     297           0 :     data[1] = val;
     298           0 :   }
     299             : 
     300           0 :   static void WriteLittleEndian(uint8_t* data, T val) {
     301             :     static_assert(sizeof(T) >= 2, kSizeErrorMsg);
     302           0 :     data[0] = val;
     303           0 :     data[1] = val >> 8;
     304           0 :   }
     305             : };
     306             : 
     307             : // Specializations for four byte words.
     308             : template <typename T>
     309             : class ByteReader<T, 4, false> {
     310             :  public:
     311           0 :   static T ReadBigEndian(const uint8_t* data) {
     312             :     static_assert(sizeof(T) >= 4, kSizeErrorMsg);
     313           0 :     return (Get(data, 0) << 24) | (Get(data, 1) << 16) | (Get(data, 2) << 8) |
     314           0 :            Get(data, 3);
     315             :   }
     316             : 
     317             :   static T ReadLittleEndian(const uint8_t* data) {
     318             :     static_assert(sizeof(T) >= 4, kSizeErrorMsg);
     319             :     return Get(data, 0) | (Get(data, 1) << 8) | (Get(data, 2) << 16) |
     320             :            (Get(data, 3) << 24);
     321             :   }
     322             : 
     323             :  private:
     324           0 :   inline static T Get(const uint8_t* data, unsigned int index) {
     325           0 :     return static_cast<T>(data[index]);
     326             :   }
     327             : };
     328             : 
     329             : // Specializations for four byte words.
     330             : template <typename T>
     331             : class ByteWriter<T, 4, false> {
     332             :  public:
     333           0 :   static void WriteBigEndian(uint8_t* data, T val) {
     334             :     static_assert(sizeof(T) >= 4, kSizeErrorMsg);
     335           0 :     data[0] = val >> 24;
     336           0 :     data[1] = val >> 16;
     337           0 :     data[2] = val >> 8;
     338           0 :     data[3] = val;
     339           0 :   }
     340             : 
     341           0 :   static void WriteLittleEndian(uint8_t* data, T val) {
     342             :     static_assert(sizeof(T) >= 4, kSizeErrorMsg);
     343           0 :     data[0] = val;
     344           0 :     data[1] = val >> 8;
     345           0 :     data[2] = val >> 16;
     346           0 :     data[3] = val >> 24;
     347           0 :   }
     348             : };
     349             : 
     350             : // Specializations for eight byte words.
     351             : template <typename T>
     352             : class ByteReader<T, 8, false> {
     353             :  public:
     354           0 :   static T ReadBigEndian(const uint8_t* data) {
     355             :     static_assert(sizeof(T) >= 8, kSizeErrorMsg);
     356             :     return
     357           0 :         (Get(data, 0) << 56) | (Get(data, 1) << 48) |
     358           0 :         (Get(data, 2) << 40) | (Get(data, 3) << 32) |
     359           0 :         (Get(data, 4) << 24) | (Get(data, 5) << 16) |
     360           0 :         (Get(data, 6) << 8)  |  Get(data, 7);
     361             :   }
     362             : 
     363             :   static T ReadLittleEndian(const uint8_t* data) {
     364             :     static_assert(sizeof(T) >= 8, kSizeErrorMsg);
     365             :     return
     366             :          Get(data, 0)        | (Get(data, 1) << 8)  |
     367             :         (Get(data, 2) << 16) | (Get(data, 3) << 24) |
     368             :         (Get(data, 4) << 32) | (Get(data, 5) << 40) |
     369             :         (Get(data, 6) << 48) | (Get(data, 7) << 56);
     370             :   }
     371             : 
     372             :  private:
     373           0 :   inline static T Get(const uint8_t* data, unsigned int index) {
     374           0 :     return static_cast<T>(data[index]);
     375             :   }
     376             : };
     377             : 
     378             : template <typename T>
     379             : class ByteWriter<T, 8, false> {
     380             :  public:
     381           0 :   static void WriteBigEndian(uint8_t* data, T val) {
     382             :     static_assert(sizeof(T) >= 8, kSizeErrorMsg);
     383           0 :     data[0] = val >> 56;
     384           0 :     data[1] = val >> 48;
     385           0 :     data[2] = val >> 40;
     386           0 :     data[3] = val >> 32;
     387           0 :     data[4] = val >> 24;
     388           0 :     data[5] = val >> 16;
     389           0 :     data[6] = val >> 8;
     390           0 :     data[7] = val;
     391           0 :   }
     392             : 
     393           0 :   static void WriteLittleEndian(uint8_t* data, T val) {
     394             :     static_assert(sizeof(T) >= 8, kSizeErrorMsg);
     395           0 :     data[0] = val;
     396           0 :     data[1] = val >> 8;
     397           0 :     data[2] = val >> 16;
     398           0 :     data[3] = val >> 24;
     399           0 :     data[4] = val >> 32;
     400           0 :     data[5] = val >> 40;
     401           0 :     data[6] = val >> 48;
     402           0 :     data[7] = val >> 56;
     403           0 :   }
     404             : };
     405             : 
     406             : }  // namespace webrtc
     407             : 
     408             : #endif  // WEBRTC_MODULES_RTP_RTCP_SOURCE_BYTE_IO_H_

Generated by: LCOV version 1.13