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

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

(1.3x) #1168: reading past the end of KTorrent's pex added.f strings

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