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, inteded 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: ReadBigEndian(const uint8_t * data)77 static T ReadBigEndian(const uint8_t* data) { 78 static_assert(B <= sizeof(T), kSizeErrorMsg); 79 return InternalReadBigEndian(data); 80 } 81 ReadLittleEndian(const uint8_t * data)82 static T ReadLittleEndian(const uint8_t* data) { 83 static_assert(B <= sizeof(T), kSizeErrorMsg); 84 return InternalReadLittleEndian(data); 85 } 86 87 private: InternalReadBigEndian(const uint8_t * data)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 InternalReadLittleEndian(const uint8_t * data)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 ReadBigEndian(const uint8_t * data)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 ReadLittleEndian(const uint8_t * data)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. ReinterpretAsSigned(U unsigned_val)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 SignExtend(const U val)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: WriteBigEndian(uint8_t * data,T val)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 WriteLittleEndian(uint8_t * data,T val)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 WriteBigEndian(uint8_t * data,T val)200 static void WriteBigEndian(uint8_t* data, T val) { 201 ByteWriter<U, B, false>::WriteBigEndian(data, ReinterpretAsUnsigned(val)); 202 } 203 WriteLittleEndian(uint8_t * data,T val)204 static void WriteLittleEndian(uint8_t* data, T val) { 205 ByteWriter<U, B, false>::WriteLittleEndian(data, 206 ReinterpretAsUnsigned(val)); 207 } 208 209 private: ReinterpretAsUnsigned(T val)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_ 403