source: trunk/libtransmission/bencode.c @ 6224

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

minor bencode cleanup: (1) remove unused BENC_NULL (2) make tr_bencInit() a private static function in bencode.c

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