• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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