#include void mcpu_text_init( mcpu_text *text ) { if( text == NULL ) return; text->data = NULL; text->length = 0; text->capacity = 0; } void mcpu_text_free( mcpu_text *text ) { if( text == NULL ) return; free( text->data ); text->data = NULL; text->length = 0; text->capacity = 0; } int mcpu_text_reserve( mcpu_text *text, size_t need ) { __mpu_char16_t *p; size_t capacity; if( text == NULL ) return( -1 ); if( need <= text->capacity ) return( 0 ); capacity = text->capacity ? text->capacity : 256; while( capacity < need ) { if( capacity > (SIZE_MAX / 2) ) { errno = EOVERFLOW; return( -1 ); } capacity *= 2; } if( capacity > (SIZE_MAX / sizeof(__mpu_char16_t)) ) { errno = EOVERFLOW; return( -1 ); } p = (__mpu_char16_t *)realloc( text->data, capacity * sizeof(__mpu_char16_t) ); if( p == NULL ) return( -1 ); text->data = p; text->capacity = capacity; return( 0 ); } int mcpu_text_append( mcpu_text *text, const __mpu_char16_t *data, size_t length ) { if( text == NULL || (data == NULL && length != 0) ) { errno = EINVAL; return( -1 ); } if( length > SIZE_MAX - text->length - 1 ) { errno = EOVERFLOW; return( -1 ); } if( mcpu_text_reserve( text, text->length + length + 1 ) != 0 ) return( -1 ); if( length != 0 ) memcpy( text->data + text->length, data, length * sizeof(__mpu_char16_t) ); text->length += length; text->data[text->length] = 0; return( 0 ); } int mcpu_text_append_char( mcpu_text *text, __mpu_char16_t ch ) { return( mcpu_text_append( text, &ch, 1 ) ); } int mcpu_text_append_ascii( mcpu_text *text, const char *s ) { if( text == NULL || s == NULL ) { errno = EINVAL; return( -1 ); } while( *s ) { unsigned char c = (unsigned char)*s++; if( c > 0x7f ) { errno = EILSEQ; return( -1 ); } if( mcpu_text_append_char( text, (__mpu_char16_t)c ) != 0 ) return( -1 ); } return( 0 ); } int mcpu_text_append_utf8( mcpu_text *text, const char *s ) { __mpu_char16_t *u; __mpu_size_t n; int rc; if( text == NULL || s == NULL ) { errno = EINVAL; return( -1 ); } n = mpu_utf8_to_ucs2( NULL, (const __mpu_char8_t *)s, 0 ); if( n == (__mpu_size_t)-1 ) return( -1 ); u = (__mpu_char16_t *)calloc( (size_t)n + 1, sizeof(__mpu_char16_t) ); if( u == NULL ) return( -1 ); if( mpu_utf8_to_ucs2( u, (const __mpu_char8_t *)s, (size_t)n + 1 ) == (__mpu_size_t)-1 ) { free( u ); return( -1 ); } rc = mcpu_text_append( text, u, (size_t)n ); free( u ); return( rc ); } int mcpu_text_from_utf8( mcpu_text *text, const char *s ) { if( text == NULL || s == NULL ) { errno = EINVAL; return( -1 ); } mcpu_text_free( text ); mcpu_text_init( text ); return( mcpu_text_append_utf8( text, s ) ); } char * mcpu_text_to_utf8( const __mpu_char16_t *data, size_t length ) { __mpu_char16_t *tmp; __mpu_char8_t *out; __mpu_size_t n; if( data == NULL && length != 0 ) { errno = EINVAL; return( NULL ); } tmp = (__mpu_char16_t *)calloc( length + 1, sizeof(__mpu_char16_t) ); if( tmp == NULL ) return( NULL ); if( length != 0 ) memcpy( tmp, data, length * sizeof(__mpu_char16_t) ); n = mpu_ucs2_to_utf8( NULL, tmp, 0 ); if( n == (__mpu_size_t)-1 ) { free( tmp ); return( NULL ); } out = (__mpu_char8_t *)calloc( (size_t)n + 1, 1 ); if( out == NULL ) { free( tmp ); return( NULL ); } if( mpu_ucs2_to_utf8( out, tmp, (size_t)n + 1 ) == (__mpu_size_t)-1 ) { free( out ); free( tmp ); return( NULL ); } free( tmp ); return( (char *)out ); } int mcpu_text_equal_ascii( const __mpu_char16_t *data, size_t length, const char *s ) { size_t i; if( data == NULL || s == NULL ) return( 0 ); for( i = 0; i < length && s[i]; ++i ) { if( data[i] != (__mpu_char16_t)(unsigned char)s[i] ) return( 0 ); } return( i == length && s[i] == 0 ); }