source: trunk/libtransmission/bencode.c @ 6600

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

make tr_bencDictFindType() private.

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