diff options
author | Andy Wingo <wingo@pobox.com> | 2012-04-01 11:29:41 -0700 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2012-04-01 14:07:07 -0700 |
commit | 2c1b79513b7b5826db48b6e5e1d7f4dc7731d13b (patch) | |
tree | 78bf6ab5e994ce17c7dff35211e2e1fe27c092c6 /libguile/strings.c | |
parent | a8004dcb4d7148ec66cbaa109a18715d757700eb (diff) | |
download | guile-2c1b79513b7b5826db48b6e5e1d7f4dc7731d13b.tar.gz |
fix scm_to_utf8_stringn for wide strings to NUL-append the strings
* libguile/strings.c (u32_u8_strlen, scm_to_utf8_stringn): Sigh, fix the
u32-to-u8 optimization to ensure that the utf8 string is
NUL-terminated.
Diffstat (limited to 'libguile/strings.c')
-rw-r--r-- | libguile/strings.c | 69 |
1 files changed, 66 insertions, 3 deletions
diff --git a/libguile/strings.c b/libguile/strings.c index 494a658e6..a9e5afe64 100644 --- a/libguile/strings.c +++ b/libguile/strings.c @@ -1874,6 +1874,39 @@ latin1_to_u8 (const scm_t_uint8 *str, size_t latin_len, return u8_result; } +/* From RFC 3629: + + Char. number range | UTF-8 octet sequence + (hexadecimal) | (binary) + --------------------+--------------------------------------------- + 0000 0000-0000 007F | 0xxxxxxx + 0000 0080-0000 07FF | 110xxxxx 10xxxxxx + 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx + 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx +*/ + +static size_t +u32_u8_strlen (const scm_t_uint32 *str, size_t len) +{ + size_t ret, i; + + for (i = 0, ret = 0; i < len; i++) + { + scm_t_uint32 c = str[i]; + + if (c <= 0x7f) + ret += 1; + else if (c <= 0x7ff) + ret += 2; + else if (c <= 0xffff) + ret += 3; + else + ret += 4; + } + + return ret; +} + char * scm_to_utf8_stringn (SCM str, size_t *lenp) { @@ -1882,9 +1915,39 @@ scm_to_utf8_stringn (SCM str, size_t *lenp) scm_i_string_length (str), NULL, lenp); else - return (char *) u32_to_u8 ((scm_t_uint32*)scm_i_string_wide_chars (str), - scm_i_string_length (str), - NULL, lenp); + { + scm_t_uint8 *buf, *ret; + size_t len, allocated; + + len = u32_u8_strlen ((scm_t_uint32*)scm_i_string_wide_chars (str), + scm_i_string_length (str)); + allocated = len + 1; + buf = scm_malloc (allocated); + + ret = u32_to_u8 ((scm_t_uint32*)scm_i_string_wide_chars (str), + scm_i_string_length (str), buf, &len); + + if (ret == buf && len + 1 == allocated) + { + ret[len] = 0; + return (char *) ret; + } + + /* An error: a bad codepoint. */ + { + int saved_errno = errno; + + free (buf); + if (!saved_errno) + abort (); + + scm_decoding_error ("scm_to_utf8_stringn", errno, + "invalid codepoint in string", str); + + /* Not reached. */ + return NULL; + } + } } scm_t_wchar * |