source: trunk/libtransmission/bencode.c @ 2024

Last change on this file since 2024 was 2024, checked in by titer, 15 years ago

Bencoded dictionaries are now sorted alphabetically, this should fix
compatibility with some clients, incl. BitTornado?-based ones.
(Reported by roee88 from LH-ABC)

  • Property svn:keywords set to Date Rev Author Id
File size: 11.0 KB
Line 
1/******************************************************************************
2 * $Id: bencode.c 2024 2007-06-10 15:38:58Z titer $
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 "transmission.h"
26
27/* setting to 1 to help expose bugs with tr_bencListAdd and tr_bencDictAdd */
28#define LIST_SIZE   20 /* number of items to increment list/dict buffer by */
29
30static int makeroom( benc_val_t * val, int count )
31{
32    int    len;
33    void * new;
34
35    assert( TYPE_LIST == val->type || TYPE_DICT == val->type );
36
37    if( val->val.l.count + count <= val->val.l.alloc )
38    {
39        return 0;
40    }
41
42    /* We need a bigger boat */
43    len = val->val.l.alloc + count +
44        ( count % LIST_SIZE ? LIST_SIZE - ( count % LIST_SIZE ) : 0 );
45    new = realloc( val->val.l.vals, len * sizeof( benc_val_t ) );
46    if( NULL == new )
47    {
48        return 1;
49    }
50
51    val->val.l.alloc = len;
52    val->val.l.vals  = new;
53
54    return 0;
55}
56
57int _tr_bencLoad( char * buf, int len, benc_val_t * val, char ** end )
58{
59    char * p, * e, * foo;
60
61    if( NULL == buf || 1 >= len )
62    {
63        return 1;
64    }
65
66    if( !end )
67    {
68        /* So we only have to check once */
69        end = &foo;
70    }
71
72    if( buf[0] == 'i' )
73    {
74        int64_t num;
75
76        e = memchr( &buf[1], 'e', len - 1 );
77        if( NULL == e )
78        {
79            return 1;
80        }
81
82        /* Integer: i1242e */
83        *e = '\0';
84        num = strtoll( &buf[1], &p, 10 );
85        *e = 'e';
86
87        if( p != e )
88        {
89            return 1;
90        }
91
92        tr_bencInitInt( val, num );
93        *end = p + 1;
94    }
95    else if( buf[0] == 'l' || buf[0] == 'd' )
96    {
97        /* List: l<item1><item2>e
98           Dict: d<string1><item1><string2><item2>e
99           A dictionary is just a special kind of list with an even
100           count of items, and where even items are strings. */
101        char * cur;
102        char   is_dict;
103        char   str_expected;
104
105        is_dict      = ( buf[0] == 'd' );
106        cur          = &buf[1];
107        str_expected = 1;
108        tr_bencInit( val, ( is_dict ? TYPE_DICT : TYPE_LIST ) );
109        while( cur - buf < len && cur[0] != 'e' )
110        {
111            if( makeroom( val, 1 ) ||
112                tr_bencLoad( cur, len - (cur - buf),
113                             &val->val.l.vals[val->val.l.count], &p ) )
114            {
115                tr_bencFree( val );
116                return 1;
117            }
118            val->val.l.count++;
119            if( is_dict && str_expected &&
120                val->val.l.vals[val->val.l.count - 1].type != TYPE_STR )
121            {
122                tr_bencFree( val );
123                return 1;
124            }
125            str_expected = !str_expected;
126
127            cur = p;
128        }
129
130        if( is_dict && ( val->val.l.count & 1 ) )
131        {
132            tr_bencFree( val );
133            return 1;
134        }
135
136        *end = cur + 1;
137    }
138    else
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    }
171
172    val->begin = buf;
173    val->end   = *end;
174
175    return 0;
176}
177
178static void __bencPrint( benc_val_t * val, int space )
179{
180    int ii;
181
182    for( ii = 0; ii < space; ii++ )
183    {
184        putc( ' ', stderr );
185    }
186
187    switch( val->type )
188    {
189        case TYPE_INT:
190            fprintf( stderr, "int:  %"PRId64"\n", val->val.i );
191            break;
192
193        case TYPE_STR:
194            for( ii = 0; val->val.s.i > ii; ii++ )
195            {
196                if( '\\' == val->val.s.s[ii] )
197                {
198                    putc( '\\', stderr );
199                    putc( '\\', stderr );
200                }
201                else if( isprint( val->val.s.s[ii] ) )
202                {
203                    putc( val->val.s.s[ii], stderr );
204                }
205                else
206                {
207                    fprintf( stderr, "\\x%02x", val->val.s.s[ii] );
208                }
209            }
210            putc( '\n', stderr );
211            break;
212
213        case TYPE_LIST:
214            fprintf( stderr, "list\n" );
215            for( ii = 0; ii < val->val.l.count; ii++ )
216            {
217                __bencPrint( &val->val.l.vals[ii], space + 1 );
218            }
219            break;
220
221        case TYPE_DICT:
222            fprintf( stderr, "dict\n" );
223            for( ii = 0; ii < val->val.l.count; ii++ )
224            {
225                __bencPrint( &val->val.l.vals[ii], space + 1 );
226            }
227            break;
228    }
229}
230
231void tr_bencPrint( benc_val_t * val )
232{
233    __bencPrint( val, 0 );
234}
235
236void tr_bencFree( benc_val_t * val )
237{
238    int i;
239
240    switch( val->type )
241    {
242        case TYPE_INT:
243            break;
244
245        case TYPE_STR:
246            if( !val->val.s.nofree )
247            {
248                free( val->val.s.s );
249            }
250            break;
251
252        case TYPE_LIST:
253        case TYPE_DICT:
254            for( i = 0; i < val->val.l.count; i++ )
255            {
256                tr_bencFree( &val->val.l.vals[i] );
257            }
258            free( val->val.l.vals );
259            break;
260    }
261}
262
263benc_val_t * tr_bencDictFind( benc_val_t * val, const char * key )
264{
265    int len, ii;
266
267    if( val->type != TYPE_DICT )
268    {
269        return NULL;
270    }
271
272    len = strlen( key );
273   
274    for( ii = 0; ii + 1 < val->val.l.count; ii += 2 )
275    {
276        if( TYPE_STR  != val->val.l.vals[ii].type ||
277            len       != val->val.l.vals[ii].val.s.i ||
278            0 != memcmp( val->val.l.vals[ii].val.s.s, key, len ) )
279        {
280            continue;
281        }
282        return &val->val.l.vals[ii+1];
283    }
284
285    return NULL;
286}
287
288benc_val_t * tr_bencDictFindFirst( benc_val_t * val, ... )
289{
290    const char * key;
291    benc_val_t * ret;
292    va_list      ap;
293
294    ret = NULL;
295    va_start( ap, val );
296    while( ( key = va_arg( ap, const char * ) ) )
297    {
298        ret = tr_bencDictFind( val, key );
299        if( NULL != ret )
300        {
301            break;
302        }
303    }
304    va_end( ap );
305
306    return ret;
307}
308
309char * tr_bencStealStr( benc_val_t * val )
310{
311    assert( TYPE_STR == val->type );
312    val->val.s.nofree = 1;
313    return val->val.s.s;
314}
315
316void _tr_bencInitStr( benc_val_t * val, char * str, int len, int nofree )
317{
318    tr_bencInit( val, TYPE_STR );
319    val->val.s.s      = str;
320    val->val.s.nofree = nofree;
321    if( 0 >= len )
322    {
323        len = ( NULL == str ? 0 : strlen( str ) );
324    }
325    val->val.s.i = len;
326}
327
328int tr_bencInitStrDup( benc_val_t * val, const char * str )
329{
330    char * new = NULL;
331
332    if( NULL != str )
333    {
334        new = strdup( str );
335        if( NULL == new )
336        {
337            return 1;
338        }
339    }
340
341    _tr_bencInitStr( val, new, 0, 0 );
342
343    return 0;
344}
345
346void tr_bencInitInt( benc_val_t * val, int64_t num )
347{
348    tr_bencInit( val, TYPE_INT );
349    val->val.i = num;
350}
351
352int tr_bencListReserve( benc_val_t * val, int count )
353{
354    assert( TYPE_LIST == val->type );
355
356    if( makeroom( val, count ) )
357    {
358        return 1;
359    }
360
361    return 0;
362}
363
364int tr_bencDictReserve( benc_val_t * val, int count )
365{
366    assert( TYPE_DICT == val->type );
367
368    if( makeroom( val, count * 2 ) )
369    {
370        return 1;
371    }
372
373    return 0;
374}
375
376benc_val_t * tr_bencListAdd( benc_val_t * list )
377{
378    benc_val_t * item;
379
380    assert( TYPE_LIST == list->type );
381    assert( list->val.l.count < list->val.l.alloc );
382
383    item = &list->val.l.vals[list->val.l.count];
384    list->val.l.count++;
385    tr_bencInit( item, TYPE_INT );
386
387    return item;
388}
389
390benc_val_t * tr_bencDictAdd( benc_val_t * dict, const char * key )
391{
392    benc_val_t * keyval, * itemval;
393    int i;
394
395    assert( TYPE_DICT == dict->type );
396    assert( dict->val.l.count + 2 <= dict->val.l.alloc );
397
398    /* Keep dictionaries sorted by keys alphabetically.
399       BitTornado-based clients (and maybe others) need this. */
400    for( i = 0; i < dict->val.l.count; i += 2 )
401    {
402        assert( TYPE_STR == dict->val.l.vals[i].type );
403        if( strcmp( key, dict->val.l.vals[i].val.s.s ) < 0 )
404            break;
405    }
406    memmove( &dict->val.l.vals[i+2], &dict->val.l.vals[i],
407             ( dict->val.l.count - i ) * sizeof(benc_val_t) );
408    keyval  = &dict->val.l.vals[i];
409    itemval = &dict->val.l.vals[i+1];
410    dict->val.l.count += 2;
411
412    tr_bencInitStr( keyval, key, -1, 1 );
413    tr_bencInit( itemval, TYPE_INT );
414
415    return itemval;
416}
417
418char * tr_bencSaveMalloc( benc_val_t * val, int * len )
419{
420    char * buf   = NULL;
421    int alloc = 0;
422
423    *len = 0;
424    if( tr_bencSave( val, &buf, len, &alloc ) )
425    {
426        if( NULL != buf )
427        {
428            free(buf);
429        }
430        *len = 0;
431        return NULL;
432    }
433
434    return buf;
435}
436
437int tr_bencSave( benc_val_t * val, char ** buf, int * used, int * max )
438{
439    int ii;   
440
441    switch( val->type )
442    {
443        case TYPE_INT:
444            if( tr_sprintf( buf, used, max, "i%"PRId64"e", val->val.i ) )
445            {
446                return 1;
447            }
448            break;
449
450        case TYPE_STR:
451            if( tr_sprintf( buf, used, max, "%i:", val->val.s.i ) ||
452                tr_concat( buf, used,  max, val->val.s.s, val->val.s.i ) )
453            {
454                return 1;
455            }
456            break;
457
458        case TYPE_LIST:
459        case TYPE_DICT:
460            if( tr_sprintf( buf, used, max,
461                            (TYPE_LIST == val->type ? "l" : "d") ) )
462            {
463                return 1;
464            }
465            for( ii = 0; val->val.l.count > ii; ii++ )
466            {
467                if( tr_bencSave( val->val.l.vals + ii, buf, used, max ) )
468                {
469                    return 1;
470                }
471            }
472            if( tr_sprintf( buf, used, max, "e" ) )
473            {
474                return 1;
475            }
476            break;
477    }
478
479    return 0;
480}
Note: See TracBrowser for help on using the repository browser.