fix bug in the benc-to-json converter.
add rison-to-json converter so we can pass commands to transmission in a uri. add unit tests for the new code.
This commit is contained in:
parent
17b9dc7462
commit
6aaa2fd39e
|
@ -58,6 +58,7 @@ noinst_HEADERS = \
|
|||
handshake.h \
|
||||
inout.h \
|
||||
ipcparse.h \
|
||||
json.h \
|
||||
list.h \
|
||||
makemeta.h \
|
||||
metainfo.h \
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <stdio.h>
|
||||
#include "transmission.h"
|
||||
#include "bencode.h"
|
||||
#include "json.h"
|
||||
#include "utils.h" /* tr_free */
|
||||
|
||||
#define VERBOSE 0
|
||||
|
@ -270,6 +271,34 @@ testParse( void )
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
testRISONSnippet( const char * rison_str, const char * expected )
|
||||
{
|
||||
char * serialized = tr_rison2json( rison_str, -1 );
|
||||
#if 0
|
||||
fprintf( stderr, " expected: [%s]\n", expected );
|
||||
fprintf( stderr, " got: [%s]\n", serialized );
|
||||
#endif
|
||||
check( !strcmp( serialized, expected ) );
|
||||
tr_free( serialized );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
testRISON( void )
|
||||
{
|
||||
int val;
|
||||
const char * rison;
|
||||
const char * expected;
|
||||
|
||||
rison = "(a:0,b:foo,c:'23skidoo')";
|
||||
expected = "{ \"a\": 0, \"b\": \"foo\", \"c\": \"23skidoo\" }";
|
||||
if(( val = testRISONSnippet( rison, expected )))
|
||||
return val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
testJSONSnippet( const char * benc_str, const char * expected )
|
||||
{
|
||||
|
@ -277,6 +306,10 @@ testJSONSnippet( const char * benc_str, const char * expected )
|
|||
char * serialized;
|
||||
tr_bencLoad( benc_str, strlen( benc_str ), &top, NULL );
|
||||
serialized = tr_bencSaveAsJSON( &top, NULL );
|
||||
#if 0
|
||||
fprintf( stderr, " expected: [%s]\n", expected );
|
||||
fprintf( stderr, " got: [%s]\n", serialized );
|
||||
#endif
|
||||
check( !strcmp( serialized, expected ) );
|
||||
tr_free( serialized );
|
||||
tr_bencFree( &top );
|
||||
|
@ -310,6 +343,11 @@ testJSON( void )
|
|||
if(( val = testJSONSnippet( benc_str, expected )))
|
||||
return val;
|
||||
|
||||
benc_str = "d4:argsd6:statuslee6:result7:successe";
|
||||
expected = "{ \"args\": { \"status\": [ ] }, \"result\": \"success\" }";
|
||||
if(( val = testJSONSnippet( benc_str, expected )))
|
||||
return val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -362,6 +400,9 @@ main( void )
|
|||
if(( i = testJSON( )))
|
||||
return i;
|
||||
|
||||
if(( i = testRISON( )))
|
||||
return i;
|
||||
|
||||
if(( i = testStackSmash( )))
|
||||
return i;
|
||||
|
||||
|
|
|
@ -1036,18 +1036,14 @@ jsonChildFunc( struct jsonWalk * data )
|
|||
const int i = parentState->childIndex++;
|
||||
if( ! ( i % 2 ) )
|
||||
evbuffer_add_printf( data->out, ": " );
|
||||
else if( parentState->childIndex < parentState->childCount )
|
||||
evbuffer_add_printf( data->out, ", " );
|
||||
else
|
||||
evbuffer_add_printf( data->out, " }" );
|
||||
evbuffer_add_printf( data->out, ", " );
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_LIST: {
|
||||
if( ++parentState->childIndex < parentState->childCount )
|
||||
evbuffer_add_printf( data->out, ", " );
|
||||
else
|
||||
evbuffer_add_printf( data->out, " ]" );
|
||||
++parentState->childIndex;
|
||||
evbuffer_add_printf( data->out, ", " );
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1109,6 +1105,8 @@ jsonDictBeginFunc( const tr_benc * val, void * vdata )
|
|||
struct jsonWalk * data = vdata;
|
||||
jsonPushParent( data, val );
|
||||
evbuffer_add_printf( data->out, "{ " );
|
||||
if( !val->val.l.count )
|
||||
evbuffer_add_printf( data->out, " " );
|
||||
}
|
||||
static void
|
||||
jsonListBeginFunc( const tr_benc * val, void * vdata )
|
||||
|
@ -1116,11 +1114,18 @@ jsonListBeginFunc( const tr_benc * val, void * vdata )
|
|||
struct jsonWalk * data = vdata;
|
||||
jsonPushParent( data, val );
|
||||
evbuffer_add_printf( data->out, "[ " );
|
||||
if( !val->val.l.count )
|
||||
evbuffer_add_printf( data->out, " " );
|
||||
}
|
||||
static void
|
||||
jsonContainerEndFunc( const tr_benc * val UNUSED, void * vdata )
|
||||
jsonContainerEndFunc( const tr_benc * val, void * vdata )
|
||||
{
|
||||
struct jsonWalk * data = vdata;
|
||||
EVBUFFER_LENGTH( data->out ) -= 2;
|
||||
if( tr_bencIsDict( val ) )
|
||||
evbuffer_add_printf( data->out, " }" );
|
||||
else /* list */
|
||||
evbuffer_add_printf( data->out, " ]" );
|
||||
jsonPopParent( data );
|
||||
jsonChildFunc( data );
|
||||
}
|
||||
|
|
|
@ -11,11 +11,12 @@
|
|||
*/
|
||||
|
||||
#include <assert.h>
|
||||
//#include <string.h> /* memcpy, memcmp, strstr */
|
||||
//#include <stdlib.h> /* qsort */
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h> /* printf */
|
||||
//#include <limits.h> /* INT_MAX */
|
||||
//
|
||||
|
||||
#include <event.h> /* evbuffer */
|
||||
|
||||
#include "JSON_checker.h"
|
||||
|
||||
#include "transmission.h"
|
||||
|
@ -145,3 +146,121 @@ tr_jsonParse( const void * vbuf,
|
|||
tr_ptrArrayFree( data.stack, NULL );
|
||||
return err;
|
||||
}
|
||||
|
||||
/***
|
||||
**** RISON-to-JSON converter
|
||||
***/
|
||||
|
||||
enum { ESCAPE,
|
||||
STRING_BEGIN,
|
||||
STRING, ESCAPE_STRING,
|
||||
UNQUOTED_STRING, ESCAPE_UNQUOTED_STRING,
|
||||
VAL_BEGIN,
|
||||
OTHER };
|
||||
|
||||
char*
|
||||
tr_rison2json( const char * str, int rison_len )
|
||||
{
|
||||
struct evbuffer * out = evbuffer_new( );
|
||||
int stack[1000], *parents=stack;
|
||||
int mode = OTHER;
|
||||
char * ret;
|
||||
const char * end;
|
||||
|
||||
if( rison_len < 0 )
|
||||
end = str + strlen( str );
|
||||
else
|
||||
end = str + rison_len;
|
||||
|
||||
#define IN_OBJECT ((parents!=stack) && (parents[-1]=='}'))
|
||||
|
||||
for( ; str!=end; ++str )
|
||||
{
|
||||
if( mode == ESCAPE )
|
||||
{
|
||||
switch( *str )
|
||||
{
|
||||
case '(': evbuffer_add_printf( out, "[ " ); *parents++ = ']'; break;
|
||||
case 't': evbuffer_add_printf( out, " true" ); break;
|
||||
case 'f': evbuffer_add_printf( out, " false" ); break;
|
||||
case 'n': evbuffer_add_printf( out, " null" ); break;
|
||||
default: fprintf( stderr, "invalid escape sequence!\n" ); break;
|
||||
}
|
||||
mode = OTHER;
|
||||
}
|
||||
else if( mode == STRING_BEGIN )
|
||||
{
|
||||
switch( *str )
|
||||
{
|
||||
case '\'': evbuffer_add_printf( out, "\"" ); mode = STRING; break;
|
||||
case ')': evbuffer_add_printf( out, " %c", *--parents ); mode = OTHER; break;
|
||||
default: evbuffer_add_printf( out, "\"%c", *str ); mode = UNQUOTED_STRING; break;
|
||||
}
|
||||
}
|
||||
else if( mode == UNQUOTED_STRING )
|
||||
{
|
||||
switch( *str )
|
||||
{
|
||||
case '\'': evbuffer_add_printf( out, "\"" ); mode = OTHER; break;
|
||||
case ':': evbuffer_add_printf( out, "\": "); mode = VAL_BEGIN; break;
|
||||
case '!': mode = ESCAPE_UNQUOTED_STRING; break;
|
||||
case ',': if( IN_OBJECT ) { evbuffer_add_printf( out, "\", "); mode = STRING_BEGIN; break; }
|
||||
/* fallthrough */
|
||||
default: evbuffer_add_printf( out, "%c", *str ); break;
|
||||
}
|
||||
}
|
||||
else if( mode == VAL_BEGIN )
|
||||
{
|
||||
if( *str == '\'' ) { evbuffer_add_printf( out, "\"" ); mode = STRING; }
|
||||
else if( isdigit( *str ) ) { evbuffer_add_printf( out, "%c", *str ); mode = OTHER; }
|
||||
else { evbuffer_add_printf( out, "\"%c", *str ); mode = UNQUOTED_STRING; }
|
||||
}
|
||||
else if( mode == STRING )
|
||||
{
|
||||
switch( *str )
|
||||
{
|
||||
case '\'': evbuffer_add_printf( out, "\"" ); mode = OTHER; break;
|
||||
case '!': mode = ESCAPE_STRING; break;
|
||||
default: evbuffer_add_printf( out, "%c", *str ); break;
|
||||
}
|
||||
}
|
||||
else if( mode == ESCAPE_STRING || mode == ESCAPE_UNQUOTED_STRING )
|
||||
{
|
||||
switch( *str )
|
||||
{
|
||||
case '!': evbuffer_add_printf( out, "!" ); break;
|
||||
case '\'': evbuffer_add_printf( out, "'" ); break;
|
||||
default: fprintf( stderr, "invalid string escape sequence\n" ); break;
|
||||
}
|
||||
if( mode == ESCAPE_UNQUOTED_STRING ) mode = UNQUOTED_STRING;
|
||||
if( mode == ESCAPE_STRING ) mode = STRING;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch( *str )
|
||||
{
|
||||
case '(': evbuffer_add_printf( out, "{ " ); mode=STRING_BEGIN; *parents++ = '}'; break;
|
||||
case '!': mode = ESCAPE; break;
|
||||
case ')': evbuffer_add_printf( out, " %c", *--parents ); break;
|
||||
case '\'': evbuffer_add_printf( out, "\"" ); mode = STRING; break;
|
||||
case ':': if( IN_OBJECT ) {
|
||||
evbuffer_add_printf( out, ": " ); mode = VAL_BEGIN;
|
||||
} else {
|
||||
evbuffer_add_printf( out, "%c", *str );
|
||||
}
|
||||
break;
|
||||
case ',': if( IN_OBJECT ) {
|
||||
evbuffer_add_printf( out, ", " ); mode = STRING_BEGIN;
|
||||
} else {
|
||||
evbuffer_add_printf( out, "%c", *str );
|
||||
}
|
||||
break;
|
||||
default: evbuffer_add_printf( out, "%c", *str ); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = tr_strdup( (char*) EVBUFFER_DATA( out ) );
|
||||
evbuffer_free( out );
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
|
||||
*
|
||||
* This file is licensed by the GPL version 2. Works owned by the
|
||||
* Transmission project are granted a special exemption to clause 2(b)
|
||||
* so that the bulk of its code can remain under the MIT license.
|
||||
* This exemption does not extend to derived works not owned by
|
||||
* the Transmission project.
|
||||
*
|
||||
* $Id:$
|
||||
*/
|
||||
|
||||
#ifndef TR_JSON_H
|
||||
|
||||
int tr_jsonParse( const void * vbuf,
|
||||
const void * bufend,
|
||||
struct tr_benc * setme_benc,
|
||||
const uint8_t ** setme_end );
|
||||
|
||||
char* tr_rison2json( const char * rison,
|
||||
int rison_len );
|
||||
|
||||
#endif
|
|
@ -16,6 +16,7 @@
|
|||
#include "transmission.h"
|
||||
#include "bencode.h"
|
||||
#include "rpc.h"
|
||||
#include "json.h"
|
||||
#include "torrent.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
@ -604,21 +605,42 @@ request_exec( struct tr_handle * handle,
|
|||
if( !result )
|
||||
result = "success";
|
||||
tr_bencDictAddStr( &response, "result", result );
|
||||
fprintf( stderr, "response [%s]", tr_bencSave( &response, NULL ) );
|
||||
tr_bencPrint( &response );
|
||||
out = tr_bencSaveAsJSON( &response, response_len );
|
||||
tr_bencFree( &response );
|
||||
return out;
|
||||
}
|
||||
|
||||
char*
|
||||
tr_rpc_request_exec( struct tr_handle * handle,
|
||||
const void * request_json,
|
||||
int request_len,
|
||||
int * response_len )
|
||||
tr_rpc_request_exec_json( struct tr_handle * handle,
|
||||
const void * request_json,
|
||||
int request_len,
|
||||
int * response_len )
|
||||
{
|
||||
tr_benc top;
|
||||
int have_content = !tr_jsonParse( request_json, (const char*)request_json + request_len, &top, NULL );
|
||||
char * ret = request_exec( handle, have_content ? &top : NULL, response_len );
|
||||
int have_content;
|
||||
char * ret;
|
||||
|
||||
if( request_len < 0 )
|
||||
request_len = strlen( request_json );
|
||||
|
||||
have_content = !tr_jsonParse( request_json, (const char*)request_json + request_len, &top, NULL );
|
||||
ret = request_exec( handle, have_content ? &top : NULL, response_len );
|
||||
|
||||
if( have_content )
|
||||
tr_bencFree( &top );
|
||||
return ret;
|
||||
}
|
||||
|
||||
char*
|
||||
tr_rpc_request_exec_rison( struct tr_handle * handle,
|
||||
const void * request_rison,
|
||||
int request_len,
|
||||
int * response_len )
|
||||
{
|
||||
char * json = tr_rison2json( request_rison, request_len );
|
||||
char * ret = tr_rpc_request_exec_json( handle, json, -1, response_len );
|
||||
tr_free( json );
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -15,10 +15,18 @@
|
|||
|
||||
struct tr_handle;
|
||||
|
||||
/* http://www.json.org/ */
|
||||
char*
|
||||
tr_rpc_request_exec( struct tr_handle * handle,
|
||||
const void * request_json,
|
||||
int request_len,
|
||||
int * response_len );
|
||||
tr_rpc_request_exec_json( struct tr_handle * handle,
|
||||
const void * request_json,
|
||||
int request_len,
|
||||
int * response_len );
|
||||
|
||||
/* http://mjtemplate.org/examples/rison.html */
|
||||
char*
|
||||
tr_rpc_request_exec_rison( struct tr_handle * handle,
|
||||
const void * request_rison,
|
||||
int request_len,
|
||||
int * response_len );
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue