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

Last change on this file since 6483 was 6483, checked in by charles, 13 years ago

(libT 1.3x) #1176: memory leaks in libtransmission

  • 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 6483 2008-08-11 17:00:22Z 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    tr_ptrArray * parentStack = tr_ptrArrayNew( );
321    top->type = 0; /* not initialized yet */
322    const int err = tr_bencParseImpl( buf, end, top, parentStack, setme_end );
323    if( err )
324        tr_bencFree( top ); 
325    tr_ptrArrayFree( parentStack, NULL );
326    return err;
327}
328
329int
330tr_bencLoad( const void  * buf_in,
331             int           buflen,
332             tr_benc     * setme_benc,
333             char       ** setme_end )
334{
335    const uint8_t * buf = buf_in;
336    const uint8_t * end;
337    const int ret = tr_bencParse( buf, buf+buflen, setme_benc, &end );
338    if( !ret && setme_end )
339        *setme_end = (char*) end;
340    return ret;
341}
342
343/***
344****
345***/
346
347static int
348dictIndexOf( tr_benc * val, const char * key )
349{
350    int len, ii;
351
352    if( !tr_bencIsDict( val ) )
353        return -1;
354
355    len = strlen( key );
356   
357    for( ii = 0; ii + 1 < val->val.l.count; ii += 2 )
358    {
359        if( TYPE_STR  != val->val.l.vals[ii].type ||
360            len       != val->val.l.vals[ii].val.s.i ||
361            0 != memcmp( val->val.l.vals[ii].val.s.s, key, len ) )
362        {
363            continue;
364        }
365        return ii;
366    }
367
368    return -1;
369}
370
371tr_benc *
372tr_bencDictFind( tr_benc * val, const char * key )
373{
374    const int i = dictIndexOf( val, key );
375    return i<0 ? NULL : &val->val.l.vals[i+1];
376}
377
378tr_benc*
379tr_bencDictFindType( tr_benc * val, const char * key, int type )
380{
381    tr_benc * ret = tr_bencDictFind( val, key );
382    return ret && ret->type == type ? ret : NULL;
383}
384
385tr_benc *
386tr_bencDictFindFirst( tr_benc * val, ... )
387{
388    const char * key;
389    tr_benc * ret;
390    va_list      ap;
391
392    ret = NULL;
393    va_start( ap, val );
394    while(( key = va_arg( ap, const char * )))
395        if(( ret = tr_bencDictFind( val, key )))
396            break;
397    va_end( ap );
398
399    return ret;
400}
401
402int
403tr_bencListSize( const tr_benc * list )
404{
405    return tr_bencIsList( list ) ? list->val.l.count : 0;
406}
407
408tr_benc*
409tr_bencListChild( tr_benc * val, int i )
410{
411    tr_benc * ret = NULL;
412    if( tr_bencIsList( val ) && ( i >= 0 ) && ( i < val->val.l.count ) )
413        ret = val->val.l.vals + i;
414    return ret;
415}
416
417int
418tr_bencGetInt ( const tr_benc * val, int64_t * setme )
419{
420    const int success = tr_bencIsInt( val );
421    if( success )
422        *setme = val->val.i ;
423    return success;
424}
425
426int
427tr_bencGetStr( const tr_benc * val, const char ** setme )
428{
429    const int success = tr_bencIsString( val );
430    if( success )
431        *setme = val->val.s.s;
432    return success;
433}
434
435int
436tr_bencDictFindInt( tr_benc * dict, const char * key, int64_t * setme )
437{
438    int found = FALSE;
439    tr_benc * child = tr_bencDictFindType( dict, key, TYPE_INT );
440    if( child )
441        found = tr_bencGetInt( child, setme );
442    return found;
443}
444
445int
446tr_bencDictFindDouble( tr_benc * dict, const char * key, double * setme )
447{
448    const char * str;
449    const int success = tr_bencDictFindStr( dict, key, &str );
450    if( success )
451        *setme = strtod( str, NULL );
452    return success;
453}
454
455int
456tr_bencDictFindList( tr_benc * dict, const char * key, tr_benc ** setme )
457{
458    int found = FALSE;
459    tr_benc * child = tr_bencDictFindType( dict, key, TYPE_LIST );
460    if( child ) {
461        *setme = child;
462        found = TRUE;
463    }
464    return found;
465}
466
467int
468tr_bencDictFindDict( tr_benc * dict, const char * key, tr_benc ** setme )
469{
470    int found = FALSE;
471    tr_benc * child = tr_bencDictFindType( dict, key, TYPE_DICT );
472    if( child ) {
473        *setme = child;
474        found = TRUE;
475    }
476    return found;
477}
478
479int
480tr_bencDictFindStr( tr_benc * dict, const char * key, const char ** setme )
481{
482    int found = FALSE;
483    tr_benc * child = tr_bencDictFindType( dict, key, TYPE_STR );
484    if( child ) {
485        *setme = child->val.s.s;
486        found = TRUE;
487    }
488    return found;
489}
490
491int
492tr_bencDictFindRaw( tr_benc         * dict,
493                    const char      * key,
494                    const uint8_t  ** setme_raw, 
495                    size_t          * setme_len )
496{
497    int found = FALSE;
498    tr_benc * child = tr_bencDictFindType( dict, key, TYPE_STR );
499    if( child ) {
500        *setme_raw = (uint8_t*) child->val.s.s;
501        *setme_len = child->val.s.i;
502        found = TRUE;
503    }
504    return found;
505}
506
507
508/***
509****
510***/
511
512void
513_tr_bencInitStr( tr_benc * val, char * str, int len, int nofree )
514{
515    tr_bencInit( val, TYPE_STR );
516    val->val.s.s      = str;
517    val->val.s.nofree = nofree;
518    if( 0 >= len )
519    {
520        len = ( NULL == str ? 0 : strlen( str ) );
521    }
522    val->val.s.i = len;
523}
524
525void
526tr_bencInitRaw( tr_benc * val, const void * src, size_t byteCount )
527{
528    tr_bencInit( val, TYPE_STR );
529    val->val.s.i = byteCount;
530    val->val.s.s = tr_memdup( src, byteCount );
531    val->val.s.nofree = 0;
532}
533
534int
535tr_bencInitStrDup( tr_benc * val, const char * str )
536{
537    char * newStr = tr_strdup( str );
538    if( newStr == NULL )
539        return 1;
540
541    _tr_bencInitStr( val, newStr, 0, 0 );
542    return 0;
543}
544
545void
546tr_bencInitInt( tr_benc * val, int64_t num )
547{
548    tr_bencInit( val, TYPE_INT );
549    val->val.i = num;
550}
551
552int
553tr_bencInitList( tr_benc * val, int reserveCount )
554{
555    tr_bencInit( val, TYPE_LIST );
556    return tr_bencListReserve( val, reserveCount );
557}
558
559int
560tr_bencListReserve( tr_benc * val, int count )
561{
562    assert( tr_bencIsList( val ) );
563    return makeroom( val, count );
564}
565
566int
567tr_bencInitDict( tr_benc * val, int reserveCount )
568{
569    tr_bencInit( val, TYPE_DICT );
570    return tr_bencDictReserve( val, reserveCount );
571}
572
573int
574tr_bencDictReserve( tr_benc * val, int count )
575{
576    assert( tr_bencIsDict( val ) );
577    return makeroom( val, count * 2 );
578}
579
580tr_benc *
581tr_bencListAdd( tr_benc * list )
582{
583    tr_benc * item;
584
585    assert( tr_bencIsList( list ) );
586
587    if( list->val.l.count == list->val.l.alloc )
588        tr_bencListReserve( list, LIST_SIZE );
589
590    assert( list->val.l.count < list->val.l.alloc );
591
592    item = &list->val.l.vals[list->val.l.count];
593    list->val.l.count++;
594    tr_bencInit( item, TYPE_INT );
595
596    return item;
597}
598tr_benc *
599tr_bencListAddInt( tr_benc * list, int64_t val )
600{
601    tr_benc * node = tr_bencListAdd( list );
602    tr_bencInitInt( node, val );
603    return node;
604}
605tr_benc *
606tr_bencListAddStr( tr_benc * list, const char * val )
607{
608    tr_benc * node = tr_bencListAdd( list );
609    tr_bencInitStrDup( node, val );
610    return node;
611}
612tr_benc*
613tr_bencListAddList( tr_benc * list, int reserveCount )
614{
615    tr_benc * child = tr_bencListAdd( list );
616    tr_bencInitList( child, reserveCount );
617    return child;
618}
619tr_benc*
620tr_bencListAddDict( tr_benc * list, int reserveCount )
621{
622    tr_benc * child = tr_bencListAdd( list );
623    tr_bencInitDict( child, reserveCount );
624    return child;
625}
626
627tr_benc *
628tr_bencDictAdd( tr_benc * dict, const char * key )
629{
630    tr_benc * keyval, * itemval;
631
632    assert( tr_bencIsDict( dict ) );
633    if( dict->val.l.count + 2 > dict->val.l.alloc )
634        makeroom( dict, 2 );
635    assert( dict->val.l.count + 2 <= dict->val.l.alloc );
636
637    keyval = dict->val.l.vals + dict->val.l.count++;
638    tr_bencInitStrDup( keyval, key );
639
640    itemval = dict->val.l.vals + dict->val.l.count++;
641    tr_bencInit( itemval, TYPE_INT );
642
643    return itemval;
644}
645tr_benc*
646tr_bencDictAddInt( tr_benc * dict, const char * key, int64_t val )
647{
648    tr_benc * child = tr_bencDictAdd( dict, key );
649    tr_bencInitInt( child, val );
650    return child;
651}
652tr_benc*
653tr_bencDictAddStr( tr_benc * dict, const char * key, const char * val )
654{
655    tr_benc * child = tr_bencDictAdd( dict, key );
656    tr_bencInitStrDup( child, val );
657    return child;
658}
659tr_benc*
660tr_bencDictAddDouble( tr_benc * dict, const char * key, double d )
661{
662    char buf[128];
663    tr_snprintf( buf, sizeof( buf ), "%f", d );
664    return tr_bencDictAddStr( dict, key, buf );
665}
666tr_benc*
667tr_bencDictAddList( tr_benc * dict, const char * key, int reserveCount )
668{
669    tr_benc * child = tr_bencDictAdd( dict, key );
670    tr_bencInitList( child, reserveCount );
671    return child;
672}
673tr_benc*
674tr_bencDictAddDict( tr_benc * dict, const char * key, int reserveCount )
675{
676    tr_benc * child = tr_bencDictAdd( dict, key );
677    tr_bencInitDict( child, reserveCount );
678    return child;
679}
680tr_benc*
681tr_bencDictAddRaw( tr_benc * dict, const char * key, const void * src, size_t len )
682{
683    tr_benc * child = tr_bencDictAdd( dict, key );
684    tr_bencInitRaw( child, src, len );
685    return child;
686}
687
688int
689tr_bencDictRemove( tr_benc * dict, const char * key )
690{
691    int i = dictIndexOf( dict, key );
692    if( i >= 0 )
693    {
694        const int n = dict->val.l.count;
695        tr_bencFree( &dict->val.l.vals[i] );
696        tr_bencFree( &dict->val.l.vals[i+1] );
697        if( i + 2 < n )
698        {
699            dict->val.l.vals[i]   = dict->val.l.vals[n-2];
700            dict->val.l.vals[i+1] = dict->val.l.vals[n-1];
701        }
702        dict->val.l.count -= 2;
703    }
704    return i >= 0; /* return true if found */
705}
706
707
708/***
709****  BENC WALKING
710***/
711
712struct KeyIndex
713{
714    const char * key;
715    int index;
716};
717
718static int
719compareKeyIndex( const void * va, const void * vb )
720{
721    const struct KeyIndex * a = va;
722    const struct KeyIndex * b = vb;
723    return strcmp( a->key, b->key );
724}
725
726struct SaveNode
727{
728    const tr_benc * val;
729    int valIsVisited;
730    int childCount;
731    int childIndex;
732    int * children;
733};
734
735static struct SaveNode*
736nodeNewDict( const tr_benc * val )
737{
738    int i, j;
739    int nKeys;
740    struct SaveNode * node;
741    struct KeyIndex * indices;
742
743    assert( tr_bencIsDict( val ) );
744
745    nKeys = val->val.l.count / 2;
746    node = tr_new0( struct SaveNode, 1 );
747    node->val = val;
748    node->children = tr_new0( int, nKeys * 2 );
749
750    /* ugh, a dictionary's children have to be sorted by key... */
751    indices = tr_new( struct KeyIndex, nKeys );
752    for( i=j=0; i<(nKeys*2); i+=2, ++j ) {
753        indices[j].key = val->val.l.vals[i].val.s.s;
754        indices[j].index = i;
755    }
756    qsort( indices, j, sizeof(struct KeyIndex), compareKeyIndex );
757    for( i=0; i<j; ++i ) {
758        const int index = indices[i].index;
759        node->children[ node->childCount++ ] = index;
760        node->children[ node->childCount++ ] = index + 1;
761    }
762
763    assert( node->childCount == nKeys * 2 );
764    tr_free( indices );
765    return node;
766}
767
768static struct SaveNode*
769nodeNewList( const tr_benc * val )
770{
771    int i, n;
772    struct SaveNode * node;
773
774    assert( tr_bencIsList( val ) );
775
776    n = val->val.l.count;
777    node = tr_new0( struct SaveNode, 1 );
778    node->val = val;
779    node->childCount = n;
780    node->children = tr_new0( int, n );
781    for( i=0; i<n; ++i ) /* a list's children don't need to be reordered */
782        node->children[i] = i;
783
784    return node;
785}
786
787static struct SaveNode*
788nodeNewLeaf( const tr_benc * val )
789{
790    struct SaveNode * node;
791
792    assert( !isContainer( val ) );
793
794    node = tr_new0( struct SaveNode, 1 );
795    node->val = val;
796    return node;
797}
798
799static struct SaveNode*
800nodeNew( const tr_benc * val )
801{
802    struct SaveNode * node;
803
804    if( tr_bencIsList( val ) )
805        node = nodeNewList( val );
806    else if( tr_bencIsDict( val ) )
807        node = nodeNewDict( val );
808    else
809        node = nodeNewLeaf( val );
810
811    return node;
812}
813
814typedef void (*BencWalkFunc)( const tr_benc * val, void * user_data );
815
816struct WalkFuncs
817{
818    BencWalkFunc intFunc;
819    BencWalkFunc stringFunc;
820    BencWalkFunc dictBeginFunc;
821    BencWalkFunc listBeginFunc;
822    BencWalkFunc containerEndFunc;
823};
824
825/**
826 * This function's previous recursive implementation was
827 * easier to read, but was vulnerable to a smash-stacking
828 * attack via maliciously-crafted bencoded data. (#667)
829 */
830static void
831bencWalk( const tr_benc      * top,
832          struct WalkFuncs   * walkFuncs,
833          void               * user_data )
834{
835    tr_ptrArray * stack = tr_ptrArrayNew( );
836    tr_ptrArrayAppend( stack, nodeNew( top ) );
837
838    while( !tr_ptrArrayEmpty( stack ) )
839    {
840        struct SaveNode * node = tr_ptrArrayBack( stack );
841        const tr_benc * val;
842
843        if( !node->valIsVisited )
844        {
845            val = node->val;
846            node->valIsVisited = TRUE;
847        }
848        else if( node->childIndex < node->childCount )
849        {
850            const int index = node->children[ node->childIndex++ ];
851            val = node->val->val.l.vals +  index;
852        }
853        else /* done with this node */
854        {
855            if( isContainer( node->val ) )
856                walkFuncs->containerEndFunc( node->val, user_data );
857            tr_ptrArrayPop( stack );
858            tr_free( node->children );
859            tr_free( node );
860            continue;
861        }
862
863        if( val ) switch( val->type )
864        {
865            case TYPE_INT:
866                walkFuncs->intFunc( val, user_data );
867                break;
868
869            case TYPE_STR:
870                walkFuncs->stringFunc( val, user_data );
871                break;
872
873            case TYPE_LIST:
874                if( val != node->val )
875                    tr_ptrArrayAppend( stack, nodeNew( val ) );
876                else
877                    walkFuncs->listBeginFunc( val, user_data );
878                break;
879
880            case TYPE_DICT:
881                if( val != node->val )
882                    tr_ptrArrayAppend( stack, nodeNew( val ) );
883                else
884                    walkFuncs->dictBeginFunc( val, user_data );
885                break;
886
887            default:
888                /* did caller give us an uninitialized val? */
889                tr_err( _( "Invalid metadata" ) );
890                break;
891        }
892    }
893
894    tr_ptrArrayFree( stack, NULL );
895}
896
897/****
898*****
899****/
900
901static void
902saveIntFunc( const tr_benc * val, void * evbuf )
903{
904    evbuffer_add_printf( evbuf, "i%"PRId64"e", val->val.i );
905}
906static void
907saveStringFunc( const tr_benc * val, void * vevbuf )
908{
909    struct evbuffer * evbuf = vevbuf;
910    evbuffer_add_printf( evbuf, "%d:", val->val.s.i );
911    evbuffer_add( evbuf, val->val.s.s, val->val.s.i );
912}
913static void
914saveDictBeginFunc( const tr_benc * val UNUSED, void * evbuf )
915{
916    evbuffer_add_printf( evbuf, "d" );
917}
918static void
919saveListBeginFunc( const tr_benc * val UNUSED, void * evbuf )
920{
921    evbuffer_add_printf( evbuf, "l" );
922}
923static void
924saveContainerEndFunc( const tr_benc * val UNUSED, void * evbuf )
925{
926    evbuffer_add_printf( evbuf, "e" );
927}
928char*
929tr_bencSave( const tr_benc * top, int * len )
930{
931    char * ret;
932    struct WalkFuncs walkFuncs;
933    struct evbuffer * out = evbuffer_new( );
934
935    walkFuncs.intFunc = saveIntFunc;
936    walkFuncs.stringFunc = saveStringFunc;
937    walkFuncs.dictBeginFunc = saveDictBeginFunc;
938    walkFuncs.listBeginFunc = saveListBeginFunc;
939    walkFuncs.containerEndFunc = saveContainerEndFunc;
940    bencWalk( top, &walkFuncs, out );
941   
942    if( len )
943        *len = EVBUFFER_LENGTH( out );
944    ret = tr_strndup( (char*) EVBUFFER_DATA( out ), EVBUFFER_LENGTH( out ) );
945    evbuffer_free( out );
946    return ret;
947}
948
949/***
950****
951***/
952
953static void
954freeDummyFunc( const tr_benc * val UNUSED, void * buf UNUSED  )
955{
956}
957static void
958freeStringFunc( const tr_benc * val, void * freeme )
959{
960    if( !val->val.s.nofree )
961        tr_ptrArrayAppend( freeme, val->val.s.s );
962}
963static void
964freeContainerBeginFunc( const tr_benc * val, void * freeme )
965{
966    tr_ptrArrayAppend( freeme, val->val.l.vals );
967}
968void
969tr_bencFree( tr_benc * val )
970{
971    if( val && val->type )
972    {
973        tr_ptrArray * freeme = tr_ptrArrayNew( );
974        struct WalkFuncs walkFuncs;
975
976        walkFuncs.intFunc = freeDummyFunc;
977        walkFuncs.stringFunc = freeStringFunc;
978        walkFuncs.dictBeginFunc = freeContainerBeginFunc;
979        walkFuncs.listBeginFunc = freeContainerBeginFunc;
980        walkFuncs.containerEndFunc = freeDummyFunc;
981        bencWalk( val, &walkFuncs, freeme );
982
983        tr_ptrArrayFree( freeme, tr_free );
984    }
985}
986
987/***
988****
989***/
990
991struct WalkPrint
992{
993    int depth;
994    FILE * out;
995};
996static void
997printLeadingSpaces( struct WalkPrint * data )
998{
999    const int width = data->depth * 2;
1000    fprintf( data->out, "%*.*s", width, width, " " );
1001}
1002static void
1003printIntFunc( const tr_benc * val, void * vdata )
1004{
1005    struct WalkPrint * data = vdata;
1006    printLeadingSpaces( data );
1007    fprintf( data->out, "int:  %"PRId64"\n", val->val.i );
1008}
1009static void
1010printStringFunc( const tr_benc * val, void * vdata )
1011{
1012    int ii;
1013    struct WalkPrint * data = vdata;
1014    printLeadingSpaces( data );
1015    fprintf( data->out, "string:  " );
1016    for( ii = 0; val->val.s.i > ii; ii++ )
1017    {
1018        if( '\\' == val->val.s.s[ii] ) {
1019            putc( '\\', data->out );
1020            putc( '\\', data->out );
1021        } else if( isprint( val->val.s.s[ii] ) ) {
1022            putc( val->val.s.s[ii], data->out );
1023        } else {
1024            fprintf( data->out, "\\x%02x", val->val.s.s[ii] );
1025        }
1026    }
1027    fprintf( data->out, "\n" );
1028}
1029static void
1030printListBeginFunc( const tr_benc * val UNUSED, void * vdata )
1031{
1032    struct WalkPrint * data = vdata;
1033    printLeadingSpaces( data );
1034    fprintf( data->out, "list\n" );
1035    ++data->depth;
1036}
1037static void
1038printDictBeginFunc( const tr_benc * val UNUSED, void * vdata )
1039{
1040    struct WalkPrint * data = vdata;
1041    printLeadingSpaces( data );
1042    fprintf( data->out, "dict\n" );
1043    ++data->depth;
1044}
1045static void
1046printContainerEndFunc( const tr_benc * val UNUSED, void * vdata )
1047{
1048    struct WalkPrint * data = vdata;
1049    --data->depth;
1050}
1051void
1052tr_bencPrint( const tr_benc * val )
1053{
1054    struct WalkFuncs walkFuncs;
1055    struct WalkPrint walkPrint;
1056
1057    walkFuncs.intFunc = printIntFunc;
1058    walkFuncs.stringFunc = printStringFunc;
1059    walkFuncs.dictBeginFunc = printDictBeginFunc;
1060    walkFuncs.listBeginFunc = printListBeginFunc;
1061    walkFuncs.containerEndFunc = printContainerEndFunc;
1062
1063    walkPrint.out = stderr;
1064    walkPrint.depth = 0;
1065    bencWalk( val, &walkFuncs, &walkPrint );
1066}
1067
1068/***
1069****
1070***/
1071
1072struct ParentState
1073{
1074    int bencType;
1075    int childIndex;
1076    int childCount;
1077};
1078 
1079struct jsonWalk
1080{
1081    tr_list * parents;
1082    struct evbuffer * out;
1083};
1084
1085static void
1086jsonIndent( struct jsonWalk * data )
1087{
1088    const int width = tr_list_size( data->parents ) * 4;
1089    evbuffer_add_printf( data->out, "\n%*.*s", width, width, " " );
1090}
1091
1092static void
1093jsonChildFunc( struct jsonWalk * data )
1094{
1095    if( data->parents )
1096    {
1097        struct ParentState * parentState = data->parents->data;
1098
1099        switch( parentState->bencType )
1100        {
1101            case TYPE_DICT: {
1102                const int i = parentState->childIndex++;
1103                if( ! ( i % 2 ) )
1104                    evbuffer_add_printf( data->out, ": " );
1105                else {
1106                    evbuffer_add_printf( data->out, ", " );
1107                    jsonIndent( data );
1108                }
1109                break;
1110            }
1111
1112            case TYPE_LIST: {
1113                ++parentState->childIndex;
1114                evbuffer_add_printf( data->out, ", " );
1115                jsonIndent( data );
1116                break;
1117            }
1118
1119            default:
1120                break;
1121        }
1122    }
1123}
1124
1125static void
1126jsonPushParent( struct jsonWalk * data, const tr_benc * benc )
1127{
1128    struct ParentState * parentState = tr_new( struct ParentState, 1 );
1129    parentState->bencType = benc->type;
1130    parentState->childIndex = 0;
1131    parentState->childCount = benc->val.l.count;
1132    tr_list_prepend( &data->parents, parentState );
1133}
1134
1135static void
1136jsonPopParent( struct jsonWalk * data )
1137{
1138    tr_free( tr_list_pop_front( &data->parents ) );
1139}
1140
1141static void
1142jsonIntFunc( const tr_benc * val, void * vdata )
1143{
1144    struct jsonWalk * data = vdata;
1145    evbuffer_add_printf( data->out, "%"PRId64, val->val.i );
1146    jsonChildFunc( data );
1147}
1148static void
1149jsonStringFunc( const tr_benc * val, void * vdata )
1150{
1151    struct jsonWalk * data = vdata;
1152    const char *it, *end;
1153    evbuffer_add_printf( data->out, "\"" );
1154    for( it=val->val.s.s, end=it+val->val.s.i; it!=end; ++it )
1155    {
1156        switch( *it ) {
1157            case '/' : evbuffer_add_printf( data->out, "\\/" ); break;
1158            case '\b': evbuffer_add_printf( data->out, "\\b" ); break;
1159            case '\f': evbuffer_add_printf( data->out, "\\f" ); break;
1160            case '\n': evbuffer_add_printf( data->out, "\\n" ); break;
1161            case '\r': evbuffer_add_printf( data->out, "\\r" ); break;
1162            case '\t': evbuffer_add_printf( data->out, "\\t" ); break;
1163            case '"' : evbuffer_add_printf( data->out, "\\\"" ); break;
1164            case '\\': evbuffer_add_printf( data->out, "\\\\" ); break;
1165            default: {
1166                if( isascii( *it ) )
1167                    evbuffer_add_printf( data->out, "%c", *it );
1168                else
1169                    evbuffer_add_printf( data->out, "\\u%0x", (unsigned int)*it );
1170                break;
1171            }
1172        }
1173    }
1174    evbuffer_add_printf( data->out, "\"" );
1175    jsonChildFunc( data );
1176}
1177static void
1178jsonDictBeginFunc( const tr_benc * val, void * vdata )
1179{
1180    struct jsonWalk * data = vdata;
1181    jsonPushParent( data, val );
1182    evbuffer_add_printf( data->out, "{" );
1183    if( val->val.l.count )
1184        jsonIndent( data );
1185}
1186static void
1187jsonListBeginFunc( const tr_benc * val, void * vdata )
1188{
1189    const int nChildren = tr_bencListSize( val );
1190    struct jsonWalk * data = vdata;
1191    jsonPushParent( data, val );
1192    evbuffer_add_printf( data->out, "[" );
1193    if( nChildren )
1194        jsonIndent( data );
1195}
1196static void
1197jsonContainerEndFunc( const tr_benc * val, void * vdata )
1198{
1199    size_t i;
1200    struct jsonWalk * data = vdata;
1201    char * str;
1202    int emptyContainer = FALSE;
1203
1204    /* trim out the trailing comma, if any */
1205    str = (char*) EVBUFFER_DATA( data->out );
1206    for( i=EVBUFFER_LENGTH( data->out )-1; i>0; --i ) {
1207        if( isspace( str[i] ) ) continue;
1208        if( str[i]==',' )
1209            EVBUFFER_LENGTH( data->out ) = i;
1210        if( str[i]=='{' || str[i]=='[' )
1211            emptyContainer = TRUE;
1212        break;
1213    }
1214
1215    jsonPopParent( data );
1216    if( !emptyContainer )
1217        jsonIndent( data );
1218    if( tr_bencIsDict( val ) )
1219        evbuffer_add_printf( data->out, "}" );
1220    else /* list */
1221        evbuffer_add_printf( data->out, "]" );
1222    jsonChildFunc( data );
1223}
1224char*
1225tr_bencSaveAsJSON( const tr_benc * top, int * len )
1226{
1227    char * ret;
1228    struct WalkFuncs walkFuncs;
1229    struct jsonWalk data;
1230
1231    data.out = evbuffer_new( );
1232    data.parents = NULL;
1233
1234    walkFuncs.intFunc = jsonIntFunc;
1235    walkFuncs.stringFunc = jsonStringFunc;
1236    walkFuncs.dictBeginFunc = jsonDictBeginFunc;
1237    walkFuncs.listBeginFunc = jsonListBeginFunc;
1238    walkFuncs.containerEndFunc = jsonContainerEndFunc;
1239
1240    bencWalk( top, &walkFuncs, &data );
1241   
1242    if( EVBUFFER_LENGTH( data.out ) )
1243        evbuffer_add_printf( data.out, "\n" );
1244    if( len )
1245        *len = EVBUFFER_LENGTH( data.out );
1246    ret = tr_strndup( (char*) EVBUFFER_DATA( data.out ), EVBUFFER_LENGTH( data.out ) );
1247    evbuffer_free( data.out );
1248    return ret;
1249}
1250
1251/***
1252****
1253***/
1254
1255static int
1256saveFile( const char * filename, const char * content, size_t len )
1257{
1258    int err = TR_OK;
1259    FILE * out = NULL;
1260
1261    out = fopen( filename, "wb+" );
1262    if( !out )
1263    {
1264        tr_err( _( "Couldn't open \"%1$s\": %2$s" ),
1265                filename, tr_strerror( errno ) );
1266        err = TR_EINVALID;
1267    }
1268    else if( fwrite( content, sizeof( char ), len, out ) != (size_t)len )
1269    {
1270        tr_err( _( "Couldn't save file \"%1$s\": %2$s" ),
1271                filename, tr_strerror( errno ) );
1272        err = TR_EINVALID;
1273    }
1274
1275    if( !err )
1276        tr_dbg( "tr_bencSaveFile saved \"%s\"", filename );
1277    if( out )
1278        fclose( out );
1279    return err;
1280}
1281
1282int
1283tr_bencSaveFile( const char * filename,  const tr_benc * b )
1284{
1285    int len;
1286    char * content = tr_bencSave( b, &len );
1287    const int err = saveFile( filename, content, len );
1288    tr_free( content );
1289    return err;
1290}
1291
1292int
1293tr_bencLoadFile( const char * filename, tr_benc * b )
1294{
1295    int ret;
1296    size_t contentLen;
1297    uint8_t * content = tr_loadFile( filename, &contentLen );
1298    ret = content ? tr_bencLoad( content, contentLen, b, NULL )
1299                  : TR_ERROR_IO_OTHER;
1300    tr_free( content );
1301    return ret;
1302}
1303
1304int
1305tr_bencSaveJSONFile( const char * filename, const tr_benc * b )
1306{
1307    int len;
1308    char * content = tr_bencSaveAsJSON( b, &len );
1309    const int err = saveFile( filename, content, len );
1310    tr_free( content );
1311    return err;
1312}
1313
1314int
1315tr_bencLoadJSONFile( const char * filename, tr_benc * b )
1316{
1317    int ret;
1318    size_t contentLen;
1319    uint8_t * content = tr_loadFile( filename, &contentLen );
1320    ret = content ? tr_jsonParse( content, contentLen, b, NULL )
1321                  : TR_ERROR_IO_OTHER;
1322    tr_free( content );
1323    return ret;
1324}
Note: See TracBrowser for help on using the repository browser.