source: trunk/libtransmission/utils.c @ 6795

Last change on this file since 6795 was 6795, checked in by charles, 14 years ago

run libT, cli, daemon, gtk through the source-code formatter "uncrustify" as promised/threatened

  • Property svn:keywords set to Date Rev Author Id
File size: 28.0 KB
Line 
1/******************************************************************************
2 * $Id: utils.c 6795 2008-09-23 19:11:04Z charles $
3 *
4 * Copyright (c) 2005-2008 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#include <assert.h>
26#include <ctype.h> /* isalpha, tolower */
27#include <errno.h>
28#include <stdarg.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h> /* strerror */
32
33#include <libgen.h> /* basename */
34#include <sys/time.h>
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <unistd.h> /* usleep, stat */
38
39#include "event.h"
40
41#ifdef WIN32
42 #include <windows.h>   /* for Sleep */
43#elif defined( __BEOS__ )
44 #include <kernel/OS.h>
45#endif
46
47#include "transmission.h"
48#include "utils.h"
49#include "platform.h"
50
51static tr_lock *      messageLock = NULL;
52static int            messageLevel = 0;
53static int            messageQueuing = FALSE;
54static tr_msg_list *  messageQueue = NULL;
55static tr_msg_list ** messageQueueTail = &messageQueue;
56
57void
58tr_msgInit( void )
59{
60    if( !messageLock )
61        messageLock = tr_lockNew( );
62}
63
64FILE*
65tr_getLog( void )
66{
67    static int    initialized = FALSE;
68    static FILE * file = NULL;
69
70    if( !initialized )
71    {
72        const char * str = getenv( "TR_DEBUG_FD" );
73        int          fd = 0;
74        if( str && *str )
75            fd = atoi( str );
76        switch( fd )
77        {
78            case 1:
79                file = stdout; break;
80
81            case 2:
82                file = stderr; break;
83
84            default:
85                file = NULL; break;
86        }
87        initialized = TRUE;
88    }
89
90    return file;
91}
92
93void
94tr_setMessageLevel( int level )
95{
96    tr_msgInit( );
97    tr_lockLock( messageLock );
98    messageLevel = MAX( 0, level );
99    tr_lockUnlock( messageLock );
100}
101
102int
103tr_getMessageLevel( void )
104{
105    int ret;
106
107    tr_msgInit( );
108    tr_lockLock( messageLock );
109    ret = messageLevel;
110    tr_lockUnlock( messageLock );
111
112    return ret;
113}
114
115void
116tr_setMessageQueuing( int enabled )
117{
118    tr_msgInit( );
119    tr_lockLock( messageLock );
120    messageQueuing = enabled;
121    tr_lockUnlock( messageLock );
122}
123
124tr_msg_list *
125tr_getQueuedMessages( void )
126{
127    tr_msg_list * ret;
128
129    assert( NULL != messageLock );
130    tr_lockLock( messageLock );
131    ret = messageQueue;
132    messageQueue = NULL;
133    messageQueueTail = &messageQueue;
134    tr_lockUnlock( messageLock );
135
136    return ret;
137}
138
139void
140tr_freeMessageList( tr_msg_list * list )
141{
142    tr_msg_list * next;
143
144    while( NULL != list )
145    {
146        next = list->next;
147        free( list->message );
148        free( list->name );
149        free( list );
150        list = next;
151    }
152}
153
154/**
155***
156**/
157
158char*
159tr_getLogTimeStr( char * buf,
160                  int    buflen )
161{
162    char           tmp[64];
163    time_t         now;
164    struct tm      now_tm;
165    struct timeval tv;
166    int            milliseconds;
167
168    now = time( NULL );
169    gettimeofday( &tv, NULL );
170
171#ifdef WIN32
172    now_tm = *localtime( &now );
173#else
174    localtime_r( &now, &now_tm );
175#endif
176    strftime( tmp, sizeof( tmp ), "%H:%M:%S", &now_tm );
177    milliseconds = (int)( tv.tv_usec / 1000 );
178    tr_snprintf( buf, buflen, "%s.%03d", tmp, milliseconds );
179
180    return buf;
181}
182
183void
184tr_deepLog( const char * file,
185            int          line,
186            const char * name,
187            const char * fmt,
188            ... )
189{
190    FILE * fp = tr_getLog( );
191
192    if( fp )
193    {
194        va_list           args;
195        char              timestr[64];
196        struct evbuffer * buf = evbuffer_new( );
197        char *            myfile = tr_strdup( file );
198
199        evbuffer_add_printf( buf, "[%s] ",
200                            tr_getLogTimeStr( timestr, sizeof( timestr ) ) );
201        if( name )
202            evbuffer_add_printf( buf, "%s ", name );
203        va_start( args, fmt );
204        evbuffer_add_vprintf( buf, fmt, args );
205        va_end( args );
206        evbuffer_add_printf( buf, " (%s:%d)\n", basename( myfile ), line );
207        fwrite( EVBUFFER_DATA( buf ), 1, EVBUFFER_LENGTH( buf ), fp );
208
209        tr_free( myfile );
210        evbuffer_free( buf );
211    }
212}
213
214/***
215****
216***/
217
218void
219tr_msg( const char * file,
220        int          line,
221        int          level,
222        const char * name,
223        const char * fmt,
224        ... )
225{
226    FILE * fp;
227
228    if( messageLock )
229        tr_lockLock( messageLock );
230
231    fp = tr_getLog( );
232
233    if( !messageLevel )
234    {
235        char * env = getenv( "TR_DEBUG" );
236        messageLevel = ( env ? atoi( env ) : 0 ) + 1;
237        messageLevel = MAX( 1, messageLevel );
238    }
239
240    if( messageLevel >= level )
241    {
242        va_list           ap;
243        struct evbuffer * buf = evbuffer_new( );
244
245        /* build the text message */
246        va_start( ap, fmt );
247        evbuffer_add_vprintf( buf, fmt, ap );
248        va_end( ap );
249
250        if( EVBUFFER_LENGTH( buf ) )
251        {
252            if( messageQueuing )
253            {
254                tr_msg_list * newmsg;
255                newmsg = tr_new0( tr_msg_list, 1 );
256                newmsg->level = level;
257                newmsg->when = time( NULL );
258                newmsg->message = tr_strdup( EVBUFFER_DATA( buf ) );
259                newmsg->file = file;
260                newmsg->line = line;
261                newmsg->name = tr_strdup( name );
262
263                *messageQueueTail = newmsg;
264                messageQueueTail = &newmsg->next;
265            }
266            else
267            {
268                if( fp == NULL )
269                    fp = stderr;
270                if( name )
271                    fprintf( fp, "%s: %s\n", name,
272                            (char*)EVBUFFER_DATA( buf ) );
273                else
274                    fprintf( fp, "%s\n", (char*)EVBUFFER_DATA( buf ) );
275                fflush( fp );
276            }
277
278            evbuffer_free( buf );
279        }
280    }
281
282    if( messageLock )
283        tr_lockUnlock( messageLock );
284}
285
286/***
287****
288***/
289
290void
291tr_set_compare( const void * va,
292                size_t aCount,
293                const void * vb,
294                size_t bCount,
295                int compare( const void * a, const void * b ),
296                size_t elementSize,
297                tr_set_func in_a_cb,
298                tr_set_func in_b_cb,
299                tr_set_func in_both_cb,
300                void * userData )
301{
302    const uint8_t * a = (const uint8_t *) va;
303    const uint8_t * b = (const uint8_t *) vb;
304    const uint8_t * aend = a + elementSize * aCount;
305    const uint8_t * bend = b + elementSize * bCount;
306
307    while( a != aend || b != bend )
308    {
309        if( a == aend )
310        {
311            ( *in_b_cb )( (void*)b, userData );
312            b += elementSize;
313        }
314        else if( b == bend )
315        {
316            ( *in_a_cb )( (void*)a, userData );
317            a += elementSize;
318        }
319        else
320        {
321            const int val = ( *compare )( a, b );
322
323            if( !val )
324            {
325                ( *in_both_cb )( (void*)a, userData );
326                a += elementSize;
327                b += elementSize;
328            }
329            else if( val < 0 )
330            {
331                ( *in_a_cb )( (void*)a, userData );
332                a += elementSize;
333            }
334            else if( val > 0 )
335            {
336                ( *in_b_cb )( (void*)b, userData );
337                b += elementSize;
338            }
339        }
340    }
341}
342
343/***
344****
345***/
346
347#ifdef DISABLE_GETTEXT
348
349const char*
350tr_strip_positional_args( const char* str )
351{
352    static size_t bufsize = 0;
353    static char * buf = NULL;
354    const size_t  len = strlen( str );
355    char *        out;
356
357    if( bufsize < len )
358    {
359        bufsize = len * 2;
360        buf = tr_renew( char, buf, bufsize );
361    }
362
363    for( out = buf; *str; ++str )
364    {
365        *out++ = *str;
366        if( ( *str == '%' ) && isdigit( str[1] ) )
367        {
368            const char * tmp = str + 1;
369            while( isdigit( *tmp ) )
370                ++tmp;
371
372            if( *tmp == '$' )
373                str = tmp;
374        }
375    }
376    *out = '\0';
377
378    return buf;
379}
380
381#endif
382
383/**
384***
385**/
386
387struct timeval
388tr_timevalMsec( uint64_t milliseconds )
389{
390    struct timeval ret;
391    const uint64_t microseconds = milliseconds * 1000;
392
393    ret.tv_sec  = microseconds / 1000000;
394    ret.tv_usec = microseconds % 1000000;
395    return ret;
396}
397
398uint8_t *
399tr_loadFile( const char * path,
400             size_t *     size )
401{
402    uint8_t *    buf;
403    struct stat  sb;
404    FILE *       file;
405    const char * err_fmt = _( "Couldn't read \"%1$s\": %2$s" );
406
407    /* try to stat the file */
408    errno = 0;
409    if( stat( path, &sb ) )
410    {
411        tr_dbg( err_fmt, path, tr_strerror( errno ) );
412        return NULL;
413    }
414
415    if( ( sb.st_mode & S_IFMT ) != S_IFREG )
416    {
417        tr_err( err_fmt, path, _( "Not a regular file" ) );
418        return NULL;
419    }
420
421    /* Load the torrent file into our buffer */
422    file = fopen( path, "rb" );
423    if( !file )
424    {
425        tr_err( err_fmt, path, tr_strerror( errno ) );
426        return NULL;
427    }
428    buf = malloc( sb.st_size );
429    if( NULL == buf )
430    {
431        tr_err( err_fmt, path, _( "Memory allocation failed" ) );
432        fclose( file );
433        return NULL;
434    }
435    if( fread( buf, sb.st_size, 1, file ) != 1 )
436    {
437        tr_err( err_fmt, path, tr_strerror( errno ) );
438        fclose( file );
439        free( buf );
440        return NULL;
441    }
442    fclose( file );
443
444    *size = sb.st_size;
445
446    return buf;
447}
448
449int
450tr_mkdir( const char * path,
451          int permissions
452#ifdef WIN32
453                       UNUSED
454#endif
455        )
456{
457#ifdef WIN32
458    if( path && isalpha( path[0] ) && path[1] == ':' && !path[2] )
459        return 0;
460    return mkdir( path );
461#else
462    return mkdir( path, permissions );
463#endif
464}
465
466int
467tr_mkdirp( const char * path_in,
468           int          permissions )
469{
470    char *      path = tr_strdup( path_in );
471    char *      p, * pp;
472    struct stat sb;
473    int         done;
474
475    /* walk past the root */
476    p = path;
477    while( *p == TR_PATH_DELIMITER )
478        ++p;
479
480    pp = p;
481    done = 0;
482    while( ( p =
483                strchr( pp, TR_PATH_DELIMITER ) ) || ( p = strchr( pp, '\0' ) ) )
484    {
485        if( !*p )
486            done = 1;
487        else
488            *p = '\0';
489
490        if( stat( path, &sb ) )
491        {
492            /* Folder doesn't exist yet */
493            if( tr_mkdir( path, permissions ) )
494            {
495                const int err = errno;
496                tr_err( _(
497                           "Couldn't create \"%1$s\": %2$s" ), path,
498                       tr_strerror( err ) );
499                tr_free( path );
500                errno = err;
501                return -1;
502            }
503        }
504        else if( ( sb.st_mode & S_IFMT ) != S_IFDIR )
505        {
506            /* Node exists but isn't a folder */
507            char buf[MAX_PATH_LENGTH];
508            tr_snprintf( buf, sizeof( buf ), _(
509                             "File \"%s\" is in the way" ), path );
510            tr_err( _( "Couldn't create \"%1$s\": %2$s" ), path_in, buf );
511            tr_free( path );
512            errno = ENOTDIR;
513            return -1;
514        }
515
516        if( done )
517            break;
518
519        *p = TR_PATH_DELIMITER;
520        p++;
521        pp = p;
522    }
523
524    tr_free( path );
525    return 0;
526}
527
528void
529tr_buildPath( char *      buf,
530              size_t      buflen,
531              const char *first_element,
532              ... )
533{
534    struct evbuffer * evbuf;
535    const char *      element = first_element;
536    va_list           vl;
537
538    evbuf = evbuffer_new( );
539    va_start( vl, first_element );
540
541    while( element )
542    {
543        if( EVBUFFER_LENGTH( evbuf ) )
544            evbuffer_add_printf( evbuf, "%c", TR_PATH_DELIMITER );
545        evbuffer_add_printf( evbuf, "%s", element );
546        element = (const char*) va_arg( vl, const char* );
547    }
548
549    if( EVBUFFER_LENGTH( evbuf ) )
550        tr_strlcpy( buf, EVBUFFER_DATA( evbuf ), buflen );
551    else
552        *buf = '\0';
553
554    va_end( vl );
555    evbuffer_free( evbuf );
556}
557
558int
559tr_ioErrorFromErrno( int err )
560{
561    switch( err )
562    {
563        case 0:
564            return TR_OK;
565
566        case EACCES:
567        case EROFS:
568            return TR_ERROR_IO_PERMISSIONS;
569
570        case ENOSPC:
571            return TR_ERROR_IO_SPACE;
572
573        case EMFILE:
574            return TR_ERROR_IO_OPEN_FILES;
575
576        case EFBIG:
577            return TR_ERROR_IO_FILE_TOO_BIG;
578
579        default:
580            tr_err( "generic i/o errno from errno: %s", tr_strerror( errno ) );
581            return TR_ERROR_IO_OTHER;
582    }
583}
584
585const char *
586tr_errorString( int code )
587{
588    switch( code )
589    {
590        case TR_OK:
591            return _( "No error" );
592
593        case TR_ERROR:
594            return _( "Unspecified error" );
595
596        case TR_ERROR_ASSERT:
597            return _( "Assert error" );
598
599        case TR_ERROR_IO_PARENT:
600            return _( "Destination folder doesn't exist" );
601
602        case TR_ERROR_IO_PERMISSIONS:
603            return tr_strerror( EACCES );
604
605        case TR_ERROR_IO_SPACE:
606            return tr_strerror( ENOSPC );
607
608        case TR_ERROR_IO_FILE_TOO_BIG:
609            return tr_strerror( EFBIG );
610
611        case TR_ERROR_IO_OPEN_FILES:
612            return tr_strerror( EMFILE );
613
614        case TR_ERROR_IO_DUP_DOWNLOAD:
615            return _(
616                       "A torrent with this name and destination folder already exists." );
617
618        case TR_ERROR_IO_CHECKSUM:
619            return _( "Checksum failed" );
620
621        case TR_ERROR_IO_OTHER:
622            return _( "Unspecified I/O error" );
623
624        case TR_ERROR_TC_ERROR:
625            return _( "Tracker error" );
626
627        case TR_ERROR_TC_WARNING:
628            return _( "Tracker warning" );
629
630        case TR_ERROR_PEER_MESSAGE:
631            return _( "Peer sent a bad message" );
632
633        default:
634            return _( "Unknown error" );
635    }
636}
637
638/****
639*****
640****/
641
642void*
643tr_memdup( const void * in,
644           int          byteCount )
645{
646    void * out = tr_new( uint8_t, byteCount );
647
648    memcpy( out, in, byteCount );
649    return out;
650}
651
652char*
653tr_strdup( const void * in )
654{
655    return tr_strndup( in, in ? strlen( (const char*)in ) : 0 );
656}
657
658char*
659tr_strndup( const void * in,
660            int          len )
661{
662    char * out = NULL;
663
664    if( len < 0 )
665    {
666        out = tr_strdup( in );
667    }
668    else if( in )
669    {
670        out = tr_malloc( len + 1 );
671        memcpy( out, in, len );
672        out[len] = '\0';
673    }
674
675    return out;
676}
677
678char*
679tr_strdup_printf( const char * fmt,
680                  ... )
681{
682    char *            ret = NULL;
683    struct evbuffer * buf;
684    va_list           ap;
685
686    buf = evbuffer_new( );
687    va_start( ap, fmt );
688
689    if( evbuffer_add_vprintf( buf, fmt, ap ) != -1 )
690        ret = tr_strdup( EVBUFFER_DATA( buf ) );
691
692    va_end( ap );
693    evbuffer_free( buf );
694    return ret;
695}
696
697void*
698tr_malloc( size_t size )
699{
700    return size ? malloc( size ) : NULL;
701}
702
703void*
704tr_malloc0( size_t size )
705{
706    void * ret = tr_malloc( size );
707
708    memset( ret, 0, size );
709    return ret;
710}
711
712void
713tr_free( void * p )
714{
715    if( p )
716        free( p );
717}
718
719const char*
720tr_strerror( int i )
721{
722    const char * ret = strerror( i );
723
724    if( ret == NULL )
725        ret = "Unknown Error";
726    return ret;
727}
728
729/****
730*****
731****/
732
733char*
734tr_strstrip( char * str )
735{
736    if( str != NULL )
737    {
738        size_t pos;
739        size_t len = strlen( str );
740
741        while( len && isspace( str[len - 1] ) )
742            --len;
743
744        str[len] = '\0';
745
746        for( pos = 0; pos < len && isspace( str[pos] ); )
747            ++pos;
748
749        len -= pos;
750        memmove( str, str + pos, len );
751        str[len] = '\0';
752    }
753
754    return str;
755}
756
757/****
758*****
759****/
760
761tr_bitfield*
762tr_bitfieldNew( size_t bitCount )
763{
764    tr_bitfield * ret = tr_new0( tr_bitfield, 1 );
765
766    ret->bitCount = bitCount;
767    ret->byteCount = ( bitCount + 7u ) / 8u;
768    ret->bits = tr_new0( uint8_t, ret->byteCount );
769    return ret;
770}
771
772tr_bitfield*
773tr_bitfieldDup( const tr_bitfield * in )
774{
775    tr_bitfield * ret = tr_new0( tr_bitfield, 1 );
776
777    ret->bitCount = in->bitCount;
778    ret->byteCount = in->byteCount;
779    ret->bits = tr_memdup( in->bits, in->byteCount );
780    return ret;
781}
782
783void
784tr_bitfieldFree( tr_bitfield * bitfield )
785{
786    if( bitfield )
787    {
788        tr_free( bitfield->bits );
789        tr_free( bitfield );
790    }
791}
792
793void
794tr_bitfieldClear( tr_bitfield * bitfield )
795{
796    memset( bitfield->bits, 0, bitfield->byteCount );
797}
798
799int
800tr_bitfieldIsEmpty( const tr_bitfield * bitfield )
801{
802    size_t i;
803
804    for( i = 0; i < bitfield->byteCount; ++i )
805        if( bitfield->bits[i] )
806            return 0;
807
808    return 1;
809}
810
811int
812tr_bitfieldAdd( tr_bitfield * bitfield,
813                size_t        nth )
814{
815    assert( bitfield );
816    assert( bitfield->bits );
817
818    if( nth >= bitfield->bitCount )
819        return -1;
820
821    bitfield->bits[nth >> 3u] |= ( 0x80 >> ( nth & 7u ) );
822    return 0;
823}
824
825/* Sets bit range [begin, end) to 1 */
826int
827tr_bitfieldAddRange( tr_bitfield * b,
828                     size_t        begin,
829                     size_t        end )
830{
831    size_t        sb, eb;
832    unsigned char sm, em;
833
834    end--;
835
836    if( ( end >= b->bitCount ) || ( begin > end ) )
837        return -1;
838
839    sb = begin >> 3;
840    sm = ~( 0xff << ( 8 - ( begin & 7 ) ) );
841    eb = end >> 3;
842    em = 0xff << ( 7 - ( end & 7 ) );
843
844    if( sb == eb )
845    {
846        b->bits[sb] |= ( sm & em );
847    }
848    else
849    {
850        b->bits[sb] |= sm;
851        b->bits[eb] |= em;
852        if( ++sb < eb )
853            memset ( b->bits + sb, 0xff, eb - sb );
854    }
855
856    return 0;
857}
858
859int
860tr_bitfieldRem( tr_bitfield * bitfield,
861                size_t        nth )
862{
863    assert( bitfield );
864    assert( bitfield->bits );
865
866    if( nth >= bitfield->bitCount )
867        return -1;
868
869    bitfield->bits[nth >> 3u] &= ( 0xff7f >> ( nth & 7u ) );
870    return 0;
871}
872
873/* Clears bit range [begin, end) to 0 */
874int
875tr_bitfieldRemRange( tr_bitfield * b,
876                     size_t        begin,
877                     size_t        end )
878{
879    size_t        sb, eb;
880    unsigned char sm, em;
881
882    end--;
883
884    if( ( end >= b->bitCount ) || ( begin > end ) )
885        return -1;
886
887    sb = begin >> 3;
888    sm = 0xff << ( 8 - ( begin & 7 ) );
889    eb = end >> 3;
890    em = ~( 0xff << ( 7 - ( end & 7 ) ) );
891
892    if( sb == eb )
893    {
894        b->bits[sb] &= ( sm | em );
895    }
896    else
897    {
898        b->bits[sb] &= sm;
899        b->bits[eb] &= em;
900        if( ++sb < eb )
901            memset ( b->bits + sb, 0, eb - sb );
902    }
903
904    return 0;
905}
906
907tr_bitfield*
908tr_bitfieldOr( tr_bitfield *       a,
909               const tr_bitfield * b )
910{
911    uint8_t *      ait;
912    const uint8_t *aend, *bit;
913
914    assert( a->bitCount == b->bitCount );
915
916    for( ait = a->bits, bit = b->bits, aend = ait + a->byteCount;
917         ait != aend; )
918        *ait++ |= *bit++;
919
920    return a;
921}
922
923/* set 'a' to all the flags that were in 'a' but not 'b' */
924void
925tr_bitfieldDifference( tr_bitfield *       a,
926                       const tr_bitfield * b )
927{
928    uint8_t *      ait;
929    const uint8_t *aend, *bit;
930
931    assert( a->bitCount == b->bitCount );
932
933    for( ait = a->bits, bit = b->bits, aend = ait + a->byteCount;
934         ait != aend; )
935        *ait++ &= ~( *bit++ );
936}
937
938size_t
939tr_bitfieldCountTrueBits( const tr_bitfield* b )
940{
941    size_t           ret = 0;
942    const uint8_t *  it, *end;
943    static const int trueBitCount[512] = {
944        0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3,
945        4, 2, 3, 3, 4, 3, 4, 4, 5,
946        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
947        5, 3, 4, 4, 5, 4, 5, 5, 6,
948        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
949        5, 3, 4, 4, 5, 4, 5, 5, 6,
950        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
951        6, 4, 5, 5, 6, 5, 6, 6, 7,
952        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
953        5, 3, 4, 4, 5, 4, 5, 5, 6,
954        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
955        6, 4, 5, 5, 6, 5, 6, 6, 7,
956        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
957        6, 4, 5, 5, 6, 5, 6, 6, 7,
958        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
959        7, 5, 6, 6, 7, 6, 7, 7, 8,
960        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
961        5, 3, 4, 4, 5, 4, 5, 5, 6,
962        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
963        6, 4, 5, 5, 6, 5, 6, 6, 7,
964        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
965        6, 4, 5, 5, 6, 5, 6, 6, 7,
966        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
967        7, 5, 6, 6, 7, 6, 7, 7, 8,
968        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
969        6, 4, 5, 5, 6, 5, 6, 6, 7,
970        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
971        7, 5, 6, 6, 7, 6, 7, 7, 8,
972        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
973        7, 5, 6, 6, 7, 6, 7, 7, 8,
974        4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 5, 6, 6, 7, 6, 7, 7,
975        8, 6, 7, 7, 8, 7, 8, 8, 9
976    };
977
978    if( !b )
979        return 0;
980
981    for( it = b->bits, end = it + b->byteCount; it != end; ++it )
982        ret += trueBitCount[*it];
983
984    return ret;
985}
986
987/***
988****
989***/
990
991uint64_t
992tr_date( void )
993{
994    struct timeval tv;
995
996    gettimeofday( &tv, NULL );
997    return (uint64_t) tv.tv_sec * 1000 + ( tv.tv_usec / 1000 );
998}
999
1000void
1001tr_wait( uint64_t delay_milliseconds )
1002{
1003#ifdef __BEOS__
1004    snooze( 1000 * delay_milliseconds );
1005#elif defined( WIN32 )
1006    Sleep( (DWORD)delay_milliseconds );
1007#else
1008    usleep( 1000 * delay_milliseconds );
1009#endif
1010}
1011
1012/***
1013****
1014***/
1015
1016int
1017tr_snprintf( char *       buf,
1018             size_t       buflen,
1019             const char * fmt,
1020             ... )
1021{
1022    int     len;
1023    va_list args;
1024
1025    va_start( args, fmt );
1026    len = evutil_vsnprintf( buf, buflen, fmt, args );
1027    va_end( args );
1028    return len;
1029}
1030
1031/*
1032 * Copy src to string dst of size siz.  At most siz-1 characters
1033 * will be copied.  Always NUL terminates (unless siz == 0).
1034 * Returns strlen(src); if retval >= siz, truncation occurred.
1035 */
1036size_t
1037tr_strlcpy( char *       dst,
1038            const void * src,
1039            size_t       siz )
1040{
1041#ifdef HAVE_STRLCPY
1042    return strlcpy( dst, src, siz );
1043#else
1044    char *      d = dst;
1045    const char *s = src;
1046    size_t      n = siz;
1047
1048    assert( s );
1049    assert( d );
1050
1051    /* Copy as many bytes as will fit */
1052    if( n != 0 )
1053    {
1054        while( --n != 0 )
1055        {
1056            if( ( *d++ = *s++ ) == '\0' )
1057                break;
1058        }
1059    }
1060
1061    /* Not enough room in dst, add NUL and traverse rest of src */
1062    if( n == 0 )
1063    {
1064        if( siz != 0 )
1065            *d = '\0'; /* NUL-terminate dst */
1066        while( *s++ )
1067            ;
1068    }
1069
1070    return s - (char*)src - 1;  /* count does not include NUL */
1071#endif
1072}
1073
1074/***
1075****
1076***/
1077
1078double
1079tr_getRatio( double numerator,
1080             double denominator )
1081{
1082    double ratio;
1083
1084    if( denominator )
1085        ratio = numerator / denominator;
1086    else if( numerator )
1087        ratio = TR_RATIO_INF;
1088    else
1089        ratio = TR_RATIO_NA;
1090
1091    return ratio;
1092}
1093
1094void
1095tr_sha1_to_hex( char *          out,
1096                const uint8_t * sha1 )
1097{
1098    static const char hex[] = "0123456789abcdef";
1099    int               i;
1100
1101    for( i = 0; i < 20; i++ )
1102    {
1103        unsigned int val = *sha1++;
1104        *out++ = hex[val >> 4];
1105        *out++ = hex[val & 0xf];
1106    }
1107    *out = '\0';
1108}
1109
1110/***
1111****
1112***/
1113
1114int
1115tr_httpIsValidURL( const char * url )
1116{
1117    const char *        c;
1118    static const char * rfc2396_valid_chars =
1119        "abcdefghijklmnopqrstuvwxyz" /* lowalpha */
1120        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* upalpha */
1121        "0123456789"                 /* digit */
1122        "-_.!~*'()"                  /* mark */
1123        ";/?:@&=+$,"                 /* reserved */
1124        "<>#%<\""                    /* delims */
1125        "{}|\\^[]`";                 /* unwise */
1126
1127    if( url == NULL )
1128        return FALSE;
1129
1130    for( c = url; c && *c; ++c )
1131        if( !strchr( rfc2396_valid_chars, *c ) )
1132            return FALSE;
1133
1134    return !tr_httpParseURL( url, -1, NULL, NULL, NULL );
1135}
1136
1137int
1138tr_httpParseURL( const char * url_in,
1139                 int          len,
1140                 char **      setme_host,
1141                 int *        setme_port,
1142                 char **      setme_path )
1143{
1144    int          err;
1145    int          port = 0;
1146    int          n;
1147    char *       tmp;
1148    char *       pch;
1149    const char * protocol = NULL;
1150    const char * host = NULL;
1151    const char * path = NULL;
1152
1153    tmp = tr_strndup( url_in, len );
1154    if( ( pch = strstr( tmp, "://" ) ) )
1155    {
1156        *pch = '\0';
1157        protocol = tmp;
1158        pch += 3;
1159/*fprintf( stderr, "protocol is [%s]... what's left is [%s]\n", protocol, pch
1160  );*/
1161        if( ( n = strcspn( pch, ":/" ) ) )
1162        {
1163            const int havePort = pch[n] == ':';
1164            host = pch;
1165            pch += n;
1166            *pch++ = '\0';
1167/*fprintf( stderr, "host is [%s]... what's left is [%s]\n", host, pch );*/
1168            if( havePort )
1169            {
1170                char * end;
1171                port = strtol( pch, &end, 10 );
1172                pch = end;
1173/*fprintf( stderr, "port is [%d]... what's left is [%s]\n", port, pch );*/
1174            }
1175            path = pch;
1176/*fprintf( stderr, "path is [%s]\n", path );*/
1177        }
1178    }
1179
1180    err = !host || !path || !protocol
1181          || ( strcmp( protocol, "http" ) && strcmp( protocol, "https" ) );
1182
1183    if( !err && !port )
1184    {
1185        if( !strcmp( protocol, "http" ) ) port = 80;
1186        if( !strcmp( protocol, "https" ) ) port = 443;
1187    }
1188
1189    if( !err )
1190    {
1191        if( setme_host ){ ( (char*)host )[-3] = ':'; *setme_host =
1192                              tr_strdup( protocol ); }
1193        if( setme_path ){ ( (char*)path )[-1] = '/'; *setme_path =
1194                              tr_strdup( path - 1 ); }
1195        if( setme_port ) *setme_port = port;
1196    }
1197
1198
1199    tr_free( tmp );
1200    return err;
1201}
1202
1203#include <string.h>
1204#include <openssl/sha.h>
1205#include <openssl/hmac.h>
1206#include <openssl/evp.h>
1207#include <openssl/bio.h>
1208#include <openssl/buffer.h>
1209
1210char *
1211tr_base64_encode( const void * input,
1212                  int          length,
1213                  int *        setme_len )
1214{
1215    char *    ret;
1216    BIO *     b64;
1217    BIO *     bmem;
1218    BUF_MEM * bptr;
1219
1220    if( length < 1 )
1221        length = strlen( input );
1222
1223    bmem = BIO_new( BIO_s_mem( ) );
1224    b64 = BIO_new( BIO_f_base64( ) );
1225    b64 = BIO_push( b64, bmem );
1226    BIO_write( b64, input, length );
1227    (void) BIO_flush( b64 );
1228    BIO_get_mem_ptr( b64, &bptr );
1229    ret = tr_strndup( bptr->data, bptr->length );
1230    if( setme_len )
1231        *setme_len = bptr->length;
1232
1233    BIO_free_all( b64 );
1234    return ret;
1235}
1236
1237char *
1238tr_base64_decode( const void * input,
1239                  int          length,
1240                  int *        setme_len )
1241{
1242    char * ret;
1243    BIO *  b64;
1244    BIO *  bmem;
1245    int    retlen;
1246
1247    if( length < 1 )
1248        length = strlen( input );
1249
1250    ret = tr_new0( char, length );
1251    b64 = BIO_new( BIO_f_base64( ) );
1252    bmem = BIO_new_mem_buf( (unsigned char*)input, length );
1253    bmem = BIO_push( b64, bmem );
1254    retlen = BIO_read( bmem, ret, length );
1255    if( !retlen )
1256    {
1257        /* try again, but with the BIO_FLAGS_BASE64_NO_NL flag */
1258        BIO_free_all( bmem );
1259        b64 = BIO_new( BIO_f_base64( ) );
1260        BIO_set_flags( b64, BIO_FLAGS_BASE64_NO_NL );
1261        bmem = BIO_new_mem_buf( (unsigned char*)input, length );
1262        bmem = BIO_push( b64, bmem );
1263        retlen = BIO_read( bmem, ret, length );
1264    }
1265
1266    if( setme_len )
1267        *setme_len = retlen;
1268
1269    BIO_free_all( bmem );
1270    return ret;
1271}
1272
Note: See TracBrowser for help on using the repository browser.