File Coverage

srl_reader_varint.h
Criterion Covered Total %
statement 29 36 80.5
branch 30 42 71.4
condition n/a
subroutine n/a
pod n/a
total 59 78 75.6


line stmt bran cond sub pod time code
1             #ifndef SRL_READER_VARINT_H_
2             #define SRL_READER_VARINT_H_
3              
4             #include "srl_inline.h"
5             #include "srl_common.h"
6             #include "srl_reader.h"
7             #include "srl_reader_error.h"
8              
9             SRL_STATIC_INLINE void
10             srl_skip_varint(pTHX_ srl_reader_buffer_t *buf)
11             {
12             U8 max_varint_len = sizeof(UV) == sizeof(U32) ? 5 : 10;
13             while (SRL_RDR_NOT_DONE(buf) && *buf->pos & 0x80) {
14             buf->pos++;
15             if (!max_varint_len--)
16             SRL_RDR_ERROR(buf, "varint too long");
17             }
18              
19             if (expect_false( SRL_RDR_DONE(buf) ))
20             SRL_RDR_ERROR(buf, "end of packet reached before varint parsed");
21              
22             buf->pos++;
23             }
24              
25             SRL_STATIC_INLINE UV
26             srl_varint_length(pTHX_ UV value)
27             {
28             UV length = 0;
29             while (value >= 0x80) {
30             length++;
31             value >>= 7;
32             }
33              
34             return ++length;
35             }
36              
37             SRL_STATIC_INLINE UV
38 3740           srl_read_varint_uv_safe(pTHX_ srl_reader_buffer_t *buf)
39             {
40 3740           UV uv= 0;
41 3740           unsigned int lshift= 0;
42              
43 3740 50         while (SRL_RDR_NOT_DONE(buf) && *buf->pos & 0x80) {
    50          
44 0           uv |= ((UV)(*buf->pos++ & 0x7F) << lshift);
45 0           lshift += 7;
46 0 0         if (lshift > (sizeof(UV) * 8))
47 0           SRL_RDR_ERROR(buf, "varint too big");
48             }
49              
50 3740 50         if (expect_true( SRL_RDR_NOT_DONE(buf) )) {
51 3740           uv |= ((UV)*buf->pos++ << lshift);
52             } else {
53 0           SRL_RDR_ERROR(buf, "end of packet reached before varint parsed");
54             }
55              
56 3740           return uv;
57             }
58              
59             #define SET_UV_FROM_VARINT(buf, uv, ptr) STMT_START { \
60             U32 b; \
61             \
62             /* Splitting into 32-bit pieces gives better performance on 32-bit \
63             processors. */ \
64             U32 part0 = 0, part1 = 0, part2 = 0; \
65             do { \
66             \
67             b = *(ptr++); part0 = b ; if (!(b & 0x80)) break; \
68             part0 -= 0x80; \
69             b = *(ptr++); part0 += b << 7; if (!(b & 0x80)) break; \
70             part0 -= 0x80 << 7; \
71             b = *(ptr++); part0 += b << 14; if (!(b & 0x80)) break; \
72             part0 -= 0x80 << 14; \
73             b = *(ptr++); part0 += b << 21; if (!(b & 0x80)) break; \
74             part0 -= 0x80 << 21; \
75             \
76             b = *(ptr++); part1 = b ; if (!(b & 0x80)) break; \
77             part1 -= 0x80; \
78             b = *(ptr++); part1 += b << 7; if (!(b & 0x80)) break; \
79             part1 -= 0x80 << 7; \
80             b = *(ptr++); part1 += b << 14; if (!(b & 0x80)) break; \
81             part1 -= 0x80 << 14; \
82             b = *(ptr++); part1 += b << 21; if (!(b & 0x80)) break; \
83             part1 -= 0x80 << 21; \
84             \
85             b = *(ptr++); part2 = b ; if (!(b & 0x80)) break; \
86             part2 -= 0x80; \
87             b = *(ptr++); part2 += b << 7; if (!(b & 0x80)) break; \
88             /* "part2 -= 0x80 << 7" is irrelevant because (0x80 << 7) << 56 is 0. */\
89             \
90             /* We have overrun the maximum size of a varint (10 bytes). The data \
91             must be corrupt. */ \
92             SRL_RDR_ERROR(buf, "varint not terminated in time, corrupt packet"); \
93             \
94             } while (0); \
95             \
96             uv= (((UV)part0) ) | \
97             (((UV)part1) << 28) | \
98             (((UV)part2) << 56); \
99             \
100             } STMT_END
101              
102             SRL_STATIC_INLINE UV
103             srl_read_varint_uv_nocheck(pTHX_ srl_reader_buffer_t *buf)
104             {
105             UV uv= 0;
106             unsigned int lshift= 0;
107              
108             while (*buf->pos & 0x80) {
109             uv |= ((UV)(*buf->pos++ & 0x7F) << lshift);
110             lshift += 7;
111             if (expect_false( lshift > (sizeof(UV) * 8) ))
112             SRL_RDR_ERROR(buf, "varint too big");
113             }
114              
115             uv |= ((UV)(*buf->pos++) << lshift);
116             return uv;
117             }
118              
119             SRL_STATIC_INLINE UV
120             srl_read_varint_u32_nocheck(pTHX_ srl_reader_buffer_t *buf)
121             {
122             const U8* ptr = buf->pos;
123             U32 b;
124             U32 part0 = 0;
125              
126             b = *(ptr++); part0 = b ; if (!(b & 0x80)) goto done;
127             part0 -= 0x80;
128             b = *(ptr++); part0 += b << 7; if (!(b & 0x80)) goto done;
129             part0 -= 0x80 << 7;
130             b = *(ptr++); part0 += b << 14; if (!(b & 0x80)) goto done;
131             part0 -= 0x80 << 14;
132             b = *(ptr++); part0 += b << 21; if (!(b & 0x80)) goto done;
133             part0 -= 0x80 << 21;
134             b = *(ptr++); part0 += b << 28; if (b < 16) goto done;
135              
136             SRL_RDR_ERROR(buf, "varint overflows U32, cannot restore packet");
137              
138             done:
139             buf->pos= (U8*)ptr;
140              
141             return part0;
142             }
143              
144             SRL_STATIC_INLINE UV
145 2738115           srl_read_varint_u64_nocheck(pTHX_ srl_reader_buffer_t *buf)
146             {
147             UV uv;
148 2738115           const U8* ptr = buf->pos;
149              
150 2738115 100         SET_UV_FROM_VARINT(buf, uv, ptr);
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    100          
    50          
151              
152 2738115           buf->pos= (U8*)ptr;
153              
154 2738115           return uv;
155             }
156              
157             SRL_STATIC_INLINE UV
158 2741855           srl_read_varint_uv(pTHX_ srl_reader_buffer_t *buf)
159             {
160             /* TODO check expect_true log */
161             /* So. This is a bit of a funky piece of logic. Essentially,
162             * we can use the unrolled-loop version of varint decoding
163             * IFF there's certainly enough space in the input buffer
164             * even for the longest possible varint (11 chars, but see
165             * definition of SRL_MAX_VARINT_LENGTH) OR if we know that the
166             * unrolled logic will terminate with an error in case it
167             * reaches the end of the buffer. The latter condition
168             * is true if the varint continuation bit (high bit of the byte)
169             * is not set on the last byte in the buffer (because then the
170             * unrolled logic is guaranteed to terminate before over-reading
171             * past the end of the buffer. */
172 2741855 100         if (expect_true( buf->end - buf->pos >= SRL_MAX_VARINT_LENGTH )
173 823031 100         || !(*(buf->end - 1) & 0x80))
174             {
175             if (sizeof(UV) == sizeof(U32)) {
176             return srl_read_varint_u32_nocheck(aTHX_ buf);
177             } else {
178 2738115           return srl_read_varint_u64_nocheck(aTHX_ buf);
179             }
180             } else {
181 3740           return srl_read_varint_uv_safe(aTHX_ buf);
182             }
183             }
184              
185             SRL_STATIC_INLINE UV
186 349506           srl_read_varint_uv_offset(pTHX_ srl_reader_buffer_t *buf, const char * const errstr)
187             {
188 349506           const UV offset= srl_read_varint_uv(aTHX_ buf);
189             /* A "copy" reference can only refer to things that precede it
190             * in the same body. This check asserts that it at least does not
191             * refer to anything that is yet to be decoded. */
192 349506 50         if (expect_false( buf->body_pos + offset >= buf->pos )) {
193 0           SRL_RDR_ERRORf4(buf, "Corrupted packet%s. Offset %"UVuf" points past current position %"UVuf" in packet with length of %"UVuf" bytes long",
194             errstr, offset, (UV)SRL_RDR_POS_OFS(buf), (UV)SRL_RDR_SIZE(buf));
195             }
196 349506           return offset;
197             }
198              
199             SRL_STATIC_INLINE UV
200 1483512           srl_read_varint_uv_length(pTHX_ srl_reader_buffer_t *buf, const char * const errstr)
201             {
202 1483512           UV len= srl_read_varint_uv(aTHX_ buf);
203 1483512 50         SRL_RDR_ASSERT_SPACE(buf, len, errstr);
    50          
    50          
204 1483512           return len;
205             }
206              
207             SRL_STATIC_INLINE UV
208 416480           srl_read_varint_uv_count(pTHX_ srl_reader_buffer_t *buf, const char * const errstr)
209             {
210 416480           UV len= srl_read_varint_uv(aTHX_ buf);
211 416480 50         if (expect_false( len > I32_MAX )) {
212 0           SRL_RDR_ERRORf3(buf, "Corrupted packet%s. Count %"UVuf" exceeds I32_MAX (%i), which is impossible.",
213             errstr, len, I32_MAX);
214             }
215 416480           return len;
216             }
217              
218             #endif