source: trunk/libtransmission/bencode.c @ 6612

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

bencode cleanup: remove unused functions and unnecessary #includes

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