2 * gunicode.c: Some Unicode routines
5 * Miguel de Icaza (miguel@novell.com)
7 * (C) 2006 Novell, Inc.
9 * utf8 validation code came from:
10 * libxml2-2.6.26 licensed under the MIT X11 license
12 * Authors credit in libxml's string.c:
13 * William Brack <wbrack@mmm.com.hk>
16 * Permission is hereby granted, free of charge, to any person obtaining
17 * a copy of this software and associated documentation files (the
18 * "Software"), to deal in the Software without restriction, including
19 * without limitation the rights to use, copy, modify, merge, publish,
20 * distribute, sublicense, and/or sell copies of the Software, and to
21 * permit persons to whom the Software is furnished to do so, subject to
22 * the following conditions:
24 * The above copyright notice and this permission notice shall be
25 * included in all copies or substantial portions of the Software.
27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
48 static char *my_charset;
49 static gboolean is_utf8;
52 g_unichar_type (gunichar c)
54 g_error ("%s", "g_unichar_type is not implemented");
59 g_unichar_tolower (gunichar c)
61 g_error ("%s", "g_unichar_type is not implemented");
66 g_unichar_isxdigit (gunichar c)
68 return (g_unichar_xdigit_value (c) != -1);
73 g_unichar_xdigit_value (gunichar c)
75 if (c >= 0x30 && c <= 0x39) /*0-9*/
77 if (c >= 0x41 && c <= 0x46) /*A-F*/
79 if (c >= 0x61 && c <= 0x66) /*a-f*/
85 g_convert (const gchar *str, gssize len,
86 const gchar *to_codeset, const gchar *from_codeset,
87 gsize *bytes_read, gsize *bytes_written, GError **error)
93 char *buffer, *output;
94 const char *strptr = (const char *) str;
95 size_t str_len = len == -1 ? strlen (str) : len;
97 size_t left, out_left;
99 convertor = iconv_open (to_codeset, from_codeset);
100 if (convertor == (iconv_t) -1){
106 buffer_size = str_len + 1 + 8;
107 buffer = g_malloc (buffer_size);
112 int res = iconv (convertor, (char **) &strptr, &left, &output, &out_left);
113 if (res == (size_t) -1){
116 size_t extra_space = 8 + left;
117 size_t output_used = output - buffer;
119 buffer_size += extra_space;
121 n = g_realloc (buffer, buffer_size);
125 *error = g_error_new (NULL, G_CONVERT_ERROR_FAILED, "No memory left");
131 out_left += extra_space;
132 output = buffer + output_used;
133 } else if (errno == EILSEQ){
135 *error = g_error_new (NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE, "Invalid multi-byte sequence on input");
139 } else if (errno == EINVAL){
141 *error = g_error_new (NULL, G_CONVERT_ERROR_PARTIAL_INPUT, "Partial character sequence");
148 if (bytes_read != NULL)
149 *bytes_read = strptr - str;
150 if (bytes_written != NULL)
151 *bytes_written = output - buffer;
155 iconv_close (convertor);
161 * This is broken, and assumes an UTF8 system, but will do for eglib's first user
164 g_filename_from_utf8 (const gchar *utf8string, gssize len, gsize *bytes_read, gsize *bytes_written, GError **error)
169 len = strlen (utf8string);
171 res = g_malloc (len + 1);
172 g_strlcpy (res, utf8string, len + 1);
177 g_get_charset (G_CONST_RETURN char **charset)
181 if (my_charset == NULL){
182 my_charset = g_strdup (nl_langinfo (CODESET));
183 is_utf8 = strcmp (my_charset, "UTF-8") == 0;
187 *charset = my_charset;
194 g_locale_to_utf8 (const gchar *opsysstring, gssize len, gsize *bytes_read, gsize *bytes_written, GError **error)
196 g_get_charset (NULL);
198 return g_convert (opsysstring, len, "UTF-8", my_charset, bytes_read, bytes_written, error);
202 g_locale_from_utf8 (const gchar *utf8string, gssize len, gsize *bytes_read, gsize *bytes_written, GError **error)
204 g_get_charset (NULL);
206 return g_convert (utf8string, len, my_charset, "UTF-8", bytes_read, bytes_written, error);
210 * @utf: Pointer to putative UTF-8 encoded string.
212 * Checks @utf for being valid UTF-8. @utf is assumed to be
213 * null-terminated. This function is not super-strict, as it will
214 * allow longer UTF-8 sequences than necessary. Note that Java is
215 * capable of producing these sequences if provoked. Also note, this
216 * routine checks for the 4-byte maximum size, but does not check for
217 * 0x10ffff maximum value.
219 * Return value: true if @utf is valid.
222 g_utf8_validate (const gchar *utf, gssize max_len, const gchar **end)
226 g_return_val_if_fail (utf != NULL, FALSE);
229 max_len = strlen (utf);
232 * utf is a string of 1, 2, 3 or 4 bytes. The valid strings
233 * are as follows (in "bit format"):
234 * 0xxxxxxx valid 1-byte
235 * 110xxxxx 10xxxxxx valid 2-byte
236 * 1110xxxx 10xxxxxx 10xxxxxx valid 3-byte
237 * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx valid 4-byte
239 for (ix = 0; ix < max_len;) { /* string is 0-terminated */
243 if ((c & 0x80) == 0x00) { /* 1-byte code, starts with 10 */
245 } else if ((c & 0xe0) == 0xc0) {/* 2-byte code, starts with 110 */
246 if (((ix+1) >= max_len) || (utf[ix+1] & 0xc0 ) != 0x80){
252 } else if ((c & 0xf0) == 0xe0) {/* 3-byte code, starts with 1110 */
253 if (((ix + 2) >= max_len) ||
254 ((utf[ix+1] & 0xc0) != 0x80) ||
255 ((utf[ix+2] & 0xc0) != 0x80)){
261 } else if ((c & 0xf8) == 0xf0) {/* 4-byte code, starts with 11110 */
262 if (((ix + 3) >= max_len) ||
263 ((utf[ix+1] & 0xc0) != 0x80) ||
264 ((utf[ix+2] & 0xc0) != 0x80) ||
265 ((utf[ix+3] & 0xc0) != 0x80)){
271 } else {/* unknown encoding */