source: trunk/libtransmission/utils.c @ 6897

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

make MAX_PATH_LENGTH private to libtransmission. add tr_dirname() and tr_basename() utility / portability wrappers

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