Changeset 5828


Ignore:
Timestamp:
May 13, 2008, 12:52:58 PM (14 years ago)
Author:
charles
Message:

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.

Location:
trunk/libtransmission
Files:
1 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/Makefile.am

    r5827 r5828  
    5959    inout.h \
    6060    ipcparse.h \
     61    json.h \
    6162    list.h \
    6263    makemeta.h \
  • trunk/libtransmission/bencode-test.c

    r5821 r5828  
    22#include "transmission.h"
    33#include "bencode.h"
     4#include "json.h"
    45#include "utils.h" /* tr_free */
    56
     
    272273
    273274static int
     275testRISONSnippet( const char * rison_str, const char * expected )
     276{
     277    char * serialized = tr_rison2json( rison_str, -1 );
     278#if 0
     279fprintf( stderr, " expected: [%s]\n", expected );
     280fprintf( stderr, "      got: [%s]\n", serialized );
     281#endif
     282    check( !strcmp( serialized, expected ) );
     283    tr_free( serialized );
     284    return 0;
     285}
     286
     287static int
     288testRISON( void )
     289{
     290    int val;
     291    const char * rison;
     292    const char * expected;
     293
     294    rison = "(a:0,b:foo,c:'23skidoo')";
     295    expected = "{ \"a\": 0, \"b\": \"foo\", \"c\": \"23skidoo\" }";
     296    if(( val = testRISONSnippet( rison, expected )))
     297        return val;
     298
     299    return 0;
     300}
     301
     302static int
    274303testJSONSnippet( const char * benc_str, const char * expected )
    275304{
     
    278307    tr_bencLoad( benc_str, strlen( benc_str ), &top, NULL );
    279308    serialized = tr_bencSaveAsJSON( &top, NULL );
     309#if 0
     310fprintf( stderr, " expected: [%s]\n", expected );
     311fprintf( stderr, "      got: [%s]\n", serialized );
     312#endif
    280313    check( !strcmp( serialized, expected ) );
    281314    tr_free( serialized );
     
    308341    benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3ed1:ai0eee";
    309342    expected = "{ \"foo\": [ 1, 2, 3, { \"a\": 0 } ], \"hello\": 1, \"world\": 2 }";
     343    if(( val = testJSONSnippet( benc_str, expected )))
     344        return val;
     345
     346    benc_str = "d4:argsd6:statuslee6:result7:successe";
     347    expected = "{ \"args\": { \"status\": [  ] }, \"result\": \"success\" }";
    310348    if(( val = testJSONSnippet( benc_str, expected )))
    311349        return val;
     
    363401        return i;
    364402
     403    if(( i = testRISON( )))
     404        return i;
     405
    365406    if(( i = testStackSmash( )))
    366407        return i;
  • trunk/libtransmission/bencode.c

    r5821 r5828  
    10371037                if( ! ( i % 2 ) )
    10381038                    evbuffer_add_printf( data->out, ": " );
    1039                 else if( parentState->childIndex < parentState->childCount )
     1039                else
    10401040                    evbuffer_add_printf( data->out, ", " );
    1041                 else
    1042                     evbuffer_add_printf( data->out, " }" );
    10431041                break;
    10441042            }
    10451043
    10461044            case TYPE_LIST: {
    1047                 if( ++parentState->childIndex < parentState->childCount )
    1048                     evbuffer_add_printf( data->out, ", " );
    1049                 else
    1050                     evbuffer_add_printf( data->out, " ]" );
     1045                ++parentState->childIndex;
     1046                evbuffer_add_printf( data->out, ", " );
    10511047                break;
    10521048            }
     
    11101106    jsonPushParent( data, val );
    11111107    evbuffer_add_printf( data->out, "{ " );
     1108    if( !val->val.l.count )
     1109        evbuffer_add_printf( data->out, "  " );
    11121110}
    11131111static void
     
    11171115    jsonPushParent( data, val );
    11181116    evbuffer_add_printf( data->out, "[ " );
    1119 }
    1120 static void
    1121 jsonContainerEndFunc( const tr_benc * val UNUSED, void * vdata )
     1117    if( !val->val.l.count )
     1118        evbuffer_add_printf( data->out, "  " );
     1119}
     1120static void
     1121jsonContainerEndFunc( const tr_benc * val, void * vdata )
    11221122{
    11231123    struct jsonWalk * data = vdata;
     1124    EVBUFFER_LENGTH( data->out ) -= 2;
     1125    if( tr_bencIsDict( val ) )
     1126        evbuffer_add_printf( data->out, " }" );
     1127    else /* list */
     1128        evbuffer_add_printf( data->out, " ]" );
    11241129    jsonPopParent( data );
    11251130    jsonChildFunc( data );
  • trunk/libtransmission/json.c

    r5811 r5828  
    1212
    1313#include <assert.h>
    14 //#include <string.h> /* memcpy, memcmp, strstr */
    15 //#include <stdlib.h> /* qsort */
     14#include <ctype.h>
     15#include <string.h>
    1616#include <stdio.h> /* printf */
    17 //#include <limits.h> /* INT_MAX */
    18 //
     17
     18#include <event.h> /* evbuffer */
     19
    1920#include "JSON_checker.h"
    2021
     
    146147    return err;
    147148}
     149
     150/***
     151**** RISON-to-JSON converter
     152***/
     153
     154enum { ESCAPE,
     155       STRING_BEGIN,
     156       STRING, ESCAPE_STRING,
     157       UNQUOTED_STRING, ESCAPE_UNQUOTED_STRING,
     158       VAL_BEGIN,
     159       OTHER };
     160
     161char*
     162tr_rison2json( const char * str, int rison_len )
     163{
     164    struct evbuffer * out = evbuffer_new( );
     165    int stack[1000], *parents=stack;
     166    int mode = OTHER;
     167    char * ret;
     168    const char * end;
     169
     170    if( rison_len < 0 )
     171        end = str + strlen( str );
     172    else
     173        end = str + rison_len;
     174
     175#define IN_OBJECT ((parents!=stack) && (parents[-1]=='}'))
     176
     177    for( ; str!=end; ++str )
     178    {
     179        if( mode == ESCAPE )
     180        {
     181            switch( *str )
     182            {
     183                case '(': evbuffer_add_printf( out, "[ " ); *parents++ = ']'; break;
     184                case 't': evbuffer_add_printf( out, " true" ); break;
     185                case 'f': evbuffer_add_printf( out, " false" ); break;
     186                case 'n': evbuffer_add_printf( out, " null" ); break;
     187                default: fprintf( stderr, "invalid escape sequence!\n" ); break;
     188            }
     189            mode = OTHER;
     190        }
     191        else if( mode == STRING_BEGIN )
     192        {
     193            switch( *str )
     194            {
     195                case '\'': evbuffer_add_printf( out, "\"" ); mode = STRING; break;
     196                case ')': evbuffer_add_printf( out, " %c", *--parents ); mode = OTHER; break;
     197                default: evbuffer_add_printf( out, "\"%c", *str ); mode = UNQUOTED_STRING; break;
     198            }
     199        }
     200        else if( mode == UNQUOTED_STRING )
     201        {
     202            switch( *str )
     203            {
     204                case '\'': evbuffer_add_printf( out, "\"" ); mode = OTHER; break;
     205                case ':': evbuffer_add_printf( out, "\": "); mode = VAL_BEGIN; break;
     206                case '!': mode = ESCAPE_UNQUOTED_STRING; break;
     207                case ',': if( IN_OBJECT ) { evbuffer_add_printf( out, "\", "); mode = STRING_BEGIN; break; }
     208                          /* fallthrough */
     209                default: evbuffer_add_printf( out, "%c", *str ); break;
     210            }
     211        }
     212        else if( mode == VAL_BEGIN )
     213        {
     214            if( *str == '\'' ) { evbuffer_add_printf( out, "\"" ); mode = STRING; }
     215            else if( isdigit( *str ) ) { evbuffer_add_printf( out, "%c", *str ); mode = OTHER; }
     216            else { evbuffer_add_printf( out, "\"%c", *str ); mode = UNQUOTED_STRING; }
     217        }
     218        else if( mode == STRING )
     219        {
     220            switch( *str )
     221            {
     222                case '\'': evbuffer_add_printf( out, "\"" ); mode = OTHER; break;
     223                case '!': mode = ESCAPE_STRING; break;
     224                default: evbuffer_add_printf( out, "%c", *str ); break;
     225            }
     226        }
     227        else if( mode == ESCAPE_STRING || mode == ESCAPE_UNQUOTED_STRING )
     228        {
     229            switch( *str )
     230            {
     231                case '!': evbuffer_add_printf( out, "!" ); break;
     232                case '\'': evbuffer_add_printf( out, "'" ); break;
     233                default: fprintf( stderr, "invalid string escape sequence\n" ); break;
     234            }
     235            if( mode == ESCAPE_UNQUOTED_STRING ) mode = UNQUOTED_STRING;
     236            if( mode == ESCAPE_STRING ) mode = STRING;
     237        }
     238        else
     239        {
     240            switch( *str )
     241            {
     242                case '(': evbuffer_add_printf( out, "{ " ); mode=STRING_BEGIN; *parents++ = '}'; break;
     243                case '!': mode = ESCAPE; break;
     244                case ')': evbuffer_add_printf( out, " %c", *--parents ); break;
     245                case '\'': evbuffer_add_printf( out, "\"" ); mode = STRING; break;
     246                case ':': if( IN_OBJECT ) {
     247                              evbuffer_add_printf( out, ": " ); mode = VAL_BEGIN;
     248                          } else {
     249                              evbuffer_add_printf( out, "%c", *str );
     250                          }
     251                          break;
     252                case ',': if( IN_OBJECT ) {
     253                              evbuffer_add_printf( out, ", " ); mode = STRING_BEGIN;
     254                          } else {
     255                              evbuffer_add_printf( out, "%c", *str );
     256                          }
     257                          break;
     258                default: evbuffer_add_printf( out, "%c", *str ); break;
     259            }
     260        }
     261    }
     262
     263    ret = tr_strdup( (char*) EVBUFFER_DATA( out ) );
     264    evbuffer_free( out );
     265    return ret;
     266}
  • trunk/libtransmission/rpc.c

    r5827 r5828  
    1717#include "bencode.h"
    1818#include "rpc.h"
     19#include "json.h"
    1920#include "torrent.h"
    2021#include "utils.h"
     
    605606         result = "success";
    606607    tr_bencDictAddStr( &response, "result", result );
     608fprintf( stderr, "response [%s]", tr_bencSave( &response, NULL ) );
     609tr_bencPrint( &response );
    607610    out = tr_bencSaveAsJSON( &response, response_len );
    608611    tr_bencFree( &response );
     
    611614
    612615char*
    613 tr_rpc_request_exec( struct tr_handle  * handle,
    614                      const void        * request_json,
    615                      int                 request_len,
    616                      int               * response_len )
     616tr_rpc_request_exec_json( struct tr_handle  * handle,
     617                         const void         * request_json,
     618                         int                  request_len,
     619                         int                * response_len )
    617620{
    618621    tr_benc top;
    619     int have_content = !tr_jsonParse( request_json, (const char*)request_json + request_len, &top, NULL );
    620     char * ret = request_exec( handle, have_content ? &top : NULL, response_len );
     622    int have_content;
     623    char * ret;
     624
     625    if( request_len < 0 )
     626        request_len = strlen( request_json );
     627
     628    have_content = !tr_jsonParse( request_json, (const char*)request_json + request_len, &top, NULL );
     629    ret = request_exec( handle, have_content ? &top : NULL, response_len );
     630
    621631    if( have_content )
    622632        tr_bencFree( &top );
    623633    return ret;
    624634}
     635
     636char*
     637tr_rpc_request_exec_rison( struct tr_handle  * handle,
     638                           const void        * request_rison,
     639                           int                 request_len,
     640                           int               * response_len )
     641{
     642    char * json = tr_rison2json( request_rison, request_len );
     643    char * ret = tr_rpc_request_exec_json( handle, json, -1, response_len );
     644    tr_free( json );
     645    return ret;
     646}
  • trunk/libtransmission/rpc.h

    r5827 r5828  
    1616struct tr_handle;
    1717
     18/* http://www.json.org/ */
    1819char*
    19 tr_rpc_request_exec( struct tr_handle  * handle,
    20                      const void        * request_json,
    21                      int                 request_len,
    22                      int               * response_len );
     20tr_rpc_request_exec_json( struct tr_handle  * handle,
     21                          const void        * request_json,
     22                          int                 request_len,
     23                          int               * response_len );
     24
     25/* http://mjtemplate.org/examples/rison.html */
     26char*
     27tr_rpc_request_exec_rison( struct tr_handle  * handle,
     28                           const void        * request_rison,
     29                           int                 request_len,
     30                           int               * response_len );
    2331
    2432#endif
Note: See TracChangeset for help on using the changeset viewer.