source: trunk/libtransmission/bencode.c @ 6389

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

(libT) make the licensing consistent across all the files which only contain my code

  • Property svn:keywords set to Date Rev Author Id
File size: 30.9 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 6389 2008-07-22 23:28:28Z 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 != NULL ) && ( 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 != NULL );
180    assert( parentStack != NULL );
181
182    if( tr_ptrArrayEmpty( parentStack ) )
183        return top;
184
185    parent = tr_ptrArrayBack( parentStack );
186    assert( parent != NULL );
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 != NULL ) )
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 != NULL )
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 != NULL )
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.