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 190