source: trunk/libtransmission/bencode.c @ 7166

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

(libT) #1491: json floats decimal separator depends on language settings

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