add benc-to-json conversion + unit tests.

This commit is contained in:
Charles Kerr 2008-05-12 17:54:57 +00:00
parent 7e36f684a9
commit 911bce88c9
3 changed files with 95 additions and 52 deletions

View File

@ -271,12 +271,12 @@ testParse( void )
} }
static int static int
testPHPSnippet( const char * benc_str, const char * expected ) testJSONSnippet( const char * benc_str, const char * expected )
{ {
tr_benc top; tr_benc top;
char * serialized; char * serialized;
tr_bencLoad( benc_str, strlen( benc_str ), &top, NULL ); tr_bencLoad( benc_str, strlen( benc_str ), &top, NULL );
serialized = tr_bencSaveAsSerializedPHP( &top, NULL ); serialized = tr_bencSaveAsJSON( &top, NULL );
check( !strcmp( serialized, expected ) ); check( !strcmp( serialized, expected ) );
tr_free( serialized ); tr_free( serialized );
tr_bencFree( &top ); tr_bencFree( &top );
@ -284,25 +284,30 @@ testPHPSnippet( const char * benc_str, const char * expected )
} }
static int static int
testPHP( void ) testJSON( void )
{ {
int val; int val;
const char * benc_str; const char * benc_str;
const char * expected; const char * expected;
benc_str = "i6e"; benc_str = "i6e";
expected = "i:6;"; expected = "6";
if(( val = testPHPSnippet( benc_str, expected ))) if(( val = testJSONSnippet( benc_str, expected )))
return val; return val;
benc_str = "d3:cow3:moo4:spam4:eggse"; benc_str = "d5:helloi1e5:worldi2ee";
expected = "a:2:{s:3:\"cow\";s:3:\"moo\";s:4:\"spam\";s:4:\"eggs\";}"; expected = "{ \"hello\": 1, \"world\": 2 }";
if(( val = testPHPSnippet( benc_str, expected ))) if(( val = testJSONSnippet( benc_str, expected )))
return val; return val;
benc_str = "l3:cow3:moo4:spam4:eggse"; benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3ee";
expected = "a:4:{i:0;s:3:\"cow\";i:1;s:3:\"moo\";i:2;s:4:\"spam\";i:3;s:4:\"eggs\";}"; expected = "{ \"foo\": [ 1, 2, 3 ], \"hello\": 1, \"world\": 2 }";
if(( val = testPHPSnippet( benc_str, expected ))) if(( val = testJSONSnippet( benc_str, expected )))
return val;
benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3ed1:ai0eee";
expected = "{ \"foo\": [ 1, 2, 3, { \"a\": 0 } ], \"hello\": 1, \"world\": 2 }";
if(( val = testJSONSnippet( benc_str, expected )))
return val; return val;
return 0; return 0;
@ -354,7 +359,7 @@ main( void )
if(( i = testParse( ))) if(( i = testParse( )))
return i; return i;
if(( i = testPHP( ))) if(( i = testJSON( )))
return i; return i;
if(( i = testStackSmash( ))) if(( i = testStackSmash( )))

View File

@ -1012,95 +1012,133 @@ tr_bencPrint( const tr_benc * val )
struct ParentState struct ParentState
{ {
int type; int bencType;
int index; int childIndex;
int childCount;
}; };
struct phpWalk struct jsonWalk
{ {
tr_list * parents; tr_list * parents;
struct evbuffer * out; struct evbuffer * out;
}; };
static void static void
phpChildFunc( struct phpWalk * data ) jsonChildFunc( struct jsonWalk * data )
{ {
if( data->parents ) if( data->parents )
{ {
struct ParentState * parentState = data->parents->data; struct ParentState * parentState = data->parents->data;
if( parentState->type == TYPE_LIST ) switch( parentState->bencType )
evbuffer_add_printf( data->out, "i:%d;", parentState->index++ ); {
case TYPE_DICT: {
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, " }" );
break;
}
case TYPE_LIST: {
if( ++parentState->childIndex < parentState->childCount )
evbuffer_add_printf( data->out, ", " );
else
evbuffer_add_printf( data->out, " ]" );
break;
}
default:
break;
}
} }
} }
static void static void
phpPushParent( struct phpWalk * data, int type ) jsonPushParent( struct jsonWalk * data, const tr_benc * benc )
{ {
struct ParentState * parentState = tr_new( struct ParentState, 1 ); struct ParentState * parentState = tr_new( struct ParentState, 1 );
parentState->type = type; parentState->bencType = benc->type;
parentState->index = 0; parentState->childIndex = 0;
parentState->childCount = benc->val.l.count;
tr_list_prepend( &data->parents, parentState ); tr_list_prepend( &data->parents, parentState );
} }
static void static void
phpPopParent( struct phpWalk * data ) jsonPopParent( struct jsonWalk * data )
{ {
tr_free( tr_list_pop_front( &data->parents ) ); tr_free( tr_list_pop_front( &data->parents ) );
} }
static void static void
phpIntFunc( const tr_benc * val, void * vdata ) jsonIntFunc( const tr_benc * val, void * vdata )
{ {
struct phpWalk * data = vdata; struct jsonWalk * data = vdata;
phpChildFunc( data ); evbuffer_add_printf( data->out, "%"PRId64, val->val.i );
evbuffer_add_printf( data->out, "i:%"PRId64";", val->val.i ); jsonChildFunc( data );
} }
static void static void
phpStringFunc( const tr_benc * val, void * vdata ) jsonStringFunc( const tr_benc * val, void * vdata )
{ {
struct phpWalk * data = vdata; struct jsonWalk * data = vdata;
phpChildFunc( data ); const char *it, *end;
evbuffer_add_printf( data->out, "s:%d:\"%s\";", val->val.s.i, val->val.s.s ); evbuffer_add_printf( data->out, "\"" );
for( it=val->val.s.s, end=it+val->val.s.i; it!=end; ++it )
{
switch( *it ) {
case '"' : evbuffer_add_printf( data->out, "\\\"" ); break;
case '/' : evbuffer_add_printf( data->out, "\\/" ); break;
case '\b': evbuffer_add_printf( data->out, "\\b" ); break;
case '\f': evbuffer_add_printf( data->out, "\\f" ); break;
case '\n': evbuffer_add_printf( data->out, "\\n" ); break;
case '\r': evbuffer_add_printf( data->out, "\\n" ); break;
case '\t': evbuffer_add_printf( data->out, "\\n" ); break;
case '\\': evbuffer_add_printf( data->out, "\\\\" ); break;
default: evbuffer_add_printf( data->out, "%c", *it ); break;
}
}
evbuffer_add_printf( data->out, "\"" );
jsonChildFunc( data );
} }
static void static void
phpDictBeginFunc( const tr_benc * val, void * vdata ) jsonDictBeginFunc( const tr_benc * val, void * vdata )
{ {
struct phpWalk * data = vdata; struct jsonWalk * data = vdata;
phpChildFunc( data ); jsonPushParent( data, val );
phpPushParent( data, TYPE_DICT ); evbuffer_add_printf( data->out, "{ " );
evbuffer_add_printf( data->out, "a:%d:{", val->val.l.count/2 );
} }
static void static void
phpListBeginFunc( const tr_benc * val, void * vdata ) jsonListBeginFunc( const tr_benc * val, void * vdata )
{ {
struct phpWalk * data = vdata; struct jsonWalk * data = vdata;
phpChildFunc( data ); jsonPushParent( data, val );
phpPushParent( data, TYPE_LIST ); evbuffer_add_printf( data->out, "[ " );
evbuffer_add_printf( data->out, "a:%d:{", val->val.l.count );
} }
static void static void
phpContainerEndFunc( const tr_benc * val UNUSED, void * vdata ) jsonContainerEndFunc( const tr_benc * val UNUSED, void * vdata )
{ {
struct phpWalk * data = vdata; struct jsonWalk * data = vdata;
phpPopParent( data ); jsonPopParent( data );
evbuffer_add_printf( data->out, "}" ); jsonChildFunc( data );
} }
char* char*
tr_bencSaveAsSerializedPHP( const tr_benc * top, int * len ) tr_bencSaveAsJSON( const tr_benc * top, int * len )
{ {
char * ret; char * ret;
struct WalkFuncs walkFuncs; struct WalkFuncs walkFuncs;
struct phpWalk data; struct jsonWalk data;
data.out = evbuffer_new( ); data.out = evbuffer_new( );
data.parents = NULL; data.parents = NULL;
walkFuncs.intFunc = phpIntFunc; walkFuncs.intFunc = jsonIntFunc;
walkFuncs.stringFunc = phpStringFunc; walkFuncs.stringFunc = jsonStringFunc;
walkFuncs.dictBeginFunc = phpDictBeginFunc; walkFuncs.dictBeginFunc = jsonDictBeginFunc;
walkFuncs.listBeginFunc = phpListBeginFunc; walkFuncs.listBeginFunc = jsonListBeginFunc;
walkFuncs.containerEndFunc = phpContainerEndFunc; walkFuncs.containerEndFunc = jsonContainerEndFunc;
bencWalk( top, &walkFuncs, &data ); bencWalk( top, &walkFuncs, &data );

View File

@ -116,7 +116,7 @@ tr_benc * tr_bencDictAddDict( tr_benc * dict, const char * key, int reserveCo
tr_benc * tr_bencDictAddRaw( tr_benc * dict, const char * key, const void *, size_t len ); tr_benc * tr_bencDictAddRaw( tr_benc * dict, const char * key, const void *, size_t len );
char* tr_bencSave( const tr_benc * val, int * len ); char* tr_bencSave( const tr_benc * val, int * len );
char* tr_bencSaveAsSerializedPHP( const tr_benc * top, int * len ); char* tr_bencSaveAsJSON( const tr_benc * top, int * len );
int tr_bencSaveFile( const char * filename, const tr_benc * ); int tr_bencSaveFile( const char * filename, const tr_benc * );
int tr_bencLoadFile( const char * filename, tr_benc * ); int tr_bencLoadFile( const char * filename, tr_benc * );