source: trunk/libtransmission/utils.c @ 7656

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

(trunk libT) #1675: better utf8 validation of metainfo name, creator, and comment fields

  • Property svn:keywords set to Date Rev Author Id
File size: 28.9 KB
Line 
1/*
2 * This file Copyright (C) 2009 Charles Kerr <charles@transmissionbt.com>
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: utils.c 7656 2009-01-10 22:48:58Z charles $
11 */
12
13#include <assert.h>
14#include <ctype.h> /* isalpha, tolower */
15#include <errno.h>
16#include <stdarg.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h> /* strerror, memset */
20
21#include <libgen.h> /* basename */
22#include <sys/time.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <unistd.h> /* usleep, stat, getcwd */
26
27#include "event.h"
28
29#ifdef WIN32
30 #include <direct.h> /* _getcwd */
31 #include <windows.h> /* Sleep */
32#endif
33
34#include "transmission.h"
35#include "ConvertUTF.h"
36#include "list.h"
37#include "utils.h"
38#include "platform.h"
39
40static tr_lock *      messageLock = NULL;
41static int            messageLevel = 0;
42static tr_bool        messageQueuing = FALSE;
43static tr_msg_list *  messageQueue = NULL;
44static tr_msg_list ** messageQueueTail = &messageQueue;
45
46#ifndef WIN32
47    /* make null versions of these win32 functions */
48    static int IsDebuggerPresent( void ) { return FALSE; }
49    static void OutputDebugString( const void * unused UNUSED ) { }
50#endif
51
52static void
53tr_msgInit( void )
54{
55    static tr_bool initialized = FALSE;
56
57    if( !initialized )
58    {
59        char * env = getenv( "TR_DEBUG" );
60        messageLevel = ( env ? atoi( env ) : 0 ) + 1;
61        messageLevel = MAX( 1, messageLevel );
62
63        messageLock = tr_lockNew( );
64
65        initialized = TRUE;
66    }
67}
68
69FILE*
70tr_getLog( void )
71{
72    static int    initialized = FALSE;
73    static FILE * file = NULL;
74
75    if( !initialized )
76    {
77        const char * str = getenv( "TR_DEBUG_FD" );
78        int          fd = 0;
79        if( str && *str )
80            fd = atoi( str );
81        switch( fd )
82        {
83            case 1:
84                file = stdout; break;
85
86            case 2:
87                file = stderr; break;
88
89            default:
90                file = NULL; break;
91        }
92        initialized = TRUE;
93    }
94
95    return file;
96}
97
98void
99tr_setMessageLevel( int level )
100{
101    tr_msgInit( );
102    tr_lockLock( messageLock );
103
104    messageLevel = MAX( 0, level );
105
106    tr_lockUnlock( messageLock );
107}
108
109int
110tr_getMessageLevel( void )
111{
112    int ret;
113    tr_msgInit( );
114    tr_lockLock( messageLock );
115
116    ret = messageLevel;
117
118    tr_lockUnlock( messageLock );
119    return ret;
120}
121
122void
123tr_setMessageQueuing( tr_bool enabled )
124{
125    tr_msgInit( );
126    tr_lockLock( messageLock );
127
128    messageQueuing = enabled;
129
130    tr_lockUnlock( messageLock );
131}
132
133tr_bool
134tr_getMessageQueuing( void )
135{
136    int ret;
137    tr_msgInit( );
138    tr_lockLock( messageLock );
139
140    ret = messageQueuing;
141
142    tr_lockUnlock( messageLock );
143    return ret;
144}
145
146tr_msg_list *
147tr_getQueuedMessages( void )
148{
149    tr_msg_list * ret;
150    tr_msgInit( );
151    tr_lockLock( messageLock );
152
153    ret = messageQueue;
154    messageQueue = NULL;
155    messageQueueTail = &messageQueue;
156
157    tr_lockUnlock( messageLock );
158    return ret;
159}
160
161void
162tr_freeMessageList( tr_msg_list * list )
163{
164    tr_msg_list * next;
165
166    while( NULL != list )
167    {
168        next = list->next;
169        free( list->message );
170        free( list->name );
171        free( list );
172        list = next;
173    }
174}
175
176/**
177***
178**/
179
180static struct tm *
181tr_localtime_r( time_t *_clock, struct tm *_result )
182{
183#ifdef HAVE_LOCALTIME_R
184    return localtime_r( _clock, _result );
185#else
186    struct tm *p = localtime( _clock );
187    if( p )
188        *(_result) = *p;
189    return p;
190#endif
191}
192
193char*
194tr_getLogTimeStr( char * buf,
195                  int    buflen )
196{
197    char           tmp[64];
198    time_t         now;
199    struct tm      now_tm;
200    struct timeval tv;
201    int            milliseconds;
202
203    now = time( NULL );
204    gettimeofday( &tv, NULL );
205
206    tr_localtime_r( &now, &now_tm );
207    strftime( tmp, sizeof( tmp ), "%H:%M:%S", &now_tm );
208    milliseconds = (int)( tv.tv_usec / 1000 );
209    tr_snprintf( buf, buflen, "%s.%03d", tmp, milliseconds );
210
211    return buf;
212}
213
214tr_bool
215tr_deepLoggingIsActive( void )
216{
217    static int8_t deepLoggingIsActive = -1;
218
219    if( deepLoggingIsActive < 0 )
220        deepLoggingIsActive = IsDebuggerPresent() || (tr_getLog()!=NULL);
221
222    return deepLoggingIsActive != 0;
223}
224
225void
226tr_deepLog( const char  * file,
227            int           line,
228            const char  * name,
229            const char  * fmt,
230            ... )
231{
232    FILE * fp = tr_getLog( );
233    if( fp || IsDebuggerPresent( ) )
234    {
235        va_list           args;
236        char              timestr[64];
237        struct evbuffer * buf = tr_getBuffer( );
238        char *            base = tr_basename( file );
239
240        evbuffer_add_printf( buf, "[%s] ",
241                            tr_getLogTimeStr( timestr, sizeof( timestr ) ) );
242        if( name )
243            evbuffer_add_printf( buf, "%s ", name );
244        va_start( args, fmt );
245        evbuffer_add_vprintf( buf, fmt, args );
246        va_end( args );
247        evbuffer_add_printf( buf, " (%s:%d)\n", base, line );
248        OutputDebugString( EVBUFFER_DATA( buf ) );
249        if(fp)
250            (void) fwrite( EVBUFFER_DATA( buf ), 1, EVBUFFER_LENGTH( buf ), fp );
251
252        tr_free( base );
253        tr_releaseBuffer( buf );
254    }
255}
256
257/***
258****
259***/
260   
261
262int
263tr_msgLoggingIsActive( int level )
264{
265    tr_msgInit( );
266
267    return messageLevel >= level;
268}
269
270void
271tr_msg( const char * file,
272        int          line,
273        int          level,
274        const char * name,
275        const char * fmt,
276        ... )
277{
278    FILE * fp;
279    tr_msgInit( );
280    tr_lockLock( messageLock );
281
282    fp = tr_getLog( );
283
284    if( messageLevel >= level )
285    {
286        char buf[MAX_STACK_ARRAY_SIZE];
287        va_list ap;
288
289        /* build the text message */
290        *buf = '\0';
291        va_start( ap, fmt );
292        evutil_vsnprintf( buf, sizeof( buf ), fmt, ap );
293        va_end( ap );
294
295        OutputDebugString( buf );
296
297        if( *buf )
298        {
299            if( messageQueuing )
300            {
301                tr_msg_list * newmsg;
302                newmsg = tr_new0( tr_msg_list, 1 );
303                newmsg->level = level;
304                newmsg->when = time( NULL );
305                newmsg->message = tr_strdup( buf );
306                newmsg->file = file;
307                newmsg->line = line;
308                newmsg->name = tr_strdup( name );
309
310                *messageQueueTail = newmsg;
311                messageQueueTail = &newmsg->next;
312            }
313            else
314            {
315                if( fp == NULL )
316                    fp = stderr;
317                if( name )
318                    fprintf( fp, "%s: %s\n", name, buf );
319                else
320                    fprintf( fp, "%s\n", buf );
321                fflush( fp );
322            }
323        }
324    }
325
326    tr_lockUnlock( messageLock );
327}
328
329/***
330****
331***/
332
333void
334tr_set_compare( const void * va,
335                size_t aCount,
336                const void * vb,
337                size_t bCount,
338                int compare( const void * a, const void * b ),
339                size_t elementSize,
340                tr_set_func in_a_cb,
341                tr_set_func in_b_cb,
342                tr_set_func in_both_cb,
343                void * userData )
344{
345    const uint8_t * a = (const uint8_t *) va;
346    const uint8_t * b = (const uint8_t *) vb;
347    const uint8_t * aend = a + elementSize * aCount;
348    const uint8_t * bend = b + elementSize * bCount;
349
350    while( a != aend || b != bend )
351    {
352        if( a == aend )
353        {
354            ( *in_b_cb )( (void*)b, userData );
355            b += elementSize;
356        }
357        else if( b == bend )
358        {
359            ( *in_a_cb )( (void*)a, userData );
360            a += elementSize;
361        }
362        else
363        {
364            const int val = ( *compare )( a, b );
365
366            if( !val )
367            {
368                ( *in_both_cb )( (void*)a, userData );
369                a += elementSize;
370                b += elementSize;
371            }
372            else if( val < 0 )
373            {
374                ( *in_a_cb )( (void*)a, userData );
375                a += elementSize;
376            }
377            else if( val > 0 )
378            {
379                ( *in_b_cb )( (void*)b, userData );
380                b += elementSize;
381            }
382        }
383    }
384}
385
386/***
387****
388***/
389
390#ifdef DISABLE_GETTEXT
391
392const char*
393tr_strip_positional_args( const char* str )
394{
395    static size_t bufsize = 0;
396    static char * buf = NULL;
397    const size_t  len = strlen( str );
398    char *        out;
399
400    if( bufsize < len )
401    {
402        bufsize = len * 2;
403        buf = tr_renew( char, buf, bufsize );
404    }
405
406    for( out = buf; *str; ++str )
407    {
408        *out++ = *str;
409        if( ( *str == '%' ) && isdigit( str[1] ) )
410        {
411            const char * tmp = str + 1;
412            while( isdigit( *tmp ) )
413                ++tmp;
414
415            if( *tmp == '$' )
416                str = tmp;
417        }
418    }
419    *out = '\0';
420
421    return buf;
422}
423
424#endif
425
426/**
427***
428**/
429
430void
431tr_timevalMsec( uint64_t milliseconds, struct timeval * setme )
432{
433    const uint64_t microseconds = milliseconds * 1000;
434    assert( setme != NULL );
435    setme->tv_sec  = microseconds / 1000000;
436    setme->tv_usec = microseconds % 1000000;
437}
438
439uint8_t *
440tr_loadFile( const char * path,
441             size_t *     size )
442{
443    uint8_t *    buf;
444    struct stat  sb;
445    FILE *       file;
446    const char * err_fmt = _( "Couldn't read \"%1$s\": %2$s" );
447
448    /* try to stat the file */
449    errno = 0;
450    if( stat( path, &sb ) )
451    {
452        const int err = errno;
453        tr_dbg( err_fmt, path, tr_strerror( errno ) );
454        errno = err;
455        return NULL;
456    }
457
458    if( ( sb.st_mode & S_IFMT ) != S_IFREG )
459    {
460        tr_err( err_fmt, path, _( "Not a regular file" ) );
461        errno = EISDIR;
462        return NULL;
463    }
464
465    /* Load the torrent file into our buffer */
466    file = fopen( path, "rb" );
467    if( !file )
468    {
469        const int err = errno;
470        tr_err( err_fmt, path, tr_strerror( errno ) );
471        errno = err;
472        return NULL;
473    }
474    buf = malloc( sb.st_size );
475    if( !buf )
476    {
477        const int err = errno;
478        tr_err( err_fmt, path, _( "Memory allocation failed" ) );
479        fclose( file );
480        errno = err;
481        return NULL;
482    }
483    if( fread( buf, sb.st_size, 1, file ) != 1 )
484    {
485        const int err = errno;
486        tr_err( err_fmt, path, tr_strerror( errno ) );
487        fclose( file );
488        free( buf );
489        errno = err;
490        return NULL;
491    }
492
493    fclose( file );
494    *size = sb.st_size;
495    return buf;
496}
497
498char*
499tr_basename( const char * path )
500{
501    char * tmp = tr_strdup( path );
502    char * ret = tr_strdup( basename( tmp ) );
503    tr_free( tmp );
504    return ret;
505}
506
507char*
508tr_dirname( const char * path )
509{
510    char * tmp = tr_strdup( path );
511    char * ret = tr_strdup( dirname( tmp ) );
512    tr_free( tmp );
513    return ret;
514}
515
516int
517tr_mkdir( const char * path,
518          int permissions
519#ifdef WIN32
520                       UNUSED
521#endif
522        )
523{
524#ifdef WIN32
525    if( path && isalpha( path[0] ) && path[1] == ':' && !path[2] )
526        return 0;
527    return mkdir( path );
528#else
529    return mkdir( path, permissions );
530#endif
531}
532
533int
534tr_mkdirp( const char * path_in,
535           int          permissions )
536{
537    char *      path = tr_strdup( path_in );
538    char *      p, * pp;
539    struct stat sb;
540    int         done;
541
542    /* walk past the root */
543    p = path;
544    while( *p == TR_PATH_DELIMITER )
545        ++p;
546
547    pp = p;
548    done = 0;
549    while( ( p =
550                strchr( pp, TR_PATH_DELIMITER ) ) || ( p = strchr( pp, '\0' ) ) )
551    {
552        if( !*p )
553            done = 1;
554        else
555            *p = '\0';
556
557        if( stat( path, &sb ) )
558        {
559            /* Folder doesn't exist yet */
560            if( tr_mkdir( path, permissions ) )
561            {
562                const int err = errno;
563                tr_err( _(
564                           "Couldn't create \"%1$s\": %2$s" ), path,
565                       tr_strerror( err ) );
566                tr_free( path );
567                errno = err;
568                return -1;
569            }
570        }
571        else if( ( sb.st_mode & S_IFMT ) != S_IFDIR )
572        {
573            /* Node exists but isn't a folder */
574            char * buf = tr_strdup_printf( _( "File \"%s\" is in the way" ), path );
575            tr_err( _( "Couldn't create \"%1$s\": %2$s" ), path_in, buf );
576            tr_free( buf );
577            tr_free( path );
578            errno = ENOTDIR;
579            return -1;
580        }
581
582        if( done )
583            break;
584
585        *p = TR_PATH_DELIMITER;
586        p++;
587        pp = p;
588    }
589
590    tr_free( path );
591    return 0;
592}
593
594char*
595tr_buildPath( const char *first_element, ... )
596{
597    size_t bufLen = 0;
598    const char * element;
599    char * buf;
600    char * pch;
601    va_list vl;
602
603    /* pass 1: allocate enough space for the string */
604    va_start( vl, first_element );
605    element = first_element;
606    while( element ) {
607        bufLen += strlen( element ) + 1;
608        element = (const char*) va_arg( vl, const char* );
609    }
610    pch = buf = tr_new( char, bufLen );
611    va_end( vl );
612
613    /* pass 2: build the string piece by piece */
614    va_start( vl, first_element );
615    element = first_element;
616    while( element ) {
617        const size_t elementLen = strlen( element );
618        memcpy( pch, element, elementLen );
619        pch += elementLen;
620        *pch++ = TR_PATH_DELIMITER;
621        element = (const char*) va_arg( vl, const char* );
622    }
623    va_end( vl );
624
625    /* terminate the string.  if nonempty, eat the unwanted trailing slash */
626    if( pch != buf )
627        --pch;
628    *pch++ = '\0';
629
630    /* sanity checks & return */
631    assert( pch - buf == (off_t)bufLen );
632    return buf;
633}
634
635/****
636*****
637****/
638
639char*
640tr_strndup( const void * in,
641            int          len )
642{
643    char * out = NULL;
644
645    if( len < 0 )
646    {
647        out = tr_strdup( in );
648    }
649    else if( in )
650    {
651        out = tr_malloc( len + 1 );
652        memcpy( out, in, len );
653        out[len] = '\0';
654    }
655
656    return out;
657}
658
659char*
660tr_strdup_printf( const char * fmt, ... )
661{
662    char *            ret = NULL;
663    struct evbuffer * buf;
664    va_list           ap;
665
666    buf = tr_getBuffer( );
667    va_start( ap, fmt );
668
669    if( evbuffer_add_vprintf( buf, fmt, ap ) != -1 )
670        ret = tr_strdup( EVBUFFER_DATA( buf ) );
671
672    va_end( ap );
673    tr_releaseBuffer( buf );
674    return ret;
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_bitfieldConstruct( tr_bitfield * b, size_t bitCount )
721{
722    b->bitCount = bitCount;
723    b->byteCount = ( bitCount + 7u ) / 8u;
724    b->bits = tr_new0( uint8_t, b->byteCount );
725    return b;
726}
727
728tr_bitfield*
729tr_bitfieldDestruct( tr_bitfield * b )
730{
731    if( b )
732        tr_free( b->bits );
733    return b;
734}
735
736tr_bitfield*
737tr_bitfieldDup( const tr_bitfield * in )
738{
739    tr_bitfield * ret = tr_new0( tr_bitfield, 1 );
740
741    ret->bitCount = in->bitCount;
742    ret->byteCount = in->byteCount;
743    ret->bits = tr_memdup( in->bits, in->byteCount );
744    return ret;
745}
746
747void
748tr_bitfieldClear( tr_bitfield * bitfield )
749{
750    memset( bitfield->bits, 0, bitfield->byteCount );
751}
752
753int
754tr_bitfieldIsEmpty( const tr_bitfield * bitfield )
755{
756    size_t i;
757
758    for( i = 0; i < bitfield->byteCount; ++i )
759        if( bitfield->bits[i] )
760            return 0;
761
762    return 1;
763}
764
765int
766tr_bitfieldAdd( tr_bitfield * bitfield,
767                size_t        nth )
768{
769    assert( bitfield );
770    assert( bitfield->bits );
771
772    if( nth >= bitfield->bitCount )
773        return -1;
774
775    bitfield->bits[nth >> 3u] |= ( 0x80 >> ( nth & 7u ) );
776    return 0;
777}
778
779/* Sets bit range [begin, end) to 1 */
780int
781tr_bitfieldAddRange( tr_bitfield * b,
782                     size_t        begin,
783                     size_t        end )
784{
785    size_t        sb, eb;
786    unsigned char sm, em;
787
788    end--;
789
790    if( ( end >= b->bitCount ) || ( begin > end ) )
791        return -1;
792
793    sb = begin >> 3;
794    sm = ~( 0xff << ( 8 - ( begin & 7 ) ) );
795    eb = end >> 3;
796    em = 0xff << ( 7 - ( end & 7 ) );
797
798    if( sb == eb )
799    {
800        b->bits[sb] |= ( sm & em );
801    }
802    else
803    {
804        b->bits[sb] |= sm;
805        b->bits[eb] |= em;
806        if( ++sb < eb )
807            memset ( b->bits + sb, 0xff, eb - sb );
808    }
809
810    return 0;
811}
812
813int
814tr_bitfieldRem( tr_bitfield * bitfield,
815                size_t        nth )
816{
817    assert( bitfield );
818    assert( bitfield->bits );
819
820    if( nth >= bitfield->bitCount )
821        return -1;
822
823    bitfield->bits[nth >> 3u] &= ( 0xff7f >> ( nth & 7u ) );
824    return 0;
825}
826
827/* Clears bit range [begin, end) to 0 */
828int
829tr_bitfieldRemRange( tr_bitfield * b,
830                     size_t        begin,
831                     size_t        end )
832{
833    size_t        sb, eb;
834    unsigned char sm, em;
835
836    end--;
837
838    if( ( end >= b->bitCount ) || ( begin > end ) )
839        return -1;
840
841    sb = begin >> 3;
842    sm = 0xff << ( 8 - ( begin & 7 ) );
843    eb = end >> 3;
844    em = ~( 0xff << ( 7 - ( end & 7 ) ) );
845
846    if( sb == eb )
847    {
848        b->bits[sb] &= ( sm | em );
849    }
850    else
851    {
852        b->bits[sb] &= sm;
853        b->bits[eb] &= em;
854        if( ++sb < eb )
855            memset ( b->bits + sb, 0, eb - sb );
856    }
857
858    return 0;
859}
860
861tr_bitfield*
862tr_bitfieldOr( tr_bitfield *       a,
863               const tr_bitfield * b )
864{
865    uint8_t *      ait;
866    const uint8_t *aend, *bit;
867
868    assert( a->bitCount == b->bitCount );
869
870    for( ait = a->bits, bit = b->bits, aend = ait + a->byteCount;
871         ait != aend; )
872        *ait++ |= *bit++;
873
874    return a;
875}
876
877/* set 'a' to all the flags that were in 'a' but not 'b' */
878void
879tr_bitfieldDifference( tr_bitfield *       a,
880                       const tr_bitfield * b )
881{
882    uint8_t *      ait;
883    const uint8_t *aend, *bit;
884
885    assert( a->bitCount == b->bitCount );
886
887    for( ait = a->bits, bit = b->bits, aend = ait + a->byteCount;
888         ait != aend; )
889        *ait++ &= ~( *bit++ );
890}
891
892size_t
893tr_bitfieldCountTrueBits( const tr_bitfield* b )
894{
895    size_t           ret = 0;
896    const uint8_t *  it, *end;
897    static const int trueBitCount[512] = {
898        0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3,
899        4, 2, 3, 3, 4, 3, 4, 4, 5,
900        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
901        5, 3, 4, 4, 5, 4, 5, 5, 6,
902        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
903        5, 3, 4, 4, 5, 4, 5, 5, 6,
904        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
905        6, 4, 5, 5, 6, 5, 6, 6, 7,
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        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
911        6, 4, 5, 5, 6, 5, 6, 6, 7,
912        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
913        7, 5, 6, 6, 7, 6, 7, 7, 8,
914        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
915        5, 3, 4, 4, 5, 4, 5, 5, 6,
916        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
917        6, 4, 5, 5, 6, 5, 6, 6, 7,
918        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
919        6, 4, 5, 5, 6, 5, 6, 6, 7,
920        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
921        7, 5, 6, 6, 7, 6, 7, 7, 8,
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        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
927        7, 5, 6, 6, 7, 6, 7, 7, 8,
928        4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 5, 6, 6, 7, 6, 7, 7,
929        8, 6, 7, 7, 8, 7, 8, 8, 9
930    };
931
932    if( !b )
933        return 0;
934
935    for( it = b->bits, end = it + b->byteCount; it != end; ++it )
936        ret += trueBitCount[*it];
937
938    return ret;
939}
940
941/***
942****
943***/
944
945uint64_t
946tr_date( void )
947{
948    struct timeval tv;
949
950    gettimeofday( &tv, NULL );
951    return (uint64_t) tv.tv_sec * 1000 + ( tv.tv_usec / 1000 );
952}
953
954void
955tr_wait( uint64_t delay_milliseconds )
956{
957#ifdef WIN32
958    Sleep( (DWORD)delay_milliseconds );
959#else
960    usleep( 1000 * delay_milliseconds );
961#endif
962}
963
964/***
965****
966***/
967
968int
969tr_snprintf( char *       buf,
970             size_t       buflen,
971             const char * fmt,
972             ... )
973{
974    int     len;
975    va_list args;
976
977    va_start( args, fmt );
978    len = evutil_vsnprintf( buf, buflen, fmt, args );
979    va_end( args );
980    return len;
981}
982
983/*
984 * Copy src to string dst of size siz.  At most siz-1 characters
985 * will be copied.  Always NUL terminates (unless siz == 0).
986 * Returns strlen(src); if retval >= siz, truncation occurred.
987 */
988size_t
989tr_strlcpy( char *       dst,
990            const void * src,
991            size_t       siz )
992{
993#ifdef HAVE_STRLCPY
994    return strlcpy( dst, src, siz );
995#else
996    char *      d = dst;
997    const char *s = src;
998    size_t      n = siz;
999
1000    assert( s );
1001    assert( d );
1002
1003    /* Copy as many bytes as will fit */
1004    if( n != 0 )
1005    {
1006        while( --n != 0 )
1007        {
1008            if( ( *d++ = *s++ ) == '\0' )
1009                break;
1010        }
1011    }
1012
1013    /* Not enough room in dst, add NUL and traverse rest of src */
1014    if( n == 0 )
1015    {
1016        if( siz != 0 )
1017            *d = '\0'; /* NUL-terminate dst */
1018        while( *s++ )
1019            ;
1020    }
1021
1022    return s - (char*)src - 1;  /* count does not include NUL */
1023#endif
1024}
1025
1026/***
1027****
1028***/
1029
1030double
1031tr_getRatio( double numerator,
1032             double denominator )
1033{
1034    double ratio;
1035
1036    if( denominator )
1037        ratio = numerator / denominator;
1038    else if( numerator )
1039        ratio = TR_RATIO_INF;
1040    else
1041        ratio = TR_RATIO_NA;
1042
1043    return ratio;
1044}
1045
1046void
1047tr_sha1_to_hex( char *          out,
1048                const uint8_t * sha1 )
1049{
1050    static const char hex[] = "0123456789abcdef";
1051    int               i;
1052
1053    for( i = 0; i < 20; i++ )
1054    {
1055        unsigned int val = *sha1++;
1056        *out++ = hex[val >> 4];
1057        *out++ = hex[val & 0xf];
1058    }
1059    *out = '\0';
1060}
1061
1062/***
1063****
1064***/
1065
1066int
1067tr_httpIsValidURL( const char * url )
1068{
1069    const char *        c;
1070    static const char * rfc2396_valid_chars =
1071        "abcdefghijklmnopqrstuvwxyz" /* lowalpha */
1072        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* upalpha */
1073        "0123456789"                 /* digit */
1074        "-_.!~*'()"                  /* mark */
1075        ";/?:@&=+$,"                 /* reserved */
1076        "<>#%<\""                    /* delims */
1077        "{}|\\^[]`";                 /* unwise */
1078
1079    if( url == NULL )
1080        return FALSE;
1081
1082    for( c = url; c && *c; ++c )
1083        if( !strchr( rfc2396_valid_chars, *c ) )
1084            return FALSE;
1085
1086    return !tr_httpParseURL( url, -1, NULL, NULL, NULL );
1087}
1088
1089int
1090tr_httpParseURL( const char * url_in,
1091                 int          len,
1092                 char **      setme_host,
1093                 int *        setme_port,
1094                 char **      setme_path )
1095{
1096    int          err;
1097    int          port = 0;
1098    int          n;
1099    char *       tmp;
1100    char *       pch;
1101    const char * protocol = NULL;
1102    const char * host = NULL;
1103    const char * path = NULL;
1104
1105    tmp = tr_strndup( url_in, len );
1106    if( ( pch = strstr( tmp, "://" ) ) )
1107    {
1108        *pch = '\0';
1109        protocol = tmp;
1110        pch += 3;
1111/*fprintf( stderr, "protocol is [%s]... what's left is [%s]\n", protocol, pch
1112  );*/
1113        if( ( n = strcspn( pch, ":/" ) ) )
1114        {
1115            const int havePort = pch[n] == ':';
1116            host = pch;
1117            pch += n;
1118            *pch++ = '\0';
1119/*fprintf( stderr, "host is [%s]... what's left is [%s]\n", host, pch );*/
1120            if( havePort )
1121            {
1122                char * end;
1123                port = strtol( pch, &end, 10 );
1124                pch = end;
1125/*fprintf( stderr, "port is [%d]... what's left is [%s]\n", port, pch );*/
1126            }
1127            path = pch;
1128/*fprintf( stderr, "path is [%s]\n", path );*/
1129        }
1130    }
1131
1132    err = !host || !path || !protocol
1133          || ( strcmp( protocol, "http" ) && strcmp( protocol, "https" ) );
1134
1135    if( !err && !port )
1136    {
1137        if( !strcmp( protocol, "http" ) ) port = 80;
1138        if( !strcmp( protocol, "https" ) ) port = 443;
1139    }
1140
1141    if( !err )
1142    {
1143        if( setme_host ){ ( (char*)host )[-3] = ':'; *setme_host =
1144                              tr_strdup( protocol ); }
1145        if( setme_path ){ ( (char*)path )[-1] = '/'; *setme_path =
1146                              tr_strdup( path - 1 ); }
1147        if( setme_port ) *setme_port = port;
1148    }
1149
1150
1151    tr_free( tmp );
1152    return err;
1153}
1154
1155#include <string.h>
1156#include <openssl/sha.h>
1157#include <openssl/hmac.h>
1158#include <openssl/evp.h>
1159#include <openssl/bio.h>
1160#include <openssl/buffer.h>
1161
1162char *
1163tr_base64_encode( const void * input,
1164                  int          length,
1165                  int *        setme_len )
1166{
1167    char *    ret;
1168    BIO *     b64;
1169    BIO *     bmem;
1170    BUF_MEM * bptr;
1171
1172    if( length < 1 )
1173        length = strlen( input );
1174
1175    bmem = BIO_new( BIO_s_mem( ) );
1176    b64 = BIO_new( BIO_f_base64( ) );
1177    b64 = BIO_push( b64, bmem );
1178    BIO_write( b64, input, length );
1179    (void) BIO_flush( b64 );
1180    BIO_get_mem_ptr( b64, &bptr );
1181    ret = tr_strndup( bptr->data, bptr->length );
1182    if( setme_len )
1183        *setme_len = bptr->length;
1184
1185    BIO_free_all( b64 );
1186    return ret;
1187}
1188
1189char *
1190tr_base64_decode( const void * input,
1191                  int          length,
1192                  int *        setme_len )
1193{
1194    char * ret;
1195    BIO *  b64;
1196    BIO *  bmem;
1197    int    retlen;
1198
1199    if( length < 1 )
1200        length = strlen( input );
1201
1202    ret = tr_new0( char, length );
1203    b64 = BIO_new( BIO_f_base64( ) );
1204    bmem = BIO_new_mem_buf( (unsigned char*)input, length );
1205    bmem = BIO_push( b64, bmem );
1206    retlen = BIO_read( bmem, ret, length );
1207    if( !retlen )
1208    {
1209        /* try again, but with the BIO_FLAGS_BASE64_NO_NL flag */
1210        BIO_free_all( bmem );
1211        b64 = BIO_new( BIO_f_base64( ) );
1212        BIO_set_flags( b64, BIO_FLAGS_BASE64_NO_NL );
1213        bmem = BIO_new_mem_buf( (unsigned char*)input, length );
1214        bmem = BIO_push( b64, bmem );
1215        retlen = BIO_read( bmem, ret, length );
1216    }
1217
1218    if( setme_len )
1219        *setme_len = retlen;
1220
1221    BIO_free_all( bmem );
1222    return ret;
1223}
1224
1225int
1226tr_ptr2int( void* v )
1227{
1228    return (intptr_t)v;
1229}
1230
1231void*
1232tr_int2ptr( int i )
1233{
1234    return (void*)(intptr_t)i;
1235}
1236
1237/***
1238****
1239***/
1240
1241static tr_list * _bufferList = NULL;
1242
1243static tr_lock *
1244getBufferLock( void )
1245{
1246    static tr_lock * lock = NULL;
1247    if( lock == NULL )
1248        lock = tr_lockNew( );
1249    return lock;
1250}
1251
1252struct evbuffer*
1253tr_getBuffer( void )
1254{
1255    struct evbuffer * buf;
1256    tr_lock * l = getBufferLock( );
1257    tr_lockLock( l );
1258
1259    buf = tr_list_pop_front( &_bufferList );
1260    if( buf == NULL )
1261        buf = evbuffer_new( );
1262
1263    tr_lockUnlock( l );
1264    return buf;
1265}
1266
1267void
1268tr_releaseBuffer( struct evbuffer * buf )
1269{
1270    tr_lock * l = getBufferLock( );
1271    tr_lockLock( l );
1272
1273    evbuffer_drain( buf, EVBUFFER_LENGTH( buf ) );
1274    assert( EVBUFFER_LENGTH( buf ) == 0 );
1275    tr_list_prepend( &_bufferList, buf );
1276
1277    tr_lockUnlock( l );
1278}
1279
1280/***
1281****
1282***/
1283
1284int
1285tr_lowerBound( const void * key,
1286               const void * base,
1287               size_t       nmemb,
1288               size_t       size,
1289               int       (* compar)(const void* key, const void* arrayMember),
1290               tr_bool    * exact_match )
1291{
1292    size_t first = 0;
1293    const char * cbase = base;
1294
1295    while( nmemb )
1296    {
1297        const size_t half = nmemb / 2;
1298        const size_t middle = first + half;
1299        const int c = compar( key, cbase + size*middle );
1300
1301        if( c < 0 )
1302        {
1303            first = middle + 1;
1304            nmemb = nmemb - half - 1;
1305        }
1306        else if( !c )
1307        {
1308            if( exact_match )
1309                *exact_match = TRUE;
1310            return middle;
1311        }
1312        else
1313        {
1314            nmemb = half;
1315        }
1316    }
1317
1318    if( exact_match )
1319        *exact_match = FALSE;
1320
1321    return first;
1322}
1323
1324/***
1325****
1326***/
1327
1328char*
1329tr_utf8clean( const char * str, ssize_t max_len, tr_bool * err )
1330{
1331    const char zero = '\0';
1332    char * ret;
1333    struct evbuffer * buf = evbuffer_new( );
1334    const char * end;
1335
1336    if( err != NULL )
1337        *err = FALSE;
1338
1339    if( max_len < 0 )
1340        max_len = (ssize_t) strlen( str );
1341
1342    while( !tr_utf8_validate ( str, max_len, &end ) )
1343    {
1344        const ssize_t good_len = end - str;
1345
1346        evbuffer_add( buf, str, good_len );
1347        max_len -= ( good_len + 1 );
1348        str += ( good_len + 1 );
1349        evbuffer_add( buf, "?", 1 );
1350
1351        if( err != NULL )
1352            *err = TRUE;
1353    }
1354
1355    evbuffer_add( buf, str, max_len );
1356    evbuffer_add( buf, &zero, 1 );
1357    ret = tr_memdup( EVBUFFER_DATA( buf ), EVBUFFER_LENGTH( buf ) );
1358    assert( tr_utf8_validate( ret, -1, NULL ) );
1359    evbuffer_free( buf );
1360    return ret;
1361}
Note: See TracBrowser for help on using the repository browser.