~ubuntu-branches/ubuntu/maverick/transmission/maverick

« back to all changes in this revision

Viewing changes to libtransmission/bencode.c

  • Committer: Bazaar Package Importer
  • Author(s): Philipp Benner
  • Date: 2006-08-29 20:50:41 UTC
  • Revision ID: james.westby@ubuntu.com-20060829205041-mzhpiqksdf7pbk17
Tags: upstream-0.6.1.dfsg
ImportĀ upstreamĀ versionĀ 0.6.1.dfsg

Show diffs side-by-side

added added

removed removed

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