Line data Source code
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:
79 0 : static T ReadBigEndian(const uint8_t* data) {
80 : static_assert(B <= sizeof(T), kSizeErrorMsg);
81 0 : 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 0 : static T InternalReadBigEndian(const uint8_t* data) {
91 0 : T val(0);
92 0 : for (unsigned int i = 0; i < B; ++i)
93 0 : val |= static_cast<T>(data[i]) << ((B - 1 - i) * 8);
94 0 : 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.
106 : template <typename T, unsigned int B>
107 : class ByteReader<T, B, true> {
108 : public:
109 : typedef typename UnsignedOf<T>::Type U;
110 :
111 0 : static T ReadBigEndian(const uint8_t* data) {
112 0 : U unsigned_val = ByteReader<T, B, false>::ReadBigEndian(data);
113 : if (B < sizeof(T))
114 0 : unsigned_val = SignExtend(unsigned_val);
115 0 : 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 0 : static T ReinterpretAsSigned(U unsigned_val) {
131 : // An unsigned value with only the highest order bit set (ex 0x80).
132 : const U kUnsignedHighestBitMask =
133 0 : 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 0 : const T kSignedHighestBitMask = std::numeric_limits<T>::min();
137 :
138 : T val;
139 0 : 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 0 : val = static_cast<T>(unsigned_val & ~kUnsignedHighestBitMask);
143 0 : val |= kSignedHighestBitMask;
144 : } else {
145 0 : val = static_cast<T>(unsigned_val);
146 : }
147 0 : 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 0 : static U SignExtend(const U val) {
156 0 : const uint8_t kMsb = static_cast<uint8_t>(val >> ((B - 1) * 8));
157 0 : 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 0 : const U kUsedBitsMask = (1 << ((B % sizeof(T)) * 8)) - 1;
164 0 : return ~kUsedBitsMask | val;
165 : }
166 0 : 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:
181 0 : static void WriteBigEndian(uint8_t* data, T val) {
182 : static_assert(B <= sizeof(T), kSizeErrorMsg);
183 0 : for (unsigned int i = 0; i < B; ++i) {
184 0 : data[i] = val >> ((B - 1 - i) * 8);
185 : }
186 0 : }
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.
197 : template <typename T, unsigned int B>
198 : class ByteWriter<T, B, true> {
199 : public:
200 : typedef typename UnsignedOf<T>::Type U;
201 :
202 0 : static void WriteBigEndian(uint8_t* data, T val) {
203 0 : ByteWriter<U, B, false>::WriteBigEndian(data, ReinterpretAsUnsigned(val));
204 0 : }
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 0 : 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 0 : 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 0 : static T ReadBigEndian(const uint8_t* data) {
252 : static_assert(sizeof(T) == 1, kSizeErrorMsg);
253 0 : 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 0 : static void WriteBigEndian(uint8_t* data, T val) {
266 : static_assert(sizeof(T) == 1, kSizeErrorMsg);
267 0 : data[0] = val;
268 0 : }
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 0 : static T ReadBigEndian(const uint8_t* data) {
281 : static_assert(sizeof(T) >= 2, kSizeErrorMsg);
282 0 : 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 0 : static void WriteBigEndian(uint8_t* data, T val) {
295 : static_assert(sizeof(T) >= 2, kSizeErrorMsg);
296 0 : data[0] = val >> 8;
297 0 : data[1] = val;
298 0 : }
299 :
300 0 : static void WriteLittleEndian(uint8_t* data, T val) {
301 : static_assert(sizeof(T) >= 2, kSizeErrorMsg);
302 0 : data[0] = val;
303 0 : data[1] = val >> 8;
304 0 : }
305 : };
306 :
307 : // Specializations for four byte words.
308 : template <typename T>
309 : class ByteReader<T, 4, false> {
310 : public:
311 0 : static T ReadBigEndian(const uint8_t* data) {
312 : static_assert(sizeof(T) >= 4, kSizeErrorMsg);
313 0 : return (Get(data, 0) << 24) | (Get(data, 1) << 16) | (Get(data, 2) << 8) |
314 0 : Get(data, 3);
315 : }
316 :
317 : static T ReadLittleEndian(const uint8_t* data) {
318 : static_assert(sizeof(T) >= 4, kSizeErrorMsg);
319 : return Get(data, 0) | (Get(data, 1) << 8) | (Get(data, 2) << 16) |
320 : (Get(data, 3) << 24);
321 : }
322 :
323 : private:
324 0 : inline static T Get(const uint8_t* data, unsigned int index) {
325 0 : return static_cast<T>(data[index]);
326 : }
327 : };
328 :
329 : // Specializations for four byte words.
330 : template <typename T>
331 : class ByteWriter<T, 4, false> {
332 : public:
333 0 : static void WriteBigEndian(uint8_t* data, T val) {
334 : static_assert(sizeof(T) >= 4, kSizeErrorMsg);
335 0 : data[0] = val >> 24;
336 0 : data[1] = val >> 16;
337 0 : data[2] = val >> 8;
338 0 : data[3] = val;
339 0 : }
340 :
341 0 : static void WriteLittleEndian(uint8_t* data, T val) {
342 : static_assert(sizeof(T) >= 4, kSizeErrorMsg);
343 0 : data[0] = val;
344 0 : data[1] = val >> 8;
345 0 : data[2] = val >> 16;
346 0 : data[3] = val >> 24;
347 0 : }
348 : };
349 :
350 : // Specializations for eight byte words.
351 : template <typename T>
352 : class ByteReader<T, 8, false> {
353 : public:
354 0 : static T ReadBigEndian(const uint8_t* data) {
355 : static_assert(sizeof(T) >= 8, kSizeErrorMsg);
356 : return
357 0 : (Get(data, 0) << 56) | (Get(data, 1) << 48) |
358 0 : (Get(data, 2) << 40) | (Get(data, 3) << 32) |
359 0 : (Get(data, 4) << 24) | (Get(data, 5) << 16) |
360 0 : (Get(data, 6) << 8) | Get(data, 7);
361 : }
362 :
363 : static T ReadLittleEndian(const uint8_t* data) {
364 : static_assert(sizeof(T) >= 8, kSizeErrorMsg);
365 : return
366 : Get(data, 0) | (Get(data, 1) << 8) |
367 : (Get(data, 2) << 16) | (Get(data, 3) << 24) |
368 : (Get(data, 4) << 32) | (Get(data, 5) << 40) |
369 : (Get(data, 6) << 48) | (Get(data, 7) << 56);
370 : }
371 :
372 : private:
373 0 : inline static T Get(const uint8_t* data, unsigned int index) {
374 0 : return static_cast<T>(data[index]);
375 : }
376 : };
377 :
378 : template <typename T>
379 : class ByteWriter<T, 8, false> {
380 : public:
381 0 : static void WriteBigEndian(uint8_t* data, T val) {
382 : static_assert(sizeof(T) >= 8, kSizeErrorMsg);
383 0 : data[0] = val >> 56;
384 0 : data[1] = val >> 48;
385 0 : data[2] = val >> 40;
386 0 : data[3] = val >> 32;
387 0 : data[4] = val >> 24;
388 0 : data[5] = val >> 16;
389 0 : data[6] = val >> 8;
390 0 : data[7] = val;
391 0 : }
392 :
393 0 : static void WriteLittleEndian(uint8_t* data, T val) {
394 : static_assert(sizeof(T) >= 8, kSizeErrorMsg);
395 0 : data[0] = val;
396 0 : data[1] = val >> 8;
397 0 : data[2] = val >> 16;
398 0 : data[3] = val >> 24;
399 0 : data[4] = val >> 32;
400 0 : data[5] = val >> 40;
401 0 : data[6] = val >> 48;
402 0 : data[7] = val >> 56;
403 0 : }
404 : };
405 :
406 : } // namespace webrtc
407 :
408 : #endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_BYTE_IO_H_
|