]> granicus.if.org Git - transmission/commitdiff
get rid of strlcat_utf8()
authorCharles Kerr <charles@transmissionbt.com>
Wed, 20 Aug 2008 19:21:57 +0000 (19:21 +0000)
committerCharles Kerr <charles@transmissionbt.com>
Wed, 20 Aug 2008 19:21:57 +0000 (19:21 +0000)
libtransmission/metainfo.c

index 71c0f3281385d34634ac6d524a1e5cc805a00b64..7f9e4a807cbdd8809e010584ff5cb07336c6d2b9 100644 (file)
 /***********************************************************************
  * Local prototypes
  **********************************************************************/
-static int parseFiles( tr_info * inf, tr_benc * name,
-                       tr_benc * files, tr_benc * length );
+static int parseFiles( tr_info * inf, tr_benc * files, tr_benc * length );
 
 /***
 ****
 ***/
 
-#define WANTBYTES( want, got ) \
-    if( (want) > (got) ) { return; } else { (got) -= (want); }
-static void
-strlcat_utf8( void * dest, const void * src, size_t len, char skip )
-{
-    char       * s      = dest;
-    const char * append = src;
-    const char * p;
-
-    /* don't overwrite the nul at the end */
-    len--;
-
-    /* Go to the end of the destination string */
-    while( s[0] )
-    {
-        s++;
-        len--;
-    }
-
-    /* Now start appending, converting on the fly if necessary */
-    for( p = append; p[0]; )
-    {
-        /* skip over the requested character */
-        if( skip == p[0] )
-        {
-            p++;
-            continue;
-        }
-
-        if( !( p[0] & 0x80 ) )
-        {
-            /* ASCII character */
-            WANTBYTES( 1, len );
-            *(s++) = *(p++);
-            continue;
-        }
-
-        if( ( p[0] & 0xE0 ) == 0xC0 && ( p[1] & 0xC0 ) == 0x80 )
-        {
-            /* 2-bytes UTF-8 character */
-            WANTBYTES( 2, len );
-            *(s++) = *(p++); *(s++) = *(p++);
-            continue;
-        }
-
-        if( ( p[0] & 0xF0 ) == 0xE0 && ( p[1] & 0xC0 ) == 0x80 &&
-            ( p[2] & 0xC0 ) == 0x80 )
-        {
-            /* 3-bytes UTF-8 character */
-            WANTBYTES( 3, len );
-            *(s++) = *(p++); *(s++) = *(p++);
-            *(s++) = *(p++);
-            continue;
-        }
-
-        if( ( p[0] & 0xF8 ) == 0xF0 && ( p[1] & 0xC0 ) == 0x80 &&
-            ( p[2] & 0xC0 ) == 0x80 && ( p[3] & 0xC0 ) == 0x80 )
-        {
-            /* 4-bytes UTF-8 character */
-            WANTBYTES( 4, len );
-            *(s++) = *(p++); *(s++) = *(p++);
-            *(s++) = *(p++); *(s++) = *(p++);
-            continue;
-        }
-
-        /* ISO 8859-1 -> UTF-8 conversion */
-        WANTBYTES( 2, len );
-        *(s++) = 0xC0 | ( ( *p & 0xFF ) >> 6 );
-        *(s++) = 0x80 | ( *(p++) & 0x3F );
-    }
-}
-
 static char*
 getTorrentFilename( const tr_handle  * handle,
                     const tr_info    * inf )
@@ -308,10 +235,13 @@ tr_metainfoParse( const tr_handle  * handle,
                   tr_info          * inf,
                   const tr_benc    * meta_in )
 {
-    tr_piece_index_t i;
-    tr_benc * beInfo, * val, * val2;
+    int64_t i;
+    const char * str;
+    const uint8_t * raw;
+    size_t rawlen;
+    tr_piece_index_t pi;
+    tr_benc * beInfo;
     tr_benc * meta = (tr_benc *) meta_in;
-    char buf[4096];
 
     /* info_hash: urlencoded 20-byte SHA1 hash of the value of the info key
      * from the Metainfo file. Note that the value will be a bencoded 
@@ -321,6 +251,7 @@ tr_metainfoParse( const tr_handle  * handle,
         int len;
         char * str = tr_bencSave( beInfo, &len );
         tr_sha1( inf->hash, str, len, NULL );
+        tr_sha1_to_hex( inf->hashString, inf->hash );
         tr_free( str );
     }
     else
@@ -329,85 +260,68 @@ tr_metainfoParse( const tr_handle  * handle,
         return TR_EINVALID;
     }
 
-    tr_sha1_to_hex( inf->hashString, inf->hash );
+    /* name */
+    if( !tr_bencDictFindStr( beInfo, "name.utf-8", &str ) )
+        if( !tr_bencDictFindStr( beInfo, "name", &str ) )
+            str = NULL;
+    tr_free( inf->name );
+    inf->name = tr_strdup( str );
+    if( !str || !*str ) {
+        tr_err( _( "Invalid metadata entry \"%s\"" ), "name" );
+        return TR_EINVALID;
+    }
 
     /* comment */
-    memset( buf, '\0', sizeof( buf ) );
-    val = tr_bencDictFindFirst( meta, "comment.utf-8", "comment", NULL );
-    if( tr_bencIsString( val ) )
-        strlcat_utf8( buf, val->val.s.s, sizeof( buf ), 0 );
+    if( !tr_bencDictFindStr( meta, "comment.utf-8", &str ) )
+        if( !tr_bencDictFindStr( meta, "comment", &str ) )
+            str = "";
     tr_free( inf->comment );
-    inf->comment = tr_strdup( buf );
+    inf->comment = tr_strdup( str );
     
     /* creator */
-    memset( buf, '\0', sizeof( buf ) );
-    val = tr_bencDictFindFirst( meta, "created by.utf-8", "created by", NULL );
-    if( tr_bencIsString( val ) )
-        strlcat_utf8( buf, val->val.s.s, sizeof( buf ), 0 );
+    if( !tr_bencDictFindStr( meta, "created by.utf-8", &str ) )
+        if( !tr_bencDictFindStr( meta, "created by", &str ) )
+            str = "";
     tr_free( inf->creator );
-    inf->creator = tr_strdup( buf );
+    inf->creator = tr_strdup( str );
     
     /* Date created */
-    inf->dateCreated = 0;
-    val = tr_bencDictFind( meta, "creation date" );
-    if( tr_bencIsInt( val ) )
-        inf->dateCreated = val->val.i;
+    if( !tr_bencDictFindInt( meta, "creation date", &i ) )
+        i = 0;
+    inf->dateCreated = i;
     
     /* Private torrent */
-    val  = tr_bencDictFind( beInfo, "private" );
-    val2 = tr_bencDictFind( meta,  "private" );
-    if( ( tr_bencIsInt(val) && val->val.i ) ||
-        ( tr_bencIsInt(val2) && val2->val.i ) )
-    {
-        inf->isPrivate = 1;
-    }
+    if( !tr_bencDictFindInt( beInfo, "private", &i ) )
+        if( !tr_bencDictFindInt( meta, "private", &i ) )
+            i = 0;
+    inf->isPrivate = i != 0;
     
     /* Piece length */
-    val = tr_bencDictFind( beInfo, "piece length" );
-    if( !tr_bencIsInt( val ) )
-    {
-        if( val )
-            tr_nerr( inf->name, _( "Invalid metadata entry \"%s\"" ), "piece length" );
-        else
-            tr_nerr( inf->name, _( "Missing metadata entry \"%s\"" ), "piece length" );
+    if( tr_bencDictFindInt( beInfo, "piece length", &i ) && ( i > 0 ) )
+        inf->pieceSize = i;
+    else {
+        tr_nerr( inf->name, _( "Invalid metadata entry \"%s\"" ), "piece length" );
         goto fail;
     }
-    inf->pieceSize = val->val.i;
 
     /* Hashes */
-    val = tr_bencDictFind( beInfo, "pieces" );
-    if( !tr_bencIsString( val ) )
-    {
-        if( val )
-            tr_nerr( inf->name, _( "Invalid metadata entry \"%s\"" ), "pieces" );
-        else
-            tr_nerr( inf->name, _( "Missing metadata entry \"%s\"" ), "pieces" );
-        goto fail;
-    }
-    if( val->val.s.i % SHA_DIGEST_LENGTH )
-    {
+    if( !tr_bencDictFindRaw( beInfo, "pieces", &raw, &rawlen ) || ( rawlen % SHA_DIGEST_LENGTH ) ) {
         tr_nerr( inf->name, _( "Invalid metadata entry \"%s\"" ), "pieces" );
         goto fail;
     }
-    inf->pieceCount = val->val.s.i / SHA_DIGEST_LENGTH;
-
-    inf->pieces = calloc ( inf->pieceCount, sizeof(tr_piece) );
-
-    for ( i=0; i<inf->pieceCount; ++i )
-    {
-        memcpy (inf->pieces[i].hash, &val->val.s.s[i*SHA_DIGEST_LENGTH], SHA_DIGEST_LENGTH);
-    }
-
-    /* get file or top directory name */
-    val = tr_bencDictFindFirst( beInfo, "name.utf-8", "name", NULL );
-    if( parseFiles( inf, val,
-                    tr_bencDictFind( beInfo, "files" ),
-                    tr_bencDictFind( beInfo, "length" ) ) )
+    inf->pieceCount = rawlen / SHA_DIGEST_LENGTH;
+    inf->pieces = tr_new0( tr_piece, inf->pieceCount );
+    for ( pi=0; pi<inf->pieceCount; ++pi )
+        memcpy( inf->pieces[pi].hash, &raw[pi*SHA_DIGEST_LENGTH], SHA_DIGEST_LENGTH );
+
+    /* files */
+    if( parseFiles( inf, tr_bencDictFind( beInfo, "files" ),
+                         tr_bencDictFind( beInfo, "length" ) ) )
     {
         goto fail;
     }
 
-    if( !inf->fileCount || !inf->totalSize || !inf->pieceSize )
+    if( !inf->fileCount || !inf->totalSize )
     {
         tr_nerr( inf->name, _( "Torrent is corrupt" ) ); /* the content is missing! */
         goto fail;
@@ -469,59 +383,36 @@ void tr_metainfoFree( tr_info * inf )
 }
 
 static int
-getfile( char ** setme, const char * prefix, tr_benc * name )
+getfile( char ** setme, const char * root, tr_benc * path )
 {
-    const char ** list;
-    int           ii, jj;
-    char          buf[4096];
-
-    if( !tr_bencIsList( name ) )
-        return TR_EINVALID;
-
-    list = calloc( name->val.l.count, sizeof( list[0] ) );
-    if( !list )
-        return TR_EINVALID;
+    int err;
 
-    for( ii = jj = 0; name->val.l.count > ii; ii++ )
+    if( !tr_bencIsList( path ) )
     {
-        tr_benc * dir = &name->val.l.vals[ii];
-
-        if( !tr_bencIsString( dir ) )
-            continue;
+        err = TR_EINVALID;
+    }
+    else
+    {
+        struct evbuffer * buf = evbuffer_new( );
+        int n = tr_bencListSize( path );
+        int i;
 
-        if( 0 == strcmp( "..", dir->val.s.s ) )
-        {
-            if( 0 < jj )
-            {
-                jj--;
+        evbuffer_add( buf, root, strlen( root ) );
+        for( i=0; i<n; ++i ) {
+            const char * str;
+            if( tr_bencGetStr( tr_bencListChild( path, i ), &str ) && strcmp( str, ".." ) ) {
+                evbuffer_add( buf, TR_PATH_DELIMITER_STR, 1 );
+                evbuffer_add( buf, str, strlen( str ) );
             }
         }
-        else if( 0 != strcmp( ".", dir->val.s.s ) )
-        {
-            list[jj] = dir->val.s.s;
-            jj++;
-        }
-    }
 
-    if( 0 == jj )
-    {
-        free( list );
-        return TR_EINVALID;
-    }
-
-    memset( buf, 0, sizeof( buf ) );
-    strlcat_utf8( buf, prefix, sizeof(buf), 0 );
-    for( ii = 0; jj > ii; ii++ )
-    {
-        strlcat_utf8( buf, TR_PATH_DELIMITER_STR, sizeof(buf), 0 );
-        strlcat_utf8( buf, list[ii], sizeof(buf), TR_PATH_DELIMITER );
+        *setme = tr_strndup( EVBUFFER_DATA( buf ), EVBUFFER_LENGTH( buf ) );
+        /* fprintf( stderr, "[%s]\n", *setme ); */
+        evbuffer_free( buf );
+        err = TR_OK;
     }
-    free( list );
 
-    tr_free( *setme );
-    *setme = tr_strdup( buf );
-
-    return TR_OK;
+    return err;
 }
 
 void
@@ -540,39 +431,18 @@ tr_metainfoRemoveSaved( const tr_handle * handle,
 }
 
 static int
-parseFiles( tr_info * inf, tr_benc * name,
-            tr_benc * files, tr_benc * length )
+parseFiles( tr_info * inf, tr_benc * files, tr_benc * length )
 {
     tr_benc * item, * path;
     int ii;
-    char buf[4096];
-
-    if( !tr_bencIsString( name ) )
-    {
-        if( name )
-            tr_err( _( "Invalid metadata entry \"%s\"" ), "name" );
-        else
-            tr_err( _( "Missing metadata entry \"%s\"" ), "name" );
-        return TR_EINVALID;
-    }
-
-    memset( buf, 0, sizeof( buf ) );
-    strlcat_utf8( buf, name->val.s.s, sizeof( buf ), 0 );
-    tr_free( inf->name );
-    inf->name = tr_strdup( buf );
-    if( !inf->name || !*inf->name )
-    {
-        tr_err( _( "Invalid metadata entry \"%s\"" ), "name" );
-        return TR_EINVALID;
-    }
     inf->totalSize = 0;
 
     if( tr_bencIsList( files ) )
     {
         /* Multi-file mode */
         inf->isMultifile = 1;
-        inf->fileCount = files->val.l.count;
-        inf->files     = calloc( inf->fileCount, sizeof( inf->files[0] ) );
+        inf->fileCount   = files->val.l.count;
+        inf->files       = tr_new0( tr_file, inf->fileCount );
 
         if( !inf->files )
             return TR_EINVALID;
@@ -604,21 +474,16 @@ parseFiles( tr_info * inf, tr_benc * name,
     }
     else if( tr_bencIsInt( length ) )
     {
-        char buf[4096];
-
         /* Single-file mode */
         inf->isMultifile = 0;
         inf->fileCount = 1;
-        inf->files     = calloc( 1, sizeof( inf->files[0] ) );
+        inf->files = tr_new0( tr_file, 1 );
 
         if( !inf->files )
             return TR_EINVALID;
 
-        memset( buf, 0, sizeof( buf ) );
-        strlcat_utf8( buf, name->val.s.s, sizeof(buf), TR_PATH_DELIMITER );
         tr_free( inf->files[0].name );
-        inf->files[0].name = tr_strdup( buf );
-
+        inf->files[0].name   = tr_strdup( inf->name );
         inf->files[0].length = length->val.i;
         inf->totalSize      += length->val.i;
     }