source: trunk/libtransmission/bencode.c @ 3828

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

fix torrent metafile creation error introduced in trunk in r3735 and reported by tiennou in ticket #478

  • Property svn:keywords set to Date Rev Author Id
File size: 12.2 KB
Line 
1/******************************************************************************
2 * $Id: bencode.c 3828 2007-11-15 15:07:05Z 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:", (int)val->val.i );
421            evbuffer_add( out, val->val.s.s, val->val.i );
422            break;
423
424        case TYPE_LIST:
425            evbuffer_add_printf( out, "l" );
426            for( ii = 0; val->val.l.count > ii; ii++ )
427                saveImpl( out, val->val.l.vals + ii );
428            evbuffer_add_printf( out, "e" );
429            break;
430
431        case TYPE_DICT:
432            /* Keys must be strings and appear in sorted order
433               (sorted as raw strings, not alphanumerics). */
434            evbuffer_add_printf( out, "d" );
435            if( 1 ) {
436                int i;
437                struct KeyIndex * indices = tr_new( struct KeyIndex, val->val.l.count );
438                for( ii=i=0; i<val->val.l.count; i+=2 ) {
439                    indices[ii].key = val->val.l.vals[i].val.s.s;
440                    indices[ii].index = i;
441                    ii++;
442                }
443                qsort( indices, ii, sizeof(struct KeyIndex), compareKeyIndex );
444                for( i=0; i<ii; ++i ) {
445                    const int index = indices[i].index;
446                    saveImpl( out, val->val.l.vals + index );
447                    saveImpl( out, val->val.l.vals + index + 1 );
448                }
449                tr_free( indices );
450            }
451            evbuffer_add_printf( out, "e" );
452            break;
453    }
454}
455
456char*
457tr_bencSave( const benc_val_t * val, int * len )
458{
459    struct evbuffer * buf = evbuffer_new( );
460    char * ret;
461    saveImpl( buf, val );
462    if( len != NULL )
463        *len = EVBUFFER_LENGTH( buf );
464    ret = tr_strndup( (char*) EVBUFFER_DATA( buf ), EVBUFFER_LENGTH( buf ) );
465    evbuffer_free( buf );
466    return ret;
467}
468
469/**
470***
471**/
472
473int
474tr_bencIsStr ( const benc_val_t * val )
475{
476    return val!=NULL && val->type==TYPE_STR;
477}
478
479int
480tr_bencIsInt ( const benc_val_t * val )
481{
482    return val!=NULL && val->type==TYPE_INT;
483}
484
485int
486tr_bencIsList( const benc_val_t * val )
487{
488    return val!=NULL && val->type==TYPE_LIST;
489}
490
491int
492tr_bencIsDict( const benc_val_t * val )
493{
494    return val!=NULL && val->type==TYPE_DICT;
495}
Note: See TracBrowser for help on using the repository browser.