source: trunk/libtransmission/bencode.c @ 3775

Last change on this file since 3775 was 3775, checked in by charles, 15 years ago

undoing the r3773-r3774 experiment.

  • Property svn:keywords set to Date Rev Author Id
File size: 12.2 KB
Line 
1/******************************************************************************
2 * $Id: bencode.c 3775 2007-11-09 20:07:52Z charles $
3 *
4 * Copyright (c) 2005-2007 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#include <assert.h>
26#include <ctype.h> /* isdigit, isprint */
27#include <stdarg.h>
28#include <stdio.h>
29#include <stdlib.h>
30
31#include <event.h>
32
33#include "transmission.h"
34#include "bencode.h"
35#include "utils.h"
36
37/* setting to 1 to help expose bugs with tr_bencListAdd and tr_bencDictAdd */
38#define LIST_SIZE   20 /* number of items to increment list/dict buffer by */
39
40static int makeroom( benc_val_t * val, int count )
41{
42    assert( TYPE_LIST == val->type || TYPE_DICT == val->type );
43
44    if( val->val.l.count + count > val->val.l.alloc )
45    {
46        /* We need a bigger boat */
47        const int len = val->val.l.alloc + count +
48            ( count % LIST_SIZE ? LIST_SIZE - ( count % LIST_SIZE ) : 0 );
49        void * new = realloc( val->val.l.vals, len * sizeof( benc_val_t ) );
50        if( NULL == new )
51            return 1;
52
53        val->val.l.alloc = len;
54        val->val.l.vals  = new;
55    }
56
57    return 0;
58}
59
60int _tr_bencLoad( char * buf, int len, benc_val_t * val, char ** end )
61{
62    char * p, * e, * foo;
63
64    if( !end )
65    {
66        /* So we only have to check once */
67        end = &foo;
68    }
69
70    for( ;; )
71    {
72        if( !buf || len<1 ) /* no more text to parse... */
73            return 1;
74
75        if( *buf=='i' ) /* Integer: i1234e */
76        {
77            int64_t num;
78
79            e = memchr( &buf[1], 'e', len - 1 );
80            if( !e )
81                return 1;
82
83            *e = '\0';
84            num = strtoll( &buf[1], &p, 10 );
85            *e = 'e';
86
87            if( p != e )
88                return 1;
89
90            tr_bencInitInt( val, num );
91            *end = p + 1;
92            break;
93        }
94        else if( *buf=='l' || *buf=='d' )
95        {
96            /* List: l<item1><item2>e
97               Dict: d<string1><item1><string2><item2>e
98               A dictionary is just a special kind of list with an even
99               count of items, and where even items are strings. */
100            char * cur;
101            char   is_dict;
102            char   str_expected;
103
104            is_dict      = ( buf[0] == 'd' );
105            cur          = &buf[1];
106            str_expected = 1;
107            tr_bencInit( val, ( is_dict ? TYPE_DICT : TYPE_LIST ) );
108            while( cur - buf < len && cur[0] != 'e' )
109            {
110                if( makeroom( val, 1 ) ||
111                    tr_bencLoad( cur, len - (cur - buf),
112                                 &val->val.l.vals[val->val.l.count], &p ) )
113                {
114                    tr_bencFree( val );
115                    return 1;
116                }
117                val->val.l.count++;
118                if( is_dict && str_expected &&
119                    val->val.l.vals[val->val.l.count - 1].type != TYPE_STR )
120                {
121                    tr_bencFree( val );
122                    return 1;
123                }
124                str_expected = !str_expected;
125
126                cur = p;
127            }
128
129            if( is_dict && ( val->val.l.count & 1 ) )
130            {
131                tr_bencFree( val );
132                return 1;
133            }
134
135            *end = cur + 1;
136            break;
137        }
138        else if( isdigit(*buf) )
139        {
140            int    slen;
141            char * sbuf;
142
143            e = memchr( buf, ':', len );
144            if( NULL == e )
145            {
146                return 1;
147            }
148
149            /* String: 12:whateverword */
150            e[0] = '\0';
151            slen = strtol( buf, &p, 10 );
152            e[0] = ':';
153
154            if( p != e || 0 > slen || len - ( ( p + 1 ) - buf ) < slen )
155            {
156                return 1;
157            }
158
159            sbuf = malloc( slen + 1 );
160            if( NULL == sbuf )
161            {
162                return 1;
163            }
164
165            memcpy( sbuf, p + 1, slen );
166            sbuf[slen] = '\0';
167            tr_bencInitStr( val, sbuf, slen, 0 );
168
169            *end = p + 1 + val->val.s.i;
170            break;
171        }
172        else /* invalid bencoded text... march past it */
173        {
174            ++buf;
175            --len;
176        }
177    }
178
179    val->begin = buf;
180    val->end   = *end;
181
182    return 0;
183}
184
185static void __bencPrint( benc_val_t * val, int space )
186{
187    int ii;
188
189    for( ii = 0; ii < space; ii++ )
190    {
191        putc( ' ', stderr );
192    }
193
194    switch( val->type )
195    {
196        case TYPE_INT:
197            fprintf( stderr, "int:  %"PRId64"\n", val->val.i );
198            break;
199
200        case TYPE_STR:
201            for( ii = 0; val->val.s.i > ii; ii++ )
202            {
203                if( '\\' == val->val.s.s[ii] )
204                {
205                    putc( '\\', stderr );
206                    putc( '\\', stderr );
207                }
208                else if( isprint( val->val.s.s[ii] ) )
209                {
210                    putc( val->val.s.s[ii], stderr );
211                }
212                else
213                {
214                    fprintf( stderr, "\\x%02x", val->val.s.s[ii] );
215                }
216            }
217            putc( '\n', stderr );
218            break;
219
220        case TYPE_LIST:
221            fprintf( stderr, "list\n" );
222            for( ii = 0; ii < val->val.l.count; ii++ )
223            {
224                __bencPrint( &val->val.l.vals[ii], space + 1 );
225            }
226            break;
227
228        case TYPE_DICT:
229            fprintf( stderr, "dict\n" );
230            for( ii = 0; ii < val->val.l.count; ii++ )
231            {
232                __bencPrint( &val->val.l.vals[ii], space + 1 );
233            }
234            break;
235    }
236}
237
238void tr_bencPrint( benc_val_t * val )
239{
240    __bencPrint( val, 0 );
241}
242
243void tr_bencFree( benc_val_t * val )
244{
245    int i;
246
247    switch( val->type )
248    {
249        case TYPE_INT:
250            break;
251
252        case TYPE_STR:
253            if( !val->val.s.nofree )
254            {
255                free( val->val.s.s );
256            }
257            break;
258
259        case TYPE_LIST:
260        case TYPE_DICT:
261            for( i = 0; i < val->val.l.count; i++ )
262            {
263                tr_bencFree( &val->val.l.vals[i] );
264            }
265            free( val->val.l.vals );
266            break;
267    }
268}
269
270benc_val_t * tr_bencDictFind( benc_val_t * val, const char * key )
271{
272    int len, ii;
273
274    if( val->type != TYPE_DICT )
275    {
276        return NULL;
277    }
278
279    len = strlen( key );
280   
281    for( ii = 0; ii + 1 < val->val.l.count; ii += 2 )
282    {
283        if( TYPE_STR  != val->val.l.vals[ii].type ||
284            len       != val->val.l.vals[ii].val.s.i ||
285            0 != memcmp( val->val.l.vals[ii].val.s.s, key, len ) )
286        {
287            continue;
288        }
289        return &val->val.l.vals[ii+1];
290    }
291
292    return NULL;
293}
294
295benc_val_t * tr_bencDictFindFirst( benc_val_t * val, ... )
296{
297    const char * key;
298    benc_val_t * ret;
299    va_list      ap;
300
301    ret = NULL;
302    va_start( ap, val );
303    while( ( key = va_arg( ap, const char * ) ) )
304    {
305        ret = tr_bencDictFind( val, key );
306        if( NULL != ret )
307        {
308            break;
309        }
310    }
311    va_end( ap );
312
313    return ret;
314}
315
316char * tr_bencStealStr( benc_val_t * val )
317{
318    assert( TYPE_STR == val->type );
319    val->val.s.nofree = 1;
320    return val->val.s.s;
321}
322
323void _tr_bencInitStr( benc_val_t * val, char * str, int len, int nofree )
324{
325    tr_bencInit( val, TYPE_STR );
326    val->val.s.s      = str;
327    val->val.s.nofree = nofree;
328    if( 0 >= len )
329    {
330        len = ( NULL == str ? 0 : strlen( str ) );
331    }
332    val->val.s.i = len;
333}
334
335int tr_bencInitStrDup( benc_val_t * val, const char * str )
336{
337    char * newStr = tr_strdup( str );
338    if( newStr == NULL )
339        return 1;
340
341    _tr_bencInitStr( val, newStr, 0, 0 );
342    return 0;
343}
344
345void tr_bencInitInt( benc_val_t * val, int64_t num )
346{
347    tr_bencInit( val, TYPE_INT );
348    val->val.i = num;
349}
350
351int tr_bencListReserve( benc_val_t * val, int count )
352{
353    assert( TYPE_LIST == val->type );
354
355    return makeroom( val, count );
356}
357
358int tr_bencDictReserve( benc_val_t * val, int count )
359{
360    assert( TYPE_DICT == val->type );
361
362    return makeroom( val, count * 2 );
363}
364
365benc_val_t * tr_bencListAdd( benc_val_t * list )
366{
367    benc_val_t * item;
368
369    assert( tr_bencIsList( list ) );
370    assert( list->val.l.count < list->val.l.alloc );
371
372    item = &list->val.l.vals[list->val.l.count];
373    list->val.l.count++;
374    tr_bencInit( item, TYPE_INT );
375
376    return item;
377}
378
379benc_val_t * tr_bencDictAdd( benc_val_t * dict, const char * key )
380{
381    benc_val_t * keyval, * itemval;
382
383    assert( tr_bencIsDict( dict ) );
384    assert( dict->val.l.count + 2 <= dict->val.l.alloc );
385
386    keyval = dict->val.l.vals + dict->val.l.count++;
387    tr_bencInitStr( keyval, (char*)key, -1, 1 );
388
389    itemval = dict->val.l.vals + dict->val.l.count++;
390    tr_bencInit( itemval, TYPE_INT );
391
392    return itemval;
393}
394
395struct KeyIndex
396{
397    const char * key;
398    int index;
399};
400
401static int compareKeyIndex( const void * va, const void * vb )
402{
403    const struct KeyIndex * a = va;
404    const struct KeyIndex * b = vb;
405    return strcmp( a->key, b->key );
406}
407
408static void
409saveImpl( struct evbuffer * out, const benc_val_t * val )
410{
411    int ii;
412
413    switch( val->type )
414    {
415        case TYPE_INT:
416            evbuffer_add_printf( out, "i%"PRId64"e", val->val.i );
417            break;
418
419        case TYPE_STR:
420            evbuffer_add_printf( out, "%i:%s", (int)val->val.i, val->val.s.s );
421            break;
422
423        case TYPE_LIST:
424            evbuffer_add_printf( out, "l" );
425            for( ii = 0; val->val.l.count > ii; ii++ )
426                saveImpl( out, val->val.l.vals + ii );
427            evbuffer_add_printf( out, "e" );
428            break;
429
430        case TYPE_DICT:
431            /* Keys must be strings and appear in sorted order
432               (sorted as raw strings, not alphanumerics). */
433            evbuffer_add_printf( out, "d" );
434            if( 1 ) {
435                int i;
436                struct KeyIndex * indices = tr_new( struct KeyIndex, val->val.l.count );
437                for( ii=i=0; i<val->val.l.count; i+=2 ) {
438                    indices[ii].key = val->val.l.vals[i].val.s.s;
439                    indices[ii].index = i;
440                    ii++;
441                }
442                qsort( indices, ii, sizeof(struct KeyIndex), compareKeyIndex );
443                for( i=0; i<ii; ++i ) {
444                    const int index = indices[i].index;
445                    saveImpl( out, val->val.l.vals + index );
446                    saveImpl( out, val->val.l.vals + index + 1 );
447                }
448                tr_free( indices );
449            }
450            evbuffer_add_printf( out, "e" );
451            break;
452    }
453}
454
455char*
456tr_bencSave( const benc_val_t * val, int * len )
457{
458    struct evbuffer * buf = evbuffer_new( );
459    char * ret;
460    saveImpl( buf, val );
461    if( len != NULL )
462        *len = EVBUFFER_LENGTH( buf );
463    ret = tr_strndup( (char*) EVBUFFER_DATA( buf ), EVBUFFER_LENGTH( buf ) );
464    evbuffer_free( buf );
465    return ret;
466}
467
468/**
469***
470**/
471
472int
473tr_bencIsStr ( const benc_val_t * val )
474{
475    return val!=NULL && val->type==TYPE_STR;
476}
477
478int
479tr_bencIsInt ( const benc_val_t * val )
480{
481    return val!=NULL && val->type==TYPE_INT;
482}
483
484int
485tr_bencIsList( const benc_val_t * val )
486{
487    return val!=NULL && val->type==TYPE_LIST;
488}
489
490int
491tr_bencIsDict( const benc_val_t * val )
492{
493    return val!=NULL && val->type==TYPE_DICT;
494}
Note: See TracBrowser for help on using the repository browser.