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