• 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 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