source: trunk/libtransmission/utils.c @ 6981

Last change on this file since 6981 was 6981, checked in by charles, 13 years ago

(libT) one more low-hanging fruit from softwareelves' Shark reports: simplify tr_buildPath() to shave off another few %

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