[dovecot-cvs] dovecot/src/lib-charset charset-iconv.c,1.7,1.8 charset-utf8.h,1.2,1.3

cras at procontrol.fi cras at procontrol.fi
Sun Dec 8 07:23:10 EET 2002


Update of /home/cvs/dovecot/src/lib-charset
In directory danu:/tmp/cvs-serv19285/lib-charset

Modified Files:
	charset-iconv.c charset-utf8.h 
Log Message:
Added buffer API. Point is to hide all buffer writing behind this API which
verifies that nothing overflows. Much better than doing the same checks all
around the code, even if it is slightly slower.

Buffer reading is still mostly done directly, that isn't such a big security
risk and I can't think of a reasonable API for it anyway.



Index: charset-iconv.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-charset/charset-iconv.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- charset-iconv.c	3 Dec 2002 13:55:44 -0000	1.7
+++ charset-iconv.c	8 Dec 2002 05:23:07 -0000	1.8
@@ -1,6 +1,7 @@
 /* Copyright (C) 2002 Timo Sirainen */
 
 #include "lib.h"
+#include "buffer.h"
 #include "charset-utf8.h"
 
 #ifdef HAVE_ICONV_H
@@ -66,49 +67,87 @@
 		(void)iconv(t->cd, NULL, NULL, NULL, NULL);
 }
 
-int charset_to_ucase_utf8(CharsetTranslation *t,
-			  const unsigned char **inbuf, size_t *insize,
-			  unsigned char *outbuf, size_t *outsize)
+static void str_ucase_utf8(const unsigned char *src, size_t src_size,
+			   Buffer *dest, size_t destpos)
 {
-	ICONV_CONST char *ic_inbuf;
-	char *ic_outbuf;
-	size_t outleft, max_size, i;
+	char *destbuf;
+	size_t i;
+
+	destbuf = buffer_get_space(dest, destpos, src_size);
+	for (i = 0; i < src_size; i++)
+		destbuf[i] = i_toupper(src[i]); /* FIXME: utf8 */
+}
+
+CharsetResult
+charset_to_ucase_utf8(CharsetTranslation *t,
+		      const Buffer *src, size_t *src_pos, Buffer *dest)
+{
+	ICONV_CONST char *ic_srcbuf;
+	char *ic_destbuf;
+	size_t srcleft, destpos, destleft, size;
+        CharsetResult ret;
+
+	destpos = buffer_get_used_size(dest);
+	destleft = buffer_get_size(dest) - destpos;
 
 	if (t->cd == NULL) {
 		/* no translation needed - just copy it to outbuf uppercased */
-		max_size = I_MIN(*insize, *outsize);
-		for (i = 0; i < max_size; i++)
-			outbuf[i] = i_toupper((*inbuf)[i]); /* FIXME: utf8 */
-		*insize = 0;
-		*outsize = max_size;
-		return TRUE;
+		size = buffer_get_used_size(src);
+		if (size > destleft)
+			size = destleft;
+		str_ucase_utf8(buffer_get_data(src, NULL), size, dest, destpos);
+		if (src_pos != NULL)
+			*src_pos = size;
+		return CHARSET_RET_OK;
 	}
 
-	ic_inbuf = (ICONV_CONST char *) *inbuf;
-	ic_outbuf = (char *) outbuf;
-	outleft = *outsize;
+	size = destleft;
+	ic_srcbuf = (ICONV_CONST char *) buffer_get_data(src, &srcleft);
+	ic_destbuf = buffer_append_space(dest, destleft);
 
-	if (iconv(t->cd, &ic_inbuf, insize,
-		  &ic_outbuf, &outleft) == (size_t)-1) {
-		if (errno != E2BIG && errno != EINVAL) {
-			/* should be EILSEQ - invalid input */
-			return FALSE;
-		}
+	if (iconv(t->cd, &ic_srcbuf, &srcleft,
+		  &ic_destbuf, &destleft) != (size_t)-1)
+		ret = CHARSET_RET_OK;
+	else if (errno == E2BIG)
+		ret = CHARSET_RET_OUTPUT_FULL;
+	else if (errno == EINVAL)
+		ret = CHARSET_RET_INCOMPLETE_INPUT;
+	else {
+		/* should be EILSEQ */
+		return CHARSET_RET_INVALID_INPUT;
 	}
+	size -= destleft;
 
-	*inbuf = (const unsigned char *) ic_inbuf;
-	*outsize -= outleft;
+	/* give back the memory we didn't use */
+	buffer_set_used_size(dest, buffer_get_used_size(dest) - destleft);
 
-	max_size = *outsize;
-	for (i = 0; i < max_size; i++)
-		outbuf[i] = i_toupper(outbuf[i]); /* FIXME: utf8 */
+	if (src_pos != NULL)
+		*src_pos = buffer_get_used_size(src) - srcleft;
 
-	return TRUE;
+	str_ucase_utf8((unsigned char *) ic_destbuf - size, size,
+		       dest, destpos);
+	return ret;
+}
+
+static const char *alloc_str_ucase_utf8(const Buffer *data, size_t *utf8_size)
+{
+	const char *buf;
+	size_t size;
+	Buffer *dest;
+
+	buf = buffer_get_data(data, &size);
+
+	dest = buffer_create_dynamic(data_stack_pool, size, (size_t)-1);
+	str_ucase_utf8(buf, size, dest, 0);
+	if (utf8_size != NULL)
+		*utf8_size = buffer_get_used_size(dest);
+	buffer_append_c(dest, '\0');
+	return buffer_free_without_data(dest);
 }
 
 const char *
 charset_to_ucase_utf8_string(const char *charset, int *unknown_charset,
-			     const unsigned char *buf, size_t *size)
+			     const Buffer *data, size_t *utf8_size)
 {
 	iconv_t cd;
 	ICONV_CONST char *inbuf;
@@ -116,12 +155,10 @@
 	size_t inleft, outleft, outsize, pos;
 
 	if (charset == NULL || strcasecmp(charset, "us-ascii") == 0 ||
-	    strcasecmp(charset, "ascii") == 0) {
-		outbuf = t_malloc(*size + 1);
-		memcpy(outbuf, buf, *size);
-		outbuf[*size] = '\0';
-		return str_ucase(outbuf); /* FIXME: utf8 */
-	}
+	    strcasecmp(charset, "ascii") == 0 ||
+	    strcasecmp(charset, "UTF-8") == 0 ||
+	    strcasecmp(charset, "UTF8") == 0)
+	       return alloc_str_ucase_utf8(data, utf8_size);
 
 	cd = iconv_open("UTF-8", charset);
 	if (cd == (iconv_t)-1) {
@@ -133,10 +170,9 @@
 	if (unknown_charset != NULL)
 		*unknown_charset = FALSE;
 
-	inbuf = (ICONV_CONST char *) buf;
-	inleft = *size;
+	inbuf = (ICONV_CONST char *) buffer_get_data(data, &inleft);;
 
-	outsize = outleft = *size * 2;
+	outsize = outleft = inleft * 2;
 	outbuf = outpos = t_buffer_get(outsize + 1);
 
 	while (iconv(cd, &inbuf, &inleft, &outpos, &outleft) == (size_t)-1) {
@@ -155,9 +191,10 @@
 		outpos = outbuf + pos;
 	}
 
-	*size = (size_t) (outpos - outbuf);
+	if (utf8_size != NULL)
+		*utf8_size = (size_t) (outpos - outbuf);
 	*outpos++ = '\0';
-	t_buffer_alloc(*size + 1);
+	t_buffer_alloc((size_t) (outpos - outbuf));
 
 	str_ucase(outbuf); /* FIXME: utf8 */
 

Index: charset-utf8.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib-charset/charset-utf8.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- charset-utf8.h	13 Nov 2002 11:08:18 -0000	1.2
+++ charset-utf8.h	8 Dec 2002 05:23:07 -0000	1.3
@@ -1,6 +1,13 @@
 #ifndef __CHARSET_UTF8_H
 #define __CHARSET_UTF8_H
 
+typedef enum {
+	CHARSET_RET_OK = 1,
+	CHARSET_RET_OUTPUT_FULL = 0,
+	CHARSET_RET_INCOMPLETE_INPUT = -1,
+	CHARSET_RET_INVALID_INPUT = -2
+} CharsetResult;
+
 typedef struct _CharsetTranslation CharsetTranslation;
 
 /* Begin translation to UTF-8. */
@@ -11,18 +18,16 @@
 
 void charset_to_utf8_reset(CharsetTranslation *t);
 
-/* Convert inbuf to UTF-8. inbuf and inbuf_size is updated to specify beginning
-   of data that was not written to outbuf, either because of inbuf ended with
-   incomplete character sequence or because the outbuf got full. Returns TRUE
-   if no conversion errors were detected. */
-int charset_to_ucase_utf8(CharsetTranslation *t,
-			  const unsigned char **inbuf, size_t *insize,
-			  unsigned char *outbuf, size_t *outsize);
+/* Translate src to UTF-8. If src_pos is non-NULL, it's updated to first
+   non-translated character in src. */
+CharsetResult
+charset_to_ucase_utf8(CharsetTranslation *t,
+		      const Buffer *src, size_t *src_pos, Buffer *dest);
 
-/* Simple wrapper for above functions. size is updated to strlen() of
-   returned UTF-8 string. */
+/* Simple wrapper for above functions. If utf8_size is non-NULL, it's set
+   to same as strlen(returned data). */
 const char *
 charset_to_ucase_utf8_string(const char *charset, int *unknown_charset,
-			     const unsigned char *buf, size_t *size);
+			     const Buffer *data, size_t *utf8_size);
 
 #endif




More information about the dovecot-cvs mailing list