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: ReadBigEndian(const uint8_t * data)79 static T ReadBigEndian(const uint8_t* data) { 80 static_assert(B <= sizeof(T), kSizeErrorMsg); 81 return InternalReadBigEndian(data); 82 } 83 ReadLittleEndian(const uint8_t * data)84 static T ReadLittleEndian(const uint8_t* data) { 85 static_assert(B <= sizeof(T), kSizeErrorMsg); 86 return InternalReadLittleEndian(data); 87 } 88 89 private: InternalReadBigEndian(const uint8_t * data)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 InternalReadLittleEndian(const uint8_t * data)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 ReadBigEndian(const uint8_t * data)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 ReadLittleEndian(const uint8_t * data)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. ReinterpretAsSigned(U unsigned_val)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 SignExtend(const U val)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 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: WriteBigEndian(uint8_t * data,T val)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 WriteLittleEndian(uint8_t * data,T val)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 WriteBigEndian(uint8_t * data,T val)202 static void WriteBigEndian(uint8_t* data, T val) { 203 ByteWriter<U, B, false>::WriteBigEndian(data, ReinterpretAsUnsigned(val)); 204 } 205 WriteLittleEndian(uint8_t * data,T val)206 static void WriteLittleEndian(uint8_t* data, T val) { 207 ByteWriter<U, B, false>::WriteLittleEndian(data, 208 ReinterpretAsUnsigned(val)); 209 } 210 211 private: ReinterpretAsUnsigned(T val)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 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 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 262 template <typename T> 263 class 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 277 template <typename T> 278 class 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 291 template <typename T> 292 class 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. 308 template <typename T> 309 class 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. 323 template <typename T> 324 class 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. 344 template <typename T> 345 class 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 371 template <typename T> 372 class 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