1 /*
2  *  Copyright (c) 2012 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 #include "modules/rtp_rtcp/source/byte_io.h"
12 
13 #include <limits>
14 
15 #include "test/gtest.h"
16 
17 namespace webrtc {
18 namespace {
19 
20 class ByteIoTest : public ::testing::Test {
21  protected:
22   ByteIoTest() = default;
23   ~ByteIoTest() override = default;
24 
25   enum { kAlignments = sizeof(uint64_t) - 1 };
26 
27   // Method to create a test value that is not the same when byte reversed.
28   template <typename T>
CreateTestValue(bool negative,uint8_t num_bytes)29   T CreateTestValue(bool negative, uint8_t num_bytes) {
30     // Examples of output:
31     // T = int32_t, negative = false, num_bytes = 4: 0x00010203
32     // T = int32_t, negative = true, num_bytes = 4: 0xFFFEFDFC
33     // T = int32_t, negative = false, num_bytes = 3: 0x000102
34     // * T = int32_t, negative = true, num_bytes = 3: 0xFFFEFD
35 
36     T val = 0;
37     for (uint8_t i = 0; i != num_bytes; ++i) {
38       val = (val << 8) + (negative ? (0xFF - i) : (i + 1));
39     }
40 
41     // This loop will create a sign extend mask if num_bytes if necessary.
42     // For the last example (marked * above), the number needs to be sign
43     // extended to be a valid int32_t. The sign extend mask is 0xFF000000.
44     // Comments for each step with this example below.
45     if (std::numeric_limits<T>::is_signed && negative &&
46         num_bytes < sizeof(T)) {
47       // Start with mask = 0xFFFFFFFF.
48       T mask = static_cast<T>(-1);
49       // Create a temporary for the lowest byte (0x000000FF).
50       const T neg_byte = static_cast<T>(0xFF);
51       for (int i = 0; i < num_bytes; ++i) {
52         // And the inverse of the temporary and the mask:
53         // 0xFFFFFFFF & 0xFFFFFF00 = 0xFFFFFF00.
54         // 0xFFFFFF00 & 0xFFFF00FF = 0xFFFF0000.
55         // 0xFFFF0000 & 0xFF00FFFF = 0xFF000000.
56         mask &= ~(neg_byte << (i * 8));
57       }
58       // Add the sign extension mask to the actual value.
59       val |= mask;
60     }
61     return val;
62   }
63 
64   // Populate byte buffer with value, in big endian format.
65   template <typename T>
PopulateTestData(uint8_t * data,T value,int num_bytes,bool bigendian)66   void PopulateTestData(uint8_t* data, T value, int num_bytes, bool bigendian) {
67     if (bigendian) {
68       for (int i = 0; i < num_bytes; ++i) {
69         data[i] = (value >> ((num_bytes - i - 1) * 8)) & 0xFF;
70       }
71     } else {
72       for (int i = 0; i < num_bytes; ++i) {
73         data[i] = (value >> (i * 8)) & 0xFF;
74       }
75     }
76   }
77 
78   // Test reading big endian numbers.
79   // Template arguments: Type T, read method RM(buffer), B bytes of data.
80   template <typename T, T (*RM)(const uint8_t*), int B>
TestRead(bool big_endian)81   void TestRead(bool big_endian) {
82     // Test both for values that are positive and negative (if signed)
83     for (int neg = 0; neg < 2; ++neg) {
84       bool negative = neg > 0;
85 
86       // Write test value to byte buffer, in big endian format.
87       T test_value = CreateTestValue<T>(negative, B);
88       uint8_t bytes[B + kAlignments];
89 
90       // Make one test for each alignment.
91       for (int i = 0; i < kAlignments; ++i) {
92         PopulateTestData(bytes + i, test_value, B, big_endian);
93 
94         // Check that test value is retrieved from buffer when used read method.
95         EXPECT_EQ(test_value, RM(bytes + i));
96       }
97     }
98   }
99 
100   // Test writing big endian numbers.
101   // Template arguments: Type T, write method WM(buffer, value), B bytes of data
102   template <typename T, void (*WM)(uint8_t*, T), int B>
TestWrite(bool big_endian)103   void TestWrite(bool big_endian) {
104     // Test both for values that are positive and negative (if signed).
105     for (int neg = 0; neg < 2; ++neg) {
106       bool negative = neg > 0;
107 
108       // Write test value to byte buffer, in big endian format.
109       T test_value = CreateTestValue<T>(negative, B);
110       uint8_t expected_bytes[B + kAlignments];
111       uint8_t bytes[B + kAlignments];
112 
113       // Make one test for each alignment.
114       for (int i = 0; i < kAlignments; ++i) {
115         PopulateTestData(expected_bytes + i, test_value, B, big_endian);
116 
117         // Zero initialize buffer and let WM populate it.
118         memset(bytes, 0, B + kAlignments);
119         WM(bytes + i, test_value);
120 
121         // Check that data produced by WM is big endian as expected.
122         for (int j = 0; j < B; ++j) {
123           EXPECT_EQ(expected_bytes[i + j], bytes[i + j]);
124         }
125       }
126     }
127   }
128 };
129 
TEST_F(ByteIoTest,Test16UBitBigEndian)130 TEST_F(ByteIoTest, Test16UBitBigEndian) {
131   TestRead<uint16_t, ByteReader<uint16_t>::ReadBigEndian, sizeof(uint16_t)>(
132       true);
133   TestWrite<uint16_t, ByteWriter<uint16_t>::WriteBigEndian, sizeof(uint16_t)>(
134       true);
135 }
136 
TEST_F(ByteIoTest,Test24UBitBigEndian)137 TEST_F(ByteIoTest, Test24UBitBigEndian) {
138   TestRead<uint32_t, ByteReader<uint32_t, 3>::ReadBigEndian, 3>(true);
139   TestWrite<uint32_t, ByteWriter<uint32_t, 3>::WriteBigEndian, 3>(true);
140 }
141 
TEST_F(ByteIoTest,Test32UBitBigEndian)142 TEST_F(ByteIoTest, Test32UBitBigEndian) {
143   TestRead<uint32_t, ByteReader<uint32_t>::ReadBigEndian, sizeof(uint32_t)>(
144       true);
145   TestWrite<uint32_t, ByteWriter<uint32_t>::WriteBigEndian, sizeof(uint32_t)>(
146       true);
147 }
148 
TEST_F(ByteIoTest,Test64UBitBigEndian)149 TEST_F(ByteIoTest, Test64UBitBigEndian) {
150   TestRead<uint64_t, ByteReader<uint64_t>::ReadBigEndian, sizeof(uint64_t)>(
151       true);
152   TestWrite<uint64_t, ByteWriter<uint64_t>::WriteBigEndian, sizeof(uint64_t)>(
153       true);
154 }
155 
TEST_F(ByteIoTest,Test16SBitBigEndian)156 TEST_F(ByteIoTest, Test16SBitBigEndian) {
157   TestRead<int16_t, ByteReader<int16_t>::ReadBigEndian, sizeof(int16_t)>(true);
158   TestWrite<int16_t, ByteWriter<int16_t>::WriteBigEndian, sizeof(int16_t)>(
159       true);
160 }
161 
TEST_F(ByteIoTest,Test24SBitBigEndian)162 TEST_F(ByteIoTest, Test24SBitBigEndian) {
163   TestRead<int32_t, ByteReader<int32_t, 3>::ReadBigEndian, 3>(true);
164   TestWrite<int32_t, ByteWriter<int32_t, 3>::WriteBigEndian, 3>(true);
165 }
166 
TEST_F(ByteIoTest,Test32SBitBigEndian)167 TEST_F(ByteIoTest, Test32SBitBigEndian) {
168   TestRead<int32_t, ByteReader<int32_t>::ReadBigEndian, sizeof(int32_t)>(true);
169   TestWrite<int32_t, ByteWriter<int32_t>::WriteBigEndian, sizeof(int32_t)>(
170       true);
171 }
172 
TEST_F(ByteIoTest,Test64SBitBigEndian)173 TEST_F(ByteIoTest, Test64SBitBigEndian) {
174   TestRead<int64_t, ByteReader<int64_t>::ReadBigEndian, sizeof(int64_t)>(true);
175   TestWrite<int64_t, ByteWriter<int64_t>::WriteBigEndian, sizeof(int64_t)>(
176       true);
177 }
178 
TEST_F(ByteIoTest,Test16UBitLittleEndian)179 TEST_F(ByteIoTest, Test16UBitLittleEndian) {
180   TestRead<uint16_t, ByteReader<uint16_t>::ReadLittleEndian, sizeof(uint16_t)>(
181       false);
182   TestWrite<uint16_t, ByteWriter<uint16_t>::WriteLittleEndian,
183             sizeof(uint16_t)>(false);
184 }
185 
TEST_F(ByteIoTest,Test24UBitLittleEndian)186 TEST_F(ByteIoTest, Test24UBitLittleEndian) {
187   TestRead<uint32_t, ByteReader<uint32_t, 3>::ReadLittleEndian, 3>(false);
188   TestWrite<uint32_t, ByteWriter<uint32_t, 3>::WriteLittleEndian, 3>(false);
189 }
190 
TEST_F(ByteIoTest,Test32UBitLittleEndian)191 TEST_F(ByteIoTest, Test32UBitLittleEndian) {
192   TestRead<uint32_t, ByteReader<uint32_t>::ReadLittleEndian, sizeof(uint32_t)>(
193       false);
194   TestWrite<uint32_t, ByteWriter<uint32_t>::WriteLittleEndian,
195             sizeof(uint32_t)>(false);
196 }
197 
TEST_F(ByteIoTest,Test64UBitLittleEndian)198 TEST_F(ByteIoTest, Test64UBitLittleEndian) {
199   TestRead<uint64_t, ByteReader<uint64_t>::ReadLittleEndian, sizeof(uint64_t)>(
200       false);
201   TestWrite<uint64_t, ByteWriter<uint64_t>::WriteLittleEndian,
202             sizeof(uint64_t)>(false);
203 }
204 
TEST_F(ByteIoTest,Test16SBitLittleEndian)205 TEST_F(ByteIoTest, Test16SBitLittleEndian) {
206   TestRead<int16_t, ByteReader<int16_t>::ReadLittleEndian, sizeof(int16_t)>(
207       false);
208   TestWrite<int16_t, ByteWriter<int16_t>::WriteLittleEndian, sizeof(int16_t)>(
209       false);
210 }
211 
TEST_F(ByteIoTest,Test24SBitLittleEndian)212 TEST_F(ByteIoTest, Test24SBitLittleEndian) {
213   TestRead<int32_t, ByteReader<int32_t, 3>::ReadLittleEndian, 3>(false);
214   TestWrite<int32_t, ByteWriter<int32_t, 3>::WriteLittleEndian, 3>(false);
215 }
216 
TEST_F(ByteIoTest,Test32SBitLittleEndian)217 TEST_F(ByteIoTest, Test32SBitLittleEndian) {
218   TestRead<int32_t, ByteReader<int32_t>::ReadLittleEndian, sizeof(int32_t)>(
219       false);
220   TestWrite<int32_t, ByteWriter<int32_t>::WriteLittleEndian, sizeof(int32_t)>(
221       false);
222 }
223 
TEST_F(ByteIoTest,Test64SBitLittleEndian)224 TEST_F(ByteIoTest, Test64SBitLittleEndian) {
225   TestRead<int64_t, ByteReader<int64_t>::ReadLittleEndian, sizeof(int64_t)>(
226       false);
227   TestWrite<int64_t, ByteWriter<int64_t>::WriteLittleEndian, sizeof(int64_t)>(
228       false);
229 }
230 
231 // Sets up a fixed byte array and converts N bytes from the array into a
232 // uint64_t. Verifies the value with hard-coded reference.
TEST(ByteIo,SanityCheckFixedByteArrayUnsignedReadBigEndian)233 TEST(ByteIo, SanityCheckFixedByteArrayUnsignedReadBigEndian) {
234   uint8_t data[8] = {0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88};
235   uint64_t value = ByteReader<uint64_t, 2>::ReadBigEndian(data);
236   EXPECT_EQ(static_cast<uint64_t>(0xFFEE), value);
237   value = ByteReader<uint64_t, 3>::ReadBigEndian(data);
238   EXPECT_EQ(static_cast<uint64_t>(0xFFEEDD), value);
239   value = ByteReader<uint64_t, 4>::ReadBigEndian(data);
240   EXPECT_EQ(static_cast<uint64_t>(0xFFEEDDCC), value);
241   value = ByteReader<uint64_t, 5>::ReadBigEndian(data);
242   EXPECT_EQ(static_cast<uint64_t>(0xFFEEDDCCBB), value);
243   value = ByteReader<uint64_t, 6>::ReadBigEndian(data);
244   EXPECT_EQ(static_cast<uint64_t>(0xFFEEDDCCBBAA), value);
245   value = ByteReader<uint64_t, 7>::ReadBigEndian(data);
246   EXPECT_EQ(static_cast<uint64_t>(0xFFEEDDCCBBAA99), value);
247   value = ByteReader<uint64_t, 8>::ReadBigEndian(data);
248   EXPECT_EQ(static_cast<uint64_t>(0xFFEEDDCCBBAA9988), value);
249 }
250 
251 // Same as above, but for little-endian reading.
TEST(ByteIo,SanityCheckFixedByteArrayUnsignedReadLittleEndian)252 TEST(ByteIo, SanityCheckFixedByteArrayUnsignedReadLittleEndian) {
253   uint8_t data[8] = {0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88};
254   uint64_t value = ByteReader<uint64_t, 2>::ReadLittleEndian(data);
255   EXPECT_EQ(static_cast<uint64_t>(0xEEFF), value);
256   value = ByteReader<uint64_t, 3>::ReadLittleEndian(data);
257   EXPECT_EQ(static_cast<uint64_t>(0xDDEEFF), value);
258   value = ByteReader<uint64_t, 4>::ReadLittleEndian(data);
259   EXPECT_EQ(static_cast<uint64_t>(0xCCDDEEFF), value);
260   value = ByteReader<uint64_t, 5>::ReadLittleEndian(data);
261   EXPECT_EQ(static_cast<uint64_t>(0xBBCCDDEEFF), value);
262   value = ByteReader<uint64_t, 6>::ReadLittleEndian(data);
263   EXPECT_EQ(static_cast<uint64_t>(0xAABBCCDDEEFF), value);
264   value = ByteReader<uint64_t, 7>::ReadLittleEndian(data);
265   EXPECT_EQ(static_cast<uint64_t>(0x99AABBCCDDEEFF), value);
266   value = ByteReader<uint64_t, 8>::ReadLittleEndian(data);
267   EXPECT_EQ(static_cast<uint64_t>(0x8899AABBCCDDEEFF), value);
268 }
269 }  // namespace
270 }  // namespace webrtc
271