source: trunk/libtransmission/utils.c @ 6924

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

further win32 portability fixes from Spry

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