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 43namespace 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. 56static_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. 64template <typename T> 65struct 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. 70template <typename T, 71 unsigned int B = sizeof(T), 72 bool is_signed = std::numeric_limits<T>::is_signed> 73class ByteReader; 74 75// Specialization of ByteReader for unsigned types. 76template <typename T, unsigned int B> 77class 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. 106template <typename T, unsigned int B> 107class 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 172template <typename T, 173 unsigned int B = sizeof(T), 174 bool is_signed = std::numeric_limits<T>::is_signed> 175class ByteWriter; 176 177// Specialization of ByteWriter for unsigned types. 178template <typename T, unsigned int B> 179class 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. 197template <typename T, unsigned int B> 198class 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 225template <> 226struct UnsignedOf<int8_t> { 227 typedef uint8_t Type; 228}; 229template <> 230struct UnsignedOf<int16_t> { 231 typedef uint16_t Type; 232}; 233template <> 234struct UnsignedOf<int32_t> { 235 typedef uint32_t Type; 236}; 237template <> 238struct 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 248template <typename T> 249class 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 262template <typename T> 263class 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 277template <typename T> 278class 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 291template <typename T> 292class 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. 308template <typename T> 309class 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. 323template <typename T> 324class 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. 344template <typename T> 345class 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 371template <typename T> 372class 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