source: trunk/libtransmission/variant-benc.c

Last change on this file was 14644, checked in by mikedld, 5 years ago

Remove useless checks and definitions (C99)

Now that MSVC support for C99 is quite good, remove previously needed but
now unused checks and definitions, like PRI* format macros (including
PRIdMAX and TR_PRIuSIZE, replaced with %jd and %zu) and inline macro.
Also, remove ssize_t typedef and replace few occurences with ev_ssize_t.
Also, remove check for stdbool.h availability (guaranteed by C99) and
include it unconditionally (except when in C++ mode).

  • Property svn:keywords set to Date Rev Author Id
File size: 7.9 KB
Line 
1/*
2 * This file Copyright (C) 2008-2014 Mnemosyne LLC
3 *
4 * It may be used under the GNU GPL versions 2 or 3
5 * or any future license endorsed by Mnemosyne LLC.
6 *
7 * $Id: variant-benc.c 14644 2015-12-29 19:37:31Z mikedld $
8 */
9
10#include <assert.h>
11#include <ctype.h> /* isdigit() */
12#include <errno.h>
13#include <stdlib.h> /* strtoul() */
14#include <string.h> /* strlen(), memchr() */
15
16#include <event2/buffer.h>
17
18#include "ConvertUTF.h"
19
20#define __LIBTRANSMISSION_VARIANT_MODULE__
21#include "transmission.h"
22#include "ptrarray.h"
23#include "utils.h" /* tr_snprintf() */
24#include "variant.h"
25#include "variant-common.h"
26
27/***
28****  tr_variantParse()
29****  tr_variantLoad()
30***/
31
32/**
33 * The initial i and trailing e are beginning and ending delimiters.
34 * You can have negative numbers such as i-3e. You cannot prefix the
35 * number with a zero such as i04e. However, i0e is valid.
36 * Example: i3e represents the integer "3"
37 * NOTE: The maximum number of bit of this integer is unspecified,
38 * but to handle it as a signed 64bit integer is mandatory to handle
39 * "large files" aka .torrent for more that 4Gbyte
40 */
41int
42tr_bencParseInt (const uint8_t  * buf,
43                 const uint8_t  * bufend,
44                 const uint8_t ** setme_end,
45                 int64_t        * setme_val)
46{
47  char * endptr;
48  const void * begin;
49  const void * end;
50  int64_t val;
51
52  if (buf >= bufend)
53    return EILSEQ;
54  if (*buf != 'i')
55    return EILSEQ;
56
57  begin = buf + 1;
58  end = memchr (begin, 'e', (bufend - buf) - 1);
59  if (end == NULL)
60    return EILSEQ;
61
62  errno = 0;
63  val = evutil_strtoll (begin, &endptr, 10);
64  if (errno || (endptr != end)) /* incomplete parse */
65    return EILSEQ;
66  if (val && * (const char*)begin == '0') /* no leading zeroes! */
67    return EILSEQ;
68
69  *setme_end = (const uint8_t*)end + 1;
70  *setme_val = val;
71  return 0;
72}
73
74/**
75 * Byte strings are encoded as follows:
76 * <string length encoded in base ten ASCII>:<string data>
77 * Note that there is no constant beginning delimiter, and no ending delimiter.
78 * Example: 4:spam represents the string "spam"
79 */
80int
81tr_bencParseStr (const uint8_t  * buf,
82                 const uint8_t  * bufend,
83                 const uint8_t ** setme_end,
84                 const uint8_t ** setme_str,
85                 size_t *         setme_strlen)
86{
87  const void * end;
88  size_t len;
89  char * ulend;
90  const uint8_t * strbegin;
91  const uint8_t * strend;
92
93  if (buf >= bufend)
94    goto err;
95
96  if (!isdigit (*buf))
97    goto err;
98
99  end = memchr (buf, ':', bufend - buf);
100  if (end == NULL)
101    goto err;
102
103  errno = 0;
104  len = strtoul ((const char*)buf, &ulend, 10);
105  if (errno || ulend != end)
106    goto err;
107
108  strbegin = (const uint8_t*)end + 1;
109  strend = strbegin + len;
110  if ((strend<strbegin) || (strend>bufend))
111    goto err;
112
113  *setme_end = (const uint8_t*)end + 1 + len;
114  *setme_str = (const uint8_t*)end + 1;
115  *setme_strlen = len;
116  return 0;
117
118err:
119  *setme_end = NULL;
120  *setme_str = NULL;
121  *setme_strlen= 0;
122  return EILSEQ;
123}
124
125static tr_variant*
126get_node (tr_ptrArray * stack, tr_quark * key, tr_variant * top, int * err)
127{
128  tr_variant * node = NULL;
129
130  if (tr_ptrArrayEmpty (stack))
131    {
132      node = top;
133    }
134  else
135    {
136      tr_variant * parent = tr_ptrArrayBack (stack);
137
138      if (tr_variantIsList (parent))
139        {
140          node = tr_variantListAdd (parent);
141        }
142      else if (*key && tr_variantIsDict (parent))
143        {
144          node = tr_variantDictAdd (parent, *key);
145          *key = 0;
146        }
147      else
148        {
149          *err = EILSEQ;
150        }
151    }
152
153  return node;
154}
155
156/**
157 * This function's previous recursive implementation was
158 * easier to read, but was vulnerable to a smash-stacking
159 * attack via maliciously-crafted bencoded data. (#667)
160 */
161int
162tr_variantParseBenc (const void    * buf_in,
163                     const void    * bufend_in,
164                     tr_variant    * top,
165                     const char   ** setme_end)
166{
167  int err = 0;
168  const uint8_t * buf = buf_in;
169  const uint8_t * bufend = bufend_in;
170  tr_ptrArray stack = TR_PTR_ARRAY_INIT;
171  tr_quark key = 0;
172
173  tr_variantInit (top, 0);
174
175  while (buf != bufend)
176    {
177      if (buf > bufend) /* no more text to parse... */
178        err = EILSEQ;
179
180      if (err)
181        break;
182
183      if (*buf == 'i') /* int */
184        {
185          int64_t val;
186          const uint8_t * end;
187          tr_variant * v;
188
189          if ((err = tr_bencParseInt (buf, bufend, &end, &val)))
190            break;
191          buf = end;
192
193          if ((v = get_node (&stack, &key, top, &err)))
194            tr_variantInitInt (v, val);
195        }
196      else if (*buf == 'l') /* list */
197        {
198          tr_variant * v;
199
200          ++buf;
201
202          if ((v = get_node (&stack, &key, top, &err)))
203            {
204              tr_variantInitList (v, 0);
205              tr_ptrArrayAppend (&stack, v);
206            }
207        }
208      else if (*buf == 'd') /* dict */
209        {
210          tr_variant * v;
211
212          ++buf;
213
214          if ((v = get_node (&stack, &key, top, &err)))
215            {
216              tr_variantInitDict (v, 0);
217              tr_ptrArrayAppend (&stack, v);
218            }
219        }
220      else if (*buf == 'e') /* end of list or dict */
221        {
222          ++buf;
223
224          if (tr_ptrArrayEmpty (&stack) || (key != 0))
225            {
226              err = EILSEQ;
227              break;
228            }
229          else
230            {
231              tr_ptrArrayPop (&stack);
232              if (tr_ptrArrayEmpty (&stack))
233                break;
234            }
235        }
236      else if (isdigit (*buf)) /* string? */
237        {
238          tr_variant * v;
239          const uint8_t * end;
240          const uint8_t * str;
241          size_t str_len;
242
243          if ((err = tr_bencParseStr (buf, bufend, &end, &str, &str_len)))
244            break;
245          buf = end;
246
247          if (!key && !tr_ptrArrayEmpty(&stack) && tr_variantIsDict(tr_ptrArrayBack(&stack)))
248            key = tr_quark_new (str, str_len);
249          else if ((v = get_node (&stack, &key, top, &err)))
250            tr_variantInitStr (v, str, str_len);
251        }
252      else /* invalid bencoded text... march past it */
253        {
254          ++buf;
255        }
256
257      if (tr_ptrArrayEmpty (&stack))
258        break;
259    }
260
261  if (!err && (!top->type || !tr_ptrArrayEmpty(&stack)))
262    err = EILSEQ;
263
264  if (!err && setme_end)
265    *setme_end = (const char*) buf;
266
267  tr_ptrArrayDestruct (&stack, NULL);
268  return err;
269}
270
271/****
272*****
273****/
274
275static void
276saveIntFunc (const tr_variant * val, void * evbuf)
277{
278  evbuffer_add_printf (evbuf, "i%" PRId64 "e", val->val.i);
279}
280
281static void
282saveBoolFunc (const tr_variant * val, void * evbuf)
283{
284  if (val->val.b)
285    evbuffer_add (evbuf, "i1e", 3);
286  else
287    evbuffer_add (evbuf, "i0e", 3);
288}
289
290static void
291saveRealFunc (const tr_variant * val, void * evbuf)
292{
293  int len;
294  char buf[128];
295
296  len = tr_snprintf (buf, sizeof (buf), "%f", val->val.d);
297  evbuffer_add_printf (evbuf, "%d:", len);
298  evbuffer_add (evbuf, buf, len);
299}
300
301static void
302saveStringFunc (const tr_variant * v, void * evbuf)
303{
304  size_t len;
305  const char * str;
306  tr_variantGetStr (v, &str, &len);
307  evbuffer_add_printf (evbuf, "%zu:", len);
308  evbuffer_add (evbuf, str, len);
309}
310
311static void
312saveDictBeginFunc (const tr_variant * val UNUSED, void * evbuf)
313{
314  evbuffer_add (evbuf, "d", 1);
315}
316
317static void
318saveListBeginFunc (const tr_variant * val UNUSED, void * evbuf)
319{
320  evbuffer_add (evbuf, "l", 1);
321}
322
323static void
324saveContainerEndFunc (const tr_variant * val UNUSED, void * evbuf)
325{
326  evbuffer_add (evbuf, "e", 1);
327}
328
329static const struct VariantWalkFuncs walk_funcs = { saveIntFunc,
330                                                    saveBoolFunc,
331                                                    saveRealFunc,
332                                                    saveStringFunc,
333                                                    saveDictBeginFunc,
334                                                    saveListBeginFunc,
335                                                    saveContainerEndFunc };
336
337void
338tr_variantToBufBenc (const tr_variant * top, struct evbuffer * buf)
339{
340  tr_variantWalk (top, &walk_funcs, buf, true);
341}
342
Note: See TracBrowser for help on using the repository browser.