source: branches/1.3x/libtransmission/bencode.c @ 6489

Last change on this file since 6489 was 6489, checked in by charles, 14 years ago

(1.3x) lots of C correctness tweaks suggested by sparse/cgcc

  • Property svn:keywords set to Date Rev Author Id
File size: 31.8 KB
Line 
1/*
2 * This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: bencode.c 6489 2008-08-11 19:05:00Z charles $
11 */
12
13#include <assert.h>
14#include <ctype.h> /* isdigit, isprint, isspace */
15#include <errno.h>
16#include <stdarg.h>
17#include <stdio.h>
18#include <stdlib.h>
19
20#include <event.h> /* evbuffer */
21
22#include "transmission.h"
23#include "bencode.h"
24#include "json.h"
25#include "list.h"
26#include "ptrarray.h"
27#include "utils.h" /* tr_new(), tr_free() */
28
29/**
30***
31**/
32
33int
34tr_bencIsType( const tr_benc * val, int type )
35{
36    return ( ( val ) && ( val->type == type ) );
37}
38
39static int
40isContainer( const tr_benc * val )
41{
42    return tr_bencIsList(val) || tr_bencIsDict(val);
43}
44static int
45isSomething( const tr_benc * val )
46{
47    return isContainer(val) || tr_bencIsInt(val) || tr_bencIsString(val);
48}
49
50static void
51tr_bencInit( tr_benc * val, int type )
52{
53    memset( val, 0, sizeof( *val ) );
54    val->type = type;
55}
56
57
58/***
59****  tr_bencParse()
60****  tr_bencLoad()
61***/
62
63/**
64 * The initial i and trailing e are beginning and ending delimiters.
65 * You can have negative numbers such as i-3e. You cannot prefix the
66 * number with a zero such as i04e. However, i0e is valid. 
67 * Example: i3e represents the integer "3"
68 * NOTE: The maximum number of bit of this integer is unspecified,
69 * but to handle it as a signed 64bit integer is mandatory to handle
70 * "large files" aka .torrent for more that 4Gbyte
71 */
72int
73tr_bencParseInt( const uint8_t  * buf,
74                 const uint8_t  * bufend,
75                 const uint8_t ** setme_end, 
76                 int64_t        * setme_val )
77{
78    int err = TR_OK;
79    char * endptr;
80    const void * begin;
81    const void * end;
82    int64_t val;
83
84    if( buf >= bufend )
85        return TR_ERROR;
86    if( *buf != 'i' )
87        return TR_ERROR;
88
89    begin = buf + 1;
90    end = memchr( begin, 'e', (bufend-buf)-1 );
91    if( end == NULL )
92        return TR_ERROR;
93
94    errno = 0;
95    val = strtoll( begin, &endptr, 10 );
96    if( errno || ( endptr != end ) ) /* incomplete parse */
97        err = TR_ERROR;
98    else if( val && *(const char*)begin=='0' ) /* no leading zeroes! */
99        err = TR_ERROR;
100    else {
101        *setme_end = end + 1;
102        *setme_val = val;
103    }
104
105    return err;
106}
107
108
109/**
110 * Byte strings are encoded as follows:
111 * <string length encoded in base ten ASCII>:<string data>
112 * Note that there is no constant beginning delimiter, and no ending delimiter.
113 * Example: 4:spam represents the string "spam"
114 */
115int
116tr_bencParseStr( const uint8_t  * buf,
117                 const uint8_t  * bufend,
118                 const uint8_t ** setme_end,
119                 uint8_t       ** setme_str,
120                 size_t         * setme_strlen )
121{
122    size_t len;
123    const void * end;
124    char * endptr;
125
126    if( buf >= bufend )
127        return TR_ERROR;
128
129    if( !isdigit( *buf  ) )
130        return TR_ERROR;
131
132    end = memchr( buf, ':', bufend-buf );
133    if( end == NULL )
134        return TR_ERROR;
135
136    errno = 0;
137    len = strtoul( (const char*)buf, &endptr, 10 );
138    if( errno || endptr!=end )
139        return TR_ERROR;
140
141    if( (const uint8_t*)end + 1 + len > bufend )
142        return TR_ERROR;
143
144    *setme_end = end + 1 + len;
145    *setme_str = (uint8_t*) tr_strndup( end + 1, len );
146    *setme_strlen = len;
147    return TR_OK;
148}
149
150/* setting to 1 to help expose bugs with tr_bencListAdd and tr_bencDictAdd */
151#define LIST_SIZE 8 /* number of items to increment list/dict buffer by */
152
153static int
154makeroom( tr_benc * val, int count )
155{
156    assert( TYPE_LIST == val->type || TYPE_DICT == val->type );
157
158    if( val->val.l.count + count > val->val.l.alloc )
159    {
160        /* We need a bigger boat */
161        const int len = val->val.l.alloc + count +
162            ( count % LIST_SIZE ? LIST_SIZE - ( count % LIST_SIZE ) : 0 );
163        void * new = realloc( val->val.l.vals, len * sizeof( tr_benc ) );
164        if( NULL == new )
165            return 1;
166
167        val->val.l.alloc = len;
168        val->val.l.vals  = new;
169    }
170
171    return 0;
172}
173
174static tr_benc*
175getNode( tr_benc * top, tr_ptrArray * parentStack, int type )
176{
177    tr_benc * parent;
178
179    assert( top );
180    assert( parentStack );
181
182    if( tr_ptrArrayEmpty( parentStack ) )
183        return top;
184
185    parent = tr_ptrArrayBack( parentStack );
186    assert( parent );
187
188    /* dictionary keys must be strings */
189    if( ( parent->type == TYPE_DICT )
190        && ( type != TYPE_STR )
191        && ( ! ( parent->val.l.count % 2 ) ) )
192        return NULL;
193
194    makeroom( parent, 1 );
195    return parent->val.l.vals + parent->val.l.count++;
196}
197
198/**
199 * This function's previous recursive implementation was
200 * easier to read, but was vulnerable to a smash-stacking
201 * attack via maliciously-crafted bencoded data. (#667)
202 */
203static int
204tr_bencParseImpl( const void     * buf_in,
205                  const void     * bufend_in,
206                  tr_benc        * top,
207                  tr_ptrArray    * parentStack,
208                  const uint8_t ** setme_end )
209{
210    int err;
211    const uint8_t * buf = buf_in;
212    const uint8_t * bufend = bufend_in;
213
214    tr_bencInit( top, 0 );
215
216    while( buf != bufend )
217    {
218        if( buf > bufend ) /* no more text to parse... */
219            return 1;
220
221        if( *buf=='i' ) /* int */
222        {
223            int64_t val;
224            const uint8_t * end;
225            int err;
226            tr_benc * node;
227
228            if(( err = tr_bencParseInt( buf, bufend, &end, &val )))
229                return err;
230
231            node = getNode( top, parentStack, TYPE_INT );
232            if( !node )
233                return TR_ERROR;
234
235            tr_bencInitInt( node, val );
236            buf = end;
237
238            if( tr_ptrArrayEmpty( parentStack ) )
239                break;
240        }
241        else if( *buf=='l' ) /* list */
242        {
243            tr_benc * node = getNode( top, parentStack, TYPE_LIST );
244            if( !node )
245                return TR_ERROR;
246            tr_bencInit( node, TYPE_LIST );
247            tr_ptrArrayAppend( parentStack, node );
248            ++buf;
249        }
250        else if( *buf=='d' ) /* dict */
251        {
252            tr_benc * node = getNode( top, parentStack, TYPE_DICT );
253            if( !node )
254                return TR_ERROR;
255            tr_bencInit( node, TYPE_DICT );
256            tr_ptrArrayAppend( parentStack, node );
257            ++buf;
258        }
259        else if( *buf=='e' ) /* end of list or dict */
260        {
261            tr_benc * node;
262            ++buf;
263            if( tr_ptrArrayEmpty( parentStack ) )
264                return TR_ERROR;
265
266            node = tr_ptrArrayBack( parentStack );
267            if( tr_bencIsDict( node ) && ( node->val.l.count % 2 ) ) {
268                /* odd # of children in dict */
269                tr_bencFree( &node->val.l.vals [ --node->val.l.count ] );
270                return TR_ERROR;
271            }
272
273            tr_ptrArrayPop( parentStack );
274            if( tr_ptrArrayEmpty( parentStack ) )
275                break;
276        }
277        else if( isdigit(*buf) ) /* string? */
278        {
279            const uint8_t * end;
280            uint8_t * str;
281            size_t str_len;
282            int err;
283            tr_benc * node;
284
285            if(( err = tr_bencParseStr( buf, bufend, &end, &str, &str_len )))
286                return err;
287
288            node = getNode( top, parentStack, TYPE_STR );
289            if( !node ) {
290                tr_free( str );
291                return TR_ERROR;
292            }
293
294            tr_bencInitStr( node, str, str_len, 0 );
295            buf = end;
296
297            if( tr_ptrArrayEmpty( parentStack ) )
298                break;
299        }
300        else /* invalid bencoded text... march past it */
301        {
302            ++buf;
303        }
304    }
305
306    err = !isSomething( top ) || !tr_ptrArrayEmpty( parentStack );
307
308    if( !err && setme_end )
309        *setme_end = buf;
310
311    return err;
312}
313
314int
315tr_bencParse( const void     * buf,
316              const void     * end,
317              tr_benc        * top,
318              const uint8_t ** setme_end )
319{
320    int err;
321    tr_ptrArray * parentStack = tr_ptrArrayNew( );
322
323    top->type = 0; /* not initialized yet */
324    err = tr_bencParseImpl( buf, end, top, parentStack, setme_end );
325    if( err )
326        tr_bencFree( top ); 
327
328    tr_ptrArrayFree( parentStack, NULL );
329    return err;
330}
331
332int
333tr_bencLoad( const void  * buf_in,
334             int           buflen,
335             tr_benc     * setme_benc,
336             char       ** setme_end )
337{
338    const uint8_t * buf = buf_in;
339    const uint8_t * end;
340    const int ret = tr_bencParse( buf, buf+buflen, setme_benc, &end );
341    if( !ret && setme_end )
342        *setme_end = (char*) end;
343    return ret;
344}
345
346/***
347****
348***/
349
350static int
351dictIndexOf( tr_benc * val, const char * key )
352{
353    int len, ii;
354
355    if( !tr_bencIsDict( val ) )
356        return -1;
357
358    len = strlen( key );
359   
360    for( ii = 0; ii + 1 < val->val.l.count; ii += 2 )
361    {
362        if( TYPE_STR  != val->val.l.vals[ii].type ||
363            len       != val->val.l.vals[ii].val.s.i ||
364            0 != memcmp( val->val.l.vals[ii].val.s.s, key, len ) )
365        {
366            continue;
367        }
368        return ii;
369    }
370
371    return -1;
372}
373
374tr_benc *
375tr_bencDictFind( tr_benc * val, const char * key )
376{
377    const int i = dictIndexOf( val, key );
378    return i<0 ? NULL : &val->val.l.vals[i+1];
379}
380
381tr_benc*
382tr_bencDictFindType( tr_benc * val, const char * key, int type )
383{
384    tr_benc * ret = tr_bencDictFind( val, key );
385    return ret && ret->type == type ? ret : NULL;
386}
387
388tr_benc *
389tr_bencDictFindFirst( tr_benc * val, ... )
390{
391    const char * key;
392    tr_benc * ret;
393    va_list      ap;
394
395    ret = NULL;
396    va_start( ap, val );
397    while(( key = va_arg( ap, const char * )))
398        if(( ret = tr_bencDictFind( val, key )))
399            break;
400    va_end( ap );
401
402    return ret;
403}
404
405int
406tr_bencListSize( const tr_benc * list )
407{
408    return tr_bencIsList( list ) ? list->val.l.count : 0;
409}
410
411tr_benc*
412tr_bencListChild( tr_benc * val, int i )
413{
414    tr_benc * ret = NULL;
415    if( tr_bencIsList( val ) && ( i >= 0 ) && ( i < val->val.l.count ) )
416        ret = val->val.l.vals + i;
417    return ret;
418}
419
420int
421tr_bencGetInt ( const tr_benc * val, int64_t * setme )
422{
423    const int success = tr_bencIsInt( val );
424    if( success )
425        *setme = val->val.i ;
426    return success;
427}
428
429int
430tr_bencGetStr( const tr_benc * val, const char ** setme )
431{
432    const int success = tr_bencIsString( val );
433    if( success )
434        *setme = val->val.s.s;
435    return success;
436}
437
438int
439tr_bencDictFindInt( tr_benc * dict, const char * key, int64_t * setme )
440{
441    int found = FALSE;
442    tr_benc * child = tr_bencDictFindType( dict, key, TYPE_INT );
443    if( child )
444        found = tr_bencGetInt( child, setme );
445    return found;
446}
447
448int
449tr_bencDictFindDouble( tr_benc * dict, const char * key, double * setme )
450{
451    const char * str;
452    const int success = tr_bencDictFindStr( dict, key, &str );
453    if( success )
454        *setme = strtod( str, NULL );
455    return success;
456}
457
458int
459tr_bencDictFindList( tr_benc * dict, const char * key, tr_benc ** setme )
460{
461    int found = FALSE;
462    tr_benc * child = tr_bencDictFindType( dict, key, TYPE_LIST );
463    if( child ) {
464        *setme = child;
465        found = TRUE;
466    }
467    return found;
468}
469
470int
471tr_bencDictFindDict( tr_benc * dict, const char * key, tr_benc ** setme )
472{
473    int found = FALSE;
474    tr_benc * child = tr_bencDictFindType( dict, key, TYPE_DICT );
475    if( child ) {
476        *setme = child;
477        found = TRUE;
478    }
479    return found;
480}
481
482int
483tr_bencDictFindStr( tr_benc * dict, const char * key, const char ** setme )
484{
485    int found = FALSE;
486    tr_benc * child = tr_bencDictFindType( dict, key, TYPE_STR );
487    if( child ) {
488        *setme = child->val.s.s;
489        found = TRUE;
490    }
491    return found;
492}
493
494int
495tr_bencDictFindRaw( tr_benc         * dict,
496                    const char      * key,
497                    const uint8_t  ** setme_raw, 
498                    size_t          * setme_len )
499{
500    int found = FALSE;
501    tr_benc * child = tr_bencDictFindType( dict, key, TYPE_STR );
502    if( child ) {
503        *setme_raw = (uint8_t*) child->val.s.s;
504        *setme_len = child->val.s.i;
505        found = TRUE;
506    }
507    return found;
508}
509
510
511/***
512****
513***/
514
515void
516_tr_bencInitStr( tr_benc * val, char * str, int len, int nofree )
517{
518    tr_bencInit( val, TYPE_STR );
519    val->val.s.s      = str;
520    val->val.s.nofree = nofree;
521    if( 0 >= len )
522    {
523        len = ( NULL == str ? 0 : strlen( str ) );
524    }
525    val->val.s.i = len;
526}
527
528void
529tr_bencInitRaw( tr_benc * val, const void * src, size_t byteCount )
530{
531    tr_bencInit( val, TYPE_STR );
532    val->val.s.i = byteCount;
533    val->val.s.s = tr_memdup( src, byteCount );
534    val->val.s.nofree = 0;
535}
536
537int
538tr_bencInitStrDup( tr_benc * val, const char * str )
539{
540    char * newStr = tr_strdup( str );
541    if( newStr == NULL )
542        return 1;
543
544    _tr_bencInitStr( val, newStr, 0, 0 );
545    return 0;
546}
547
548void
549tr_bencInitInt( tr_benc * val, int64_t num )
550{
551    tr_bencInit( val, TYPE_INT );
552    val->val.i = num;
553}
554
555int
556tr_bencInitList( tr_benc * val, int reserveCount )
557{
558    tr_bencInit( val, TYPE_LIST );
559    return tr_bencListReserve( val, reserveCount );
560}
561
562int
563tr_bencListReserve( tr_benc * val, int count )
564{
565    assert( tr_bencIsList( val ) );
566    return makeroom( val, count );
567}
568
569int
570tr_bencInitDict( tr_benc * val, int reserveCount )
571{
572    tr_bencInit( val, TYPE_DICT );
573    return tr_bencDictReserve( val, reserveCount );
574}
575
576int
577tr_bencDictReserve( tr_benc * val, int count )
578{
579    assert( tr_bencIsDict( val ) );
580    return makeroom( val, count * 2 );
581}
582
583tr_benc *
584tr_bencListAdd( tr_benc * list )
585{
586    tr_benc * item;
587
588    assert( tr_bencIsList( list ) );
589
590    if( list->val.l.count == list->val.l.alloc )
591        tr_bencListReserve( list, LIST_SIZE );
592
593    assert( list->val.l.count < list->val.l.alloc );
594
595    item = &list->val.l.vals[list->val.l.count];
596    list->val.l.count++;
597    tr_bencInit( item, TYPE_INT );
598
599    return item;
600}
601tr_benc *
602tr_bencListAddInt( tr_benc * list, int64_t val )
603{
604    tr_benc * node = tr_bencListAdd( list );
605    tr_bencInitInt( node, val );
606    return node;
607}
608tr_benc *
609tr_bencListAddStr( tr_benc * list, const char * val )
610{
611    tr_benc * node = tr_bencListAdd( list );
612    tr_bencInitStrDup( node, val );
613    return node;
614}
615tr_benc*
616tr_bencListAddList( tr_benc * list, int reserveCount )
617{
618    tr_benc * child = tr_bencListAdd( list );
619    tr_bencInitList( child, reserveCount );
620    return child;
621}
622tr_benc*
623tr_bencListAddDict( tr_benc * list, int reserveCount )
624{
625    tr_benc * child = tr_bencListAdd( list );
626    tr_bencInitDict( child, reserveCount );
627    return child;
628}
629
630tr_benc *
631tr_bencDictAdd( tr_benc * dict, const char * key )
632{
633    tr_benc * keyval, * itemval;
634
635    assert( tr_bencIsDict( dict ) );
636    if( dict->val.l.count + 2 > dict->val.l.alloc )
637        makeroom( dict, 2 );
638    assert( dict->val.l.count + 2 <= dict->val.l.alloc );
639
640    keyval = dict->val.l.vals + dict->val.l.count++;
641    tr_bencInitStrDup( keyval, key );
642
643    itemval = dict->val.l.vals + dict->val.l.count++;
644    tr_bencInit( itemval, TYPE_INT );
645
646    return itemval;
647}
648tr_benc*
649tr_bencDictAddInt( tr_benc * dict, const char * key, int64_t val )
650{
651    tr_benc * child = tr_bencDictAdd( dict, key );
652    tr_bencInitInt( child, val );
653    return child;
654}
655tr_benc*
656tr_bencDictAddStr( tr_benc * dict, const char * key, const char * val )
657{
658    tr_benc * child = tr_bencDictAdd( dict, key );
659    tr_bencInitStrDup( child, val );
660    return child;
661}
662tr_benc*
663tr_bencDictAddDouble( tr_benc * dict, const char * key, double d )
664{
665    char buf[128];
666    tr_snprintf( buf, sizeof( buf ), "%f", d );
667    return tr_bencDictAddStr( dict, key, buf );
668}
669tr_benc*
670tr_bencDictAddList( tr_benc * dict, const char * key, int reserveCount )
671{
672    tr_benc * child = tr_bencDictAdd( dict, key );
673    tr_bencInitList( child, reserveCount );
674    return child;
675}
676tr_benc*
677tr_bencDictAddDict( tr_benc * dict, const char * key, int reserveCount )
678{
679    tr_benc * child = tr_bencDictAdd( dict, key );
680    tr_bencInitDict( child, reserveCount );
681    return child;
682}
683tr_benc*
684tr_bencDictAddRaw( tr_benc * dict, const char * key, const void * src, size_t len )
685{
686    tr_benc * child = tr_bencDictAdd( dict, key );
687    tr_bencInitRaw( child, src, len );
688    return child;
689}
690
691int
692tr_bencDictRemove( tr_benc * dict, const char * key )
693{
694    int i = dictIndexOf( dict, key );
695    if( i >= 0 )
696    {
697        const int n = dict->val.l.count;
698        tr_bencFree( &dict->val.l.vals[i] );
699        tr_bencFree( &dict->val.l.vals[i+1] );
700        if( i + 2 < n )
701        {
702            dict->val.l.vals[i]   = dict->val.l.vals[n-2];
703            dict->val.l.vals[i+1] = dict->val.l.vals[n-1];
704        }
705        dict->val.l.count -= 2;
706    }
707    return i >= 0; /* return true if found */
708}
709
710
711/***
712****  BENC WALKING
713***/
714
715struct KeyIndex
716{
717    const char * key;
718    int index;
719};
720
721static int
722compareKeyIndex( const void * va, const void * vb )
723{
724    const struct KeyIndex * a = va;
725    const struct KeyIndex * b = vb;
726    return strcmp( a->key, b->key );
727}
728
729struct SaveNode
730{
731    const tr_benc * val;
732    int valIsVisited;
733    int childCount;
734    int childIndex;
735    int * children;
736};
737
738static struct SaveNode*
739nodeNewDict( const tr_benc * val )
740{
741    int i, j;
742    int nKeys;
743    struct SaveNode * node;
744    struct KeyIndex * indices;
745
746    assert( tr_bencIsDict( val ) );
747
748    nKeys = val->val.l.count / 2;
749    node = tr_new0( struct SaveNode, 1 );
750    node->val = val;
751    node->children = tr_new0( int, nKeys * 2 );
752
753    /* ugh, a dictionary's children have to be sorted by key... */
754    indices = tr_new( struct KeyIndex, nKeys );
755    for( i=j=0; i<(nKeys*2); i+=2, ++j ) {
756        indices[j].key = val->val.l.vals[i].val.s.s;
757        indices[j].index = i;
758    }
759    qsort( indices, j, sizeof(struct KeyIndex), compareKeyIndex );
760    for( i=0; i<j; ++i ) {
761        const int index = indices[i].index;
762        node->children[ node->childCount++ ] = index;
763        node->children[ node->childCount++ ] = index + 1;
764    }
765
766    assert( node->childCount == nKeys * 2 );
767    tr_free( indices );
768    return node;
769}
770
771static struct SaveNode*
772nodeNewList( const tr_benc * val )
773{
774    int i, n;
775    struct SaveNode * node;
776
777    assert( tr_bencIsList( val ) );
778
779    n = val->val.l.count;
780    node = tr_new0( struct SaveNode, 1 );
781    node->val = val;
782    node->childCount = n;
783    node->children = tr_new0( int, n );
784    for( i=0; i<n; ++i ) /* a list's children don't need to be reordered */
785        node->children[i] = i;
786
787    return node;
788}
789
790static struct SaveNode*
791nodeNewLeaf( const tr_benc * val )
792{
793    struct SaveNode * node;
794
795    assert( !isContainer( val ) );
796
797    node = tr_new0( struct SaveNode, 1 );
798    node->val = val;
799    return node;
800}
801
802static struct SaveNode*
803nodeNew( const tr_benc * val )
804{
805    struct SaveNode * node;
806
807    if( tr_bencIsList( val ) )
808        node = nodeNewList( val );
809    else if( tr_bencIsDict( val ) )
810        node = nodeNewDict( val );
811    else
812        node = nodeNewLeaf( val );
813
814    return node;
815}
816
817typedef void (*BencWalkFunc)( const tr_benc * val, void * user_data );
818
819struct WalkFuncs
820{
821    BencWalkFunc intFunc;
822    BencWalkFunc stringFunc;
823    BencWalkFunc dictBeginFunc;
824    BencWalkFunc listBeginFunc;
825    BencWalkFunc containerEndFunc;
826};
827
828/**
829 * This function's previous recursive implementation was
830 * easier to read, but was vulnerable to a smash-stacking
831 * attack via maliciously-crafted bencoded data. (#667)
832 */
833static void
834bencWalk( const tr_benc      * top,
835          struct WalkFuncs   * walkFuncs,
836          void               * user_data )
837{
838    tr_ptrArray * stack = tr_ptrArrayNew( );
839    tr_ptrArrayAppend( stack, nodeNew( top ) );
840
841    while( !tr_ptrArrayEmpty( stack ) )
842    {
843        struct SaveNode * node = tr_ptrArrayBack( stack );
844        const tr_benc * val;
845
846        if( !node->valIsVisited )
847        {
848            val = node->val;
849            node->valIsVisited = TRUE;
850        }
851        else if( node->childIndex < node->childCount )
852        {
853            const int index = node->children[ node->childIndex++ ];
854            val = node->val->val.l.vals +  index;
855        }
856        else /* done with this node */
857        {
858            if( isContainer( node->val ) )
859                walkFuncs->containerEndFunc( node->val, user_data );
860            tr_ptrArrayPop( stack );
861            tr_free( node->children );
862            tr_free( node );
863            continue;
864        }
865
866        if( val ) switch( val->type )
867        {
868            case TYPE_INT:
869                walkFuncs->intFunc( val, user_data );
870                break;
871
872            case TYPE_STR:
873                walkFuncs->stringFunc( val, user_data );
874                break;
875
876            case TYPE_LIST:
877                if( val != node->val )
878                    tr_ptrArrayAppend( stack, nodeNew( val ) );
879                else
880                    walkFuncs->listBeginFunc( val, user_data );
881                break;
882
883            case TYPE_DICT:
884                if( val != node->val )
885                    tr_ptrArrayAppend( stack, nodeNew( val ) );
886                else
887                    walkFuncs->dictBeginFunc( val, user_data );
888                break;
889
890            default:
891                /* did caller give us an uninitialized val? */
892                tr_err( _( "Invalid metadata" ) );
893                break;
894        }
895    }
896
897    tr_ptrArrayFree( stack, NULL );
898}
899
900/****
901*****
902****/
903
904static void
905saveIntFunc( const tr_benc * val, void * evbuf )
906{
907    evbuffer_add_printf( evbuf, "i%"PRId64"e", val->val.i );
908}
909static void
910saveStringFunc( const tr_benc * val, void * vevbuf )
911{
912    struct evbuffer * evbuf = vevbuf;
913    evbuffer_add_printf( evbuf, "%d:", val->val.s.i );
914    evbuffer_add( evbuf, val->val.s.s, val->val.s.i );
915}
916static void
917saveDictBeginFunc( const tr_benc * val UNUSED, void * evbuf )
918{
919    evbuffer_add_printf( evbuf, "d" );
920}
921static void
922saveListBeginFunc( const tr_benc * val UNUSED, void * evbuf )
923{
924    evbuffer_add_printf( evbuf, "l" );
925}
926static void
927saveContainerEndFunc( const tr_benc * val UNUSED, void * evbuf )
928{
929    evbuffer_add_printf( evbuf, "e" );
930}
931char*
932tr_bencSave( const tr_benc * top, int * len )
933{
934    char * ret;
935    struct WalkFuncs walkFuncs;
936    struct evbuffer * out = evbuffer_new( );
937
938    walkFuncs.intFunc = saveIntFunc;
939    walkFuncs.stringFunc = saveStringFunc;
940    walkFuncs.dictBeginFunc = saveDictBeginFunc;
941    walkFuncs.listBeginFunc = saveListBeginFunc;
942    walkFuncs.containerEndFunc = saveContainerEndFunc;
943    bencWalk( top, &walkFuncs, out );
944   
945    if( len )
946        *len = EVBUFFER_LENGTH( out );
947    ret = tr_strndup( (char*) EVBUFFER_DATA( out ), EVBUFFER_LENGTH( out ) );
948    evbuffer_free( out );
949    return ret;
950}
951
952/***
953****
954***/
955
956static void
957freeDummyFunc( const tr_benc * val UNUSED, void * buf UNUSED  )
958{
959}
960static void
961freeStringFunc( const tr_benc * val, void * freeme )
962{
963    if( !val->val.s.nofree )
964        tr_ptrArrayAppend( freeme, val->val.s.s );
965}
966static void
967freeContainerBeginFunc( const tr_benc * val, void * freeme )
968{
969    tr_ptrArrayAppend( freeme, val->val.l.vals );
970}
971void
972tr_bencFree( tr_benc * val )
973{
974    if( val && val->type )
975    {
976        tr_ptrArray * freeme = tr_ptrArrayNew( );
977        struct WalkFuncs walkFuncs;
978
979        walkFuncs.intFunc = freeDummyFunc;
980        walkFuncs.stringFunc = freeStringFunc;
981        walkFuncs.dictBeginFunc = freeContainerBeginFunc;
982        walkFuncs.listBeginFunc = freeContainerBeginFunc;
983        walkFuncs.containerEndFunc = freeDummyFunc;
984        bencWalk( val, &walkFuncs, freeme );
985
986        tr_ptrArrayFree( freeme, tr_free );
987    }
988}
989
990/***
991****
992***/
993
994struct WalkPrint
995{
996    int depth;
997    FILE * out;
998};
999static void
1000printLeadingSpaces( struct WalkPrint * data )
1001{
1002    const int width = data->depth * 2;
1003    fprintf( data->out, "%*.*s", width, width, " " );
1004}
1005static void
1006printIntFunc( const tr_benc * val, void * vdata )
1007{
1008    struct WalkPrint * data = vdata;
1009    printLeadingSpaces( data );
1010    fprintf( data->out, "int:  %"PRId64"\n", val->val.i );
1011}
1012static void
1013printStringFunc( const tr_benc * val, void * vdata )
1014{
1015    int ii;
1016    struct WalkPrint * data = vdata;
1017    printLeadingSpaces( data );
1018    fprintf( data->out, "string:  " );
1019    for( ii = 0; val->val.s.i > ii; ii++ )
1020    {
1021        if( '\\' == val->val.s.s[ii] ) {
1022            putc( '\\', data->out );
1023            putc( '\\', data->out );
1024        } else if( isprint( val->val.s.s[ii] ) ) {
1025            putc( val->val.s.s[ii], data->out );
1026        } else {
1027            fprintf( data->out, "\\x%02x", val->val.s.s[ii] );
1028        }
1029    }
1030    fprintf( data->out, "\n" );
1031}
1032static void
1033printListBeginFunc( const tr_benc * val UNUSED, void * vdata )
1034{
1035    struct WalkPrint * data = vdata;
1036    printLeadingSpaces( data );
1037    fprintf( data->out, "list\n" );
1038    ++data->depth;
1039}
1040static void
1041printDictBeginFunc( const tr_benc * val UNUSED, void * vdata )
1042{
1043    struct WalkPrint * data = vdata;
1044    printLeadingSpaces( data );
1045    fprintf( data->out, "dict\n" );
1046    ++data->depth;
1047}
1048static void
1049printContainerEndFunc( const tr_benc * val UNUSED, void * vdata )
1050{
1051    struct WalkPrint * data = vdata;
1052    --data->depth;
1053}
1054void
1055tr_bencPrint( const tr_benc * val )
1056{
1057    struct WalkFuncs walkFuncs;
1058    struct WalkPrint walkPrint;
1059
1060    walkFuncs.intFunc = printIntFunc;
1061    walkFuncs.stringFunc = printStringFunc;
1062    walkFuncs.dictBeginFunc = printDictBeginFunc;
1063    walkFuncs.listBeginFunc = printListBeginFunc;
1064    walkFuncs.containerEndFunc = printContainerEndFunc;
1065
1066    walkPrint.out = stderr;
1067    walkPrint.depth = 0;
1068    bencWalk( val, &walkFuncs, &walkPrint );
1069}
1070
1071/***
1072****
1073***/
1074
1075struct ParentState
1076{
1077    int bencType;
1078    int childIndex;
1079    int childCount;
1080};
1081 
1082struct jsonWalk
1083{
1084    tr_list * parents;
1085    struct evbuffer * out;
1086};
1087
1088static void
1089jsonIndent( struct jsonWalk * data )
1090{
1091    const int width = tr_list_size( data->parents ) * 4;
1092    evbuffer_add_printf( data->out, "\n%*.*s", width, width, " " );
1093}
1094
1095static void
1096jsonChildFunc( struct jsonWalk * data )
1097{
1098    if( data->parents )
1099    {
1100        struct ParentState * parentState = data->parents->data;
1101
1102        switch( parentState->bencType )
1103        {
1104            case TYPE_DICT: {
1105                const int i = parentState->childIndex++;
1106                if( ! ( i % 2 ) )
1107                    evbuffer_add_printf( data->out, ": " );
1108                else {
1109                    evbuffer_add_printf( data->out, ", " );
1110                    jsonIndent( data );
1111                }
1112                break;
1113            }
1114
1115            case TYPE_LIST: {
1116                ++parentState->childIndex;
1117                evbuffer_add_printf( data->out, ", " );
1118                jsonIndent( data );
1119                break;
1120            }
1121
1122            default:
1123                break;
1124        }
1125    }
1126}
1127
1128static void
1129jsonPushParent( struct jsonWalk * data, const tr_benc * benc )
1130{
1131    struct ParentState * parentState = tr_new( struct ParentState, 1 );
1132    parentState->bencType = benc->type;
1133    parentState->childIndex = 0;
1134    parentState->childCount = benc->val.l.count;
1135    tr_list_prepend( &data->parents, parentState );
1136}
1137
1138static void
1139jsonPopParent( struct jsonWalk * data )
1140{
1141    tr_free( tr_list_pop_front( &data->parents ) );
1142}
1143
1144static void
1145jsonIntFunc( const tr_benc * val, void * vdata )
1146{
1147    struct jsonWalk * data = vdata;
1148    evbuffer_add_printf( data->out, "%"PRId64, val->val.i );
1149    jsonChildFunc( data );
1150}
1151static void
1152jsonStringFunc( const tr_benc * val, void * vdata )
1153{
1154    struct jsonWalk * data = vdata;
1155    const char *it, *end;
1156    evbuffer_add_printf( data->out, "\"" );
1157    for( it=val->val.s.s, end=it+val->val.s.i; it!=end; ++it )
1158    {
1159        switch( *it ) {
1160            case '/' : evbuffer_add_printf( data->out, "\\/" ); break;
1161            case '\b': evbuffer_add_printf( data->out, "\\b" ); break;
1162            case '\f': evbuffer_add_printf( data->out, "\\f" ); break;
1163            case '\n': evbuffer_add_printf( data->out, "\\n" ); break;
1164            case '\r': evbuffer_add_printf( data->out, "\\r" ); break;
1165            case '\t': evbuffer_add_printf( data->out, "\\t" ); break;
1166            case '"' : evbuffer_add_printf( data->out, "\\\"" ); break;
1167            case '\\': evbuffer_add_printf( data->out, "\\\\" ); break;
1168            default: {
1169                if( isascii( *it ) )
1170                    evbuffer_add_printf( data->out, "%c", *it );
1171                else
1172                    evbuffer_add_printf( data->out, "\\u%0x", (unsigned int)*it );
1173                break;
1174            }
1175        }
1176    }
1177    evbuffer_add_printf( data->out, "\"" );
1178    jsonChildFunc( data );
1179}
1180static void
1181jsonDictBeginFunc( const tr_benc * val, void * vdata )
1182{
1183    struct jsonWalk * data = vdata;
1184    jsonPushParent( data, val );
1185    evbuffer_add_printf( data->out, "{" );
1186    if( val->val.l.count )
1187        jsonIndent( data );
1188}
1189static void
1190jsonListBeginFunc( const tr_benc * val, void * vdata )
1191{
1192    const int nChildren = tr_bencListSize( val );
1193    struct jsonWalk * data = vdata;
1194    jsonPushParent( data, val );
1195    evbuffer_add_printf( data->out, "[" );
1196    if( nChildren )
1197        jsonIndent( data );
1198}
1199static void
1200jsonContainerEndFunc( const tr_benc * val, void * vdata )
1201{
1202    size_t i;
1203    struct jsonWalk * data = vdata;
1204    char * str;
1205    int emptyContainer = FALSE;
1206
1207    /* trim out the trailing comma, if any */
1208    str = (char*) EVBUFFER_DATA( data->out );
1209    for( i=EVBUFFER_LENGTH( data->out )-1; i>0; --i ) {
1210        if( isspace( str[i] ) ) continue;
1211        if( str[i]==',' )
1212            EVBUFFER_LENGTH( data->out ) = i;
1213        if( str[i]=='{' || str[i]=='[' )
1214            emptyContainer = TRUE;
1215        break;
1216    }
1217
1218    jsonPopParent( data );
1219    if( !emptyContainer )
1220        jsonIndent( data );
1221    if( tr_bencIsDict( val ) )
1222        evbuffer_add_printf( data->out, "}" );
1223    else /* list */
1224        evbuffer_add_printf( data->out, "]" );
1225    jsonChildFunc( data );
1226}
1227char*
1228tr_bencSaveAsJSON( const tr_benc * top, int * len )
1229{
1230    char * ret;
1231    struct WalkFuncs walkFuncs;
1232    struct jsonWalk data;
1233
1234    data.out = evbuffer_new( );
1235    data.parents = NULL;
1236
1237    walkFuncs.intFunc = jsonIntFunc;
1238    walkFuncs.stringFunc = jsonStringFunc;
1239    walkFuncs.dictBeginFunc = jsonDictBeginFunc;
1240    walkFuncs.listBeginFunc = jsonListBeginFunc;
1241    walkFuncs.containerEndFunc = jsonContainerEndFunc;
1242
1243    bencWalk( top, &walkFuncs, &data );
1244   
1245    if( EVBUFFER_LENGTH( data.out ) )
1246        evbuffer_add_printf( data.out, "\n" );
1247    if( len )
1248        *len = EVBUFFER_LENGTH( data.out );
1249    ret = tr_strndup( (char*) EVBUFFER_DATA( data.out ), EVBUFFER_LENGTH( data.out ) );
1250    evbuffer_free( data.out );
1251    return ret;
1252}
1253
1254/***
1255****
1256***/
1257
1258static int
1259saveFile( const char * filename, const char * content, size_t len )
1260{
1261    int err = TR_OK;
1262    FILE * out = NULL;
1263
1264    out = fopen( filename, "wb+" );
1265    if( !out )
1266    {
1267        tr_err( _( "Couldn't open \"%1$s\": %2$s" ),
1268                filename, tr_strerror( errno ) );
1269        err = TR_EINVALID;
1270    }
1271    else if( fwrite( content, sizeof( char ), len, out ) != (size_t)len )
1272    {
1273        tr_err( _( "Couldn't save file \"%1$s\": %2$s" ),
1274                filename, tr_strerror( errno ) );
1275        err = TR_EINVALID;
1276    }
1277
1278    if( !err )
1279        tr_dbg( "tr_bencSaveFile saved \"%s\"", filename );
1280    if( out )
1281        fclose( out );
1282    return err;
1283}
1284
1285int
1286tr_bencSaveFile( const char * filename,  const tr_benc * b )
1287{
1288    int len;
1289    char * content = tr_bencSave( b, &len );
1290    const int err = saveFile( filename, content, len );
1291    tr_free( content );
1292    return err;
1293}
1294
1295int
1296tr_bencLoadFile( const char * filename, tr_benc * b )
1297{
1298    int ret;
1299    size_t contentLen;
1300    uint8_t * content = tr_loadFile( filename, &contentLen );
1301    ret = content ? tr_bencLoad( content, contentLen, b, NULL )
1302                  : TR_ERROR_IO_OTHER;
1303    tr_free( content );
1304    return ret;
1305}
1306
1307int
1308tr_bencSaveJSONFile( const char * filename, const tr_benc * b )
1309{
1310    int len;
1311    char * content = tr_bencSaveAsJSON( b, &len );
1312    const int err = saveFile( filename, content, len );
1313    tr_free( content );
1314    return err;
1315}
1316
1317int
1318tr_bencLoadJSONFile( const char * filename, tr_benc * b )
1319{
1320    int ret;
1321    size_t contentLen;
1322    uint8_t * content = tr_loadFile( filename, &contentLen );
1323    ret = content ? tr_jsonParse( content, contentLen, b, NULL )
1324                  : TR_ERROR_IO_OTHER;
1325    tr_free( content );
1326    return ret;
1327}
Note: See TracBrowser for help on using the repository browser.