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