fix the 1.04 bencode errors reported in the forums this morning. add regression tests.
This commit is contained in:
parent
7394a49a09
commit
3334ea8401
|
@ -136,6 +136,29 @@ testStr( void )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
testString( const char * str, int isGood )
|
||||||
|
{
|
||||||
|
benc_val_t val;
|
||||||
|
const uint8_t * end = NULL;
|
||||||
|
char * saved;
|
||||||
|
const size_t len = strlen( str );
|
||||||
|
int savedLen;
|
||||||
|
int err = tr_bencParse( str, str+len, &val , &end );
|
||||||
|
if( !isGood ) {
|
||||||
|
check( err );
|
||||||
|
} else {
|
||||||
|
check( !err );
|
||||||
|
check( end == (const uint8_t*)str + len );
|
||||||
|
saved = tr_bencSave( &val, &savedLen );
|
||||||
|
check( !strcmp( saved, str ) );
|
||||||
|
check( len == (size_t)savedLen );
|
||||||
|
tr_free( saved );
|
||||||
|
tr_bencFree( &val );
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
testParse( void )
|
testParse( void )
|
||||||
{
|
{
|
||||||
|
@ -184,15 +207,22 @@ testParse( void )
|
||||||
tr_free( saved );
|
tr_free( saved );
|
||||||
tr_bencFree( &val );
|
tr_bencFree( &val );
|
||||||
|
|
||||||
end = NULL;
|
if(( err = testString( "llleee", TRUE )))
|
||||||
snprintf( (char*)buf, sizeof( buf ), "llleee" );
|
return err;
|
||||||
err = tr_bencParse( buf, buf + sizeof( buf ), &val , &end );
|
if(( err = testString( "d3:cow3:moo4:spam4:eggse", TRUE )))
|
||||||
check( !err );
|
return err;
|
||||||
check( end == buf + 6 );
|
if(( err = testString( "d4:spaml1:a1:bee", TRUE )))
|
||||||
saved = tr_bencSave( &val, &len );
|
return err;
|
||||||
check( !strcmp( saved, "llleee" ) );
|
#if 0
|
||||||
tr_free( saved );
|
if(( err = testString( "d9:publisher3:bob18:publisher.location4:home17:publisher-webpage15:www.example.come", TRUE )))
|
||||||
tr_bencFree( &val );
|
return err;
|
||||||
|
#endif
|
||||||
|
if(( err = testString( "d8:completei1e8:intervali1800e12:min intervali1800e5:peers0:e", TRUE )))
|
||||||
|
return err;
|
||||||
|
if(( err = testString( "d1:ai0e1:be", FALSE ))) /* odd number of children */
|
||||||
|
return err;
|
||||||
|
if(( err = testString( "", FALSE )))
|
||||||
|
return err;
|
||||||
|
|
||||||
/* nested containers
|
/* nested containers
|
||||||
* parse an unsorted dict
|
* parse an unsorted dict
|
||||||
|
@ -209,13 +239,6 @@ testParse( void )
|
||||||
tr_free( saved );
|
tr_free( saved );
|
||||||
tr_bencFree( &val );
|
tr_bencFree( &val );
|
||||||
|
|
||||||
end = NULL;
|
|
||||||
snprintf( (char*)buf, sizeof( buf ), "d8:completei1e8:intervali1800e12:min intervali1800e5:peers0:e" );
|
|
||||||
err = tr_bencParse( buf, buf+sizeof( buf ), &val, &end );
|
|
||||||
check( !err );
|
|
||||||
check( end == buf + strlen( (const char*)buf ) );
|
|
||||||
tr_bencFree( &val );
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,27 +41,25 @@
|
||||||
**/
|
**/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
isInt( const benc_val_t * val )
|
isType( const benc_val_t * val, int type )
|
||||||
{
|
{
|
||||||
return val!=NULL && val->type==TYPE_INT;
|
return ( ( val != NULL ) && ( val->type == type ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
#define isInt(v) ( isType( ( v ), TYPE_INT ) )
|
||||||
isList( const benc_val_t * val )
|
#define isString(v) ( isType( ( v ), TYPE_STR ) )
|
||||||
{
|
#define isList(v) ( isType( ( v ), TYPE_LIST ) )
|
||||||
return val!=NULL && val->type==TYPE_LIST;
|
#define isDict(v) ( isType( ( v ), TYPE_DICT ) )
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
isDict( const benc_val_t * val )
|
|
||||||
{
|
|
||||||
return val!=NULL && val->type==TYPE_DICT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
isContainer( const benc_val_t * val )
|
isContainer( const benc_val_t * val )
|
||||||
{
|
{
|
||||||
return val!=NULL && ( val->type & ( TYPE_DICT | TYPE_LIST ) );
|
return isList(val) || isDict(val);
|
||||||
|
}
|
||||||
|
static int
|
||||||
|
isSomething( const benc_val_t * val )
|
||||||
|
{
|
||||||
|
return isContainer(val) || isInt(val) || isString(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
benc_val_t*
|
benc_val_t*
|
||||||
|
@ -229,6 +227,8 @@ tr_bencParse( const void * buf_in,
|
||||||
const uint8_t * bufend = bufend_in;
|
const uint8_t * bufend = bufend_in;
|
||||||
tr_ptrArray * parentStack = tr_ptrArrayNew( );
|
tr_ptrArray * parentStack = tr_ptrArrayNew( );
|
||||||
|
|
||||||
|
tr_bencInit( top, 0 );
|
||||||
|
|
||||||
while( buf != bufend )
|
while( buf != bufend )
|
||||||
{
|
{
|
||||||
if( buf > bufend ) /* no more text to parse... */
|
if( buf > bufend ) /* no more text to parse... */
|
||||||
|
@ -274,9 +274,15 @@ tr_bencParse( const void * buf_in,
|
||||||
}
|
}
|
||||||
else if( *buf=='e' ) /* end of list or dict */
|
else if( *buf=='e' ) /* end of list or dict */
|
||||||
{
|
{
|
||||||
|
benc_val_t * node;
|
||||||
++buf;
|
++buf;
|
||||||
if( tr_ptrArrayEmpty( parentStack ) )
|
if( tr_ptrArrayEmpty( parentStack ) )
|
||||||
return TR_ERROR;
|
return TR_ERROR;
|
||||||
|
|
||||||
|
node = tr_ptrArrayBack( parentStack );
|
||||||
|
if( isDict( node ) && ( node->val.l.count % 2 ) )
|
||||||
|
return TR_ERROR; /* odd # of children in dict */
|
||||||
|
|
||||||
tr_ptrArrayPop( parentStack );
|
tr_ptrArrayPop( parentStack );
|
||||||
if( tr_ptrArrayEmpty( parentStack ) )
|
if( tr_ptrArrayEmpty( parentStack ) )
|
||||||
break;
|
break;
|
||||||
|
@ -308,7 +314,7 @@ tr_bencParse( const void * buf_in,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = tr_ptrArrayEmpty( parentStack ) ? 0 : 1;
|
err = !isSomething( top ) || !tr_ptrArrayEmpty( parentStack );
|
||||||
|
|
||||||
if( !err && ( setme_end != NULL ) )
|
if( !err && ( setme_end != NULL ) )
|
||||||
*setme_end = buf;
|
*setme_end = buf;
|
||||||
|
@ -511,20 +517,21 @@ struct SaveNode
|
||||||
static struct SaveNode*
|
static struct SaveNode*
|
||||||
nodeNewDict( const benc_val_t * val )
|
nodeNewDict( const benc_val_t * val )
|
||||||
{
|
{
|
||||||
int i, j, n;
|
int i, j;
|
||||||
|
int nKeys;
|
||||||
struct SaveNode * node;
|
struct SaveNode * node;
|
||||||
struct KeyIndex * indices;
|
struct KeyIndex * indices;
|
||||||
|
|
||||||
assert( isDict( val ) );
|
assert( isDict( val ) );
|
||||||
|
|
||||||
n = val->val.l.count;
|
nKeys = val->val.l.count / 2;
|
||||||
node = tr_new0( struct SaveNode, 1 );
|
node = tr_new0( struct SaveNode, 1 );
|
||||||
node->val = val;
|
node->val = val;
|
||||||
node->children = tr_new0( int, n );
|
node->children = tr_new0( int, nKeys * 2 );
|
||||||
|
|
||||||
/* ugh, a dictionary's children have to be sorted by key... */
|
/* ugh, a dictionary's children have to be sorted by key... */
|
||||||
indices = tr_new( struct KeyIndex, n );
|
indices = tr_new( struct KeyIndex, nKeys );
|
||||||
for( i=j=0; i<n; i+=2, ++j ) {
|
for( i=j=0; i<(nKeys*2); i+=2, ++j ) {
|
||||||
indices[j].key = val->val.l.vals[i].val.s.s;
|
indices[j].key = val->val.l.vals[i].val.s.s;
|
||||||
indices[j].index = i;
|
indices[j].index = i;
|
||||||
}
|
}
|
||||||
|
@ -535,7 +542,7 @@ nodeNewDict( const benc_val_t * val )
|
||||||
node->children[ node->childCount++ ] = index + 1;
|
node->children[ node->childCount++ ] = index + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert( node->childCount == n );
|
assert( node->childCount == nKeys * 2 );
|
||||||
tr_free( indices );
|
tr_free( indices );
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue