1 /*
2 Copyright (c) 2012, Broadcom Europe Ltd
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the copyright holder nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <stdio.h>
29
30 #define BITS_LOG_INDENT(ctx) indent_level
31 #include "containers/containers.h"
32 #include "containers/core/containers_common.h"
33 #include "containers/core/containers_logging.h"
34 #include "containers/core/containers_bits.h"
35
36 uint32_t indent_level;
37
38 /** Bit stream containing the values 0 to 10, with each value in that many bits.
39 * At the end there is one further zero bit before the end of the stream. */
40 static uint8_t bits_0_to_10[] = {
41 0xCD, 0x0A, 0x30, 0x70, 0x80, 0x48, 0x14
42 };
43
44 /** Bit stream containing the values 0 to 10, encoded using Exp-Golomb.
45 * At the end there is one further one bit before the end of the stream. */
46 static uint8_t exp_golomb_0_to_10[] = {
47 0xA6, 0x42, 0x98, 0xE2, 0x04, 0x8A, 0x17
48 };
49
50 /** Array of signed values for the Exp-Golomb encoding of each index. */
51 static int32_t exp_golomb_values[] = {
52 0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5
53 };
54
55 /** Bit stream containing two large 32-bit values, encoded using Exp-Golomb. */
56 static uint8_t exp_golomb_large[] = {
57 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
58 };
59
60 /** Bit stream containing a 33-bit value, encoded using Exp-Golomb. */
61 static uint8_t exp_golomb_oversize[] = {
62 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80
63 };
64
plural_ext(uint32_t val)65 static const char *plural_ext(uint32_t val)
66 {
67 return (val == 1) ? "" : "s";
68 }
69
test_reset_and_available(void)70 static int test_reset_and_available(void)
71 {
72 VC_CONTAINER_BITS_T bit_stream;
73 int error_count = 0;
74
75 LOG_DEBUG(NULL, "Testing vc_container_bits_reset and vc_container_bits_available");
76 BITS_INIT(NULL, &bit_stream, bits_0_to_10, countof(bits_0_to_10));
77
78 if (!BITS_AVAILABLE(NULL, &bit_stream))
79 {
80 LOG_ERROR(NULL, "Expected initialised stream to contain bits");
81 error_count++;
82 }
83
84 BITS_RESET(NULL, &bit_stream);
85
86 if (BITS_AVAILABLE(NULL, &bit_stream))
87 {
88 LOG_ERROR(NULL, "Expected reset stream not to contain bits");
89 error_count++;
90 }
91
92 return error_count;
93 }
94
test_read_u32(void)95 static int test_read_u32(void)
96 {
97 VC_CONTAINER_BITS_T bit_stream;
98 uint32_t ii, value;
99 int error_count = 0;
100
101 LOG_DEBUG(NULL, "Testing vc_container_bits_get_u32");
102 BITS_INIT(NULL, &bit_stream, bits_0_to_10, countof(bits_0_to_10));
103
104 for (ii = 0; ii < 11; ii++)
105 {
106 value = BITS_READ_U32(NULL, &bit_stream, ii, "test_read_u32");
107 if (value != ii)
108 {
109 LOG_ERROR(NULL, "Expected %u, got %u", ii, value);
110 error_count++;
111 }
112 }
113
114 value = BITS_READ_U32(NULL, &bit_stream, 1, "Final bit");
115 if (!BITS_VALID(NULL, &bit_stream) || value)
116 {
117 LOG_ERROR(NULL, "Failed to get final bit");
118 error_count++;
119 }
120 value = BITS_READ_U32(NULL, &bit_stream, 1, "Beyond final bit");
121 if (BITS_VALID(NULL, &bit_stream) || value)
122 {
123 LOG_ERROR(NULL, "Unexpectedly succeeded reading beyond expected end of stream");
124 error_count++;
125 }
126
127 return error_count;
128 }
129
test_skip(void)130 static int test_skip(void)
131 {
132 VC_CONTAINER_BITS_T bit_stream;
133 uint32_t ii;
134 int error_count = 0;
135 uint32_t last_bits_left, bits_left;
136
137 LOG_DEBUG(NULL, "Testing vc_container_bits_skip");
138 BITS_INIT(NULL, &bit_stream, bits_0_to_10, countof(bits_0_to_10));
139
140 last_bits_left = BITS_AVAILABLE(NULL, &bit_stream);
141 for (ii = 0; ii < 11; ii++)
142 {
143 BITS_SKIP(NULL, &bit_stream, ii, "test_skip");
144 bits_left = BITS_AVAILABLE(NULL, &bit_stream);
145 if (bits_left + ii != last_bits_left)
146 {
147 int32_t actual = last_bits_left - bits_left;
148 LOG_ERROR(NULL, "Tried to skip %u bit%s, actually skipped %d bit%s",
149 ii, plural_ext(ii), actual, plural_ext(actual));
150 error_count++;
151 }
152 last_bits_left = bits_left;
153 }
154
155 BITS_SKIP(NULL, &bit_stream, 1, "Final bit");
156 if (!BITS_VALID(NULL, &bit_stream))
157 {
158 LOG_ERROR(NULL, "Failed to skip final bit");
159 error_count++;
160 }
161 if (BITS_AVAILABLE(NULL, &bit_stream))
162 {
163 LOG_ERROR(NULL, "End of stream not reached by skipping");
164 error_count++;
165 }
166
167 BITS_SKIP(NULL, &bit_stream, 1, "Beyond final bit");
168 if (BITS_VALID(NULL, &bit_stream))
169 {
170 LOG_ERROR(NULL, "Unexpectedly succeeded skipping beyond expected end of stream");
171 error_count++;
172 }
173 return error_count;
174 }
175
test_ptr_and_skip_bytes(void)176 static int test_ptr_and_skip_bytes(void)
177 {
178 VC_CONTAINER_BITS_T bit_stream;
179 uint32_t ii;
180 const uint8_t *expected_ptr;
181 int error_count = 0;
182 uint32_t last_bytes_left, bytes_left;
183
184 LOG_DEBUG(NULL, "Testing vc_container_bits_current_pointer, vc_container_bits_skip_bytes and vc_container_bits_bytes_available");
185 BITS_INIT(NULL, &bit_stream, bits_0_to_10, countof(bits_0_to_10));
186
187 last_bytes_left = BITS_BYTES_AVAILABLE(NULL, &bit_stream);
188 if (last_bytes_left != countof(bits_0_to_10))
189 {
190 LOG_ERROR(NULL, "Expected bytes available to initially match given size");
191 error_count++;
192 }
193
194 if (BITS_CURRENT_POINTER(NULL, &bit_stream) != bits_0_to_10)
195 {
196 LOG_ERROR(NULL, "Expected initial current pointer to match original buffer");
197 error_count++;
198 }
199
200 expected_ptr = bits_0_to_10;
201 for (ii = 0; ii < 4; ii++)
202 {
203 BITS_SKIP_BYTES(NULL, &bit_stream, ii, "test_ptr_and_skip_bytes");
204
205 expected_ptr += ii;
206 if (BITS_CURRENT_POINTER(NULL, &bit_stream) != expected_ptr)
207 {
208 LOG_ERROR(NULL, "Expected current pointer to have moved by %u byte%s", ii, plural_ext(ii));
209 error_count++;
210 }
211
212 bytes_left = BITS_BYTES_AVAILABLE(NULL, &bit_stream);
213 if (bytes_left + ii != last_bytes_left)
214 {
215 int32_t actual = last_bytes_left - bytes_left;
216 LOG_ERROR(NULL, "Tried to skip %u byte%s, actually skipped %d byte%s",
217 ii, plural_ext(ii), actual, plural_ext(actual));
218 error_count++;
219 }
220
221 last_bytes_left = bytes_left;
222 }
223
224 if (!bytes_left)
225 {
226 LOG_ERROR(NULL, "Reached end of stream too soon");
227 error_count++;
228 }
229 if (!BITS_VALID(NULL, &bit_stream))
230 {
231 LOG_ERROR(NULL, "Expected stream to be valid");
232 error_count++;
233 }
234
235 BITS_SKIP_BYTES(NULL, &bit_stream, bytes_left + 1, "Beyond end of stream");
236 if (BITS_VALID(NULL, &bit_stream))
237 {
238 LOG_ERROR(NULL, "Unexpectedly succeeded skipping bytes beyond end of stream");
239 error_count++;
240 }
241 if (BITS_BYTES_AVAILABLE(NULL, &bit_stream))
242 {
243 LOG_ERROR(NULL, "Expected stream to have been reset");
244 error_count++;
245 }
246
247 return error_count;
248 }
249
test_reduce_bytes(void)250 static int test_reduce_bytes(void)
251 {
252 VC_CONTAINER_BITS_T bit_stream;
253 uint32_t ii;
254 int error_count = 0;
255 uint32_t last_bytes_left, bytes_left;
256
257 LOG_DEBUG(NULL, "Testing vc_container_bits_reduce_bytes");
258 BITS_INIT(NULL, &bit_stream, bits_0_to_10, countof(bits_0_to_10));
259
260 last_bytes_left = BITS_BYTES_AVAILABLE(NULL, &bit_stream);
261 if (last_bytes_left != countof(bits_0_to_10))
262 {
263 LOG_ERROR(NULL, "Expected bytes available to initially match given size");
264 error_count++;
265 }
266
267 if (BITS_CURRENT_POINTER(NULL, &bit_stream) != bits_0_to_10)
268 {
269 LOG_ERROR(NULL, "Expected initial current pointer to match original buffer");
270 error_count++;
271 }
272
273 for (ii = 0; ii < 4; ii++)
274 {
275 BITS_REDUCE_BYTES(NULL, &bit_stream, ii, "test_reduce_bytes");
276
277 if (BITS_CURRENT_POINTER(NULL, &bit_stream) != bits_0_to_10)
278 {
279 LOG_ERROR(NULL, "Did not expect current pointer to have moved");
280 error_count++;
281 }
282
283 bytes_left = BITS_BYTES_AVAILABLE(NULL, &bit_stream);
284 if (bytes_left + ii != last_bytes_left)
285 {
286 int32_t actual = last_bytes_left - bytes_left;
287 LOG_ERROR(NULL, "Tried to reduce by %u byte%s, actually reduced by %d byte%s",
288 ii, plural_ext(ii), actual, plural_ext(actual));
289 error_count++;
290 }
291
292 last_bytes_left = bytes_left;
293 }
294
295 if (!bytes_left)
296 {
297 LOG_ERROR(NULL, "Reached end of stream too soon");
298 error_count++;
299 }
300 if (!BITS_VALID(NULL, &bit_stream))
301 {
302 LOG_ERROR(NULL, "Expected stream to be valid");
303 error_count++;
304 }
305
306 BITS_REDUCE_BYTES(NULL, &bit_stream, bytes_left + 1, "Reducing an empty stream");
307 if (BITS_VALID(NULL, &bit_stream))
308 {
309 LOG_ERROR(NULL, "Unexpectedly succeeded reducing by too many bytes");
310 error_count++;
311 }
312 if (BITS_AVAILABLE(NULL, &bit_stream))
313 {
314 LOG_ERROR(NULL, "Expected stream to have been reset");
315 error_count++;
316 }
317
318 return error_count;
319 }
320
test_copy_bytes(void)321 static int test_copy_bytes(void)
322 {
323 VC_CONTAINER_BITS_T bit_stream;
324 int error_count = 0;
325 uint8_t buffer[countof(bits_0_to_10)];
326 uint32_t ii;
327
328 LOG_DEBUG(NULL, "Testing vc_container_bits_copy_bytes");
329 BITS_INIT(NULL, &bit_stream, bits_0_to_10, countof(bits_0_to_10));
330 memset(buffer, 0, sizeof(buffer));
331
332 /* Copy whole buffer in one go */
333 BITS_COPY_BYTES(NULL, &bit_stream, countof(buffer), buffer, "Copy whole buffer");
334
335 if (!BITS_VALID(NULL, &bit_stream))
336 {
337 LOG_ERROR(NULL, "Failed to copy the whole buffer");
338 error_count++;
339 }
340
341 if (memcmp(buffer, bits_0_to_10, countof(bits_0_to_10)) != 0)
342 {
343 LOG_ERROR(NULL, "Single copy doesn't match original");
344 error_count++;
345 }
346
347 BITS_INIT(NULL, &bit_stream, bits_0_to_10, countof(bits_0_to_10));
348 memset(buffer, 0, sizeof(buffer));
349
350 /* Copy whole buffer one byte at a time */
351 for (ii = 0; ii < countof(bits_0_to_10); ii++)
352 {
353 BITS_COPY_BYTES(NULL, &bit_stream, 1, buffer + ii, "Copy buffer piecemeal");
354 }
355
356 if (!BITS_VALID(NULL, &bit_stream))
357 {
358 LOG_ERROR(NULL, "Failed to copy the buffer piecemeal");
359 error_count++;
360 }
361
362 if (memcmp(buffer, bits_0_to_10, countof(bits_0_to_10)) != 0)
363 {
364 LOG_ERROR(NULL, "Multiple copy doesn't match original");
365 error_count++;
366 }
367
368 BITS_INIT(NULL, &bit_stream, bits_0_to_10, countof(bits_0_to_10));
369 memset(buffer, 0, sizeof(buffer));
370
371 /* Copy part of buffer */
372 BITS_SKIP_BYTES(NULL, &bit_stream, 1, "Copy part of buffer");
373 BITS_REDUCE_BYTES(NULL, &bit_stream, 1, "Copy part of buffer");
374 BITS_COPY_BYTES(NULL, &bit_stream, countof(buffer) - 2, buffer, "Copy part of buffer");
375
376 if (!BITS_VALID(NULL, &bit_stream))
377 {
378 LOG_ERROR(NULL, "Failed to copy part of buffer");
379 error_count++;
380 }
381
382 if (memcmp(buffer, bits_0_to_10 + 1, countof(bits_0_to_10) - 2) != 0)
383 {
384 LOG_ERROR(NULL, "Partial copy doesn't match original");
385 error_count++;
386 }
387
388 return error_count;
389 }
390
test_skip_exp_golomb(void)391 static int test_skip_exp_golomb(void)
392 {
393 VC_CONTAINER_BITS_T bit_stream;
394 uint32_t ii;
395 int error_count = 0;
396
397 LOG_DEBUG(NULL, "Testing vc_container_bits_skip_exp_golomb");
398 BITS_INIT(NULL, &bit_stream, exp_golomb_0_to_10, countof(exp_golomb_0_to_10));
399
400 for (ii = 0; ii < 12; ii++)
401 {
402 BITS_SKIP_EXP(NULL, &bit_stream, "test_skip_exp_golomb");
403 }
404
405 if (!BITS_VALID(NULL, &bit_stream))
406 {
407 LOG_ERROR(NULL, "Failed to skip through buffer");
408 error_count++;
409 }
410
411 BITS_SKIP_EXP(NULL, &bit_stream, "Skip beyond end of stream");
412 if (BITS_VALID(NULL, &bit_stream))
413 {
414 LOG_ERROR(NULL, "Unexpectedly succeeded skipping beyond expected end of stream");
415 error_count++;
416 }
417
418 return error_count;
419 }
420
test_read_u32_exp_golomb(void)421 static int test_read_u32_exp_golomb(void)
422 {
423 VC_CONTAINER_BITS_T bit_stream;
424 uint32_t ii, value;
425 int error_count = 0;
426
427 LOG_DEBUG(NULL, "Testing vc_container_bits_get_u32_exp_golomb");
428 BITS_INIT(NULL, &bit_stream, exp_golomb_0_to_10, countof(exp_golomb_0_to_10));
429
430 for (ii = 0; ii < 11; ii++)
431 {
432 value = BITS_READ_U32_EXP(NULL, &bit_stream, "test_read_u32_exp_golomb");
433 if (value != ii)
434 {
435 LOG_ERROR(NULL, "Expected %u, got %u", ii, value);
436 error_count++;
437 }
438 }
439
440 value = BITS_READ_U32(NULL, &bit_stream, 1, "Final bit");
441 if (!BITS_VALID(NULL, &bit_stream) || !value)
442 {
443 LOG_ERROR(NULL, "Failed to get final bit (expected a 1)");
444 error_count++;
445 }
446 value = BITS_READ_U32_EXP(NULL, &bit_stream, "Beyond end of stream");
447 if (BITS_VALID(NULL, &bit_stream) || value)
448 {
449 LOG_ERROR(NULL, "Unexpectedly succeeded reading beyond expected end of stream");
450 error_count++;
451 }
452
453 /* Test getting two large (32 bit) Exp-Golomb values */
454 BITS_INIT(NULL, &bit_stream, exp_golomb_large, countof(exp_golomb_large));
455
456 value = BITS_READ_U32_EXP(NULL, &bit_stream, "Second largest 32-bit value");
457 if (value != 0xFFFFFFFE)
458 {
459 LOG_ERROR(NULL, "Failed to get second largest 32-bit value");
460 error_count++;
461 }
462
463 value = BITS_READ_U32_EXP(NULL, &bit_stream, "Largest 32-bit value");
464 if (value != 0xFFFFFFFF)
465 {
466 LOG_ERROR(NULL, "Failed to get largest 32-bit value");
467 error_count++;
468 }
469
470 /* Test getting an oversize (33 bit) Exp-Golomb value */
471 BITS_INIT(NULL, &bit_stream, exp_golomb_oversize, countof(exp_golomb_oversize));
472
473 value = BITS_READ_U32_EXP(NULL, &bit_stream, "Unsigned 33-bit value");
474 if (BITS_VALID(NULL, &bit_stream) || value)
475 {
476 LOG_ERROR(NULL, "Unexpectedly got 33-bit value: %u", value);
477 error_count++;
478 }
479
480 return error_count;
481 }
482
test_read_s32_exp_golomb(void)483 static int test_read_s32_exp_golomb(void)
484 {
485 VC_CONTAINER_BITS_T bit_stream;
486 uint32_t ii;
487 int32_t value;
488 int error_count = 0;
489
490 LOG_DEBUG(NULL, "Testing vc_container_bits_get_s32_exp_golomb");
491 BITS_INIT(NULL, &bit_stream, exp_golomb_0_to_10, countof(exp_golomb_0_to_10));
492
493 for (ii = 0; ii < 11; ii++)
494 {
495 value = BITS_READ_S32_EXP(NULL, &bit_stream, "test_read_s32_exp_golomb");
496 if (value != exp_golomb_values[ii])
497 {
498 LOG_ERROR(NULL, "Expected %u, got %u", ii, value);
499 error_count++;
500 }
501 }
502
503 value = BITS_READ_S32_EXP(NULL, &bit_stream, "Final bit");
504 if (!BITS_VALID(NULL, &bit_stream) || value)
505 {
506 LOG_ERROR(NULL, "Failed to get final Exp-Golomb value (expected a zero)");
507 error_count++;
508 }
509 value = BITS_READ_S32_EXP(NULL, &bit_stream, "Beyond final bit");
510 if (BITS_VALID(NULL, &bit_stream) || value)
511 {
512 LOG_ERROR(NULL, "Unexpectedly succeeded reading beyond expected end of stream");
513 error_count++;
514 }
515
516 /* Test getting two large (32 bit) Exp-Golomb values */
517 BITS_INIT(NULL, &bit_stream, exp_golomb_large, countof(exp_golomb_large));
518
519 value = BITS_READ_S32_EXP(NULL, &bit_stream, "Largest signed 32-bit value");
520 if (!BITS_VALID(NULL, &bit_stream) || value != -0x7FFFFFFF)
521 {
522 LOG_ERROR(NULL, "Failed to get largest signed 32-bit value: %d", value);
523 error_count++;
524 }
525
526 value = BITS_READ_S32_EXP(NULL, &bit_stream, "Just too large signed 33-bit value");
527 if (BITS_VALID(NULL, &bit_stream) || value)
528 {
529 LOG_ERROR(NULL, "Unexpectedly got slightly too large signed 32-bit value: %d", value);
530 error_count++;
531 }
532
533 /* Test getting an oversize (33 bit) Exp-Golomb value */
534 BITS_INIT(NULL, &bit_stream, exp_golomb_oversize, countof(exp_golomb_oversize));
535
536 value = BITS_READ_S32_EXP(NULL, &bit_stream, "Larger signed 33-bit value");
537 if (BITS_VALID(NULL, &bit_stream) || value)
538 {
539 LOG_ERROR(NULL, "Unexpectedly got signed 33-bit value: %d", value);
540 error_count++;
541 }
542
543 return error_count;
544 }
545
546 #ifdef ENABLE_CONTAINERS_LOG_FORMAT
test_indentation(void)547 static int test_indentation(void)
548 {
549 VC_CONTAINER_BITS_T bit_stream;
550 uint32_t ii;
551
552 LOG_DEBUG(NULL, "Testing logging indentation");
553 BITS_INIT(NULL, &bit_stream, bits_0_to_10, countof(bits_0_to_10));
554
555 for (ii = 0; ii < 11; ii++)
556 {
557 indent_level = ii;
558 BITS_READ_U32(NULL, &bit_stream, ii, "test_indentation (unit)");
559 }
560
561 BITS_INIT(NULL, &bit_stream, bits_0_to_10, countof(bits_0_to_10));
562
563 for (ii = 0; ii < 11; ii++)
564 {
565 indent_level = ii * 10;
566 BITS_READ_U32(NULL, &bit_stream, ii, "test_indentation (tens)");
567 }
568 return 0;
569 }
570 #endif
571
main(int argc,char ** argv)572 int main(int argc, char **argv)
573 {
574 int error_count = 0;
575
576 VC_CONTAINER_PARAM_UNUSED(argc);
577 VC_CONTAINER_PARAM_UNUSED(argv);
578
579 error_count += test_reset_and_available();
580 error_count += test_read_u32();
581 error_count += test_skip();
582 error_count += test_ptr_and_skip_bytes();
583 error_count += test_reduce_bytes();
584 error_count += test_copy_bytes();
585 error_count += test_skip_exp_golomb();
586 error_count += test_read_u32_exp_golomb();
587 error_count += test_read_s32_exp_golomb();
588 #ifdef ENABLE_CONTAINERS_LOG_FORMAT
589 error_count += test_indentation();
590 #endif
591
592 if (error_count)
593 {
594 LOG_ERROR(NULL, "*** %d errors reported", error_count);
595 getchar();
596 }
597
598 return error_count;
599 }
600