source: trunk/libtransmission/json.c @ 11599

Last change on this file since 11599 was 11599, checked in by charles, 11 years ago

(trunk) Join the 21st century and use only 1 space at the end sentences. This commit is nearly as important as the semi-annual ones that remove trailing spaces from the ends of lines of code... :)

  • Property svn:keywords set to Date Rev Author Id
File size: 4.8 KB
Line 
1/*
2 * This file Copyright (C) 2008-2010 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 11599 2010-12-27 19:18:17Z charles $
11 */
12
13#include <assert.h>
14#include <ctype.h>
15#include <errno.h> /* EILSEQ, EINVAL */
16#include <string.h>
17#include <stdio.h> /* printf */
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    tr_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 ), (double)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_strdup( value->vu.str.value );
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.