source: trunk/libtransmission/utils.c @ 6903

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

(libT) a few more win32 portability changes from Spry

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