source: branches/encryption/libtransmission/utils.c @ 3000

Last change on this file since 3000 was 3000, checked in by charles, 15 years ago

(encryption) fix loooong-standing off-by-one memory allocation bug in the bitfield code

  • Property svn:keywords set to Date Rev Author Id
File size: 20.9 KB
Line 
1/******************************************************************************
2 * $Id: utils.c 3000 2007-09-09 16:57:15Z charles $
3 *
4 * Copyright (c) 2005-2007 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>
27#include <errno.h>
28#include <stdarg.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32
33#include <sys/time.h>
34#include <sys/types.h>
35#include <sys/stat.h>
36#include <unistd.h> /* usleep, stat */
37
38#ifdef WIN32
39    #include <windows.h> /* for Sleep */
40#elif defined(__BEOS__)
41    #include <kernel/OS.h>
42    extern int vasprintf( char **, const char *, va_list );
43#endif
44
45#include "transmission.h"
46#include "trcompat.h"
47#include "utils.h"
48#include "platform.h"
49
50#define SPRINTF_BUFSIZE         100
51
52static tr_lock_t      * messageLock = NULL;
53static int              messageLevel = 0;
54static int              messageQueuing = FALSE;
55static tr_msg_list_t *  messageQueue = NULL;
56static tr_msg_list_t ** messageQueueTail = &messageQueue;
57
58void tr_msgInit( void )
59{
60    if( !messageLock )
61         messageLock = tr_lockNew( );
62}
63
64void tr_setMessageLevel( int level )
65{
66    tr_msgInit();
67    tr_lockLock( messageLock );
68    messageLevel = MAX( 0, level );
69    tr_lockUnlock( messageLock );
70}
71
72int tr_getMessageLevel( void )
73{
74    int ret;
75
76    tr_msgInit();
77    tr_lockLock( messageLock );
78    ret = messageLevel;
79    tr_lockUnlock( messageLock );
80
81    return ret;
82}
83
84void tr_setMessageQueuing( int enabled )
85{
86    tr_msgInit();
87    tr_lockLock( messageLock );
88    messageQueuing = enabled;
89    tr_lockUnlock( messageLock );
90}
91
92tr_msg_list_t * tr_getQueuedMessages( void )
93{
94    tr_msg_list_t * ret;
95
96    assert( NULL != messageLock );
97    tr_lockLock( messageLock );
98    ret = messageQueue;
99    messageQueue = NULL;
100    messageQueueTail = &messageQueue;
101    tr_lockUnlock( messageLock );
102
103    return ret;
104}
105
106void tr_freeMessageList( tr_msg_list_t * list )
107{
108    tr_msg_list_t * next;
109
110    while( NULL != list )
111    {
112        next = list->next;
113        free( list->message );
114        free( list );
115        list = next;
116    }
117}
118
119void tr_msg( int level, char * msg, ... )
120{
121    va_list         args1, args2;
122    tr_msg_list_t * newmsg;
123    int             len1, len2;
124
125    assert( NULL != messageLock );
126    tr_lockLock( messageLock );
127
128    if( !messageLevel )
129    {
130        char * env;
131        env          = getenv( "TR_DEBUG" );
132        messageLevel = ( env ? atoi( env ) : 0 ) + 1;
133        messageLevel = MAX( 1, messageLevel );
134    }
135
136    if( messageLevel >= level )
137    {
138        va_start( args1, msg );
139        if( messageQueuing )
140        {
141            newmsg = calloc( 1, sizeof( *newmsg ) );
142            if( NULL != newmsg )
143            {
144                newmsg->level = level;
145                newmsg->when = time( NULL );
146                len1 = len2 = 0;
147                va_start( args2, msg );
148                tr_vsprintf( &newmsg->message, &len1, &len2, msg,
149                             args1, args2 );
150                va_end( args2 );
151                if( NULL == newmsg->message )
152                {
153                    free( newmsg );
154                }
155                else
156                {
157                    *messageQueueTail = newmsg;
158                    messageQueueTail = &newmsg->next;
159                }
160            }
161        }
162        else
163        {
164            vfprintf( stderr, msg, args1 );
165            fputc( '\n', stderr );
166            fflush( stderr );
167        }
168        va_end( args1 );
169    }
170
171    tr_lockUnlock( messageLock );
172}
173
174int tr_rand( int sup )
175{
176    static int init = 0;
177
178    assert( sup > 0 );
179
180    if( !init )
181    {
182        srand( tr_date() );
183        init = 1;
184    }
185    return rand() % sup;
186}
187
188/***
189****
190***/
191
192void
193tr_set_compare( const void * va, size_t aCount,
194                const void * vb, size_t bCount,
195                int compare( const void * a, const void * b ),
196                size_t elementSize,
197                tr_set_func in_a_cb,
198                tr_set_func in_b_cb,
199                tr_set_func in_both_cb,
200                void * userData )
201{
202    size_t ai, bi;
203    const uint8_t * a = (const uint8_t *) va;
204    const uint8_t * b = (const uint8_t *) vb;
205
206    for( ai=bi=0; ai<aCount && bi<bCount; )
207    {
208        if( ai==aCount )
209        {
210            (*in_b_cb)( (void*)b, userData );
211            b += elementSize;
212        }
213        else if ( bi==bCount )
214        {
215            (*in_a_cb)( (void*)a, userData );
216            a += elementSize;
217        }
218        else
219        {
220            const int val = (*compare)( a, b );
221
222            if( !val )
223            {
224                (*in_both_cb)( (void*)a, userData );
225                a += elementSize;
226                b += elementSize;
227            }
228            else if( val < 0 )
229            {
230                (*in_a_cb)( (void*)a, userData );
231                a += elementSize;
232            }
233            else if( val > 0 )
234            {
235                (*in_b_cb)( (void*)b, userData );
236                b += elementSize;
237            }
238        }
239    }
240}
241
242/***
243****
244***/
245
246
247#if 0
248void*
249tr_memmem( const void* haystack, size_t hl,
250           const void* needle,   size_t nl)
251{
252    const char *walk, *end;
253
254    if( !nl )
255        return (void*) haystack;
256
257    if( hl < nl )
258        return NULL;
259
260    for (walk=(const char*)haystack, end=walk+hl-nl; walk!=end; ++walk)
261        if( !memcmp( walk, needle, nl ) )
262            return (void*) walk;
263
264    return NULL;
265}
266#else
267void * tr_memmem ( const void *vbig, size_t big_len,
268                   const void *vlittle, size_t little_len )
269{
270    const char *big = vbig;
271    const char *little = vlittle;
272    size_t ii, jj;
273
274    if( 0 == big_len || 0 == little_len )
275    {
276        return NULL;
277    }
278
279    for( ii = 0; ii + little_len <= big_len; ii++ )
280    {
281        for( jj = 0; jj < little_len; jj++ )
282        {
283            if( big[ii + jj] != little[jj] )
284            {
285                break;
286            }
287        }
288        if( jj == little_len )
289        {
290            return (char*)big + ii;
291        }
292    }
293
294    return NULL;
295}
296#endif
297
298/**
299***
300**/
301
302int
303tr_compareUint8 (  uint8_t a,  uint8_t b )
304{
305    if( a < b ) return -1;
306    if( a > b ) return 1;
307    return 0;
308}
309
310int
311tr_compareUint16( uint16_t a, uint16_t b )
312{
313    if( a < b ) return -1;
314    if( a > b ) return 1;
315    return 0;
316}
317
318int
319tr_compareUint32( uint32_t a, uint32_t b )
320{
321    if( a < b ) return -1;
322    if( a > b ) return 1;
323    return 0;
324}
325
326int
327tr_compareUint64( uint64_t a, uint64_t b )
328{
329    if( a < b ) return -1;
330    if( a > b ) return 1;
331    return 0;
332}
333
334/**
335***
336**/
337
338struct timeval
339timevalSec ( int seconds )
340{
341    struct timeval ret;
342    ret.tv_sec = seconds;
343    ret.tv_usec = 0;
344    return ret;
345}
346
347struct timeval
348timevalMsec ( int milliseconds )
349{
350    struct timeval ret;
351    const unsigned long microseconds = milliseconds * 1000;
352    ret.tv_sec  = microseconds / 1000000;
353    ret.tv_usec = microseconds % 1000000;
354    return ret;
355}
356
357int
358tr_mkdir( const char * path, int permissions
359#ifdef WIN32
360                                             UNUSED
361#endif
362                                                    )
363{
364#ifdef WIN32
365    return mkdir( path );
366#else
367    return mkdir( path, permissions );
368#endif
369}
370
371int
372tr_mkdirp( char * path, int permissions )
373{
374    char      * p, * pp;
375    struct stat sb;
376    int done;
377
378    p = path;
379    while( '/' == *p )
380      p++;
381    pp = p;
382    done = 0;
383    while( ( p = strchr( pp, '/' ) ) || ( p = strchr( pp, '\0' ) ) )
384    {
385        if( '\0' == *p)
386        {
387            done = 1;
388        }
389        else
390        {
391            *p = '\0';
392        }
393        if( stat( path, &sb ) )
394        {
395            /* Folder doesn't exist yet */
396            if( tr_mkdir( path, permissions ) )
397            {
398                tr_err( "Could not create directory %s (%s)", path,
399                        strerror( errno ) );
400                *p = '/';
401                return 1;
402            }
403        }
404        else if( ( sb.st_mode & S_IFMT ) != S_IFDIR )
405        {
406            /* Node exists but isn't a folder */
407            tr_err( "Remove %s, it's in the way.", path );
408            *p = '/';
409            return 1;
410        }
411        if( done )
412        {
413            break;
414        }
415        *p = '/';
416        p++;
417        pp = p;
418    }
419
420    return 0;
421}
422
423int
424tr_strncasecmp( const char * s1, const char * s2, size_t n )
425{
426    if ( !n )
427        return 0;
428
429    while( n-- != 0 && tolower( *s1 ) == tolower( *s2 ) ) {
430        if( !n || !*s1 || !*s2 )
431            break;
432        ++s1;
433        ++s2;
434    }
435
436    return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2);
437}
438
439int tr_sprintf( char ** buf, int * used, int * max, const char * format, ... )
440{
441    va_list ap1, ap2;
442    int     ret;
443
444    va_start( ap1, format );
445    va_start( ap2, format );
446    ret = tr_vsprintf( buf, used, max, format, ap1, ap2 );
447    va_end( ap2 );
448    va_end( ap1 );
449
450    return ret;
451}
452
453int tr_vsprintf( char ** buf, int * used, int * max, const char * fmt,
454                 va_list ap1, va_list ap2 )
455{
456    int     want;
457
458    want = vsnprintf( NULL, 0, fmt, ap1 );
459
460    if( tr_concat( buf, used, max, NULL, want ) )
461    {
462        return 1;
463    }
464    assert( *used + want + 1 <= *max );
465
466    *used += vsnprintf( *buf + *used, *max - *used, fmt, ap2 );
467
468    return 0;
469}
470
471#ifndef HAVE_ASPRINTF
472
473int
474asprintf( char ** buf, const char * format, ... )
475{
476    va_list ap;
477    int     ret;
478
479    va_start( ap, format );
480    ret = vasprintf( buf, format, ap );
481    va_end( ap );
482
483    return ret;
484}
485
486int
487vasprintf( char ** buf, const char * format, va_list ap )
488{
489    va_list ap2;
490    int     used, max;
491
492    va_copy( ap2, ap );
493
494    *buf = NULL;
495    used = 0;
496    max  = 0;
497
498    if( tr_vsprintf( buf, &used, &max, format, ap, ap2 ) )
499    {
500        free( *buf );
501        return -1;
502    }
503
504    return used;
505}
506
507#endif /* HAVE_ASPRINTF */
508
509int tr_concat( char ** buf, int * used, int * max, const char * data, int len )
510{
511    int     newmax;
512    char  * newbuf;
513
514    newmax = *max;
515    while( *used + len + 1 > newmax )
516    {
517        newmax += SPRINTF_BUFSIZE;
518    }
519    if( newmax > *max )
520    {
521        newbuf = realloc( *buf, newmax );
522        if( NULL == newbuf )
523        {
524            return 1;
525        }
526        *buf = newbuf;
527        *max = newmax;
528    }
529
530    if( NULL != data )
531    {
532        memcpy( *buf + *used, data, len );
533        *used += len;
534    }
535
536    return 0;
537}
538
539void
540tr_buildPath ( char *buf, size_t buflen, const char *first_element, ... )
541{
542    va_list vl;
543    char* walk = buf;
544    const char * element = first_element;
545
546    if( first_element == NULL )
547        return;
548
549    va_start( vl, first_element );
550    for( ;; ) {
551        const size_t n = strlen( element );
552        memcpy( walk, element, n );
553        walk += n;
554        element = (const char*) va_arg( vl, const char* );
555        if( element == NULL )
556            break;
557        *walk++ = TR_PATH_DELIMITER;
558    }
559    *walk = '\0';
560    assert( walk-buf <= (int)buflen );
561}
562
563int
564tr_ioErrorFromErrno( void )
565{
566    switch( errno )
567    {
568        case EACCES:
569        case EROFS:
570            return TR_ERROR_IO_PERMISSIONS;
571        case ENOSPC:
572            return TR_ERROR_IO_SPACE;
573        case EMFILE:
574            return TR_ERROR_IO_OPEN_FILES;
575        case EFBIG:
576            return TR_ERROR_IO_FILE_TOO_BIG;
577        default:
578            tr_dbg( "generic i/o errno from errno: %s", strerror( errno ) );
579            return TR_ERROR_IO_OTHER;
580    }
581}
582
583char *
584tr_errorString( int code )
585{
586    switch( code )
587    {
588        case TR_OK:
589            return "No error";
590        case TR_ERROR:
591            return "Generic error";
592        case TR_ERROR_ASSERT:
593            return "Assert error";
594        case TR_ERROR_IO_PARENT:
595            return "Download folder does not exist";
596        case TR_ERROR_IO_PERMISSIONS:
597            return "Insufficient permissions";
598        case TR_ERROR_IO_SPACE:
599            return "Insufficient free space";
600        case TR_ERROR_IO_DUP_DOWNLOAD:
601            return "Already active transfer with same name and download folder";
602        case TR_ERROR_IO_FILE_TOO_BIG:
603            return "File too large";
604        case TR_ERROR_IO_OPEN_FILES:
605            return "Too many open files";
606        case TR_ERROR_IO_OTHER:
607            return "Generic I/O error";
608    }
609    return "Unknown error";
610}
611
612/****
613*****
614****/
615
616char*
617tr_strdup( const char * in )
618{
619    return tr_strndup( in, in ? strlen(in) : 0 );
620}
621
622char*
623tr_strndup( const char * in, int len )
624{
625    char * out = NULL;
626
627    if( in != NULL )
628    {
629        out = tr_malloc( len+1 );
630        memcpy( out, in, len );
631        out[len] = '\0';
632    }
633    return out;
634}
635
636void*
637tr_calloc( size_t nmemb, size_t size )
638{
639    return nmemb && size ? calloc( nmemb, size ) : NULL;
640}
641
642void*
643tr_malloc( size_t size )
644{
645    return size ? malloc( size ) : NULL;
646}
647
648void*
649tr_malloc0( size_t size )
650{
651    void * ret = tr_malloc( size );
652    memset( ret, 0, size );
653    return ret;
654}
655
656void tr_free( void * p )
657{
658    if( p )
659        free( p );
660}
661
662/****
663*****
664****/
665
666/* note that the argument is how many bits are needed, not bytes */
667tr_bitfield*
668tr_bitfieldNew( size_t bitcount )
669{
670    tr_bitfield * ret = calloc( 1, sizeof(tr_bitfield) );
671    if( NULL == ret )
672        return NULL;
673
674    ret->len = bitcount/8u + 1;
675    ret->bits = calloc( ret->len, 1 );
676    if( NULL == ret->bits ) {
677        free( ret );
678        return NULL;
679    }
680
681    return ret;
682}
683
684tr_bitfield*
685tr_bitfieldDup( const tr_bitfield * in )
686{
687    tr_bitfield * ret = calloc( 1, sizeof(tr_bitfield) );
688    ret->len = in->len;
689    ret->bits = malloc( ret->len );
690    memcpy( ret->bits, in->bits, ret->len );
691    return ret;
692}
693
694void tr_bitfieldFree( tr_bitfield * bitfield )
695{
696    if( bitfield )
697    {
698        free( bitfield->bits );
699        free( bitfield );
700    }
701}
702
703void
704tr_bitfieldClear( tr_bitfield * bitfield )
705{
706    memset( bitfield->bits, 0, bitfield->len );
707}
708
709int
710tr_bitfieldIsEmpty( const tr_bitfield * bitfield )
711{
712    unsigned int i;
713
714    for( i=0; i<bitfield->len; ++i )
715        if( bitfield->bits[i] )
716            return 0;
717
718    return 1;
719}
720
721#define BIN(nth) ((nth>>3))
722#define BIT(nth) (1<<(7-(nth%8)))
723
724void
725tr_bitfieldAdd( tr_bitfield  * bitfield, size_t nth )
726{
727    assert( bitfield != NULL );
728    assert( BIN(nth) < bitfield->len );
729    bitfield->bits[ BIN(nth) ] |= BIT(nth);
730}
731
732void
733tr_bitfieldAddRange( tr_bitfield  * bitfield,
734                     size_t         begin,
735                     size_t         end )
736{
737    /* TODO: there are faster ways to do this */
738    unsigned int i;
739    for( i=begin; i<end; ++i )
740        tr_bitfieldAdd( bitfield, i );
741}
742
743void
744tr_bitfieldRem( tr_bitfield   * bitfield,
745                size_t          nth )
746{
747    if( bitfield != NULL )
748    {
749        const size_t bin = BIN(nth);
750        assert( bin < bitfield->len );
751        bitfield->bits[bin] &= ~BIT(nth);
752    }
753}
754
755void
756tr_bitfieldRemRange ( tr_bitfield  * b,
757                      size_t         begin,
758                      size_t         end )
759{
760    /* TODO: there are faster ways to do this */
761    unsigned int i;
762    for( i=begin; i<end; ++i )
763        tr_bitfieldRem( b, i );
764}
765
766tr_bitfield*
767tr_bitfieldNegate( tr_bitfield * b )
768{
769    uint8_t *it;
770    const uint8_t *end;
771
772    for( it=b->bits, end=it+b->len; it!=end; ++it )
773        *it = ~*it;
774
775    return b;
776}
777
778tr_bitfield*
779tr_bitfieldAnd( tr_bitfield * a, const tr_bitfield * b )
780{
781    uint8_t *ait;
782    const uint8_t *aend, *bit;
783
784    assert( a->len == b->len );
785
786    for( ait=a->bits, bit=b->bits, aend=ait+a->len; ait!=aend; ++ait, ++bit )
787        *ait &= *bit;
788
789    return a;
790}
791
792size_t
793tr_bitfieldCountTrueBits( const tr_bitfield* b )
794{
795    size_t ret = 0;
796    const uint8_t *it, *end;
797    static const int trueBitCount[512] = {
798        0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
799        1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
800        1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
801        2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
802        1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
803        2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
804        2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
805        3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
806        1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
807        2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
808        2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
809        3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
810        2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
811        3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
812        3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
813        4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9
814    };
815
816    if( !b )
817        return 0;
818
819    for( it=b->bits, end=it+b->len; it!=end; ++it )
820        ret += trueBitCount[*it];
821
822    return ret;
823}
824
825/***
826****
827***/
828
829uint64_t
830tr_date( void )
831{
832    struct timeval tv;
833    gettimeofday( &tv, NULL );
834    return (uint64_t) tv.tv_sec * 1000 + ( tv.tv_usec / 1000 );
835}
836
837void
838tr_wait( uint64_t delay_milliseconds )
839{
840#ifdef __BEOS__
841    snooze( 1000 * delay_milliseconds );
842#elif defined(WIN32)
843    Sleep( (DWORD)delay_milliseconds );
844#else
845    usleep( 1000 * delay_milliseconds );
846#endif
847}
848
849#define WANTBYTES( want, got ) \
850    if( (want) > (got) ) { return; } else { (got) -= (want); }
851void
852strlcat_utf8( void * dest, const void * src, size_t len, char skip )
853{
854    char       * s      = dest;
855    const char * append = src;
856    const char * p;
857
858    /* don't overwrite the nul at the end */
859    len--;
860
861    /* Go to the end of the destination string */
862    while( s[0] )
863    {
864        s++;
865        len--;
866    }
867
868    /* Now start appending, converting on the fly if necessary */
869    for( p = append; p[0]; )
870    {
871        /* skip over the requested character */
872        if( skip == p[0] )
873        {
874            p++;
875            continue;
876        }
877
878        if( !( p[0] & 0x80 ) )
879        {
880            /* ASCII character */
881            WANTBYTES( 1, len );
882            *(s++) = *(p++);
883            continue;
884        }
885
886        if( ( p[0] & 0xE0 ) == 0xC0 && ( p[1] & 0xC0 ) == 0x80 )
887        {
888            /* 2-bytes UTF-8 character */
889            WANTBYTES( 2, len );
890            *(s++) = *(p++); *(s++) = *(p++);
891            continue;
892        }
893
894        if( ( p[0] & 0xF0 ) == 0xE0 && ( p[1] & 0xC0 ) == 0x80 &&
895            ( p[2] & 0xC0 ) == 0x80 )
896        {
897            /* 3-bytes UTF-8 character */
898            WANTBYTES( 3, len );
899            *(s++) = *(p++); *(s++) = *(p++);
900            *(s++) = *(p++);
901            continue;
902        }
903
904        if( ( p[0] & 0xF8 ) == 0xF0 && ( p[1] & 0xC0 ) == 0x80 &&
905            ( p[2] & 0xC0 ) == 0x80 && ( p[3] & 0xC0 ) == 0x80 )
906        {
907            /* 4-bytes UTF-8 character */
908            WANTBYTES( 4, len );
909            *(s++) = *(p++); *(s++) = *(p++);
910            *(s++) = *(p++); *(s++) = *(p++);
911            continue;
912        }
913
914        /* ISO 8859-1 -> UTF-8 conversion */
915        WANTBYTES( 2, len );
916        *(s++) = 0xC0 | ( ( *p & 0xFF ) >> 6 );
917        *(s++) = 0x80 | ( *(p++) & 0x3F );
918    }
919}
920
921size_t
922bufsize_utf8( const void * vstr, int * changed )
923{
924    const char * str = vstr;
925    size_t       ii, grow;
926
927    if( NULL != changed )
928        *changed = 0;
929
930    ii   = 0;
931    grow = 1;
932    while( '\0' != str[ii] )
933    {
934        if( !( str[ii] & 0x80 ) )
935            /* ASCII character */
936            ii++;
937        else if( ( str[ii]   & 0xE0 ) == 0xC0 && ( str[ii+1] & 0xC0 ) == 0x80 )
938            /* 2-bytes UTF-8 character */
939            ii += 2;
940        else if( ( str[ii]   & 0xF0 ) == 0xE0 && ( str[ii+1] & 0xC0 ) == 0x80 &&
941                 ( str[ii+2] & 0xC0 ) == 0x80 )
942            /* 3-bytes UTF-8 character */
943            ii += 3;
944        else if( ( str[ii]   & 0xF8 ) == 0xF0 && ( str[ii+1] & 0xC0 ) == 0x80 &&
945                 ( str[ii+2] & 0xC0 ) == 0x80 && ( str[ii+3] & 0xC0 ) == 0x80 )
946            /* 4-bytes UTF-8 character */
947            ii += 4;
948        else
949        {
950            /* ISO 8859-1 -> UTF-8 conversion */
951            ii++;
952            grow++;
953            if( NULL != changed )
954                *changed = 1;
955        }
956    }
957
958    return ii + grow;
959}
Note: See TracBrowser for help on using the repository browser.