source: trunk/libtransmission/bencode.c @ 1612

Last change on this file since 1612 was 1612, checked in by joshe, 15 years ago

Remove tr_bencListIter(), it was a stupid idea.

  • Property svn:keywords set to Date Rev Author Id
File size: 10.1 KB
Line 
1/******************************************************************************
2 * $Id: bencode.c 1612 2007-03-31 17:40:28Z joshe $
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 1;
40    }
41
42    /* We need a bigger boat */
43
44    len = val->val.l.alloc + count + ( count % LIST_SIZE ? 0 : LIST_SIZE );
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 i;
181
182    for( i = 0; i < space; i++ )
183    {
184        fprintf( stderr, " " );
185    }
186
187    switch( val->type )
188    {
189        case TYPE_INT:
190            fprintf( stderr, "int:  %"PRIu64"\n", val->val.i );
191            break;
192
193        case TYPE_STR:
194            fwrite( val->val.s.s, 1, val->val.s.i, stderr );
195            putc( '\n', stderr );
196            break;
197
198        case TYPE_LIST:
199            fprintf( stderr, "list\n" );
200            for( i = 0; i < val->val.l.count; i++ )
201                __bencPrint( &val->val.l.vals[i], space + 1 );
202            break;
203
204        case TYPE_DICT:
205            fprintf( stderr, "dict\n" );
206            for( i = 0; i < val->val.l.count; i++ )
207                __bencPrint( &val->val.l.vals[i], space + 1 );
208            break;
209    }
210}
211
212void tr_bencPrint( benc_val_t * val )
213{
214    __bencPrint( val, 0 );
215}
216
217void tr_bencFree( benc_val_t * val )
218{
219    int i;
220
221    switch( val->type )
222    {
223        case TYPE_INT:
224            break;
225
226        case TYPE_STR:
227            if( !val->val.s.nofree )
228            {
229                free( val->val.s.s );
230            }
231            break;
232
233        case TYPE_LIST:
234        case TYPE_DICT:
235            for( i = 0; i < val->val.l.count; i++ )
236            {
237                tr_bencFree( &val->val.l.vals[i] );
238            }
239            free( val->val.l.vals );
240            break;
241    }
242}
243
244benc_val_t * tr_bencDictFind( benc_val_t * val, const char * key )
245{
246    int len, ii;
247
248    if( val->type != TYPE_DICT )
249    {
250        return NULL;
251    }
252
253    len = strlen( key );
254   
255    for( ii = 0; ii + 1 < val->val.l.count; ii += 2 )
256    {
257        if( TYPE_STR  != val->val.l.vals[ii].type ||
258            len       != val->val.l.vals[ii].val.s.i ||
259            0 != memcmp( val->val.l.vals[ii].val.s.s, key, len ) )
260        {
261            continue;
262        }
263        return &val->val.l.vals[ii+1];
264    }
265
266    return NULL;
267}
268
269benc_val_t * tr_bencDictFindFirst( benc_val_t * val, ... )
270{
271    const char * key;
272    benc_val_t * ret;
273    va_list      ap;
274
275    va_start( ap, val );
276    while( ( key = va_arg( ap, const char * ) ) )
277    {
278        ret = tr_bencDictFind( val, key );
279        if( NULL != ret )
280        {
281            break;
282        }
283    }
284    va_end( ap );
285
286    return ret;
287}
288
289char * tr_bencStealStr( benc_val_t * val )
290{
291    assert( TYPE_STR == val->type );
292    val->val.s.nofree = 1;
293    return val->val.s.s;
294}
295
296void _tr_bencInitStr( benc_val_t * val, char * str, int len, int nofree )
297{
298    tr_bencInit( val, TYPE_STR );
299    val->val.s.s      = str;
300    val->val.s.nofree = nofree;
301    if( 0 >= len )
302    {
303        len = ( NULL == str ? 0 : strlen( str ) );
304    }
305    val->val.s.i = len;
306}
307
308int tr_bencInitStrDup( benc_val_t * val, const char * str )
309{
310    char * new = NULL;
311
312    if( NULL != str )
313    {
314        new = strdup( str );
315        if( NULL == new )
316        {
317            return 1;
318        }
319    }
320
321    _tr_bencInitStr( val, new, 0, 0 );
322
323    return 0;
324}
325
326void tr_bencInitInt( benc_val_t * val, int64_t num )
327{
328    tr_bencInit( val, TYPE_INT );
329    val->val.i = num;
330}
331
332int tr_bencListReserve( benc_val_t * val, int count )
333{
334    assert( TYPE_LIST == val->type );
335
336    if( makeroom( val, count ) )
337    {
338        return 1;
339    }
340
341    return 0;
342}
343
344int tr_bencDictReserve( benc_val_t * val, int count )
345{
346    assert( TYPE_DICT == val->type );
347
348    if( makeroom( val, count * 2 ) )
349    {
350        return 1;
351    }
352
353    return 0;
354}
355
356benc_val_t * tr_bencListAdd( benc_val_t * list )
357{
358    benc_val_t * item;
359
360    assert( TYPE_LIST == list->type );
361    assert( list->val.l.count < list->val.l.alloc );
362
363    item = &list->val.l.vals[list->val.l.count];
364    list->val.l.count++;
365    tr_bencInit( item, TYPE_INT );
366
367    return item;
368}
369
370benc_val_t * tr_bencDictAdd( benc_val_t * dict, const char * key )
371{
372    benc_val_t * keyval, * itemval;
373
374    assert( TYPE_DICT == dict->type );
375    assert( dict->val.l.count + 2 <= dict->val.l.alloc );
376
377    keyval  = &dict->val.l.vals[dict->val.l.count];
378    dict->val.l.count++;
379    itemval = &dict->val.l.vals[dict->val.l.count];
380    dict->val.l.count++;
381
382    tr_bencInitStr( keyval, key, -1, 1 );
383    tr_bencInit( itemval, TYPE_INT );
384
385    return itemval;
386}
387
388char * tr_bencSaveMalloc( benc_val_t * val, int * len )
389{
390    char * buf   = NULL;
391    int alloc = 0;
392
393    *len = 0;
394    if( tr_bencSave( val, &buf, len, &alloc ) )
395    {
396        if( NULL != buf )
397        {
398            free(buf);
399        }
400        *len = 0;
401        return NULL;
402    }
403
404    return buf;
405}
406
407int tr_bencSave( benc_val_t * val, char ** buf, int * used, int * max )
408{
409    int ii;   
410
411    switch( val->type )
412    {
413        case TYPE_INT:
414            if( tr_sprintf( buf, used, max, "i%"PRIu64"e", val->val.i ) )
415            {
416                return 1;
417            }
418            break;
419
420        case TYPE_STR:
421            if( tr_sprintf( buf, used, max, "%i:", val->val.s.i ) ||
422                tr_concat( buf, used,  max, val->val.s.s, val->val.s.i ) )
423            {
424                return 1;
425            }
426            break;
427
428        case TYPE_LIST:
429        case TYPE_DICT:
430            if( tr_sprintf( buf, used, max,
431                            (TYPE_LIST == val->type ? "l" : "d") ) )
432            {
433                return 1;
434            }
435            for( ii = 0; val->val.l.count > ii; ii++ )
436            {
437                if( tr_bencSave( val->val.l.vals + ii, buf, used, max ) )
438                {
439                    return 1;
440                }
441            }
442            if( tr_sprintf( buf, used, max, "e" ) )
443            {
444                return 1;
445            }
446            break;
447    }
448
449    return 0;
450}
Note: See TracBrowser for help on using the repository browser.