source: trunk/libtransmission/bencode.c @ 241

Last change on this file since 241 was 241, checked in by joshe, 16 years ago

Make sure not to go past the end of the buffer when loading bencoded data.
Add code to encode using bencoding.

File size: 8.2 KB
Line 
1/******************************************************************************
2 * Copyright (c) 2005 Eric Petit
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 *****************************************************************************/
22
23#include "transmission.h"
24
25#define LIST_SIZE   20
26#define OUTBUF_SIZE 100
27
28static int tr_bencSprintf( char ** buf, size_t * used, size_t * max,
29                           char * format, ... )
30#ifdef __GNUC__
31    __attribute__ ((format (printf, 4, 5)))
32#endif
33    ;
34
35int _tr_bencLoad( char * buf, size_t len, benc_val_t * val, char ** end )
36{
37    char * p, * e, * foo;
38
39    if( 1 >= len )
40    {
41        return 1;
42    }
43
44    if( !end )
45    {
46        /* So we only have to check once */
47        end = &foo;
48    }
49
50    val->begin = buf;
51
52    if( buf[0] == 'i' )
53    {
54        e = memchr( &buf[1], 'e', len - 1 );
55        if( NULL == e )
56        {
57            return 1;
58        }
59
60        /* Integer: i1242e */
61        val->type  = TYPE_INT;
62        *e         = '\0';
63        val->val.i = strtoll( &buf[1], &p, 10 );
64        *e         = 'e';
65
66        if( p != e )
67        {
68            return 1;
69        }
70
71        val->end = p + 1;
72    }
73    else if( buf[0] == 'l' || buf[0] == 'd' )
74    {
75        /* List: l<item1><item2>e
76           Dict: d<string1><item1><string2><item2>e
77           A dictionary is just a special kind of list with an even
78           count of items, and where even items are strings. */
79        char * cur;
80        char   is_dict;
81        char   str_expected;
82
83        is_dict          = ( buf[0] == 'd' );
84        val->type        = is_dict ? TYPE_DICT : TYPE_LIST;
85        val->val.l.alloc = LIST_SIZE;
86        val->val.l.count = 0;
87        val->val.l.vals  = malloc( LIST_SIZE * sizeof( benc_val_t ) );
88        cur              = &buf[1];
89        str_expected     = 1;
90        while( (size_t)(cur - buf) < len && cur[0] != 'e' )
91        {
92            if( val->val.l.count == val->val.l.alloc )
93            {
94                /* We need a bigger boat */
95                val->val.l.alloc += LIST_SIZE;
96                val->val.l.vals   =  realloc( val->val.l.vals,
97                        val->val.l.alloc  * sizeof( benc_val_t ) );
98            }
99            if( tr_bencLoad( cur, len - (cur - buf),
100                             &val->val.l.vals[val->val.l.count], &p ) )
101            {
102                return 1;
103            }
104            if( is_dict && str_expected &&
105                val->val.l.vals[val->val.l.count].type != TYPE_STR )
106            {
107                return 1;
108            }
109            str_expected = !str_expected;
110
111            val->val.l.count++;
112            cur = p;
113        }
114
115        if( is_dict && ( val->val.l.count & 1 ) )
116        {
117            return 1;
118        }
119
120        val->end = cur + 1;
121    }
122    else
123    {
124        e = memchr( buf, ':', len );
125        if( NULL == e )
126        {
127            return 1;
128        }
129
130        /* String: 12:whateverword */
131        val->type    = TYPE_STR;
132        e[0]         = '\0';
133        val->val.s.i = strtol( buf, &p, 10 );
134        e[0]         = ':';
135
136        if( p != e || 0 > val->val.s.i ||
137            (size_t)(val->val.s.i) > len - ((p + 1) - buf) )
138        {
139            return 1;
140        }
141
142        val->val.s.s               = malloc( val->val.s.i + 1 );
143        val->val.s.s[val->val.s.i] = 0;
144        memcpy( val->val.s.s, p + 1, val->val.s.i );
145
146        val->end = p + 1 + val->val.s.i;
147    }
148
149    *end = val->end;
150
151    return 0;
152}
153
154static void __bencPrint( benc_val_t * val, int space )
155{
156    int i;
157
158    for( i = 0; i < space; i++ )
159    {
160        fprintf( stderr, " " );
161    }
162
163    switch( val->type )
164    {
165        case TYPE_INT:
166            fprintf( stderr, "int:  %lld\n", val->val.i );
167            break;
168
169        case TYPE_STR:
170            fprintf( stderr, "%s\n", val->val.s.s );
171            break;
172
173        case TYPE_LIST:
174            fprintf( stderr, "list\n" );
175            for( i = 0; i < val->val.l.count; i++ )
176                __bencPrint( &val->val.l.vals[i], space + 1 );
177            break;
178
179        case TYPE_DICT:
180            fprintf( stderr, "dict\n" );
181            for( i = 0; i < val->val.l.count; i++ )
182                __bencPrint( &val->val.l.vals[i], space + 1 );
183            break;
184    }
185}
186
187void tr_bencPrint( benc_val_t * val )
188{
189    __bencPrint( val, 0 );
190}
191
192void tr_bencFree( benc_val_t * val )
193{
194    int i;
195
196    switch( val->type )
197    {
198        case TYPE_INT:
199            break;
200
201        case TYPE_STR:
202            if( val->val.s.s )
203            {
204                free( val->val.s.s );
205            }
206            break;
207
208        case TYPE_LIST:
209        case TYPE_DICT:
210            for( i = 0; i < val->val.l.count; i++ )
211            {
212                tr_bencFree( &val->val.l.vals[i] );
213            }
214            free( val->val.l.vals );
215            break;
216    }
217}
218
219benc_val_t * tr_bencDictFind( benc_val_t * val, char * key )
220{
221    int i;
222    if( val->type != TYPE_DICT )
223    {
224        return NULL;
225    }
226   
227    for( i = 0; i < val->val.l.count; i += 2 )
228    {
229        if( !strcmp( val->val.l.vals[i].val.s.s, key ) )
230        {
231            return &val->val.l.vals[i+1];
232        }
233    }
234
235    return NULL;
236}
237
238char * tr_bencSaveMalloc( benc_val_t * val, size_t * len )
239{
240    char * buf   = NULL;
241    size_t alloc = 0;
242
243    *len = 0;
244    if( tr_bencSave( val, &buf, len, &alloc ) )
245    {
246        if( NULL != buf )
247        {
248            free(buf);
249        }
250        *len = 0;
251        return NULL;
252    }
253
254    return buf;
255}
256
257int tr_bencSave( benc_val_t * val, char ** buf, size_t * used, size_t * max )
258{
259    int ii;   
260
261    switch( val->type )
262    {
263        case TYPE_INT:
264            if( tr_bencSprintf( buf, used, max, "i%llde", val->val.i ) )
265            {
266                return 1;
267            }
268            break;
269
270        case TYPE_STR:
271            if( (int)strlen(val->val.s.s) != val->val.s.i )
272            {
273                return 1;
274            }
275            if( tr_bencSprintf( buf, used, max, "%i:%s",
276                                val->val.s.i, val->val.s.s ) )
277            {
278                return 1;
279            }
280            break;
281
282        case TYPE_LIST:
283        case TYPE_DICT:
284            if( tr_bencSprintf( buf, used, max,
285                                (TYPE_LIST == val->type ? "l" : "d") ) )
286            {
287                return 1;
288            }
289            for( ii = 0; val->val.l.count > ii; ii++ )
290            {
291                if( tr_bencSave( val->val.l.vals + ii, buf, used, max ) )
292                {
293                    return 1;
294                }
295            }
296            if( tr_bencSprintf( buf, used, max, "e" ) )
297            {
298                return 1;
299            }
300            break;
301    }
302
303    return 0;
304}
305
306static int tr_bencSprintf( char ** buf, size_t * used, size_t * max,
307                           char * format, ... )
308{
309    va_list ap;
310    int     want;
311    char  * newbuf;
312
313    va_start( ap, format );
314    want = vsnprintf( NULL, 0, format, ap );
315    va_end(ap);
316
317    while( *used + want + 1 > *max )
318    {
319        *max += OUTBUF_SIZE;
320        newbuf = realloc( *buf, *max );
321        if( NULL == newbuf )
322        {
323            return 1;
324        }
325        *buf = newbuf;
326    }
327
328    va_start( ap, format );
329    *used += vsnprintf( *buf + *used, *max - *used, format, ap );
330    va_end( ap );
331
332    return 0;
333}
Note: See TracBrowser for help on using the repository browser.