1/*
2 * librdkafka - The Apache Kafka C/C++ library
3 *
4 * Copyright (c) 2016 Magnus Edenhill
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29
30#include "rdvarint.h"
31#include "rdunittest.h"
32
33
34/**
35 * @brief Read a varint-encoded signed integer from \p slice.
36 */
37size_t rd_varint_dec_slice (rd_slice_t *slice, int64_t *nump) {
38 size_t num = 0;
39 int shift = 0;
40 unsigned char oct;
41
42 /* FIXME: Optimize to use something better than read() */
43 do {
44 size_t r = rd_slice_read(slice, &oct, sizeof(oct));
45 if (unlikely(r == 0))
46 return 0; /* Underflow */
47 num |= (uint64_t)(oct & 0x7f) << shift;
48 shift += 7;
49 } while (oct & 0x80);
50
51 *nump = (int64_t)((num >> 1) ^ -(int64_t)(num & 1));
52
53 return shift / 7;
54}
55
56
57
58
59
60static int do_test_rd_uvarint_enc_i64 (const char *file, int line,
61 int64_t num, const char *exp,
62 size_t exp_size) {
63 char buf[16] = { 0xff, 0xff, 0xff, 0xff,
64 0xff, 0xff, 0xff, 0xff,
65 0xff, 0xff, 0xff, 0xff,
66 0xff, 0xff, 0xff, 0xff };
67 size_t sz = rd_uvarint_enc_i64(buf, sizeof(buf), num);
68 size_t r;
69 int ir;
70 rd_buf_t b;
71 rd_slice_t slice, bad_slice;
72 int64_t ret_num;
73
74 if (sz != exp_size || memcmp(buf, exp, exp_size))
75 RD_UT_FAIL("i64 encode of %"PRId64": "
76 "expected size %"PRIusz" (got %"PRIusz")\n",
77 num, exp_size, sz);
78
79 /* Verify with standard decoder */
80 r = rd_varint_dec_i64(buf, sz, &ret_num);
81 RD_UT_ASSERT(!RD_UVARINT_DEC_FAILED(r),
82 "varint decode failed: %"PRIusz, r);
83 RD_UT_ASSERT(ret_num == num,
84 "varint decode returned wrong number: "
85 "%"PRId64" != %"PRId64, ret_num, num);
86
87 /* Verify with slice decoder */
88 rd_buf_init(&b, 1, 0);
89 rd_buf_push(&b, buf, sz, NULL);
90 rd_slice_init_full(&slice, &b);
91
92 /* Should fail for incomplete reads */
93 ir = rd_slice_narrow_copy(&slice, &bad_slice,
94 rd_slice_remains(&slice)-1);
95 RD_UT_ASSERT(ir, "narrow_copy failed");
96 ret_num = -1;
97 r = rd_varint_dec_slice(&bad_slice, &ret_num);
98 RD_UT_ASSERT(RD_UVARINT_DEC_FAILED(r),
99 "varint decode failed should have failed, returned %"PRIusz,
100 r);
101
102 /* Verify proper slice */
103 ret_num = -1;
104 r = rd_varint_dec_slice(&slice, &ret_num);
105 RD_UT_ASSERT(!RD_UVARINT_DEC_FAILED(r),
106 "varint decode failed: %"PRIusz, r);
107 RD_UT_ASSERT(ret_num == num,
108 "varint decode returned wrong number: "
109 "%"PRId64" != %"PRId64, ret_num, num);
110
111 rd_buf_destroy(&b);
112
113 RD_UT_PASS();
114}
115
116
117int unittest_rdvarint (void) {
118 int fails = 0;
119
120 fails += do_test_rd_uvarint_enc_i64(__FILE__, __LINE__, 23,
121 (const char[]){ 23<<1 }, 1);
122 fails += do_test_rd_uvarint_enc_i64(__FILE__, __LINE__, 253,
123 (const char[]){ 0xfa, 3 }, 2);
124
125 return fails;
126}
127