From 2905ea039d3381b6afd6479ff83a5fca33414317 Mon Sep 17 00:00:00 2001 From: yaworsky Date: Tue, 29 Nov 2005 12:13:40 +0000 Subject: Rewritten character conversion: do not fail on invalid characters. --- daemon/syslogd.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 5 deletions(-) diff --git a/daemon/syslogd.c b/daemon/syslogd.c index 165896a..5ff5401 100644 --- a/daemon/syslogd.c +++ b/daemon/syslogd.c @@ -16,6 +16,7 @@ */ #include +#include #include #include #include @@ -190,15 +191,65 @@ static struct string* try_convert_string( struct string* s, GIConv cd ) { struct string *ret; gchar *converted_str; + gchar *inbuf, *outbuf; + gsize inbytes_left, outbytes, outbytes_left; + gsize converted_str_len, converted_str_allocated; - converted_str = g_convert_with_iconv( s->gstr->str, -1, cd, NULL, NULL, NULL ); - if( !converted_str ) + converted_str_allocated = s->gstr->len + /* at least */ 1; + converted_str = g_malloc( converted_str_allocated ); + + inbuf = s->gstr->str; + inbytes_left = s->gstr->len; + outbytes = converted_str_allocated; + outbuf = converted_str; + converted_str_len = 0; + + if( 0 == inbytes_left ) + goto done; + + for(;;) { - TRACE( "conversion error\n" ); - return string_addref( s ); + size_t r; + + outbytes_left = outbytes; + + r = g_iconv( cd, &inbuf, &inbytes_left, &outbuf, &outbytes_left ); + converted_str_len += outbytes - outbytes_left; + outbytes = outbytes_left; + if( r != -1 ) + goto done; + + switch( errno ) + { + case E2BIG: + /* guess the right output length */ + outbytes = inbytes_left * + /* average size of destination char: */ + converted_str_len / (s->gstr->len - inbytes_left) + + 16; /* if the result of above expression too small */ + converted_str_allocated += outbytes; + converted_str = g_realloc( converted_str, converted_str_allocated ); + outbuf = converted_str + converted_str_len; + break; + + case EILSEQ: + inbuf++; + inbytes_left--; + /* FIXME: skip invalid characters? or replace with some fallback? */ + break; + + case EINVAL: + goto done; + + default: + TRACE( "unknown conversion error %d\n", errno ); + g_free( converted_str ); + return string_addref( s ); + } } +done: - ret = string_new( converted_str ); + ret = string_new_len( converted_str, converted_str_len ); g_free( converted_str ); return ret; } -- cgit v1.2.3