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