9e0d9554f4b9b5cf6069de7a16bc361a18722b57
[platform/upstream/glib.git] / glib / gutf8.c
1 /* gutf8.c - Operations on UTF-8 strings.
2  *
3  * Copyright (C) 1999 Tom Tromey
4  * Copyright (C) 2000 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include "config.h"
23
24 #include <stdlib.h>
25 #ifdef HAVE_CODESET
26 #include <langinfo.h>
27 #endif
28 #include <string.h>
29
30 #include "glib.h"
31
32 #ifdef G_PLATFORM_WIN32
33 #include <stdio.h>
34 #define STRICT
35 #include <windows.h>
36 #undef STRICT
37 #endif
38
39 #include "libcharset/libcharset.h"
40
41 #include "glibintl.h"
42 #include "galias.h"
43
44 #define UTF8_COMPUTE(Char, Mask, Len)                                         \
45   if (Char < 128)                                                             \
46     {                                                                         \
47       Len = 1;                                                                \
48       Mask = 0x7f;                                                            \
49     }                                                                         \
50   else if ((Char & 0xe0) == 0xc0)                                             \
51     {                                                                         \
52       Len = 2;                                                                \
53       Mask = 0x1f;                                                            \
54     }                                                                         \
55   else if ((Char & 0xf0) == 0xe0)                                             \
56     {                                                                         \
57       Len = 3;                                                                \
58       Mask = 0x0f;                                                            \
59     }                                                                         \
60   else if ((Char & 0xf8) == 0xf0)                                             \
61     {                                                                         \
62       Len = 4;                                                                \
63       Mask = 0x07;                                                            \
64     }                                                                         \
65   else if ((Char & 0xfc) == 0xf8)                                             \
66     {                                                                         \
67       Len = 5;                                                                \
68       Mask = 0x03;                                                            \
69     }                                                                         \
70   else if ((Char & 0xfe) == 0xfc)                                             \
71     {                                                                         \
72       Len = 6;                                                                \
73       Mask = 0x01;                                                            \
74     }                                                                         \
75   else                                                                        \
76     Len = -1;
77
78 #define UTF8_LENGTH(Char)              \
79   ((Char) < 0x80 ? 1 :                 \
80    ((Char) < 0x800 ? 2 :               \
81     ((Char) < 0x10000 ? 3 :            \
82      ((Char) < 0x200000 ? 4 :          \
83       ((Char) < 0x4000000 ? 5 : 6)))))
84    
85
86 #define UTF8_GET(Result, Chars, Count, Mask, Len)                             \
87   (Result) = (Chars)[0] & (Mask);                                             \
88   for ((Count) = 1; (Count) < (Len); ++(Count))                               \
89     {                                                                         \
90       if (((Chars)[(Count)] & 0xc0) != 0x80)                                  \
91         {                                                                     \
92           (Result) = -1;                                                      \
93           break;                                                              \
94         }                                                                     \
95       (Result) <<= 6;                                                         \
96       (Result) |= ((Chars)[(Count)] & 0x3f);                                  \
97     }
98
99 #define UNICODE_VALID(Char)                   \
100     ((Char) < 0x110000 &&                     \
101      (((Char) & 0xFFFFF800) != 0xD800) &&     \
102      ((Char) < 0xFDD0 || (Char) > 0xFDEF) &&  \
103      ((Char) & 0xFFFE) != 0xFFFE)
104    
105      
106 static const gchar utf8_skip_data[256] = {
107   1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
108   1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
109   1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
110   1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
111   1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
112   1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
113   2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
114   3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
115 };
116
117 const gchar * const g_utf8_skip = utf8_skip_data;
118
119 /**
120  * g_utf8_find_prev_char:
121  * @str: pointer to the beginning of a UTF-8 encoded string
122  * @p: pointer to some position within @str
123  * 
124  * Given a position @p with a UTF-8 encoded string @str, find the start
125  * of the previous UTF-8 character starting before @p. Returns %NULL if no
126  * UTF-8 characters are present in @str before @p.
127  *
128  * @p does not have to be at the beginning of a UTF-8 character. No check
129  * is made to see if the character found is actually valid other than
130  * it starts with an appropriate byte.
131  *
132  * Return value: a pointer to the found character or %NULL.
133  **/
134 gchar *
135 g_utf8_find_prev_char (const char *str,
136                        const char *p)
137 {
138   for (--p; p >= str; --p)
139     {
140       if ((*p & 0xc0) != 0x80)
141         return (gchar *)p;
142     }
143   return NULL;
144 }
145
146 /**
147  * g_utf8_find_next_char:
148  * @p: a pointer to a position within a UTF-8 encoded string
149  * @end: a pointer to the end of the string, or %NULL to indicate
150  *        that the string is nul-terminated, in which case
151  *        the returned value will be 
152  *
153  * Finds the start of the next UTF-8 character in the string after @p.
154  *
155  * @p does not have to be at the beginning of a UTF-8 character. No check
156  * is made to see if the character found is actually valid other than
157  * it starts with an appropriate byte.
158  * 
159  * Return value: a pointer to the found character or %NULL
160  **/
161 gchar *
162 g_utf8_find_next_char (const gchar *p,
163                        const gchar *end)
164 {
165   if (*p)
166     {
167       if (end)
168         for (++p; p < end && (*p & 0xc0) == 0x80; ++p)
169           ;
170       else
171         for (++p; (*p & 0xc0) == 0x80; ++p)
172           ;
173     }
174   return (p == end) ? NULL : (gchar *)p;
175 }
176
177 /**
178  * g_utf8_prev_char:
179  * @p: a pointer to a position within a UTF-8 encoded string
180  *
181  * Finds the previous UTF-8 character in the string before @p.
182  *
183  * @p does not have to be at the beginning of a UTF-8 character. No check
184  * is made to see if the character found is actually valid other than
185  * it starts with an appropriate byte. If @p might be the first
186  * character of the string, you must use g_utf8_find_prev_char() instead.
187  * 
188  * Return value: a pointer to the found character.
189  **/
190 gchar *
191 g_utf8_prev_char (const gchar *p)
192 {
193   while (TRUE)
194     {
195       p--;
196       if ((*p & 0xc0) != 0x80)
197         return (gchar *)p;
198     }
199 }
200
201 /**
202  * g_utf8_strlen:
203  * @p: pointer to the start of a UTF-8 encoded string.
204  * @max: the maximum number of bytes to examine. If @max
205  *       is less than 0, then the string is assumed to be
206  *       nul-terminated. If @max is 0, @p will not be examined and 
207  *       may be %NULL.
208  * 
209  * Returns the length of the string in characters.
210  *
211  * Return value: the length of the string in characters
212  **/
213 glong
214 g_utf8_strlen (const gchar *p,
215                gssize       max)
216 {
217   glong len = 0;
218   const gchar *start = p;
219   g_return_val_if_fail (p != NULL || max == 0, 0);
220
221   if (max < 0)
222     {
223       while (*p)
224         {
225           p = g_utf8_next_char (p);
226           ++len;
227         }
228     }
229   else
230     {
231       if (max == 0 || !*p)
232         return 0;
233       
234       p = g_utf8_next_char (p);          
235
236       while (p - start < max && *p)
237         {
238           ++len;
239           p = g_utf8_next_char (p);          
240         }
241
242       /* only do the last len increment if we got a complete
243        * char (don't count partial chars)
244        */
245       if (p - start <= max)
246         ++len;
247     }
248
249   return len;
250 }
251
252 /**
253  * g_utf8_get_char:
254  * @p: a pointer to Unicode character encoded as UTF-8
255  * 
256  * Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
257  * If @p does not point to a valid UTF-8 encoded character, results are
258  * undefined. If you are not sure that the bytes are complete
259  * valid Unicode characters, you should use g_utf8_get_char_validated()
260  * instead.
261  * 
262  * Return value: the resulting character
263  **/
264 gunichar
265 g_utf8_get_char (const gchar *p)
266 {
267   int i, mask = 0, len;
268   gunichar result;
269   unsigned char c = (unsigned char) *p;
270
271   UTF8_COMPUTE (c, mask, len);
272   if (len == -1)
273     return (gunichar)-1;
274   UTF8_GET (result, p, i, mask, len);
275
276   return result;
277 }
278
279 /**
280  * g_utf8_offset_to_pointer:
281  * @str: a UTF-8 encoded string
282  * @offset: a character offset within @str
283  * 
284  * Converts from an integer character offset to a pointer to a position
285  * within the string.
286  * 
287  * Since 2.10, this function allows to pass a negative @offset to
288  * step backwards. It is usually worth stepping backwards from the end
289  * instead of forwards if @offset is in the last fourth of the string, 
290  * since moving forward is about 3 times faster than moving backward.
291  * 
292  * Return value: the resulting pointer
293  **/
294 gchar *
295 g_utf8_offset_to_pointer  (const gchar *str,
296                            glong        offset)    
297 {
298   const gchar *s = str;
299
300   if (offset > 0) 
301     while (offset--)
302       s = g_utf8_next_char (s);
303   else
304     {
305       const char *s1;
306
307       /* This nice technique for fast backwards stepping 
308        * through a UTF-8 string was dubbed "stutter stepping" 
309        * by its inventor, Larry Ewing.
310        */
311       while (offset)
312         {
313           s1 = s;
314           s += offset;
315           while ((*s & 0xc0) == 0x80)
316             s--;
317
318           offset += g_utf8_pointer_to_offset (s, s1);
319         }
320     }
321
322   return (gchar *)s;
323 }
324
325 /**
326  * g_utf8_pointer_to_offset:
327  * @str: a UTF-8 encoded string
328  * @pos: a pointer to a position within @str
329  * 
330  * Converts from a pointer to position within a string to a integer
331  * character offset.
332  *
333  * Since 2.10, this function allows @pos to be before @str, and returns
334  * a negative offset in this case.
335  * 
336  * Return value: the resulting character offset
337  **/
338 glong    
339 g_utf8_pointer_to_offset (const gchar *str,
340                           const gchar *pos)
341 {
342   const gchar *s = str;
343   glong offset = 0;    
344
345   if (pos < str) 
346     offset = - g_utf8_pointer_to_offset (pos, str);
347   else
348     while (s < pos)
349       {
350         s = g_utf8_next_char (s);
351         offset++;
352       }
353   
354   return offset;
355 }
356
357
358 /**
359  * g_utf8_strncpy:
360  * @dest: buffer to fill with characters from @src
361  * @src: UTF-8 encoded string
362  * @n: character count
363  * 
364  * Like the standard C strncpy() function, but 
365  * copies a given number of characters instead of a given number of 
366  * bytes. The @src string must be valid UTF-8 encoded text. 
367  * (Use g_utf8_validate() on all text before trying to use UTF-8 
368  * utility functions with it.)
369  * 
370  * Return value: @dest
371  **/
372 gchar *
373 g_utf8_strncpy (gchar       *dest,
374                 const gchar *src,
375                 gsize        n)
376 {
377   const gchar *s = src;
378   while (n && *s)
379     {
380       s = g_utf8_next_char(s);
381       n--;
382     }
383   strncpy(dest, src, s - src);
384   dest[s - src] = 0;
385   return dest;
386 }
387
388 G_LOCK_DEFINE_STATIC (aliases);
389
390 static GHashTable *
391 get_alias_hash (void)
392 {
393   static GHashTable *alias_hash = NULL;
394   const char *aliases;
395
396   G_LOCK (aliases);
397
398   if (!alias_hash)
399     {
400       alias_hash = g_hash_table_new (g_str_hash, g_str_equal);
401       
402       aliases = _g_locale_get_charset_aliases ();
403       while (*aliases != '\0')
404         {
405           const char *canonical;
406           const char *alias;
407           const char **alias_array;
408           int count = 0;
409           
410           alias = aliases;
411           aliases += strlen (aliases) + 1;
412           canonical = aliases;
413           aliases += strlen (aliases) + 1;
414           
415           alias_array = g_hash_table_lookup (alias_hash, canonical);
416           if (alias_array)
417             {
418               while (alias_array[count])
419                 count++;
420             }
421           
422           alias_array = g_renew (const char *, alias_array, count + 2);
423           alias_array[count] = alias;
424           alias_array[count + 1] = NULL;
425           
426           g_hash_table_insert (alias_hash, (char *)canonical, alias_array);
427         }
428     }
429
430   G_UNLOCK (aliases);
431
432   return alias_hash;
433 }
434
435 /* As an abuse of the alias table, the following routines gets
436  * the charsets that are aliases for the canonical name.
437  */
438 G_GNUC_INTERNAL const char ** 
439 _g_charset_get_aliases (const char *canonical_name)
440 {
441   GHashTable *alias_hash = get_alias_hash ();
442
443   return g_hash_table_lookup (alias_hash, canonical_name);
444 }
445
446 static gboolean
447 g_utf8_get_charset_internal (const char  *raw_data,
448                              const char **a)
449 {
450   const char *charset = getenv("CHARSET");
451
452   if (charset && *charset)
453     {
454       *a = charset;
455
456       if (charset && strstr (charset, "UTF-8"))
457         return TRUE;
458       else
459         return FALSE;
460     }
461
462   /* The libcharset code tries to be thread-safe without
463    * a lock, but has a memory leak and a missing memory
464    * barrier, so we lock for it
465    */
466   G_LOCK (aliases);
467   charset = _g_locale_charset_unalias (raw_data);
468   G_UNLOCK (aliases);
469   
470   if (charset && *charset)
471     {
472       *a = charset;
473       
474       if (charset && strstr (charset, "UTF-8"))
475         return TRUE;
476       else
477         return FALSE;
478     }
479
480   /* Assume this for compatibility at present.  */
481   *a = "US-ASCII";
482   
483   return FALSE;
484 }
485
486 typedef struct _GCharsetCache GCharsetCache;
487
488 struct _GCharsetCache {
489   gboolean is_utf8;
490   gchar *raw;
491   gchar *charset;
492 };
493
494 static void
495 charset_cache_free (gpointer data)
496 {
497   GCharsetCache *cache = data;
498   g_free (cache->raw);
499   g_free (cache->charset);
500   g_free (cache);
501 }
502
503 /**
504  * g_get_charset:
505  * @charset: return location for character set name
506  * 
507  * Obtains the character set for the <link linkend="setlocale">current 
508  * locale</link>; you might use this character set as an argument to 
509  * g_convert(), to convert from the current locale's encoding to some 
510  * other encoding. (Frequently g_locale_to_utf8() and g_locale_from_utf8()
511  * are nice shortcuts, though.)
512  *
513  * On Windows the character set returned by this function is the
514  * so-called system default ANSI code-page. That is the character set
515  * used by the "narrow" versions of C library and Win32 functions that
516  * handle file names. It might be different from the character set
517  * used by the C library's current locale.
518  *
519  * The return value is %TRUE if the locale's encoding is UTF-8, in that
520  * case you can perhaps avoid calling g_convert().
521  *
522  * The string returned in @charset is not allocated, and should not be
523  * freed.
524  * 
525  * Return value: %TRUE if the returned charset is UTF-8
526  **/
527 gboolean
528 g_get_charset (G_CONST_RETURN char **charset) 
529 {
530   static GStaticPrivate cache_private = G_STATIC_PRIVATE_INIT;
531   GCharsetCache *cache = g_static_private_get (&cache_private);
532   const gchar *raw;
533
534   if (!cache)
535     {
536       cache = g_new0 (GCharsetCache, 1);
537       g_static_private_set (&cache_private, cache, charset_cache_free);
538     }
539
540   raw = _g_locale_charset_raw ();
541   
542   if (!(cache->raw && strcmp (cache->raw, raw) == 0))
543     {
544       const gchar *new_charset;
545             
546       g_free (cache->raw);
547       g_free (cache->charset);
548       cache->raw = g_strdup (raw);
549       cache->is_utf8 = g_utf8_get_charset_internal (raw, &new_charset);
550       cache->charset = g_strdup (new_charset);
551     }
552
553   if (charset)
554     *charset = cache->charset;
555   
556   return cache->is_utf8;
557 }
558
559 /* unicode_strchr */
560
561 /**
562  * g_unichar_to_utf8:
563  * @c: a Unicode character code
564  * @outbuf: output buffer, must have at least 6 bytes of space.
565  *       If %NULL, the length will be computed and returned
566  *       and nothing will be written to @outbuf.
567  * 
568  * Converts a single character to UTF-8.
569  * 
570  * Return value: number of bytes written
571  **/
572 int
573 g_unichar_to_utf8 (gunichar c,
574                    gchar   *outbuf)
575 {
576   /* If this gets modified, also update the copy in g_string_insert_unichar() */
577   guint len = 0;    
578   int first;
579   int i;
580
581   if (c < 0x80)
582     {
583       first = 0;
584       len = 1;
585     }
586   else if (c < 0x800)
587     {
588       first = 0xc0;
589       len = 2;
590     }
591   else if (c < 0x10000)
592     {
593       first = 0xe0;
594       len = 3;
595     }
596    else if (c < 0x200000)
597     {
598       first = 0xf0;
599       len = 4;
600     }
601   else if (c < 0x4000000)
602     {
603       first = 0xf8;
604       len = 5;
605     }
606   else
607     {
608       first = 0xfc;
609       len = 6;
610     }
611
612   if (outbuf)
613     {
614       for (i = len - 1; i > 0; --i)
615         {
616           outbuf[i] = (c & 0x3f) | 0x80;
617           c >>= 6;
618         }
619       outbuf[0] = c | first;
620     }
621
622   return len;
623 }
624
625 /**
626  * g_utf8_strchr:
627  * @p: a nul-terminated UTF-8 encoded string
628  * @len: the maximum length of @p
629  * @c: a Unicode character
630  * 
631  * Finds the leftmost occurrence of the given Unicode character
632  * in a UTF-8 encoded string, while limiting the search to @len bytes.
633  * If @len is -1, allow unbounded search.
634  * 
635  * Return value: %NULL if the string does not contain the character, 
636  *   otherwise, a pointer to the start of the leftmost occurrence of 
637  *   the character in the string.
638  **/
639 gchar *
640 g_utf8_strchr (const char *p,
641                gssize      len,
642                gunichar    c)
643 {
644   gchar ch[10];
645
646   gint charlen = g_unichar_to_utf8 (c, ch);
647   ch[charlen] = '\0';
648   
649   return g_strstr_len (p, len, ch);
650 }
651
652
653 /**
654  * g_utf8_strrchr:
655  * @p: a nul-terminated UTF-8 encoded string
656  * @len: the maximum length of @p
657  * @c: a Unicode character
658  * 
659  * Find the rightmost occurrence of the given Unicode character
660  * in a UTF-8 encoded string, while limiting the search to @len bytes.
661  * If @len is -1, allow unbounded search.
662  * 
663  * Return value: %NULL if the string does not contain the character, 
664  *   otherwise, a pointer to the start of the rightmost occurrence of the 
665  *   character in the string.
666  **/
667 gchar *
668 g_utf8_strrchr (const char *p,
669                 gssize      len,
670                 gunichar    c)
671 {
672   gchar ch[10];
673
674   gint charlen = g_unichar_to_utf8 (c, ch);
675   ch[charlen] = '\0';
676   
677   return g_strrstr_len (p, len, ch);
678 }
679
680
681 /* Like g_utf8_get_char, but take a maximum length
682  * and return (gunichar)-2 on incomplete trailing character
683  */
684 static inline gunichar
685 g_utf8_get_char_extended (const  gchar *p,
686                           gssize max_len)  
687 {
688   guint i, len;
689   gunichar wc = (guchar) *p;
690
691   if (wc < 0x80)
692     {
693       return wc;
694     }
695   else if (wc < 0xc0)
696     {
697       return (gunichar)-1;
698     }
699   else if (wc < 0xe0)
700     {
701       len = 2;
702       wc &= 0x1f;
703     }
704   else if (wc < 0xf0)
705     {
706       len = 3;
707       wc &= 0x0f;
708     }
709   else if (wc < 0xf8)
710     {
711       len = 4;
712       wc &= 0x07;
713     }
714   else if (wc < 0xfc)
715     {
716       len = 5;
717       wc &= 0x03;
718     }
719   else if (wc < 0xfe)
720     {
721       len = 6;
722       wc &= 0x01;
723     }
724   else
725     {
726       return (gunichar)-1;
727     }
728   
729   if (max_len >= 0 && len > max_len)
730     {
731       for (i = 1; i < max_len; i++)
732         {
733           if ((((guchar *)p)[i] & 0xc0) != 0x80)
734             return (gunichar)-1;
735         }
736       return (gunichar)-2;
737     }
738
739   for (i = 1; i < len; ++i)
740     {
741       gunichar ch = ((guchar *)p)[i];
742       
743       if ((ch & 0xc0) != 0x80)
744         {
745           if (ch)
746             return (gunichar)-1;
747           else
748             return (gunichar)-2;
749         }
750
751       wc <<= 6;
752       wc |= (ch & 0x3f);
753     }
754
755   if (UTF8_LENGTH(wc) != len)
756     return (gunichar)-1;
757   
758   return wc;
759 }
760
761 /**
762  * g_utf8_get_char_validated:
763  * @p: a pointer to Unicode character encoded as UTF-8
764  * @max_len: the maximum number of bytes to read, or -1, for no maximum or
765  *           if @p is nul-terminated
766  * 
767  * Convert a sequence of bytes encoded as UTF-8 to a Unicode character.
768  * This function checks for incomplete characters, for invalid characters
769  * such as characters that are out of the range of Unicode, and for
770  * overlong encodings of valid characters.
771  * 
772  * Return value: the resulting character. If @p points to a partial
773  *    sequence at the end of a string that could begin a valid 
774  *    character (or if @max_len is zero), returns (gunichar)-2; 
775  *    otherwise, if @p does not point to a valid UTF-8 encoded 
776  *    Unicode character, returns (gunichar)-1.
777  **/
778 gunichar
779 g_utf8_get_char_validated (const  gchar *p,
780                            gssize max_len)
781 {
782   gunichar result;
783
784   if (max_len == 0)
785     return (gunichar)-2;
786
787   result = g_utf8_get_char_extended (p, max_len);
788
789   if (result & 0x80000000)
790     return result;
791   else if (!UNICODE_VALID (result))
792     return (gunichar)-1;
793   else
794     return result;
795 }
796
797 /**
798  * g_utf8_to_ucs4_fast:
799  * @str: a UTF-8 encoded string
800  * @len: the maximum length of @str to use. If @len < 0, then
801  *       the string is nul-terminated.
802  * @items_written: location to store the number of characters in the
803  *                 result, or %NULL.
804  *
805  * Convert a string from UTF-8 to a 32-bit fixed width
806  * representation as UCS-4, assuming valid UTF-8 input.
807  * This function is roughly twice as fast as g_utf8_to_ucs4()
808  * but does no error checking on the input.
809  * 
810  * Return value: a pointer to a newly allocated UCS-4 string.
811  *               This value must be freed with g_free().
812  **/
813 gunichar *
814 g_utf8_to_ucs4_fast (const gchar *str,
815                      glong        len,              
816                      glong       *items_written)    
817 {
818   gint j, charlen;
819   gunichar *result;
820   gint n_chars, i;
821   const gchar *p;
822
823   g_return_val_if_fail (str != NULL, NULL);
824
825   p = str;
826   n_chars = 0;
827   if (len < 0)
828     {
829       while (*p)
830         {
831           p = g_utf8_next_char (p);
832           ++n_chars;
833         }
834     }
835   else
836     {
837       while (p < str + len && *p)
838         {
839           p = g_utf8_next_char (p);
840           ++n_chars;
841         }
842     }
843   
844   result = g_new (gunichar, n_chars + 1);
845   
846   p = str;
847   for (i=0; i < n_chars; i++)
848     {
849       gunichar wc = ((unsigned char *)p)[0];
850
851       if (wc < 0x80)
852         {
853           result[i] = wc;
854           p++;
855         }
856       else
857         { 
858           if (wc < 0xe0)
859             {
860               charlen = 2;
861               wc &= 0x1f;
862             }
863           else if (wc < 0xf0)
864             {
865               charlen = 3;
866               wc &= 0x0f;
867             }
868           else if (wc < 0xf8)
869             {
870               charlen = 4;
871               wc &= 0x07;
872             }
873           else if (wc < 0xfc)
874             {
875               charlen = 5;
876               wc &= 0x03;
877             }
878           else
879             {
880               charlen = 6;
881               wc &= 0x01;
882             }
883
884           for (j = 1; j < charlen; j++)
885             {
886               wc <<= 6;
887               wc |= ((unsigned char *)p)[j] & 0x3f;
888             }
889
890           result[i] = wc;
891           p += charlen;
892         }
893     }
894   result[i] = 0;
895
896   if (items_written)
897     *items_written = i;
898
899   return result;
900 }
901
902 /**
903  * g_utf8_to_ucs4:
904  * @str: a UTF-8 encoded string
905  * @len: the maximum length of @str to use. If @len < 0, then
906  *       the string is nul-terminated.
907  * @items_read: location to store number of bytes read, or %NULL.
908  *              If %NULL, then %G_CONVERT_ERROR_PARTIAL_INPUT will be
909  *              returned in case @str contains a trailing partial
910  *              character. If an error occurs then the index of the
911  *              invalid input is stored here.
912  * @items_written: location to store number of characters written or %NULL.
913  *                 The value here stored does not include the trailing 0
914  *                 character. 
915  * @error: location to store the error occuring, or %NULL to ignore
916  *         errors. Any of the errors in #GConvertError other than
917  *         %G_CONVERT_ERROR_NO_CONVERSION may occur.
918  *
919  * Convert a string from UTF-8 to a 32-bit fixed width
920  * representation as UCS-4. A trailing 0 will be added to the
921  * string after the converted text.
922  * 
923  * Return value: a pointer to a newly allocated UCS-4 string.
924  *               This value must be freed with g_free(). If an
925  *               error occurs, %NULL will be returned and
926  *               @error set.
927  **/
928 gunichar *
929 g_utf8_to_ucs4 (const gchar *str,
930                 glong        len,             
931                 glong       *items_read,      
932                 glong       *items_written,   
933                 GError     **error)
934 {
935   gunichar *result = NULL;
936   gint n_chars, i;
937   const gchar *in;
938   
939   in = str;
940   n_chars = 0;
941   while ((len < 0 || str + len - in > 0) && *in)
942     {
943       gunichar wc = g_utf8_get_char_extended (in, len < 0 ? 6 : str + len - in);
944       if (wc & 0x80000000)
945         {
946           if (wc == (gunichar)-2)
947             {
948               if (items_read)
949                 break;
950               else
951                 g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT,
952                              _("Partial character sequence at end of input"));
953             }
954           else
955             g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
956                          _("Invalid byte sequence in conversion input"));
957
958           goto err_out;
959         }
960
961       n_chars++;
962
963       in = g_utf8_next_char (in);
964     }
965
966   result = g_new (gunichar, n_chars + 1);
967   
968   in = str;
969   for (i=0; i < n_chars; i++)
970     {
971       result[i] = g_utf8_get_char (in);
972       in = g_utf8_next_char (in);
973     }
974   result[i] = 0;
975
976   if (items_written)
977     *items_written = n_chars;
978
979  err_out:
980   if (items_read)
981     *items_read = in - str;
982
983   return result;
984 }
985
986 /**
987  * g_ucs4_to_utf8:
988  * @str: a UCS-4 encoded string
989  * @len: the maximum length (number of characters) of @str to use. 
990  *       If @len < 0, then the string is terminated with a 0 character.
991  * @items_read: location to store number of characters read, or %NULL.
992  * @items_written: location to store number of bytes written or %NULL.
993  *                 The value here stored does not include the trailing 0
994  *                 byte. 
995  * @error: location to store the error occuring, or %NULL to ignore
996  *         errors. Any of the errors in #GConvertError other than
997  *         %G_CONVERT_ERROR_NO_CONVERSION may occur.
998  *
999  * Convert a string from a 32-bit fixed width representation as UCS-4.
1000  * to UTF-8. The result will be terminated with a 0 byte.
1001  * 
1002  * Return value: a pointer to a newly allocated UTF-8 string.
1003  *               This value must be freed with g_free(). If an
1004  *               error occurs, %NULL will be returned and
1005  *               @error set. In that case, @items_read will be
1006  *               set to the position of the first invalid input 
1007  *               character.
1008  **/
1009 gchar *
1010 g_ucs4_to_utf8 (const gunichar *str,
1011                 glong           len,              
1012                 glong          *items_read,       
1013                 glong          *items_written,    
1014                 GError        **error)
1015 {
1016   gint result_length;
1017   gchar *result = NULL;
1018   gchar *p;
1019   gint i;
1020
1021   result_length = 0;
1022   for (i = 0; len < 0 || i < len ; i++)
1023     {
1024       if (!str[i])
1025         break;
1026
1027       if (str[i] >= 0x80000000)
1028         {
1029           g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1030                        _("Character out of range for UTF-8"));
1031           goto err_out;
1032         }
1033       
1034       result_length += UTF8_LENGTH (str[i]);
1035     }
1036
1037   result = g_malloc (result_length + 1);
1038   p = result;
1039
1040   i = 0;
1041   while (p < result + result_length)
1042     p += g_unichar_to_utf8 (str[i++], p);
1043   
1044   *p = '\0';
1045
1046   if (items_written)
1047     *items_written = p - result;
1048
1049  err_out:
1050   if (items_read)
1051     *items_read = i;
1052
1053   return result;
1054 }
1055
1056 #define SURROGATE_VALUE(h,l) (((h) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000)
1057
1058 /**
1059  * g_utf16_to_utf8:
1060  * @str: a UTF-16 encoded string
1061  * @len: the maximum length (number of <type>gunichar2</type>) of @str to use. 
1062  *       If @len < 0, then the string is terminated with a 0 character.
1063  * @items_read: location to store number of words read, or %NULL.
1064  *              If %NULL, then %G_CONVERT_ERROR_PARTIAL_INPUT will be
1065  *              returned in case @str contains a trailing partial
1066  *              character. If an error occurs then the index of the
1067  *              invalid input is stored here.
1068  * @items_written: location to store number of bytes written, or %NULL.
1069  *                 The value stored here does not include the trailing
1070  *                 0 byte.
1071  * @error: location to store the error occuring, or %NULL to ignore
1072  *         errors. Any of the errors in #GConvertError other than
1073  *         %G_CONVERT_ERROR_NO_CONVERSION may occur.
1074  *
1075  * Convert a string from UTF-16 to UTF-8. The result will be
1076  * terminated with a 0 byte.
1077  *
1078  * Note that the input is expected to be already in native endianness,
1079  * an initial byte-order-mark character is not handled specially.
1080  * g_convert() can be used to convert a byte buffer of UTF-16 data of 
1081  * ambiguous endianess.
1082  * 
1083  * Return value: a pointer to a newly allocated UTF-8 string.
1084  *               This value must be freed with g_free(). If an
1085  *               error occurs, %NULL will be returned and
1086  *               @error set.
1087  **/
1088 gchar *
1089 g_utf16_to_utf8 (const gunichar2  *str,
1090                  glong             len,              
1091                  glong            *items_read,       
1092                  glong            *items_written,    
1093                  GError          **error)
1094 {
1095   /* This function and g_utf16_to_ucs4 are almost exactly identical - The lines that differ
1096    * are marked.
1097    */
1098   const gunichar2 *in;
1099   gchar *out;
1100   gchar *result = NULL;
1101   gint n_bytes;
1102   gunichar high_surrogate;
1103
1104   g_return_val_if_fail (str != NULL, NULL);
1105
1106   n_bytes = 0;
1107   in = str;
1108   high_surrogate = 0;
1109   while ((len < 0 || in - str < len) && *in)
1110     {
1111       gunichar2 c = *in;
1112       gunichar wc;
1113
1114       if (c >= 0xdc00 && c < 0xe000) /* low surrogate */
1115         {
1116           if (high_surrogate)
1117             {
1118               wc = SURROGATE_VALUE (high_surrogate, c);
1119               high_surrogate = 0;
1120             }
1121           else
1122             {
1123               g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1124                            _("Invalid sequence in conversion input"));
1125               goto err_out;
1126             }
1127         }
1128       else
1129         {
1130           if (high_surrogate)
1131             {
1132               g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1133                            _("Invalid sequence in conversion input"));
1134               goto err_out;
1135             }
1136
1137           if (c >= 0xd800 && c < 0xdc00) /* high surrogate */
1138             {
1139               high_surrogate = c;
1140               goto next1;
1141             }
1142           else
1143             wc = c;
1144         }
1145
1146       /********** DIFFERENT for UTF8/UCS4 **********/
1147       n_bytes += UTF8_LENGTH (wc);
1148
1149     next1:
1150       in++;
1151     }
1152
1153   if (high_surrogate && !items_read)
1154     {
1155       g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT,
1156                    _("Partial character sequence at end of input"));
1157       goto err_out;
1158     }
1159   
1160   /* At this point, everything is valid, and we just need to convert
1161    */
1162   /********** DIFFERENT for UTF8/UCS4 **********/
1163   result = g_malloc (n_bytes + 1);
1164   
1165   high_surrogate = 0;
1166   out = result;
1167   in = str;
1168   while (out < result + n_bytes)
1169     {
1170       gunichar2 c = *in;
1171       gunichar wc;
1172
1173       if (c >= 0xdc00 && c < 0xe000) /* low surrogate */
1174         {
1175           wc = SURROGATE_VALUE (high_surrogate, c);
1176           high_surrogate = 0;
1177         }
1178       else if (c >= 0xd800 && c < 0xdc00) /* high surrogate */
1179         {
1180           high_surrogate = c;
1181           goto next2;
1182         }
1183       else
1184         wc = c;
1185
1186       /********** DIFFERENT for UTF8/UCS4 **********/
1187       out += g_unichar_to_utf8 (wc, out);
1188
1189     next2:
1190       in++;
1191     }
1192   
1193   /********** DIFFERENT for UTF8/UCS4 **********/
1194   *out = '\0';
1195
1196   if (items_written)
1197     /********** DIFFERENT for UTF8/UCS4 **********/
1198     *items_written = out - result;
1199
1200  err_out:
1201   if (items_read)
1202     *items_read = in - str;
1203
1204   return result;
1205 }
1206
1207 /**
1208  * g_utf16_to_ucs4:
1209  * @str: a UTF-16 encoded string
1210  * @len: the maximum length (number of <type>gunichar2</type>) of @str to use. 
1211  *       If @len < 0, then the string is terminated with a 0 character.
1212  * @items_read: location to store number of words read, or %NULL.
1213  *              If %NULL, then %G_CONVERT_ERROR_PARTIAL_INPUT will be
1214  *              returned in case @str contains a trailing partial
1215  *              character. If an error occurs then the index of the
1216  *              invalid input is stored here.
1217  * @items_written: location to store number of characters written, or %NULL.
1218  *                 The value stored here does not include the trailing
1219  *                 0 character.
1220  * @error: location to store the error occuring, or %NULL to ignore
1221  *         errors. Any of the errors in #GConvertError other than
1222  *         %G_CONVERT_ERROR_NO_CONVERSION may occur.
1223  *
1224  * Convert a string from UTF-16 to UCS-4. The result will be
1225  * terminated with a 0 character.
1226  * 
1227  * Return value: a pointer to a newly allocated UCS-4 string.
1228  *               This value must be freed with g_free(). If an
1229  *               error occurs, %NULL will be returned and
1230  *               @error set.
1231  **/
1232 gunichar *
1233 g_utf16_to_ucs4 (const gunichar2  *str,
1234                  glong             len,              
1235                  glong            *items_read,       
1236                  glong            *items_written,    
1237                  GError          **error)
1238 {
1239   const gunichar2 *in;
1240   gchar *out;
1241   gchar *result = NULL;
1242   gint n_bytes;
1243   gunichar high_surrogate;
1244
1245   g_return_val_if_fail (str != NULL, NULL);
1246
1247   n_bytes = 0;
1248   in = str;
1249   high_surrogate = 0;
1250   while ((len < 0 || in - str < len) && *in)
1251     {
1252       gunichar2 c = *in;
1253       gunichar wc;
1254
1255       if (c >= 0xdc00 && c < 0xe000) /* low surrogate */
1256         {
1257           if (high_surrogate)
1258             {
1259               wc = SURROGATE_VALUE (high_surrogate, c);
1260               high_surrogate = 0;
1261             }
1262           else
1263             {
1264               g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1265                            _("Invalid sequence in conversion input"));
1266               goto err_out;
1267             }
1268         }
1269       else
1270         {
1271           if (high_surrogate)
1272             {
1273               g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1274                            _("Invalid sequence in conversion input"));
1275               goto err_out;
1276             }
1277
1278           if (c >= 0xd800 && c < 0xdc00) /* high surrogate */
1279             {
1280               high_surrogate = c;
1281               goto next1;
1282             }
1283           else
1284             wc = c;
1285         }
1286
1287       /********** DIFFERENT for UTF8/UCS4 **********/
1288       n_bytes += sizeof (gunichar);
1289
1290     next1:
1291       in++;
1292     }
1293
1294   if (high_surrogate && !items_read)
1295     {
1296       g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT,
1297                    _("Partial character sequence at end of input"));
1298       goto err_out;
1299     }
1300   
1301   /* At this point, everything is valid, and we just need to convert
1302    */
1303   /********** DIFFERENT for UTF8/UCS4 **********/
1304   result = g_malloc (n_bytes + 4);
1305   
1306   high_surrogate = 0;
1307   out = result;
1308   in = str;
1309   while (out < result + n_bytes)
1310     {
1311       gunichar2 c = *in;
1312       gunichar wc;
1313
1314       if (c >= 0xdc00 && c < 0xe000) /* low surrogate */
1315         {
1316           wc = SURROGATE_VALUE (high_surrogate, c);
1317           high_surrogate = 0;
1318         }
1319       else if (c >= 0xd800 && c < 0xdc00) /* high surrogate */
1320         {
1321           high_surrogate = c;
1322           goto next2;
1323         }
1324       else
1325         wc = c;
1326
1327       /********** DIFFERENT for UTF8/UCS4 **********/
1328       *(gunichar *)out = wc;
1329       out += sizeof (gunichar);
1330
1331     next2:
1332       in++;
1333     }
1334
1335   /********** DIFFERENT for UTF8/UCS4 **********/
1336   *(gunichar *)out = 0;
1337
1338   if (items_written)
1339     /********** DIFFERENT for UTF8/UCS4 **********/
1340     *items_written = (out - result) / sizeof (gunichar);
1341
1342  err_out:
1343   if (items_read)
1344     *items_read = in - str;
1345
1346   return (gunichar *)result;
1347 }
1348
1349 /**
1350  * g_utf8_to_utf16:
1351  * @str: a UTF-8 encoded string
1352  * @len: the maximum length (number of characters) of @str to use. 
1353  *       If @len < 0, then the string is nul-terminated.
1354  * @items_read: location to store number of bytes read, or %NULL.
1355  *              If %NULL, then %G_CONVERT_ERROR_PARTIAL_INPUT will be
1356  *              returned in case @str contains a trailing partial
1357  *              character. If an error occurs then the index of the
1358  *              invalid input is stored here.
1359  * @items_written: location to store number of <type>gunichar2</type> written, 
1360  *                 or %NULL.
1361  *                 The value stored here does not include the trailing 0.
1362  * @error: location to store the error occuring, or %NULL to ignore
1363  *         errors. Any of the errors in #GConvertError other than
1364  *         %G_CONVERT_ERROR_NO_CONVERSION may occur.
1365  *
1366  * Convert a string from UTF-8 to UTF-16. A 0 character will be
1367  * added to the result after the converted text.
1368  * 
1369  * Return value: a pointer to a newly allocated UTF-16 string.
1370  *               This value must be freed with g_free(). If an
1371  *               error occurs, %NULL will be returned and
1372  *               @error set.
1373  **/
1374 gunichar2 *
1375 g_utf8_to_utf16 (const gchar *str,
1376                  glong        len,              
1377                  glong       *items_read,       
1378                  glong       *items_written,    
1379                  GError     **error)
1380 {
1381   gunichar2 *result = NULL;
1382   gint n16;
1383   const gchar *in;
1384   gint i;
1385
1386   g_return_val_if_fail (str != NULL, NULL);
1387
1388   in = str;
1389   n16 = 0;
1390   while ((len < 0 || str + len - in > 0) && *in)
1391     {
1392       gunichar wc = g_utf8_get_char_extended (in, len < 0 ? 6 : str + len - in);
1393       if (wc & 0x80000000)
1394         {
1395           if (wc == (gunichar)-2)
1396             {
1397               if (items_read)
1398                 break;
1399               else
1400                 g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT,
1401                              _("Partial character sequence at end of input"));
1402             }
1403           else
1404             g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1405                          _("Invalid byte sequence in conversion input"));
1406
1407           goto err_out;
1408         }
1409
1410       if (wc < 0xd800)
1411         n16 += 1;
1412       else if (wc < 0xe000)
1413         {
1414           g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1415                        _("Invalid sequence in conversion input"));
1416
1417           goto err_out;
1418         }
1419       else if (wc < 0x10000)
1420         n16 += 1;
1421       else if (wc < 0x110000)
1422         n16 += 2;
1423       else
1424         {
1425           g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1426                        _("Character out of range for UTF-16"));
1427
1428           goto err_out;
1429         }
1430       
1431       in = g_utf8_next_char (in);
1432     }
1433
1434   result = g_new (gunichar2, n16 + 1);
1435   
1436   in = str;
1437   for (i = 0; i < n16;)
1438     {
1439       gunichar wc = g_utf8_get_char (in);
1440
1441       if (wc < 0x10000)
1442         {
1443           result[i++] = wc;
1444         }
1445       else
1446         {
1447           result[i++] = (wc - 0x10000) / 0x400 + 0xd800;
1448           result[i++] = (wc - 0x10000) % 0x400 + 0xdc00;
1449         }
1450       
1451       in = g_utf8_next_char (in);
1452     }
1453
1454   result[i] = 0;
1455
1456   if (items_written)
1457     *items_written = n16;
1458
1459  err_out:
1460   if (items_read)
1461     *items_read = in - str;
1462   
1463   return result;
1464 }
1465
1466 /**
1467  * g_ucs4_to_utf16:
1468  * @str: a UCS-4 encoded string
1469  * @len: the maximum length (number of characters) of @str to use. 
1470  *       If @len < 0, then the string is terminated with a 0 character.
1471  * @items_read: location to store number of bytes read, or %NULL.
1472  *              If an error occurs then the index of the invalid input
1473  *              is stored here.
1474  * @items_written: location to store number of <type>gunichar2</type> 
1475  *                 written, or %NULL. The value stored here does not 
1476  *                 include the trailing 0.
1477  * @error: location to store the error occuring, or %NULL to ignore
1478  *         errors. Any of the errors in #GConvertError other than
1479  *         %G_CONVERT_ERROR_NO_CONVERSION may occur.
1480  *
1481  * Convert a string from UCS-4 to UTF-16. A 0 character will be
1482  * added to the result after the converted text.
1483  * 
1484  * Return value: a pointer to a newly allocated UTF-16 string.
1485  *               This value must be freed with g_free(). If an
1486  *               error occurs, %NULL will be returned and
1487  *               @error set.
1488  **/
1489 gunichar2 *
1490 g_ucs4_to_utf16 (const gunichar  *str,
1491                  glong            len,              
1492                  glong           *items_read,       
1493                  glong           *items_written,    
1494                  GError         **error)
1495 {
1496   gunichar2 *result = NULL;
1497   gint n16;
1498   gint i, j;
1499
1500   n16 = 0;
1501   i = 0;
1502   while ((len < 0 || i < len) && str[i])
1503     {
1504       gunichar wc = str[i];
1505
1506       if (wc < 0xd800)
1507         n16 += 1;
1508       else if (wc < 0xe000)
1509         {
1510           g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1511                        _("Invalid sequence in conversion input"));
1512
1513           goto err_out;
1514         }
1515       else if (wc < 0x10000)
1516         n16 += 1;
1517       else if (wc < 0x110000)
1518         n16 += 2;
1519       else
1520         {
1521           g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1522                        _("Character out of range for UTF-16"));
1523
1524           goto err_out;
1525         }
1526
1527       i++;
1528     }
1529   
1530   result = g_new (gunichar2, n16 + 1);
1531   
1532   for (i = 0, j = 0; j < n16; i++)
1533     {
1534       gunichar wc = str[i];
1535
1536       if (wc < 0x10000)
1537         {
1538           result[j++] = wc;
1539         }
1540       else
1541         {
1542           result[j++] = (wc - 0x10000) / 0x400 + 0xd800;
1543           result[j++] = (wc - 0x10000) % 0x400 + 0xdc00;
1544         }
1545     }
1546   result[j] = 0;
1547
1548   if (items_written)
1549     *items_written = n16;
1550   
1551  err_out:
1552   if (items_read)
1553     *items_read = i;
1554   
1555   return result;
1556 }
1557
1558 #define CONTINUATION_CHAR                           \
1559  G_STMT_START {                                     \
1560   if ((*(guchar *)p & 0xc0) != 0x80) /* 10xxxxxx */ \
1561     goto error;                                     \
1562   val <<= 6;                                        \
1563   val |= (*(guchar *)p) & 0x3f;                     \
1564  } G_STMT_END
1565
1566 static const gchar *
1567 fast_validate (const char *str)
1568
1569 {
1570   gunichar val = 0;
1571   gunichar min = 0;
1572   const gchar *p;
1573
1574   for (p = str; *p; p++)
1575     {
1576       if (*(guchar *)p < 128)
1577         /* done */;
1578       else 
1579         {
1580           const gchar *last;
1581           
1582           last = p;
1583           if ((*(guchar *)p & 0xe0) == 0xc0) /* 110xxxxx */
1584             {
1585               if (G_UNLIKELY ((*(guchar *)p & 0x1e) == 0))
1586                 goto error;
1587               p++;
1588               if (G_UNLIKELY ((*(guchar *)p & 0xc0) != 0x80)) /* 10xxxxxx */
1589                 goto error;
1590             }
1591           else
1592             {
1593               if ((*(guchar *)p & 0xf0) == 0xe0) /* 1110xxxx */
1594                 {
1595                   min = (1 << 11);
1596                   val = *(guchar *)p & 0x0f;
1597                   goto TWO_REMAINING;
1598                 }
1599               else if ((*(guchar *)p & 0xf8) == 0xf0) /* 11110xxx */
1600                 {
1601                   min = (1 << 16);
1602                   val = *(guchar *)p & 0x07;
1603                 }
1604               else
1605                 goto error;
1606               
1607               p++;
1608               CONTINUATION_CHAR;
1609             TWO_REMAINING:
1610               p++;
1611               CONTINUATION_CHAR;
1612               p++;
1613               CONTINUATION_CHAR;
1614               
1615               if (G_UNLIKELY (val < min))
1616                 goto error;
1617
1618               if (G_UNLIKELY (!UNICODE_VALID(val)))
1619                 goto error;
1620             } 
1621           
1622           continue;
1623           
1624         error:
1625           return last;
1626         }
1627     }
1628
1629   return p;
1630 }
1631
1632 static const gchar *
1633 fast_validate_len (const char *str,
1634                    gssize      max_len)
1635
1636 {
1637   gunichar val = 0;
1638   gunichar min = 0;
1639   const gchar *p;
1640
1641   g_assert (max_len >= 0);
1642
1643   for (p = str; ((p - str) < max_len) && *p; p++)
1644     {
1645       if (*(guchar *)p < 128)
1646         /* done */;
1647       else 
1648         {
1649           const gchar *last;
1650           
1651           last = p;
1652           if ((*(guchar *)p & 0xe0) == 0xc0) /* 110xxxxx */
1653             {
1654               if (G_UNLIKELY (max_len - (p - str) < 2))
1655                 goto error;
1656               
1657               if (G_UNLIKELY ((*(guchar *)p & 0x1e) == 0))
1658                 goto error;
1659               p++;
1660               if (G_UNLIKELY ((*(guchar *)p & 0xc0) != 0x80)) /* 10xxxxxx */
1661                 goto error;
1662             }
1663           else
1664             {
1665               if ((*(guchar *)p & 0xf0) == 0xe0) /* 1110xxxx */
1666                 {
1667                   if (G_UNLIKELY (max_len - (p - str) < 3))
1668                     goto error;
1669                   
1670                   min = (1 << 11);
1671                   val = *(guchar *)p & 0x0f;
1672                   goto TWO_REMAINING;
1673                 }
1674               else if ((*(guchar *)p & 0xf8) == 0xf0) /* 11110xxx */
1675                 {
1676                   if (G_UNLIKELY (max_len - (p - str) < 4))
1677                     goto error;
1678                   
1679                   min = (1 << 16);
1680                   val = *(guchar *)p & 0x07;
1681                 }
1682               else
1683                 goto error;
1684               
1685               p++;
1686               CONTINUATION_CHAR;
1687             TWO_REMAINING:
1688               p++;
1689               CONTINUATION_CHAR;
1690               p++;
1691               CONTINUATION_CHAR;
1692               
1693               if (G_UNLIKELY (val < min))
1694                 goto error;
1695               if (G_UNLIKELY (!UNICODE_VALID(val)))
1696                 goto error;
1697             } 
1698           
1699           continue;
1700           
1701         error:
1702           return last;
1703         }
1704     }
1705
1706   return p;
1707 }
1708
1709 /**
1710  * g_utf8_validate:
1711  * @str: a pointer to character data
1712  * @max_len: max bytes to validate, or -1 to go until NUL
1713  * @end: return location for end of valid data
1714  * 
1715  * Validates UTF-8 encoded text. @str is the text to validate;
1716  * if @str is nul-terminated, then @max_len can be -1, otherwise
1717  * @max_len should be the number of bytes to validate.
1718  * If @end is non-%NULL, then the end of the valid range
1719  * will be stored there (i.e. the start of the first invalid 
1720  * character if some bytes were invalid, or the end of the text 
1721  * being validated otherwise).
1722  *
1723  * Note that g_utf8_validate() returns %FALSE if @max_len is 
1724  * positive and NUL is met before @max_len bytes have been read.
1725  *
1726  * Returns %TRUE if all of @str was valid. Many GLib and GTK+
1727  * routines <emphasis>require</emphasis> valid UTF-8 as input;
1728  * so data read from a file or the network should be checked
1729  * with g_utf8_validate() before doing anything else with it.
1730  * 
1731  * Return value: %TRUE if the text was valid UTF-8
1732  **/
1733 gboolean
1734 g_utf8_validate (const char   *str,
1735                  gssize        max_len,    
1736                  const gchar **end)
1737
1738 {
1739   const gchar *p;
1740
1741   if (max_len < 0)
1742     p = fast_validate (str);
1743   else
1744     p = fast_validate_len (str, max_len);
1745
1746   if (end)
1747     *end = p;
1748
1749   if ((max_len >= 0 && p != str + max_len) ||
1750       (max_len < 0 && *p != '\0'))
1751     return FALSE;
1752   else
1753     return TRUE;
1754 }
1755
1756 /**
1757  * g_unichar_validate:
1758  * @ch: a Unicode character
1759  * 
1760  * Checks whether @ch is a valid Unicode character. Some possible
1761  * integer values of @ch will not be valid. 0 is considered a valid
1762  * character, though it's normally a string terminator.
1763  * 
1764  * Return value: %TRUE if @ch is a valid Unicode character
1765  **/
1766 gboolean
1767 g_unichar_validate (gunichar ch)
1768 {
1769   return UNICODE_VALID (ch);
1770 }
1771
1772 /**
1773  * g_utf8_strreverse:
1774  * @str: a UTF-8 encoded string
1775  * @len: the maximum length of @str to use. If @len < 0, then
1776  *       the string is nul-terminated.
1777  *
1778  * Reverses a UTF-8 string. @str must be valid UTF-8 encoded text. 
1779  * (Use g_utf8_validate() on all text before trying to use UTF-8 
1780  * utility functions with it.)
1781  *
1782  * This function is intended for programmatic uses of reversed strings.
1783  * It pays no attention to decomposed characters, combining marks, byte 
1784  * order marks, directional indicators (LRM, LRO, etc) and similar 
1785  * characters which might need special handling when reversing a string 
1786  * for display purposes.
1787  *
1788  * Note that unlike g_strreverse(), this function returns
1789  * newly-allocated memory, which should be freed with g_free() when
1790  * no longer needed. 
1791  *
1792  * Returns: a newly-allocated string which is the reverse of @str.
1793  *
1794  * Since: 2.2
1795  */
1796 gchar *
1797 g_utf8_strreverse (const gchar *str,
1798                    gssize       len)
1799 {
1800   gchar *r, *result;
1801   const gchar *p;
1802
1803   if (len < 0)
1804     len = strlen (str);
1805
1806   result = g_new (gchar, len + 1);
1807   r = result + len;
1808   p = str;
1809   while (r > result)
1810     {
1811       gchar *m, skip = g_utf8_skip[*(guchar*) p];
1812       r -= skip;
1813       for (m = r; skip; skip--)
1814         *m++ = *p++;
1815     }
1816   result[len] = 0;
1817
1818   return result;
1819 }
1820
1821
1822 gchar *
1823 _g_utf8_make_valid (const gchar *name)
1824 {
1825   GString *string;
1826   const gchar *remainder, *invalid;
1827   gint remaining_bytes, valid_bytes;
1828   
1829   string = NULL;
1830   remainder = name;
1831   remaining_bytes = strlen (name);
1832   
1833   while (remaining_bytes != 0) 
1834     {
1835       if (g_utf8_validate (remainder, remaining_bytes, &invalid)) 
1836         break;
1837       valid_bytes = invalid - remainder;
1838     
1839       if (string == NULL) 
1840         string = g_string_sized_new (remaining_bytes);
1841
1842       g_string_append_len (string, remainder, valid_bytes);
1843       /* append U+FFFD REPLACEMENT CHARACTER */
1844       g_string_append (string, "\357\277\275");
1845       
1846       remaining_bytes -= valid_bytes + 1;
1847       remainder = invalid + 1;
1848     }
1849   
1850   if (string == NULL)
1851     return g_strdup (name);
1852   
1853   g_string_append (string, remainder);
1854
1855   g_assert (g_utf8_validate (string->str, -1, NULL));
1856   
1857   return g_string_free (string, FALSE);
1858 }
1859
1860
1861 #define __G_UTF8_C__
1862 #include "galiasdef.c"