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 | */ |
37 | size_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 | |
60 | static 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 | |
117 | int 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 | |