source: trunk/libtransmission/utils.c @ 6961

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

(libT) low-hanging fruit discovered from softwareelves' shark profile.

  • Property svn:keywords set to Date Rev Author Id
File size: 27.6 KB
Line 
1/******************************************************************************
2 * $Id: utils.c 6961 2008-10-26 15:39: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, 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    char            * ret;
606    struct evbuffer * evbuf;
607    const char      * element = first_element;
608    va_list           vl;
609
610    evbuf = evbuffer_new( );
611    va_start( vl, first_element );
612
613    while( element )
614    {
615        if( EVBUFFER_LENGTH( evbuf ) )
616            evbuffer_add_printf( evbuf, "%c", TR_PATH_DELIMITER );
617        evbuffer_add_printf( evbuf, "%s", element );
618        element = (const char*) va_arg( vl, const char* );
619    }
620
621    va_end( vl );
622    ret = tr_strndup( EVBUFFER_DATA( evbuf ), EVBUFFER_LENGTH( evbuf ) );
623    evbuffer_free( evbuf );
624    return ret;
625}
626
627/****
628*****
629****/
630
631void*
632tr_memdup( const void * in,
633           int          byteCount )
634{
635    void * out = tr_new( uint8_t, byteCount );
636
637    memcpy( out, in, byteCount );
638    return out;
639}
640
641char*
642tr_strdup( const void * in )
643{
644    return tr_strndup( in, in ? strlen( (const char*)in ) : 0 );
645}
646
647char*
648tr_strndup( const void * in,
649            int          len )
650{
651    char * out = NULL;
652
653    if( len < 0 )
654    {
655        out = tr_strdup( in );
656    }
657    else if( in )
658    {
659        out = tr_malloc( len + 1 );
660        memcpy( out, in, len );
661        out[len] = '\0';
662    }
663
664    return out;
665}
666
667char*
668tr_strdup_printf( const char * fmt,
669                  ... )
670{
671    char *            ret = NULL;
672    struct evbuffer * buf;
673    va_list           ap;
674
675    buf = evbuffer_new( );
676    va_start( ap, fmt );
677
678    if( evbuffer_add_vprintf( buf, fmt, ap ) != -1 )
679        ret = tr_strdup( EVBUFFER_DATA( buf ) );
680
681    va_end( ap );
682    evbuffer_free( buf );
683    return ret;
684}
685
686void*
687tr_malloc( size_t size )
688{
689    return size ? malloc( size ) : NULL;
690}
691
692void*
693tr_malloc0( size_t size )
694{
695    return size ? calloc( 1, size ) : NULL;
696}
697
698void
699tr_free( void * p )
700{
701    if( p )
702        free( p );
703}
704
705const char*
706tr_strerror( int i )
707{
708    const char * ret = strerror( i );
709
710    if( ret == NULL )
711        ret = "Unknown Error";
712    return ret;
713}
714
715/****
716*****
717****/
718
719char*
720tr_strstrip( char * str )
721{
722    if( str != NULL )
723    {
724        size_t pos;
725        size_t len = strlen( str );
726
727        while( len && isspace( str[len - 1] ) )
728            --len;
729
730        str[len] = '\0';
731
732        for( pos = 0; pos < len && isspace( str[pos] ); )
733            ++pos;
734
735        len -= pos;
736        memmove( str, str + pos, len );
737        str[len] = '\0';
738    }
739
740    return str;
741}
742
743/****
744*****
745****/
746
747tr_bitfield*
748tr_bitfieldNew( size_t bitCount )
749{
750    tr_bitfield * ret = tr_new0( tr_bitfield, 1 );
751
752    ret->bitCount = bitCount;
753    ret->byteCount = ( bitCount + 7u ) / 8u;
754    ret->bits = tr_new0( uint8_t, ret->byteCount );
755    return ret;
756}
757
758tr_bitfield*
759tr_bitfieldDup( const tr_bitfield * in )
760{
761    tr_bitfield * ret = tr_new0( tr_bitfield, 1 );
762
763    ret->bitCount = in->bitCount;
764    ret->byteCount = in->byteCount;
765    ret->bits = tr_memdup( in->bits, in->byteCount );
766    return ret;
767}
768
769void
770tr_bitfieldFree( tr_bitfield * bitfield )
771{
772    if( bitfield )
773    {
774        tr_free( bitfield->bits );
775        tr_free( bitfield );
776    }
777}
778
779void
780tr_bitfieldClear( tr_bitfield * bitfield )
781{
782    memset( bitfield->bits, 0, bitfield->byteCount );
783}
784
785int
786tr_bitfieldIsEmpty( const tr_bitfield * bitfield )
787{
788    size_t i;
789
790    for( i = 0; i < bitfield->byteCount; ++i )
791        if( bitfield->bits[i] )
792            return 0;
793
794    return 1;
795}
796
797int
798tr_bitfieldAdd( tr_bitfield * bitfield,
799                size_t        nth )
800{
801    assert( bitfield );
802    assert( bitfield->bits );
803
804    if( nth >= bitfield->bitCount )
805        return -1;
806
807    bitfield->bits[nth >> 3u] |= ( 0x80 >> ( nth & 7u ) );
808    return 0;
809}
810
811/* Sets bit range [begin, end) to 1 */
812int
813tr_bitfieldAddRange( tr_bitfield * b,
814                     size_t        begin,
815                     size_t        end )
816{
817    size_t        sb, eb;
818    unsigned char sm, em;
819
820    end--;
821
822    if( ( end >= b->bitCount ) || ( begin > end ) )
823        return -1;
824
825    sb = begin >> 3;
826    sm = ~( 0xff << ( 8 - ( begin & 7 ) ) );
827    eb = end >> 3;
828    em = 0xff << ( 7 - ( end & 7 ) );
829
830    if( sb == eb )
831    {
832        b->bits[sb] |= ( sm & em );
833    }
834    else
835    {
836        b->bits[sb] |= sm;
837        b->bits[eb] |= em;
838        if( ++sb < eb )
839            memset ( b->bits + sb, 0xff, eb - sb );
840    }
841
842    return 0;
843}
844
845int
846tr_bitfieldRem( tr_bitfield * bitfield,
847                size_t        nth )
848{
849    assert( bitfield );
850    assert( bitfield->bits );
851
852    if( nth >= bitfield->bitCount )
853        return -1;
854
855    bitfield->bits[nth >> 3u] &= ( 0xff7f >> ( nth & 7u ) );
856    return 0;
857}
858
859/* Clears bit range [begin, end) to 0 */
860int
861tr_bitfieldRemRange( tr_bitfield * b,
862                     size_t        begin,
863                     size_t        end )
864{
865    size_t        sb, eb;
866    unsigned char sm, em;
867
868    end--;
869
870    if( ( end >= b->bitCount ) || ( begin > end ) )
871        return -1;
872
873    sb = begin >> 3;
874    sm = 0xff << ( 8 - ( begin & 7 ) );
875    eb = end >> 3;
876    em = ~( 0xff << ( 7 - ( end & 7 ) ) );
877
878    if( sb == eb )
879    {
880        b->bits[sb] &= ( sm | em );
881    }
882    else
883    {
884        b->bits[sb] &= sm;
885        b->bits[eb] &= em;
886        if( ++sb < eb )
887            memset ( b->bits + sb, 0, eb - sb );
888    }
889
890    return 0;
891}
892
893tr_bitfield*
894tr_bitfieldOr( tr_bitfield *       a,
895               const tr_bitfield * b )
896{
897    uint8_t *      ait;
898    const uint8_t *aend, *bit;
899
900    assert( a->bitCount == b->bitCount );
901
902    for( ait = a->bits, bit = b->bits, aend = ait + a->byteCount;
903         ait != aend; )
904        *ait++ |= *bit++;
905
906    return a;
907}
908
909/* set 'a' to all the flags that were in 'a' but not 'b' */
910void
911tr_bitfieldDifference( tr_bitfield *       a,
912                       const tr_bitfield * b )
913{
914    uint8_t *      ait;
915    const uint8_t *aend, *bit;
916
917    assert( a->bitCount == b->bitCount );
918
919    for( ait = a->bits, bit = b->bits, aend = ait + a->byteCount;
920         ait != aend; )
921        *ait++ &= ~( *bit++ );
922}
923
924size_t
925tr_bitfieldCountTrueBits( const tr_bitfield* b )
926{
927    size_t           ret = 0;
928    const uint8_t *  it, *end;
929    static const int trueBitCount[512] = {
930        0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3,
931        4, 2, 3, 3, 4, 3, 4, 4, 5,
932        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
933        5, 3, 4, 4, 5, 4, 5, 5, 6,
934        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
935        5, 3, 4, 4, 5, 4, 5, 5, 6,
936        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
937        6, 4, 5, 5, 6, 5, 6, 6, 7,
938        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
939        5, 3, 4, 4, 5, 4, 5, 5, 6,
940        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
941        6, 4, 5, 5, 6, 5, 6, 6, 7,
942        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
943        6, 4, 5, 5, 6, 5, 6, 6, 7,
944        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
945        7, 5, 6, 6, 7, 6, 7, 7, 8,
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        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
949        6, 4, 5, 5, 6, 5, 6, 6, 7,
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        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
953        7, 5, 6, 6, 7, 6, 7, 7, 8,
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        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
957        7, 5, 6, 6, 7, 6, 7, 7, 8,
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        4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 5, 6, 6, 7, 6, 7, 7,
961        8, 6, 7, 7, 8, 7, 8, 8, 9
962    };
963
964    if( !b )
965        return 0;
966
967    for( it = b->bits, end = it + b->byteCount; it != end; ++it )
968        ret += trueBitCount[*it];
969
970    return ret;
971}
972
973/***
974****
975***/
976
977uint64_t
978tr_date( void )
979{
980    struct timeval tv;
981
982    gettimeofday( &tv, NULL );
983    return (uint64_t) tv.tv_sec * 1000 + ( tv.tv_usec / 1000 );
984}
985
986void
987tr_wait( uint64_t delay_milliseconds )
988{
989#ifdef __BEOS__
990    snooze( 1000 * delay_milliseconds );
991#elif defined( WIN32 )
992    Sleep( (DWORD)delay_milliseconds );
993#else
994    usleep( 1000 * delay_milliseconds );
995#endif
996}
997
998/***
999****
1000***/
1001
1002int
1003tr_snprintf( char *       buf,
1004             size_t       buflen,
1005             const char * fmt,
1006             ... )
1007{
1008    int     len;
1009    va_list args;
1010
1011    va_start( args, fmt );
1012    len = evutil_vsnprintf( buf, buflen, fmt, args );
1013    va_end( args );
1014    return len;
1015}
1016
1017/*
1018 * Copy src to string dst of size siz.  At most siz-1 characters
1019 * will be copied.  Always NUL terminates (unless siz == 0).
1020 * Returns strlen(src); if retval >= siz, truncation occurred.
1021 */
1022size_t
1023tr_strlcpy( char *       dst,
1024            const void * src,
1025            size_t       siz )
1026{
1027#ifdef HAVE_STRLCPY
1028    return strlcpy( dst, src, siz );
1029#else
1030    char *      d = dst;
1031    const char *s = src;
1032    size_t      n = siz;
1033
1034    assert( s );
1035    assert( d );
1036
1037    /* Copy as many bytes as will fit */
1038    if( n != 0 )
1039    {
1040        while( --n != 0 )
1041        {
1042            if( ( *d++ = *s++ ) == '\0' )
1043                break;
1044        }
1045    }
1046
1047    /* Not enough room in dst, add NUL and traverse rest of src */
1048    if( n == 0 )
1049    {
1050        if( siz != 0 )
1051            *d = '\0'; /* NUL-terminate dst */
1052        while( *s++ )
1053            ;
1054    }
1055
1056    return s - (char*)src - 1;  /* count does not include NUL */
1057#endif
1058}
1059
1060/***
1061****
1062***/
1063
1064double
1065tr_getRatio( double numerator,
1066             double denominator )
1067{
1068    double ratio;
1069
1070    if( denominator )
1071        ratio = numerator / denominator;
1072    else if( numerator )
1073        ratio = TR_RATIO_INF;
1074    else
1075        ratio = TR_RATIO_NA;
1076
1077    return ratio;
1078}
1079
1080void
1081tr_sha1_to_hex( char *          out,
1082                const uint8_t * sha1 )
1083{
1084    static const char hex[] = "0123456789abcdef";
1085    int               i;
1086
1087    for( i = 0; i < 20; i++ )
1088    {
1089        unsigned int val = *sha1++;
1090        *out++ = hex[val >> 4];
1091        *out++ = hex[val & 0xf];
1092    }
1093    *out = '\0';
1094}
1095
1096/***
1097****
1098***/
1099
1100int
1101tr_httpIsValidURL( const char * url )
1102{
1103    const char *        c;
1104    static const char * rfc2396_valid_chars =
1105        "abcdefghijklmnopqrstuvwxyz" /* lowalpha */
1106        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* upalpha */
1107        "0123456789"                 /* digit */
1108        "-_.!~*'()"                  /* mark */
1109        ";/?:@&=+$,"                 /* reserved */
1110        "<>#%<\""                    /* delims */
1111        "{}|\\^[]`";                 /* unwise */
1112
1113    if( url == NULL )
1114        return FALSE;
1115
1116    for( c = url; c && *c; ++c )
1117        if( !strchr( rfc2396_valid_chars, *c ) )
1118            return FALSE;
1119
1120    return !tr_httpParseURL( url, -1, NULL, NULL, NULL );
1121}
1122
1123int
1124tr_httpParseURL( const char * url_in,
1125                 int          len,
1126                 char **      setme_host,
1127                 int *        setme_port,
1128                 char **      setme_path )
1129{
1130    int          err;
1131    int          port = 0;
1132    int          n;
1133    char *       tmp;
1134    char *       pch;
1135    const char * protocol = NULL;
1136    const char * host = NULL;
1137    const char * path = NULL;
1138
1139    tmp = tr_strndup( url_in, len );
1140    if( ( pch = strstr( tmp, "://" ) ) )
1141    {
1142        *pch = '\0';
1143        protocol = tmp;
1144        pch += 3;
1145/*fprintf( stderr, "protocol is [%s]... what's left is [%s]\n", protocol, pch
1146  );*/
1147        if( ( n = strcspn( pch, ":/" ) ) )
1148        {
1149            const int havePort = pch[n] == ':';
1150            host = pch;
1151            pch += n;
1152            *pch++ = '\0';
1153/*fprintf( stderr, "host is [%s]... what's left is [%s]\n", host, pch );*/
1154            if( havePort )
1155            {
1156                char * end;
1157                port = strtol( pch, &end, 10 );
1158                pch = end;
1159/*fprintf( stderr, "port is [%d]... what's left is [%s]\n", port, pch );*/
1160            }
1161            path = pch;
1162/*fprintf( stderr, "path is [%s]\n", path );*/
1163        }
1164    }
1165
1166    err = !host || !path || !protocol
1167          || ( strcmp( protocol, "http" ) && strcmp( protocol, "https" ) );
1168
1169    if( !err && !port )
1170    {
1171        if( !strcmp( protocol, "http" ) ) port = 80;
1172        if( !strcmp( protocol, "https" ) ) port = 443;
1173    }
1174
1175    if( !err )
1176    {
1177        if( setme_host ){ ( (char*)host )[-3] = ':'; *setme_host =
1178                              tr_strdup( protocol ); }
1179        if( setme_path ){ ( (char*)path )[-1] = '/'; *setme_path =
1180                              tr_strdup( path - 1 ); }
1181        if( setme_port ) *setme_port = port;
1182    }
1183
1184
1185    tr_free( tmp );
1186    return err;
1187}
1188
1189#include <string.h>
1190#include <openssl/sha.h>
1191#include <openssl/hmac.h>
1192#include <openssl/evp.h>
1193#include <openssl/bio.h>
1194#include <openssl/buffer.h>
1195
1196char *
1197tr_base64_encode( const void * input,
1198                  int          length,
1199                  int *        setme_len )
1200{
1201    char *    ret;
1202    BIO *     b64;
1203    BIO *     bmem;
1204    BUF_MEM * bptr;
1205
1206    if( length < 1 )
1207        length = strlen( input );
1208
1209    bmem = BIO_new( BIO_s_mem( ) );
1210    b64 = BIO_new( BIO_f_base64( ) );
1211    b64 = BIO_push( b64, bmem );
1212    BIO_write( b64, input, length );
1213    (void) BIO_flush( b64 );
1214    BIO_get_mem_ptr( b64, &bptr );
1215    ret = tr_strndup( bptr->data, bptr->length );
1216    if( setme_len )
1217        *setme_len = bptr->length;
1218
1219    BIO_free_all( b64 );
1220    return ret;
1221}
1222
1223char *
1224tr_base64_decode( const void * input,
1225                  int          length,
1226                  int *        setme_len )
1227{
1228    char * ret;
1229    BIO *  b64;
1230    BIO *  bmem;
1231    int    retlen;
1232
1233    if( length < 1 )
1234        length = strlen( input );
1235
1236    ret = tr_new0( char, length );
1237    b64 = BIO_new( BIO_f_base64( ) );
1238    bmem = BIO_new_mem_buf( (unsigned char*)input, length );
1239    bmem = BIO_push( b64, bmem );
1240    retlen = BIO_read( bmem, ret, length );
1241    if( !retlen )
1242    {
1243        /* try again, but with the BIO_FLAGS_BASE64_NO_NL flag */
1244        BIO_free_all( bmem );
1245        b64 = BIO_new( BIO_f_base64( ) );
1246        BIO_set_flags( b64, BIO_FLAGS_BASE64_NO_NL );
1247        bmem = BIO_new_mem_buf( (unsigned char*)input, length );
1248        bmem = BIO_push( b64, bmem );
1249        retlen = BIO_read( bmem, ret, length );
1250    }
1251
1252    if( setme_len )
1253        *setme_len = retlen;
1254
1255    BIO_free_all( bmem );
1256    return ret;
1257}
1258
Note: See TracBrowser for help on using the repository browser.