source: trunk/libtransmission/bencode.c @ 6146

Last change on this file since 6146 was 6146, checked in by charles, 14 years ago

#966: allow blocklist support in the daemon. add extra info in the man page explaining how to add blocklists.

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