source: trunk/libtransmission/bencode.c @ 920

Last change on this file since 920 was 920, checked in by joshe, 15 years ago

Merge nat-traversal branch to trunk.

  • Property svn:keywords set to Date Rev Author Id
File size: 7.5 KB
Line 
1/******************************************************************************
2 * $Id: bencode.c 920 2006-09-25 18:37:45Z joshe $
3 *
4 * Copyright (c) 2005-2006 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 "transmission.h"
26
27#define LIST_SIZE   20
28
29int _tr_bencLoad( char * buf, int len, benc_val_t * val, char ** end )
30{
31    char * p, * e, * foo;
32
33    if( 1 >= len )
34    {
35        return 1;
36    }
37
38    if( !end )
39    {
40        /* So we only have to check once */
41        end = &foo;
42    }
43
44    val->begin = buf;
45
46    if( buf[0] == 'i' )
47    {
48        e = memchr( &buf[1], 'e', len - 1 );
49        if( NULL == e )
50        {
51            return 1;
52        }
53
54        /* Integer: i1242e */
55        val->type  = TYPE_INT;
56        *e         = '\0';
57        val->val.i = strtoll( &buf[1], &p, 10 );
58        *e         = 'e';
59
60        if( p != e )
61        {
62            return 1;
63        }
64
65        val->end = p + 1;
66    }
67    else if( buf[0] == 'l' || buf[0] == 'd' )
68    {
69        /* List: l<item1><item2>e
70           Dict: d<string1><item1><string2><item2>e
71           A dictionary is just a special kind of list with an even
72           count of items, and where even items are strings. */
73        char * cur;
74        char   is_dict;
75        char   str_expected;
76
77        is_dict          = ( buf[0] == 'd' );
78        val->type        = is_dict ? TYPE_DICT : TYPE_LIST;
79        val->val.l.alloc = LIST_SIZE;
80        val->val.l.count = 0;
81        val->val.l.vals  = malloc( LIST_SIZE * sizeof( benc_val_t ) );
82        cur              = &buf[1];
83        str_expected     = 1;
84        while( cur - buf < len && cur[0] != 'e' )
85        {
86            if( val->val.l.count == val->val.l.alloc )
87            {
88                /* We need a bigger boat */
89                val->val.l.alloc += LIST_SIZE;
90                val->val.l.vals   =  realloc( val->val.l.vals,
91                        val->val.l.alloc  * sizeof( benc_val_t ) );
92            }
93            if( tr_bencLoad( cur, len - (cur - buf),
94                             &val->val.l.vals[val->val.l.count], &p ) )
95            {
96                tr_bencFree( val );
97                return 1;
98            }
99            val->val.l.count++;
100            if( is_dict && str_expected &&
101                val->val.l.vals[val->val.l.count - 1].type != TYPE_STR )
102            {
103                tr_bencFree( val );
104                return 1;
105            }
106            str_expected = !str_expected;
107
108            cur = p;
109        }
110
111        if( is_dict && ( val->val.l.count & 1 ) )
112        {
113            tr_bencFree( val );
114            return 1;
115        }
116
117        val->end = cur + 1;
118    }
119    else
120    {
121        e = memchr( buf, ':', len );
122        if( NULL == e )
123        {
124            return 1;
125        }
126
127        /* String: 12:whateverword */
128        val->type    = TYPE_STR;
129        e[0]         = '\0';
130        val->val.s.i = strtol( buf, &p, 10 );
131        e[0]         = ':';
132
133        if( p != e || 0 > val->val.s.i ||
134            val->val.s.i > len - ((p + 1) - buf) )
135        {
136            return 1;
137        }
138
139        val->val.s.s               = malloc( val->val.s.i + 1 );
140        val->val.s.s[val->val.s.i] = 0;
141        memcpy( val->val.s.s, p + 1, val->val.s.i );
142
143        val->end = p + 1 + val->val.s.i;
144    }
145
146    *end = val->end;
147
148    return 0;
149}
150
151static void __bencPrint( benc_val_t * val, int space )
152{
153    int i;
154
155    for( i = 0; i < space; i++ )
156    {
157        fprintf( stderr, " " );
158    }
159
160    switch( val->type )
161    {
162        case TYPE_INT:
163            fprintf( stderr, "int:  %"PRIu64"\n", val->val.i );
164            break;
165
166        case TYPE_STR:
167            fprintf( stderr, "%s\n", val->val.s.s );
168            break;
169
170        case TYPE_LIST:
171            fprintf( stderr, "list\n" );
172            for( i = 0; i < val->val.l.count; i++ )
173                __bencPrint( &val->val.l.vals[i], space + 1 );
174            break;
175
176        case TYPE_DICT:
177            fprintf( stderr, "dict\n" );
178            for( i = 0; i < val->val.l.count; i++ )
179                __bencPrint( &val->val.l.vals[i], space + 1 );
180            break;
181    }
182}
183
184void tr_bencPrint( benc_val_t * val )
185{
186    __bencPrint( val, 0 );
187}
188
189void tr_bencFree( benc_val_t * val )
190{
191    int i;
192
193    switch( val->type )
194    {
195        case TYPE_INT:
196            break;
197
198        case TYPE_STR:
199            if( val->val.s.s )
200            {
201                free( val->val.s.s );
202            }
203            break;
204
205        case TYPE_LIST:
206        case TYPE_DICT:
207            for( i = 0; i < val->val.l.count; i++ )
208            {
209                tr_bencFree( &val->val.l.vals[i] );
210            }
211            free( val->val.l.vals );
212            break;
213    }
214}
215
216benc_val_t * tr_bencDictFind( benc_val_t * val, char * key )
217{
218    int i;
219    if( val->type != TYPE_DICT )
220    {
221        return NULL;
222    }
223   
224    for( i = 0; i < val->val.l.count; i += 2 )
225    {
226        if( !strcmp( val->val.l.vals[i].val.s.s, key ) )
227        {
228            return &val->val.l.vals[i+1];
229        }
230    }
231
232    return NULL;
233}
234
235char * tr_bencSaveMalloc( benc_val_t * val, int * len )
236{
237    char * buf   = NULL;
238    int alloc = 0;
239
240    *len = 0;
241    if( tr_bencSave( val, &buf, len, &alloc ) )
242    {
243        if( NULL != buf )
244        {
245            free(buf);
246        }
247        *len = 0;
248        return NULL;
249    }
250
251    return buf;
252}
253
254int tr_bencSave( benc_val_t * val, char ** buf, int * used, int * max )
255{
256    int ii;   
257
258    switch( val->type )
259    {
260        case TYPE_INT:
261            if( tr_sprintf( buf, used, max, "i%"PRIu64"e", val->val.i ) )
262            {
263                return 1;
264            }
265            break;
266
267        case TYPE_STR:
268            if( (int)strlen(val->val.s.s) != val->val.s.i )
269            {
270                return 1;
271            }
272            if( tr_sprintf( buf, used, max, "%i:%s",
273                            val->val.s.i, val->val.s.s ) )
274            {
275                return 1;
276            }
277            break;
278
279        case TYPE_LIST:
280        case TYPE_DICT:
281            if( tr_sprintf( buf, used, max,
282                            (TYPE_LIST == val->type ? "l" : "d") ) )
283            {
284                return 1;
285            }
286            for( ii = 0; val->val.l.count > ii; ii++ )
287            {
288                if( tr_bencSave( val->val.l.vals + ii, buf, used, max ) )
289                {
290                    return 1;
291                }
292            }
293            if( tr_sprintf( buf, used, max, "e" ) )
294            {
295                return 1;
296            }
297            break;
298    }
299
300    return 0;
301}
Note: See TracBrowser for help on using the repository browser.