tbe.c - libeech - bittorrent library
(HTM) git clone git://z3bra.org/libeech.git
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
tbe.c (5594B)
---
1 /* See LICENSE file for copyright and license details. */
2 #include <ctype.h>
3 #include <limits.h>
4 #include <string.h>
5
6 #include "be.h"
7
8 #define MIN(a,b) ((a)<(b)?(a):(b))
9 #define MAX(a,b) ((a)>(b)?(a):(b))
10
11 int
12 beinit(struct be *b, char *s, size_t l)
13 {
14 if (!b || !s || !l)
15 return -1;
16
17 memset(b, 0, sizeof(*b));
18 b->start = s;
19 b->end = b->start + l - 1;
20 b->off = b->start;
21
22 return 0;
23 }
24
25 int
26 beatol(char **str, long *l)
27 {
28 long s = 1;
29 long v = 0;
30 char *sp = *str;
31
32 if (!sp)
33 return -1;
34
35 /* define the sign of our number */
36 if (*sp == '-') {
37 s = -1;
38 sp++;
39 /* -0 is invalid, even for "-03" */
40 if (*sp == '0')
41 return -1;
42 }
43
44 /* 0 followed by a number is considered invalid */
45 if (sp[0] == '0' && isdigit(sp[1]))
46 return -1;
47
48 /* read out number until next non-number, or end of string */
49 while(isdigit(*sp)) {
50 v *= 10;
51 v += *sp++ - '0';
52 }
53
54 if (l)
55 *l = v * s;
56
57 /* move initial pointer to the actual read data */
58 *str = sp;
59
60 return 0;
61 }
62
63 ssize_t
64 beint(struct be *b, long *n)
65 {
66 char *sp;
67 long num;
68
69 if (!b)
70 return -1;
71
72 sp = b->off;
73
74 if (*(sp++) != 'i')
75 return -1;
76
77 beatol(&sp, &num);
78
79 if (*sp != 'e')
80 return -1;
81
82 if (n)
83 *n = num;
84
85 return sp - b->off + 1;
86 }
87
88 ssize_t
89 bestr(struct be *b, char **s, size_t *l)
90 {
91 char *sp;
92 ssize_t len;
93
94 if (!b)
95 return -1;
96
97 sp = b->off;
98
99 if (beatol(&sp, &len) < 0)
100 return -1;
101
102 if (len < 0 || *sp++ != ':')
103 return -1;
104
105 if (s)
106 *s = sp;
107
108 if (l)
109 *l = (size_t)len;
110
111 return sp - b->off + len;
112 }
113
114 ssize_t
115 belist(struct be *b, size_t *n)
116 {
117 size_t c = 0;
118 struct be i;
119
120 if (!b)
121 return -1;
122
123 beinit(&i, b->off, b->end - b->off + 1);
124
125 while(!belistover(&i)) {
126 belistnext(&i);
127 c++;
128 }
129
130 if (*i.off == 'e')
131 i.off++;
132
133 if (n)
134 *n = c;
135
136 return i.off - b->off;
137 }
138
139 ssize_t
140 bedict(struct be *b, size_t *n)
141 {
142 size_t c = 0;
143 struct be i;
144
145 if (!b)
146 return -1;
147
148 beinit(&i, b->off, b->end - b->off + 1);
149
150 while(!belistover(&i)) {
151 bedictnext(&i, NULL, NULL, NULL);
152 c++;
153 }
154
155 if (*i.off == 'e')
156 i.off++;
157
158 if (n)
159 *n = c;
160
161 return i.off - b->off;
162 }
163
164 int
165 belistover(struct be *b) {
166 return b->off >= b->end || *b->off == 'e';
167 }
168
169 int
170 belistnext(struct be *b)
171 {
172 if (!b || *b->off == 'e')
173 return -1;
174
175 if (b->off == b->start && *b->off == 'l') {
176 b->off++;
177 return 0;
178 }
179
180 return !(benext(b) > 0);
181 }
182
183 int
184 bedictnext(struct be *b, char **k, size_t *l, struct be *v)
185 {
186 if (!b || *b->off == 'e')
187 return -1;
188
189 /* move to first element if we're at the start */
190 if (b->off == b->start && *b->off == 'd')
191 b->off++;
192
193 /* retrieve key name and length */
194 if (bestr(b, k, l) < 0)
195 return -1;
196
197 if (benext(b) > 0 && v)
198 beinit(v, b->off, b->end - b->off + 1);
199
200 return !(benext(b) > 0);
201 }
202
203 ssize_t
204 benext(struct be *b)
205 {
206 int r = 0;
207
208 if (!b)
209 return -1;
210
211 /* check for end of buffer */
212 if (b->off >= b->end)
213 return -1;
214
215 /* TODO: implement betype() */
216 switch(betype(b)) {
217 case 'i':
218 r = beint(b, NULL);
219 break;
220 case 'l':
221 r = belist(b, NULL);
222 break;
223 case 'd':
224 r = bedict(b, NULL);
225 break;
226 case 's':
227 r = bestr(b, NULL, NULL);
228 break;
229 }
230
231 b->off += r;
232
233 return r;
234 }
235
236 char
237 betype(struct be *b)
238 {
239 switch(*b->off) {
240 case 'i':
241 case 'l':
242 case 'd':
243 return *b->off;
244 break; /* NOTREACHED */
245 }
246 return isdigit(*b->off) ? 's' : 0;
247 }
248
249 int
250 bekv(struct be *b, char *k, size_t l, struct be *v)
251 {
252 char *key = NULL;
253 size_t klen = 0;
254 struct be i;
255
256 if (!b)
257 return -1;
258
259 if (*b->off != 'd')
260 return -1;
261
262 beinit(&i, b->off, b->end - b->off + 1);
263
264 /* search the data 'till the end */
265 while (!belistover(&i) && !bedictnext(&i, &key, &klen, v)) {
266 /* we found our key! */
267 if (!strncmp(k, key, MIN(l, klen)))
268 return 0;
269
270 /* recursive call to search inner dictionaries */
271 if (betype(&i) == 'd' && !bekv(&i, k, l, v))
272 return 0;
273 }
274
275 /* couldn't find anything, sorry */
276 return -1;
277 }
278
279 int
280 bepath(struct be *b, char **p, size_t l)
281 {
282 char *s;
283 size_t r;
284 struct be i;
285
286 if (!b || betype(b) != 'l')
287 return -1;
288
289 beinit(&i, b->off, b->end - b->off + 1);
290
291 while(!belistnext(&i) && !belistover(&i)) {
292 if (!bestr(&i, &s, &r))
293 continue;
294 strncat(*p, "/", l);
295 strncat(*p, s, r);
296 }
297 return 0;
298 }
299
300 long
301 bekint(struct be *b, char *k, size_t kl)
302 {
303 long n;
304 struct be v;
305
306 if (bekv(b, k, kl, &v) < 0)
307 return -1;
308 if (beint(&v, &n) < 0)
309 return -1;
310
311 return n;
312 }
313
314 int
315 bekstr(struct be *b, char *k, size_t kl, struct be *s)
316 {
317 char *sp;
318 size_t vl;
319 struct be v;
320
321 if (bekv(b, k, kl, &v) < 0)
322 return -1;
323 if (bestr(&v, &sp, &vl) < 0)
324 return -1;
325
326 if (s) {
327 s->start = v.start;
328 s->off = sp;
329 s->end = sp + vl;
330 }
331
332 return 0;
333 }