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