source: trunk/libtransmission/utils.c @ 6896

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

have tr_buildPath() allocate memory from the heap rather than using an input buffer

  • Property svn:keywords set to Date Rev Author Id
File size: 26.5 KB
Line 
1/******************************************************************************
2 * $Id: utils.c 6896 2008-10-14 03:03:29Z 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 *            myfile = tr_strdup( 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", basename( myfile ), line );
208        (void) fwrite( EVBUFFER_DATA( buf ), 1, EVBUFFER_LENGTH( buf ), fp );
209
210        tr_free( myfile );
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( char  * buffer,
460           int     maxlen )
461{
462#ifdef WIN32
463    return _getcwd( buffer, maxlen );
464#else
465    return getcwd( buffer, maxlen );
466#endif
467}
468
469int
470tr_mkdir( const char * path,
471          int permissions
472#ifdef WIN32
473                       UNUSED
474#endif
475        )
476{
477#ifdef WIN32
478    if( path && isalpha( path[0] ) && path[1] == ':' && !path[2] )
479        return 0;
480    return mkdir( path );
481#else
482    return mkdir( path, permissions );
483#endif
484}
485
486int
487tr_mkdirp( const char * path_in,
488           int          permissions )
489{
490    char *      path = tr_strdup( path_in );
491    char *      p, * pp;
492    struct stat sb;
493    int         done;
494
495    /* walk past the root */
496    p = path;
497    while( *p == TR_PATH_DELIMITER )
498        ++p;
499
500    pp = p;
501    done = 0;
502    while( ( p =
503                strchr( pp, TR_PATH_DELIMITER ) ) || ( p = strchr( pp, '\0' ) ) )
504    {
505        if( !*p )
506            done = 1;
507        else
508            *p = '\0';
509
510        if( stat( path, &sb ) )
511        {
512            /* Folder doesn't exist yet */
513            if( tr_mkdir( path, permissions ) )
514            {
515                const int err = errno;
516                tr_err( _(
517                           "Couldn't create \"%1$s\": %2$s" ), path,
518                       tr_strerror( err ) );
519                tr_free( path );
520                errno = err;
521                return -1;
522            }
523        }
524        else if( ( sb.st_mode & S_IFMT ) != S_IFDIR )
525        {
526            /* Node exists but isn't a folder */
527            char buf[MAX_PATH_LENGTH];
528            tr_snprintf( buf, sizeof( buf ), _(
529                             "File \"%s\" is in the way" ), path );
530            tr_err( _( "Couldn't create \"%1$s\": %2$s" ), path_in, buf );
531            tr_free( path );
532            errno = ENOTDIR;
533            return -1;
534        }
535
536        if( done )
537            break;
538
539        *p = TR_PATH_DELIMITER;
540        p++;
541        pp = p;
542    }
543
544    tr_free( path );
545    return 0;
546}
547
548char*
549tr_buildPath( const char *first_element, ... )
550{
551    char            * ret;
552    struct evbuffer * evbuf;
553    const char      * element = first_element;
554    va_list           vl;
555
556    evbuf = evbuffer_new( );
557    va_start( vl, first_element );
558
559    while( element )
560    {
561        if( EVBUFFER_LENGTH( evbuf ) )
562            evbuffer_add_printf( evbuf, "%c", TR_PATH_DELIMITER );
563        evbuffer_add_printf( evbuf, "%s", element );
564        element = (const char*) va_arg( vl, const char* );
565    }
566
567    va_end( vl );
568    ret = tr_strndup( EVBUFFER_DATA( evbuf ), EVBUFFER_LENGTH( evbuf ) );
569    evbuffer_free( evbuf );
570    return ret;
571}
572
573/****
574*****
575****/
576
577void*
578tr_memdup( const void * in,
579           int          byteCount )
580{
581    void * out = tr_new( uint8_t, byteCount );
582
583    memcpy( out, in, byteCount );
584    return out;
585}
586
587char*
588tr_strdup( const void * in )
589{
590    return tr_strndup( in, in ? strlen( (const char*)in ) : 0 );
591}
592
593char*
594tr_strndup( const void * in,
595            int          len )
596{
597    char * out = NULL;
598
599    if( len < 0 )
600    {
601        out = tr_strdup( in );
602    }
603    else if( in )
604    {
605        out = tr_malloc( len + 1 );
606        memcpy( out, in, len );
607        out[len] = '\0';
608    }
609
610    return out;
611}
612
613char*
614tr_strdup_printf( const char * fmt,
615                  ... )
616{
617    char *            ret = NULL;
618    struct evbuffer * buf;
619    va_list           ap;
620
621    buf = evbuffer_new( );
622    va_start( ap, fmt );
623
624    if( evbuffer_add_vprintf( buf, fmt, ap ) != -1 )
625        ret = tr_strdup( EVBUFFER_DATA( buf ) );
626
627    va_end( ap );
628    evbuffer_free( buf );
629    return ret;
630}
631
632void*
633tr_malloc( size_t size )
634{
635    return size ? malloc( size ) : NULL;
636}
637
638void*
639tr_malloc0( size_t size )
640{
641    return size ? calloc( 1, size ) : NULL;
642}
643
644void
645tr_free( void * p )
646{
647    if( p )
648        free( p );
649}
650
651const char*
652tr_strerror( int i )
653{
654    const char * ret = strerror( i );
655
656    if( ret == NULL )
657        ret = "Unknown Error";
658    return ret;
659}
660
661/****
662*****
663****/
664
665char*
666tr_strstrip( char * str )
667{
668    if( str != NULL )
669    {
670        size_t pos;
671        size_t len = strlen( str );
672
673        while( len && isspace( str[len - 1] ) )
674            --len;
675
676        str[len] = '\0';
677
678        for( pos = 0; pos < len && isspace( str[pos] ); )
679            ++pos;
680
681        len -= pos;
682        memmove( str, str + pos, len );
683        str[len] = '\0';
684    }
685
686    return str;
687}
688
689/****
690*****
691****/
692
693tr_bitfield*
694tr_bitfieldNew( size_t bitCount )
695{
696    tr_bitfield * ret = tr_new0( tr_bitfield, 1 );
697
698    ret->bitCount = bitCount;
699    ret->byteCount = ( bitCount + 7u ) / 8u;
700    ret->bits = tr_new0( uint8_t, ret->byteCount );
701    return ret;
702}
703
704tr_bitfield*
705tr_bitfieldDup( const tr_bitfield * in )
706{
707    tr_bitfield * ret = tr_new0( tr_bitfield, 1 );
708
709    ret->bitCount = in->bitCount;
710    ret->byteCount = in->byteCount;
711    ret->bits = tr_memdup( in->bits, in->byteCount );
712    return ret;
713}
714
715void
716tr_bitfieldFree( tr_bitfield * bitfield )
717{
718    if( bitfield )
719    {
720        tr_free( bitfield->bits );
721        tr_free( bitfield );
722    }
723}
724
725void
726tr_bitfieldClear( tr_bitfield * bitfield )
727{
728    memset( bitfield->bits, 0, bitfield->byteCount );
729}
730
731int
732tr_bitfieldIsEmpty( const tr_bitfield * bitfield )
733{
734    size_t i;
735
736    for( i = 0; i < bitfield->byteCount; ++i )
737        if( bitfield->bits[i] )
738            return 0;
739
740    return 1;
741}
742
743int
744tr_bitfieldAdd( tr_bitfield * bitfield,
745                size_t        nth )
746{
747    assert( bitfield );
748    assert( bitfield->bits );
749
750    if( nth >= bitfield->bitCount )
751        return -1;
752
753    bitfield->bits[nth >> 3u] |= ( 0x80 >> ( nth & 7u ) );
754    return 0;
755}
756
757/* Sets bit range [begin, end) to 1 */
758int
759tr_bitfieldAddRange( tr_bitfield * b,
760                     size_t        begin,
761                     size_t        end )
762{
763    size_t        sb, eb;
764    unsigned char sm, em;
765
766    end--;
767
768    if( ( end >= b->bitCount ) || ( begin > end ) )
769        return -1;
770
771    sb = begin >> 3;
772    sm = ~( 0xff << ( 8 - ( begin & 7 ) ) );
773    eb = end >> 3;
774    em = 0xff << ( 7 - ( end & 7 ) );
775
776    if( sb == eb )
777    {
778        b->bits[sb] |= ( sm & em );
779    }
780    else
781    {
782        b->bits[sb] |= sm;
783        b->bits[eb] |= em;
784        if( ++sb < eb )
785            memset ( b->bits + sb, 0xff, eb - sb );
786    }
787
788    return 0;
789}
790
791int
792tr_bitfieldRem( tr_bitfield * bitfield,
793                size_t        nth )
794{
795    assert( bitfield );
796    assert( bitfield->bits );
797
798    if( nth >= bitfield->bitCount )
799        return -1;
800
801    bitfield->bits[nth >> 3u] &= ( 0xff7f >> ( nth & 7u ) );
802    return 0;
803}
804
805/* Clears bit range [begin, end) to 0 */
806int
807tr_bitfieldRemRange( tr_bitfield * b,
808                     size_t        begin,
809                     size_t        end )
810{
811    size_t        sb, eb;
812    unsigned char sm, em;
813
814    end--;
815
816    if( ( end >= b->bitCount ) || ( begin > end ) )
817        return -1;
818
819    sb = begin >> 3;
820    sm = 0xff << ( 8 - ( begin & 7 ) );
821    eb = end >> 3;
822    em = ~( 0xff << ( 7 - ( end & 7 ) ) );
823
824    if( sb == eb )
825    {
826        b->bits[sb] &= ( sm | em );
827    }
828    else
829    {
830        b->bits[sb] &= sm;
831        b->bits[eb] &= em;
832        if( ++sb < eb )
833            memset ( b->bits + sb, 0, eb - sb );
834    }
835
836    return 0;
837}
838
839tr_bitfield*
840tr_bitfieldOr( tr_bitfield *       a,
841               const tr_bitfield * b )
842{
843    uint8_t *      ait;
844    const uint8_t *aend, *bit;
845
846    assert( a->bitCount == b->bitCount );
847
848    for( ait = a->bits, bit = b->bits, aend = ait + a->byteCount;
849         ait != aend; )
850        *ait++ |= *bit++;
851
852    return a;
853}
854
855/* set 'a' to all the flags that were in 'a' but not 'b' */
856void
857tr_bitfieldDifference( tr_bitfield *       a,
858                       const tr_bitfield * b )
859{
860    uint8_t *      ait;
861    const uint8_t *aend, *bit;
862
863    assert( a->bitCount == b->bitCount );
864
865    for( ait = a->bits, bit = b->bits, aend = ait + a->byteCount;
866         ait != aend; )
867        *ait++ &= ~( *bit++ );
868}
869
870size_t
871tr_bitfieldCountTrueBits( const tr_bitfield* b )
872{
873    size_t           ret = 0;
874    const uint8_t *  it, *end;
875    static const int trueBitCount[512] = {
876        0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3,
877        4, 2, 3, 3, 4, 3, 4, 4, 5,
878        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
879        5, 3, 4, 4, 5, 4, 5, 5, 6,
880        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
881        5, 3, 4, 4, 5, 4, 5, 5, 6,
882        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
883        6, 4, 5, 5, 6, 5, 6, 6, 7,
884        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
885        5, 3, 4, 4, 5, 4, 5, 5, 6,
886        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
887        6, 4, 5, 5, 6, 5, 6, 6, 7,
888        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
889        6, 4, 5, 5, 6, 5, 6, 6, 7,
890        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
891        7, 5, 6, 6, 7, 6, 7, 7, 8,
892        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
893        5, 3, 4, 4, 5, 4, 5, 5, 6,
894        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
895        6, 4, 5, 5, 6, 5, 6, 6, 7,
896        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
897        6, 4, 5, 5, 6, 5, 6, 6, 7,
898        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
899        7, 5, 6, 6, 7, 6, 7, 7, 8,
900        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
901        6, 4, 5, 5, 6, 5, 6, 6, 7,
902        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
903        7, 5, 6, 6, 7, 6, 7, 7, 8,
904        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
905        7, 5, 6, 6, 7, 6, 7, 7, 8,
906        4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 5, 6, 6, 7, 6, 7, 7,
907        8, 6, 7, 7, 8, 7, 8, 8, 9
908    };
909
910    if( !b )
911        return 0;
912
913    for( it = b->bits, end = it + b->byteCount; it != end; ++it )
914        ret += trueBitCount[*it];
915
916    return ret;
917}
918
919/***
920****
921***/
922
923uint64_t
924tr_date( void )
925{
926    struct timeval tv;
927
928    gettimeofday( &tv, NULL );
929    return (uint64_t) tv.tv_sec * 1000 + ( tv.tv_usec / 1000 );
930}
931
932void
933tr_wait( uint64_t delay_milliseconds )
934{
935#ifdef __BEOS__
936    snooze( 1000 * delay_milliseconds );
937#elif defined( WIN32 )
938    Sleep( (DWORD)delay_milliseconds );
939#else
940    usleep( 1000 * delay_milliseconds );
941#endif
942}
943
944/***
945****
946***/
947
948int
949tr_snprintf( char *       buf,
950             size_t       buflen,
951             const char * fmt,
952             ... )
953{
954    int     len;
955    va_list args;
956
957    va_start( args, fmt );
958    len = evutil_vsnprintf( buf, buflen, fmt, args );
959    va_end( args );
960    return len;
961}
962
963/*
964 * Copy src to string dst of size siz.  At most siz-1 characters
965 * will be copied.  Always NUL terminates (unless siz == 0).
966 * Returns strlen(src); if retval >= siz, truncation occurred.
967 */
968size_t
969tr_strlcpy( char *       dst,
970            const void * src,
971            size_t       siz )
972{
973#ifdef HAVE_STRLCPY
974    return strlcpy( dst, src, siz );
975#else
976    char *      d = dst;
977    const char *s = src;
978    size_t      n = siz;
979
980    assert( s );
981    assert( d );
982
983    /* Copy as many bytes as will fit */
984    if( n != 0 )
985    {
986        while( --n != 0 )
987        {
988            if( ( *d++ = *s++ ) == '\0' )
989                break;
990        }
991    }
992
993    /* Not enough room in dst, add NUL and traverse rest of src */
994    if( n == 0 )
995    {
996        if( siz != 0 )
997            *d = '\0'; /* NUL-terminate dst */
998        while( *s++ )
999            ;
1000    }
1001
1002    return s - (char*)src - 1;  /* count does not include NUL */
1003#endif
1004}
1005
1006/***
1007****
1008***/
1009
1010double
1011tr_getRatio( double numerator,
1012             double denominator )
1013{
1014    double ratio;
1015
1016    if( denominator )
1017        ratio = numerator / denominator;
1018    else if( numerator )
1019        ratio = TR_RATIO_INF;
1020    else
1021        ratio = TR_RATIO_NA;
1022
1023    return ratio;
1024}
1025
1026void
1027tr_sha1_to_hex( char *          out,
1028                const uint8_t * sha1 )
1029{
1030    static const char hex[] = "0123456789abcdef";
1031    int               i;
1032
1033    for( i = 0; i < 20; i++ )
1034    {
1035        unsigned int val = *sha1++;
1036        *out++ = hex[val >> 4];
1037        *out++ = hex[val & 0xf];
1038    }
1039    *out = '\0';
1040}
1041
1042/***
1043****
1044***/
1045
1046int
1047tr_httpIsValidURL( const char * url )
1048{
1049    const char *        c;
1050    static const char * rfc2396_valid_chars =
1051        "abcdefghijklmnopqrstuvwxyz" /* lowalpha */
1052        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* upalpha */
1053        "0123456789"                 /* digit */
1054        "-_.!~*'()"                  /* mark */
1055        ";/?:@&=+$,"                 /* reserved */
1056        "<>#%<\""                    /* delims */
1057        "{}|\\^[]`";                 /* unwise */
1058
1059    if( url == NULL )
1060        return FALSE;
1061
1062    for( c = url; c && *c; ++c )
1063        if( !strchr( rfc2396_valid_chars, *c ) )
1064            return FALSE;
1065
1066    return !tr_httpParseURL( url, -1, NULL, NULL, NULL );
1067}
1068
1069int
1070tr_httpParseURL( const char * url_in,
1071                 int          len,
1072                 char **      setme_host,
1073                 int *        setme_port,
1074                 char **      setme_path )
1075{
1076    int          err;
1077    int          port = 0;
1078    int          n;
1079    char *       tmp;
1080    char *       pch;
1081    const char * protocol = NULL;
1082    const char * host = NULL;
1083    const char * path = NULL;
1084
1085    tmp = tr_strndup( url_in, len );
1086    if( ( pch = strstr( tmp, "://" ) ) )
1087    {
1088        *pch = '\0';
1089        protocol = tmp;
1090        pch += 3;
1091/*fprintf( stderr, "protocol is [%s]... what's left is [%s]\n", protocol, pch
1092  );*/
1093        if( ( n = strcspn( pch, ":/" ) ) )
1094        {
1095            const int havePort = pch[n] == ':';
1096            host = pch;
1097            pch += n;
1098            *pch++ = '\0';
1099/*fprintf( stderr, "host is [%s]... what's left is [%s]\n", host, pch );*/
1100            if( havePort )
1101            {
1102                char * end;
1103                port = strtol( pch, &end, 10 );
1104                pch = end;
1105/*fprintf( stderr, "port is [%d]... what's left is [%s]\n", port, pch );*/
1106            }
1107            path = pch;
1108/*fprintf( stderr, "path is [%s]\n", path );*/
1109        }
1110    }
1111
1112    err = !host || !path || !protocol
1113          || ( strcmp( protocol, "http" ) && strcmp( protocol, "https" ) );
1114
1115    if( !err && !port )
1116    {
1117        if( !strcmp( protocol, "http" ) ) port = 80;
1118        if( !strcmp( protocol, "https" ) ) port = 443;
1119    }
1120
1121    if( !err )
1122    {
1123        if( setme_host ){ ( (char*)host )[-3] = ':'; *setme_host =
1124                              tr_strdup( protocol ); }
1125        if( setme_path ){ ( (char*)path )[-1] = '/'; *setme_path =
1126                              tr_strdup( path - 1 ); }
1127        if( setme_port ) *setme_port = port;
1128    }
1129
1130
1131    tr_free( tmp );
1132    return err;
1133}
1134
1135#include <string.h>
1136#include <openssl/sha.h>
1137#include <openssl/hmac.h>
1138#include <openssl/evp.h>
1139#include <openssl/bio.h>
1140#include <openssl/buffer.h>
1141
1142char *
1143tr_base64_encode( const void * input,
1144                  int          length,
1145                  int *        setme_len )
1146{
1147    char *    ret;
1148    BIO *     b64;
1149    BIO *     bmem;
1150    BUF_MEM * bptr;
1151
1152    if( length < 1 )
1153        length = strlen( input );
1154
1155    bmem = BIO_new( BIO_s_mem( ) );
1156    b64 = BIO_new( BIO_f_base64( ) );
1157    b64 = BIO_push( b64, bmem );
1158    BIO_write( b64, input, length );
1159    (void) BIO_flush( b64 );
1160    BIO_get_mem_ptr( b64, &bptr );
1161    ret = tr_strndup( bptr->data, bptr->length );
1162    if( setme_len )
1163        *setme_len = bptr->length;
1164
1165    BIO_free_all( b64 );
1166    return ret;
1167}
1168
1169char *
1170tr_base64_decode( const void * input,
1171                  int          length,
1172                  int *        setme_len )
1173{
1174    char * ret;
1175    BIO *  b64;
1176    BIO *  bmem;
1177    int    retlen;
1178
1179    if( length < 1 )
1180        length = strlen( input );
1181
1182    ret = tr_new0( char, length );
1183    b64 = BIO_new( BIO_f_base64( ) );
1184    bmem = BIO_new_mem_buf( (unsigned char*)input, length );
1185    bmem = BIO_push( b64, bmem );
1186    retlen = BIO_read( bmem, ret, length );
1187    if( !retlen )
1188    {
1189        /* try again, but with the BIO_FLAGS_BASE64_NO_NL flag */
1190        BIO_free_all( bmem );
1191        b64 = BIO_new( BIO_f_base64( ) );
1192        BIO_set_flags( b64, BIO_FLAGS_BASE64_NO_NL );
1193        bmem = BIO_new_mem_buf( (unsigned char*)input, length );
1194        bmem = BIO_push( b64, bmem );
1195        retlen = BIO_read( bmem, ret, length );
1196    }
1197
1198    if( setme_len )
1199        *setme_len = retlen;
1200
1201    BIO_free_all( bmem );
1202    return ret;
1203}
1204
Note: See TracBrowser for help on using the repository browser.