source: trunk/libtransmission/bencode.c @ 6425

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

minor text cleanup

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