source: trunk/libtransmission/bencode.c @ 6944

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

remove dead code

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