source: branches/pex/libtransmission/bencode.c @ 1545

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

Fix for if unused isn't defined.
Pointless churn to silence char*/unint8_t* warnings.

  • Property svn:keywords set to Date Rev Author Id
File size: 11.0 KB
Line 
1/******************************************************************************
2 * $Id: bencode.c 1545 2007-03-08 04:53:50Z 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#define LIST_SIZE   20
28
29static int makeroom( benc_val_t * val, int count )
30{
31    int len;
32    void * new;
33
34    assert( TYPE_LIST == val->type || TYPE_DICT == val->type );
35
36    len = val->val.l.alloc;
37    while( val->val.l.count + count >= len )
38    {
39        len += LIST_SIZE;
40    }
41
42    if( len > val->val.l.alloc )
43    {
44        /* We need a bigger boat */
45        new = realloc( val->val.l.vals, len * sizeof( benc_val_t ) );
46        if( NULL == new )
47        {
48            return 1;
49        }
50        val->val.l.alloc = len;
51        val->val.l.vals = new;
52    }
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    val->begin = buf;
73
74    if( buf[0] == 'i' )
75    {
76        e = memchr( &buf[1], 'e', len - 1 );
77        if( NULL == e )
78        {
79            return 1;
80        }
81
82        /* Integer: i1242e */
83        val->type  = TYPE_INT;
84        *e         = '\0';
85        val->val.i = strtoll( &buf[1], &p, 10 );
86        *e         = 'e';
87
88        if( p != e )
89        {
90            return 1;
91        }
92
93        val->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        val->type        = is_dict ? TYPE_DICT : TYPE_LIST;
107        val->val.l.alloc = LIST_SIZE;
108        val->val.l.count = 0;
109        val->val.l.vals  = malloc( LIST_SIZE * sizeof( benc_val_t ) );
110        cur              = &buf[1];
111        str_expected     = 1;
112        while( cur - buf < len && cur[0] != 'e' )
113        {
114            if( makeroom( val, 1 ) ||
115                tr_bencLoad( cur, len - (cur - buf),
116                             &val->val.l.vals[val->val.l.count], &p ) )
117            {
118                tr_bencFree( val );
119                return 1;
120            }
121            val->val.l.count++;
122            if( is_dict && str_expected &&
123                val->val.l.vals[val->val.l.count - 1].type != TYPE_STR )
124            {
125                tr_bencFree( val );
126                return 1;
127            }
128            str_expected = !str_expected;
129
130            cur = p;
131        }
132
133        if( is_dict && ( val->val.l.count & 1 ) )
134        {
135            tr_bencFree( val );
136            return 1;
137        }
138
139        val->end = cur + 1;
140    }
141    else
142    {
143        e = memchr( buf, ':', len );
144        if( NULL == e )
145        {
146            return 1;
147        }
148
149        /* String: 12:whateverword */
150        val->type    = TYPE_STR;
151        e[0]         = '\0';
152        val->val.s.i = strtol( buf, &p, 10 );
153        e[0]         = ':';
154
155        if( p != e || 0 > val->val.s.i ||
156            val->val.s.i > len - ((p + 1) - buf) )
157        {
158            return 1;
159        }
160
161        val->val.s.s               = malloc( val->val.s.i + 1 );
162        val->val.s.s[val->val.s.i] = 0;
163        memcpy( val->val.s.s, p + 1, val->val.s.i );
164
165        val->end = p + 1 + val->val.s.i;
166    }
167
168    *end = val->end;
169
170    return 0;
171}
172
173static void __bencPrint( benc_val_t * val, int space )
174{
175    int i;
176
177    for( i = 0; i < space; i++ )
178    {
179        fprintf( stderr, " " );
180    }
181
182    switch( val->type )
183    {
184        case TYPE_INT:
185            fprintf( stderr, "int:  %"PRIu64"\n", val->val.i );
186            break;
187
188        case TYPE_STR:
189            fwrite( val->val.s.s, 1, val->val.s.i, stderr );
190            putc( '\n', stderr );
191            break;
192
193        case TYPE_LIST:
194            fprintf( stderr, "list\n" );
195            for( i = 0; i < val->val.l.count; i++ )
196                __bencPrint( &val->val.l.vals[i], space + 1 );
197            break;
198
199        case TYPE_DICT:
200            fprintf( stderr, "dict\n" );
201            for( i = 0; i < val->val.l.count; i++ )
202                __bencPrint( &val->val.l.vals[i], space + 1 );
203            break;
204    }
205}
206
207void tr_bencPrint( benc_val_t * val )
208{
209    __bencPrint( val, 0 );
210}
211
212void tr_bencFree( benc_val_t * val )
213{
214    int i;
215
216    switch( val->type )
217    {
218        case TYPE_INT:
219            break;
220
221        case TYPE_STR:
222            if( !val->val.s.nofree )
223            {
224                free( val->val.s.s );
225            }
226            break;
227
228        case TYPE_LIST:
229        case TYPE_DICT:
230            for( i = 0; i < val->val.l.count; i++ )
231            {
232                tr_bencFree( &val->val.l.vals[i] );
233            }
234            free( val->val.l.vals );
235            break;
236    }
237}
238
239benc_val_t * tr_bencDictFind( benc_val_t * val, const char * key )
240{
241    int i;
242    if( val->type != TYPE_DICT )
243    {
244        return NULL;
245    }
246   
247    for( i = 0; i < val->val.l.count; i += 2 )
248    {
249        if( !strcmp( val->val.l.vals[i].val.s.s, key ) )
250        {
251            return &val->val.l.vals[i+1];
252        }
253    }
254
255    return NULL;
256}
257
258benc_val_t * tr_bencDictFindFirst( benc_val_t * val, ... )
259{
260    const char * key;
261    benc_val_t * ret;
262    va_list      ap;
263
264    va_start( ap, val );
265    while( ( key = va_arg( ap, const char * ) ) )
266    {
267        ret = tr_bencDictFind( val, key );
268        if( NULL != ret )
269        {
270            break;
271        }
272    }
273    va_end( ap );
274
275    return ret;
276}
277
278char * tr_bencStealStr( benc_val_t * val )
279{
280    assert( TYPE_STR == val->type );
281    val->val.s.nofree = 1;
282    return val->val.s.s;
283}
284
285void _tr_bencInitStr( benc_val_t * val, char * str, int len, int nofree )
286{
287    tr_bencInit( val, TYPE_STR );
288    val->val.s.s      = str;
289    val->val.s.nofree = nofree;
290    if( 0 >= len )
291    {
292        len = ( NULL == str ? 0 : strlen( str ) );
293    }
294    val->val.s.i = len;
295}
296
297int tr_bencInitStrDup( benc_val_t * val, const char * str )
298{
299    char * new = NULL;
300
301    if( NULL != str )
302    {
303        new = strdup( str );
304        if( NULL == new )
305        {
306            return 1;
307        }
308    }
309
310    _tr_bencInitStr( val, new, 0, 0 );
311
312    return 0;
313}
314
315void tr_bencInitInt( benc_val_t * val, int64_t num )
316{
317    tr_bencInit( val, TYPE_INT );
318    val->val.i = num;
319}
320
321int tr_bencListAppend( benc_val_t * val, ... )
322{
323    va_list ap;
324    int len;
325    benc_val_t ** ptr;
326
327    assert( TYPE_LIST == val->type );
328
329    len = 0;
330    va_start( ap, val );
331    while( NULL != va_arg( ap, benc_val_t ** ) )
332    {
333        len++;
334    }
335    va_end( ap );
336
337    if( makeroom( val, len ) )
338    {
339        return 1;
340    }
341
342    va_start( ap, val );
343    while( NULL != ( ptr = va_arg( ap, benc_val_t ** ) ) )
344    {
345        *ptr = &val->val.l.vals[val->val.l.count];
346        tr_bencInit( *ptr, TYPE_INT );
347        val->val.l.count++;
348    }
349    va_end( ap );
350
351    return 0;
352}
353
354int tr_bencListExtend( benc_val_t * val, int count )
355{
356    assert( TYPE_LIST == val->type );
357
358    if( makeroom( val, count ) )
359    {
360        return 1;
361    }
362
363    return 0;
364}
365
366static inline int _tr_bencDictAppend( benc_val_t * val, va_list ap,
367                                      va_list ap2, int nofree )
368{
369    int len;
370    char * key;
371    benc_val_t ** ptr;
372
373    assert( TYPE_DICT == val->type );
374
375    len = 0;
376    while( NULL != va_arg( ap, char * ) )
377    {
378        ptr = va_arg( ap, benc_val_t ** );
379        assert( NULL != ptr );
380        len += 2;
381    }
382
383    if( makeroom( val, len ) )
384    {
385        return 1;
386    }
387
388    while( NULL != ( key = va_arg( ap2, char * ) ) )
389    {
390        if( !nofree )
391        {
392            key = strdup( key );
393            if( NULL == key )
394            {
395                return 1;
396            }
397        }
398        ptr = va_arg( ap2, benc_val_t ** );
399        tr_bencInitStr( &val->val.l.vals[val->val.l.count], key, 0, nofree );
400        val->val.l.count++;
401        *ptr = &val->val.l.vals[val->val.l.count];
402        tr_bencInit( *ptr, TYPE_INT );
403        val->val.l.count++;
404    }
405
406    return 0;
407}
408
409int tr_bencDictAppend( benc_val_t * val, ... )
410{
411    va_list ap, ap2;
412    int     ret;
413
414    va_start( ap, val );
415    va_start( ap2, val );
416    ret = _tr_bencDictAppend( val, ap, ap2, 0 );
417    va_end( ap2 );
418    va_end( ap );
419
420    return ret;
421}
422
423int tr_bencDictAppendNofree( benc_val_t * val, ... )
424{
425    va_list ap, ap2;
426    int     ret;
427
428    va_start( ap, val );
429    va_start( ap2, val );
430    ret = _tr_bencDictAppend( val, ap, ap2, 1 );
431    va_end( ap2 );
432    va_end( ap );
433
434    return ret;
435}
436
437char * tr_bencSaveMalloc( benc_val_t * val, int * len )
438{
439    char * buf   = NULL;
440    int alloc = 0;
441
442    *len = 0;
443    if( tr_bencSave( val, &buf, len, &alloc ) )
444    {
445        if( NULL != buf )
446        {
447            free(buf);
448        }
449        *len = 0;
450        return NULL;
451    }
452
453    return buf;
454}
455
456int tr_bencSave( benc_val_t * val, char ** buf, int * used, int * max )
457{
458    int ii;   
459
460    switch( val->type )
461    {
462        case TYPE_INT:
463            if( tr_sprintf( buf, used, max, "i%"PRIu64"e", val->val.i ) )
464            {
465                return 1;
466            }
467            break;
468
469        case TYPE_STR:
470            if( tr_sprintf( buf, used, max, "%i:", val->val.s.i ) ||
471                tr_concat( buf, used,  max, val->val.s.s, val->val.s.i ) )
472            {
473                return 1;
474            }
475            break;
476
477        case TYPE_LIST:
478        case TYPE_DICT:
479            if( tr_sprintf( buf, used, max,
480                            (TYPE_LIST == val->type ? "l" : "d") ) )
481            {
482                return 1;
483            }
484            for( ii = 0; val->val.l.count > ii; ii++ )
485            {
486                if( tr_bencSave( val->val.l.vals + ii, buf, used, max ) )
487                {
488                    return 1;
489                }
490            }
491            if( tr_sprintf( buf, used, max, "e" ) )
492            {
493                return 1;
494            }
495            break;
496    }
497
498    return 0;
499}
Note: See TracBrowser for help on using the repository browser.