source: trunk/libtransmission/json.c @ 12289

Last change on this file since 12289 was 12289, checked in by jordan, 11 years ago

(trunk libT) since the JSON parser gives us the string's length, we can call tr_strndup() instead of tr_strdup()

  • Property svn:keywords set to Date Rev Author Id
File size: 4.7 KB
Line 
1/*
2 * This file Copyright (C) Mnemosyne LLC
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: json.c 12289 2011-04-01 03:07:43Z jordan $
11 */
12
13#include <assert.h>
14#include <ctype.h>
15#include <stdio.h>
16#include <string.h>
17#include <errno.h> /* EILSEQ, EINVAL */
18
19#include "JSON_parser.h"
20
21#include "transmission.h"
22#include "bencode.h"
23#include "json.h"
24#include "ptrarray.h"
25#include "utils.h"
26
27struct json_benc_data
28{
29    bool        hasContent;
30    tr_benc      * top;
31    tr_ptrArray    stack;
32    char         * key;
33};
34
35static tr_benc*
36getNode( struct json_benc_data * data )
37{
38    tr_benc * parent;
39    tr_benc * node = NULL;
40
41    if( tr_ptrArrayEmpty( &data->stack ) )
42        parent = NULL;
43    else
44        parent = tr_ptrArrayBack( &data->stack );
45
46    if( !parent )
47        node = data->top;
48    else if( tr_bencIsList( parent ) )
49        node = tr_bencListAdd( parent );
50    else if( tr_bencIsDict( parent ) && data->key )
51    {
52        node = tr_bencDictAdd( parent, data->key );
53        tr_free( data->key );
54        data->key = NULL;
55    }
56
57    return node;
58}
59
60static int
61callback( void *             vdata,
62          int                type,
63          const JSON_value * value )
64{
65    struct json_benc_data * data = vdata;
66    tr_benc *               node;
67
68    switch( type )
69    {
70        case JSON_T_ARRAY_BEGIN:
71            data->hasContent = true;
72            node = getNode( data );
73            tr_bencInitList( node, 0 );
74            tr_ptrArrayAppend( &data->stack, node );
75            break;
76
77        case JSON_T_ARRAY_END:
78            tr_ptrArrayPop( &data->stack );
79            break;
80
81        case JSON_T_OBJECT_BEGIN:
82            data->hasContent = true;
83            node = getNode( data );
84            tr_bencInitDict( node, 0 );
85            tr_ptrArrayAppend( &data->stack, node );
86            break;
87
88        case JSON_T_OBJECT_END:
89            tr_ptrArrayPop( &data->stack );
90            break;
91
92        case JSON_T_FLOAT:
93            data->hasContent = true;
94            tr_bencInitReal( getNode( data ), value->vu.float_value );
95            break;
96
97        case JSON_T_NULL:
98            data->hasContent = true;
99            tr_bencInitStr( getNode( data ), "", 0 );
100            break;
101
102        case JSON_T_INTEGER:
103            data->hasContent = true;
104            tr_bencInitInt( getNode( data ), value->vu.integer_value );
105            break;
106
107        case JSON_T_TRUE:
108            data->hasContent = true;
109            tr_bencInitBool( getNode( data ), 1 );
110            break;
111
112        case JSON_T_FALSE:
113            data->hasContent = true;
114            tr_bencInitBool( getNode( data ), 0 );
115            break;
116
117        case JSON_T_STRING:
118            data->hasContent = true;
119            tr_bencInitStr( getNode( data ),
120                            value->vu.str.value,
121                            value->vu.str.length );
122            break;
123
124        case JSON_T_KEY:
125            data->hasContent = true;
126            assert( !data->key );
127            data->key = tr_strndup( value->vu.str.value, value->vu.str.length );
128            break;
129    }
130
131    return 1;
132}
133
134int
135tr_jsonParse( const char     * source,
136              const void     * vbuf,
137              size_t           len,
138              tr_benc        * setme_benc,
139              const uint8_t ** setme_end )
140{
141    int                         line = 1;
142    int                         column = 1;
143    int                         err = 0;
144    const unsigned char       * buf = vbuf;
145    const void                * bufend = buf + len;
146    JSON_config                 config;
147    struct JSON_parser_struct * checker;
148    struct json_benc_data       data;
149
150    init_JSON_config( &config );
151    config.callback = callback;
152    config.callback_ctx = &data;
153    config.depth = -1;
154
155    data.hasContent = false;
156    data.key = NULL;
157    data.top = setme_benc;
158    data.stack = TR_PTR_ARRAY_INIT;
159
160    checker = new_JSON_parser( &config );
161    while( ( buf != bufend ) && JSON_parser_char( checker, *buf ) ) {
162        if( *buf != '\n' )
163            ++column;
164        else {
165            ++line;
166            column = 1;
167        }
168        ++buf;
169    }
170
171    if( buf != bufend ) {
172        if( source )
173            tr_err( "JSON parser failed in %s at line %d, column %d: \"%.16s\"", source, line, column, buf );
174        else
175            tr_err( "JSON parser failed at line %d, column %d: \"%.16s\"", line, column, buf );
176        err = EILSEQ;
177    }
178
179    if( !data.hasContent )
180        err = EINVAL;
181
182    if( setme_end )
183        *setme_end = (const uint8_t*) buf;
184
185    delete_JSON_parser( checker );
186    tr_ptrArrayDestruct( &data.stack, NULL );
187    return err;
188}
189
Note: See TracBrowser for help on using the repository browser.