Add functions to insert a unichar as UTF-8, since this is reasonably
[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 "glibintl.h"
40
41 #define UTF8_COMPUTE(Char, Mask, Len)                                         \
42   if (Char < 128)                                                             \
43     {                                                                         \
44       Len = 1;                                                                \
45       Mask = 0x7f;                                                            \
46     }                                                                         \
47   else if ((Char & 0xe0) == 0xc0)                                             \
48     {                                                                         \
49       Len = 2;                                                                \
50       Mask = 0x1f;                                                            \
51     }                                                                         \
52   else if ((Char & 0xf0) == 0xe0)                                             \
53     {                                                                         \
54       Len = 3;                                                                \
55       Mask = 0x0f;                                                            \
56     }                                                                         \
57   else if ((Char & 0xf8) == 0xf0)                                             \
58     {                                                                         \
59       Len = 4;                                                                \
60       Mask = 0x07;                                                            \
61     }                                                                         \
62   else if ((Char & 0xfc) == 0xf8)                                             \
63     {                                                                         \
64       Len = 5;                                                                \
65       Mask = 0x03;                                                            \
66     }                                                                         \
67   else if ((Char & 0xfe) == 0xfc)                                             \
68     {                                                                         \
69       Len = 6;                                                                \
70       Mask = 0x01;                                                            \
71     }                                                                         \
72   else                                                                        \
73     Len = -1;
74
75 #define UTF8_LENGTH(Char)              \
76   ((Char) < 0x80 ? 1 :                 \
77    ((Char) < 0x800 ? 2 :               \
78     ((Char) < 0x10000 ? 3 :            \
79      ((Char) < 0x200000 ? 4 :          \
80       ((Char) < 0x4000000 ? 5 : 6)))))
81    
82
83 #define UTF8_GET(Result, Chars, Count, Mask, Len)                             \
84   (Result) = (Chars)[0] & (Mask);                                             \
85   for ((Count) = 1; (Count) < (Len); ++(Count))                               \
86     {                                                                         \
87       if (((Chars)[(Count)] & 0xc0) != 0x80)                                  \
88         {                                                                     \
89           (Result) = -1;                                                      \
90           break;                                                              \
91         }                                                                     \
92       (Result) <<= 6;                                                         \
93       (Result) |= ((Chars)[(Count)] & 0x3f);                                  \
94     }
95
96 #define UNICODE_VALID(Char)                   \
97     ((Char) < 0x110000 &&                     \
98      ((Char) < 0xD800 || (Char) >= 0xE000) && \
99      (Char) != 0xFFFE && (Char) != 0xFFFF)
100    
101      
102 gchar g_utf8_skip[256] = {
103   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,
104   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,
105   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,
106   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,
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   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,
110   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,0,0
111 };
112
113 /**
114  * g_utf8_find_prev_char:
115  * @str: pointer to the beginning of a UTF-8 string
116  * @p: pointer to some position within @str
117  * 
118  * Given a position @p with a UTF-8 encoded string @str, find the start
119  * of the previous UTF-8 character starting before @p. Returns %NULL if no
120  * UTF-8 characters are present in @p before @str.
121  *
122  * @p does not have to be at the beginning of a UTF-8 chracter. No check
123  * is made to see if the character found is actually valid other than
124  * it starts with an appropriate byte.
125  *
126  * Return value: a pointer to the found character or %NULL.
127  **/
128 gchar *
129 g_utf8_find_prev_char (const char *str,
130                        const char *p)
131 {
132   for (--p; p > str; --p)
133     {
134       if ((*p & 0xc0) != 0x80)
135         return (gchar *)p;
136     }
137   return NULL;
138 }
139
140 /**
141  * g_utf8_find_next_char:
142  * @p: a pointer to a position within a UTF-8 encoded string
143  * @end: a pointer to the end of the string, or %NULL to indicate
144  *        that the string is NULL terminated, in which case
145  *        the returned value will be 
146  *
147  * Find the start of the next utf-8 character in the string after @p
148  *
149  * @p does not have to be at the beginning of a UTF-8 chracter. No check
150  * is made to see if the character found is actually valid other than
151  * it starts with an appropriate byte.
152  * 
153  * Return value: a pointer to the found character or %NULL
154  **/
155 gchar *
156 g_utf8_find_next_char (const gchar *p,
157                        const gchar *end)
158 {
159   if (*p)
160     {
161       if (end)
162         for (++p; p < end && (*p & 0xc0) == 0x80; ++p)
163           ;
164       else
165         for (++p; (*p & 0xc0) == 0x80; ++p)
166           ;
167     }
168   return (p == end) ? NULL : (gchar *)p;
169 }
170
171 /**
172  * g_utf8_prev_char:
173  * @p: a pointer to a position within a UTF-8 encoded string
174  *
175  * Find the previous UTF-8 character in the string before @p.
176  *
177  * @p does not have to be at the beginning of a UTF-8 character. No check
178  * is made to see if the character found is actually valid other than
179  * it starts with an appropriate byte. If @p might be the first
180  * character of the string, you must use g_utf8_find_prev_char instead.
181  * 
182  * Return value: a pointer to the found character.
183  **/
184 gchar *
185 g_utf8_prev_char (const gchar *p)
186 {
187   while (TRUE)
188     {
189       p--;
190       if ((*p & 0xc0) != 0x80)
191         return (gchar *)p;
192     }
193 }
194
195 /**
196  * g_utf8_strlen:
197  * @p: pointer to the start of a UTF-8 string.
198  * @max: the maximum number of bytes to examine. If @max
199  *       is less than 0, then the string is assumed to be
200  *       nul-terminated.
201  * 
202  * Return value: the length of the string in characters
203  **/
204 glong
205 g_utf8_strlen (const gchar *p,
206                gssize       max)
207 {
208   glong len = 0;
209   const gchar *start = p;
210
211   if (max < 0)
212     {
213       while (*p)
214         {
215           p = g_utf8_next_char (p);
216           ++len;
217         }
218     }
219   else
220     {
221       if (max == 0 || !*p)
222         return 0;
223       
224       p = g_utf8_next_char (p);          
225
226       while (p - start < max && *p)
227         {
228           ++len;
229           p = g_utf8_next_char (p);          
230         }
231
232       /* only do the last len increment if we got a complete
233        * char (don't count partial chars)
234        */
235       if (p - start == max)
236         ++len;
237     }
238
239   return len;
240 }
241
242 /**
243  * g_utf8_get_char:
244  * @p: a pointer to unicode character encoded as UTF-8
245  * 
246  * Convert a sequence of bytes encoded as UTF-8 to a unicode character.
247  * If @p does not point to a valid UTF-8 encoded character, results are
248  * undefined. If you are not sure that the bytes are complete
249  * valid unicode characters, you should use g_utf8_get_char_validated()
250  * instead.
251  * 
252  * Return value: the resulting character
253  **/
254 gunichar
255 g_utf8_get_char (const gchar *p)
256 {
257   int i, mask = 0, len;
258   gunichar result;
259   unsigned char c = (unsigned char) *p;
260
261   UTF8_COMPUTE (c, mask, len);
262   if (len == -1)
263     return (gunichar)-1;
264   UTF8_GET (result, p, i, mask, len);
265
266   return result;
267 }
268
269 /**
270  * g_utf8_offset_to_pointer:
271  * @str: a UTF-8 encoded string
272  * @offset: a character offset within the string.
273  * 
274  * Converts from an integer character offset to a pointer to a position
275  * within the string.
276  * 
277  * Return value: the resulting pointer
278  **/
279 gchar *
280 g_utf8_offset_to_pointer  (const gchar *str,
281                            glong        offset)    
282 {
283   const gchar *s = str;
284   while (offset--)
285     s = g_utf8_next_char (s);
286   
287   return (gchar *)s;
288 }
289
290 /**
291  * g_utf8_pointer_to_offset:
292  * @str: a UTF-8 encoded string
293  * @pos: a pointer to a position within @str
294  * 
295  * Converts from a pointer to position within a string to a integer
296  * character offset
297  * 
298  * Return value: the resulting character offset
299  **/
300 glong    
301 g_utf8_pointer_to_offset (const gchar *str,
302                           const gchar *pos)
303 {
304   const gchar *s = str;
305   glong offset = 0;    
306   
307   while (s < pos)
308     {
309       s = g_utf8_next_char (s);
310       offset++;
311     }
312
313   return offset;
314 }
315
316
317 /**
318  * g_utf8_strncpy:
319  * @dest: buffer to fill with characters from @src
320  * @src: UTF-8 string
321  * @n: character count
322  * 
323  * Like the standard C strncpy() function, but copies a given number
324  * of characters instead of a given number of bytes. The @src string
325  * must be valid UTF-8 encoded text. (Use g_utf8_validate() on all
326  * text before trying to use UTF-8 utility functions with it.)
327  * 
328  * Return value: @dest
329  **/
330 gchar *
331 g_utf8_strncpy (gchar *dest, const gchar *src, size_t n)
332 {
333   const gchar *s = src;
334   while (n && *s)
335     {
336       s = g_utf8_next_char(s);
337       n--;
338     }
339   strncpy(dest, src, s - src);
340   dest[s - src] = 0;
341   return dest;
342 }
343
344 static gboolean
345 g_utf8_get_charset_internal (char **a)
346 {
347   char *charset = getenv("CHARSET");
348
349   if (charset && a && ! *a)
350     *a = charset;
351
352   if (charset && strstr (charset, "UTF-8"))
353       return TRUE;
354
355 #ifdef HAVE_CODESET
356   charset = nl_langinfo(CODESET);
357   if (charset)
358     {
359       if (a && ! *a)
360         *a = charset;
361       if (strcmp (charset, "UTF-8") == 0)
362         return TRUE;
363     }
364 #endif
365   
366 #if 0 /* #ifdef _NL_CTYPE_CODESET_NAME */
367   charset = nl_langinfo (_NL_CTYPE_CODESET_NAME);
368   if (charset)
369     {
370       if (a && ! *a)
371         *a = charset;
372       if (strcmp (charset, "UTF-8") == 0)
373         return TRUE;
374     }
375 #endif
376
377 #ifdef G_PLATFORM_WIN32
378   if (a && ! *a)
379     {
380       static char codepage[10];
381       
382       sprintf (codepage, "CP%d", GetACP ());
383       *a = codepage;
384       /* What about codepage 1200? Is that UTF-8? */
385       return FALSE;
386     }
387 #else
388   if (a && ! *a) 
389     *a = "US-ASCII";
390 #endif
391
392   /* Assume this for compatibility at present.  */
393   return FALSE;
394 }
395
396 static int utf8_locale_cache = -1;
397 static char *utf8_charset_cache = NULL;
398
399 /**
400  * g_get_charset:
401  * @charset: return location for character set name
402  * 
403  * Obtains the character set for the current locale; you might use
404  * this character set as an argument to g_convert(), to convert from
405  * the current locale's encoding to some other encoding. (Frequently
406  * g_locale_to_utf8() and g_locale_from_utf8() are nice shortcuts,
407  * though.)
408  *
409  * The return value is %TRUE if the locale's encoding is UTF-8, in that
410  * case you can perhaps avoid calling g_convert().
411  *
412  * The string returned in @charset is not allocated, and should not be
413  * freed.
414  * 
415  * Return value: %TRUE if the returned charset is UTF-8
416  **/
417 gboolean
418 g_get_charset (G_CONST_RETURN char **charset) 
419 {
420   if (utf8_locale_cache != -1)
421     {
422       if (charset)
423         *charset = utf8_charset_cache;
424       return utf8_locale_cache;
425     }
426   utf8_locale_cache = g_utf8_get_charset_internal (&utf8_charset_cache);
427   if (charset) 
428     *charset = utf8_charset_cache;
429   return utf8_locale_cache;
430 }
431
432 /* unicode_strchr */
433
434 /**
435  * g_unichar_to_utf8:
436  * @c: a ISO10646 character code
437  * @outbuf: output buffer, must have at least 6 bytes of space.
438  *       If %NULL, the length will be computed and returned
439  *       and nothing will be written to @out.
440  * 
441  * Convert a single character to utf8
442  * 
443  * Return value: number of bytes written
444  **/
445 int
446 g_unichar_to_utf8 (gunichar c,
447                    gchar   *outbuf)
448 {
449   guint len = 0;    
450   int first;
451   int i;
452
453   if (c < 0x80)
454     {
455       first = 0;
456       len = 1;
457     }
458   else if (c < 0x800)
459     {
460       first = 0xc0;
461       len = 2;
462     }
463   else if (c < 0x10000)
464     {
465       first = 0xe0;
466       len = 3;
467     }
468    else if (c < 0x200000)
469     {
470       first = 0xf0;
471       len = 4;
472     }
473   else if (c < 0x4000000)
474     {
475       first = 0xf8;
476       len = 5;
477     }
478   else
479     {
480       first = 0xfc;
481       len = 6;
482     }
483
484   if (outbuf)
485     {
486       for (i = len - 1; i > 0; --i)
487         {
488           outbuf[i] = (c & 0x3f) | 0x80;
489           c >>= 6;
490         }
491       outbuf[0] = c | first;
492     }
493
494   return len;
495 }
496
497 /**
498  * g_utf8_strchr:
499  * @p: a nul-terminated utf-8 string
500  * @p_len: the maximum length of p
501  * @c: a iso-10646 character
502  * 
503  * Find the leftmost occurence of the given iso-10646 character
504  * in a UTF-8 string, while limiting the search to p_len bytes.
505  * If len is -1, allow unbounded search.
506  * 
507  * Return value: NULL if the string does not contain the character, otherwise, a
508  *               a pointer to the start of the leftmost of the character in the string.
509  **/
510 gchar *
511 g_utf8_strchr (const char *p,
512                gssize      p_len,
513                gunichar    c)
514 {
515   gchar ch[10];
516
517   gint len = g_unichar_to_utf8 (c, ch);
518   ch[len] = '\0';
519   
520   return g_strstr_len (p, p_len, ch);
521 }
522
523
524 /**
525  * g_utf8_strrchr:
526  * @p: a nul-terminated utf-8 string
527  * @p_len: the maximum length of p
528  * @c: a iso-10646 character/
529  * 
530  * Find the rightmost occurence of the given iso-10646 character
531  * in a UTF-8 string, while limiting the search to p_len bytes.
532  * If len is -1, allow unbounded search.
533  * 
534  * Return value: NULL if the string does not contain the character, otherwise, a
535  *               a pointer to the start of the rightmost of the character in the string.
536  **/
537 gchar *
538 g_utf8_strrchr (const char *p,
539                 gssize      p_len,
540                 gunichar    c)
541 {
542   gchar ch[10];
543
544   gint len = g_unichar_to_utf8 (c, ch);
545   ch[len] = '\0';
546   
547   return g_strrstr_len (p, p_len, ch);
548 }
549
550
551 /* Like g_utf8_get_char, but take a maximum length
552  * and return (gunichar)-2 on incomplete trailing character
553  */
554 static inline gunichar
555 g_utf8_get_char_extended (const  gchar *p,
556                           gssize max_len)  
557 {
558   guint i, len;
559   gunichar wc = (guchar) *p;
560
561   if (wc < 0x80)
562     {
563       return wc;
564     }
565   else if (wc < 0xc0)
566     {
567       return (gunichar)-1;
568     }
569   else if (wc < 0xe0)
570     {
571       len = 2;
572       wc &= 0x1f;
573     }
574   else if (wc < 0xf0)
575     {
576       len = 3;
577       wc &= 0x0f;
578     }
579   else if (wc < 0xf8)
580     {
581       len = 4;
582       wc &= 0x07;
583     }
584   else if (wc < 0xfc)
585     {
586       len = 5;
587       wc &= 0x03;
588     }
589   else if (wc < 0xfe)
590     {
591       len = 6;
592       wc &= 0x01;
593     }
594   else
595     {
596       return (gunichar)-1;
597     }
598   
599   if (max_len >= 0 && len > max_len)
600     {
601       for (i = 1; i < max_len; i++)
602         {
603           if ((((guchar *)p)[i] & 0xc0) != 0x80)
604             return (gunichar)-1;
605         }
606       return (gunichar)-2;
607     }
608
609   for (i = 1; i < len; ++i)
610     {
611       gunichar ch = ((guchar *)p)[i];
612       
613       if ((ch & 0xc0) != 0x80)
614         {
615           if (ch)
616             return (gunichar)-1;
617           else
618             return (gunichar)-2;
619         }
620
621       wc <<= 6;
622       wc |= (ch & 0x3f);
623     }
624
625   if (UTF8_LENGTH(wc) != len)
626     return (gunichar)-1;
627   
628   return wc;
629 }
630
631 /**
632  * g_utf8_get_char_validated:
633  * @p: a pointer to unicode character encoded as UTF-8
634  * @max_len: the maximum number of bytes to read, or -1, for no maximum.
635  * 
636  * Convert a sequence of bytes encoded as UTF-8 to a unicode character.
637  * This function checks for incomplete characters, for invalid characters
638  * such as characters that are out of the range of Unicode, and for
639  * overlong encodings of valid characters.
640  * 
641  * Return value: the resulting character. If @p points to a partial
642  *    sequence at the end of a string that could begin a valid character,
643  *    returns (gunichar)-2; otherwise, if @p does not point to a valid
644  *    UTF-8 encoded unicode character, returns (gunichar)-1.
645  **/
646 gunichar
647 g_utf8_get_char_validated (const  gchar *p,
648                            gssize max_len)
649 {
650   gunichar result = g_utf8_get_char_extended (p, max_len);
651
652   if (result & 0x80000000)
653     return result;
654   else if (!UNICODE_VALID (result))
655     return (gunichar)-1;
656   else
657     return result;
658 }
659
660 /**
661  * g_utf8_to_ucs4_fast:
662  * @str: a UTF-8 encoded string
663  * @len: the maximum length of @str to use. If < 0, then
664  *       the string is %NULL terminated.
665  * @items_written: location to store the number of characters in the
666  *                 result, or %NULL.
667  *
668  * Convert a string from UTF-8 to a 32-bit fixed width
669  * representation as UCS-4, assuming valid UTF-8 input.
670  * This function is roughly twice as fast as g_utf8_to_ucs4()
671  * but does no error checking on the input.
672  * 
673  * Return value: a pointer to a newly allocated UCS-4 string.
674  *               This value must be freed with g_free()
675  **/
676 gunichar *
677 g_utf8_to_ucs4_fast (const gchar *str,
678                      glong        len,              
679                      glong       *items_written)    
680 {
681   gint j, charlen;
682   gunichar *result;
683   gint n_chars, i;
684   const gchar *p;
685
686   g_return_val_if_fail (str != NULL, NULL);
687
688   p = str;
689   n_chars = 0;
690   if (len < 0)
691     {
692       while (*p)
693         {
694           p = g_utf8_next_char (p);
695           ++n_chars;
696         }
697     }
698   else
699     {
700       while (p < str + len && *p)
701         {
702           p = g_utf8_next_char (p);
703           ++n_chars;
704         }
705     }
706   
707   result = g_new (gunichar, n_chars + 1);
708   
709   p = str;
710   for (i=0; i < n_chars; i++)
711     {
712       gunichar wc = ((unsigned char *)p)[0];
713
714       if (wc < 0x80)
715         {
716           result[i] = wc;
717           p++;
718         }
719       else
720         { 
721           if (wc < 0xe0)
722             {
723               charlen = 2;
724               wc &= 0x1f;
725             }
726           else if (wc < 0xf0)
727             {
728               charlen = 3;
729               wc &= 0x0f;
730             }
731           else if (wc < 0xf8)
732             {
733               charlen = 4;
734               wc &= 0x07;
735             }
736           else if (wc < 0xfc)
737             {
738               charlen = 5;
739               wc &= 0x03;
740             }
741           else
742             {
743               charlen = 6;
744               wc &= 0x01;
745             }
746
747           for (j = 1; j < charlen; j++)
748             {
749               wc <<= 6;
750               wc |= ((unsigned char *)p)[j] & 0x3f;
751             }
752
753           result[i] = wc;
754           p += charlen;
755         }
756     }
757   result[i] = 0;
758
759   if (items_written)
760     *items_written = i;
761
762   return result;
763 }
764
765 /**
766  * g_utf8_to_ucs4:
767  * @str: a UTF-8 encoded string
768  * @len: the maximum length of @str to use. If < 0, then
769  *       the string is %NULL terminated.
770  * @items_read: location to store number of bytes read, or %NULL.
771  *              If %NULL, then %G_CONVERT_ERROR_PARTIAL_INPUT will be
772  *              returned in case @str contains a trailing partial
773  *              character. If an error occurs then the index of the
774  *              invalid input is stored here.
775  * @items_written: location to store number of characters written or %NULL.
776  *                 The value here stored does not include the trailing 0
777  *                 character. 
778  * @error: location to store the error occuring, or %NULL to ignore
779  *         errors. Any of the errors in #GConvertError other than
780  *         %G_CONVERT_ERROR_NO_CONVERSION may occur.
781  *
782  * Convert a string from UTF-8 to a 32-bit fixed width
783  * representation as UCS-4. A trailing 0 will be added to the
784  * string after the converted text.
785  * 
786  * Return value: a pointer to a newly allocated UCS-4 string.
787  *               This value must be freed with g_free(). If an
788  *               error occurs, %NULL will be returned and
789  *               @error set.
790  **/
791 gunichar *
792 g_utf8_to_ucs4 (const gchar *str,
793                 glong        len,             
794                 glong       *items_read,      
795                 glong       *items_written,   
796                 GError     **error)
797 {
798   gunichar *result = NULL;
799   gint n_chars, i;
800   const gchar *in;
801   
802   in = str;
803   n_chars = 0;
804   while ((len < 0 || str + len - in > 0) && *in)
805     {
806       gunichar wc = g_utf8_get_char_extended (in, str + len - in);
807       if (wc & 0x80000000)
808         {
809           if (wc == (gunichar)-2)
810             {
811               if (items_read)
812                 break;
813               else
814                 g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT,
815                              _("Partial character sequence at end of input"));
816             }
817           else
818             g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
819                          _("Invalid byte sequence in conversion input"));
820
821           goto err_out;
822         }
823
824       n_chars++;
825
826       in = g_utf8_next_char (in);
827     }
828
829   result = g_new (gunichar, n_chars + 1);
830   
831   in = str;
832   for (i=0; i < n_chars; i++)
833     {
834       result[i] = g_utf8_get_char (in);
835       in = g_utf8_next_char (in);
836     }
837   result[i] = 0;
838
839   if (items_written)
840     *items_written = n_chars;
841
842  err_out:
843   if (items_read)
844     *items_read = in - str;
845
846   return result;
847 }
848
849 /**
850  * g_ucs4_to_utf8:
851  * @str: a UCS-4 encoded string
852  * @len: the maximum length of @str to use. If < 0, then
853  *       the string is %NULL terminated.
854  * @items_read: location to store number of characters read read, or %NULL.
855  * @items_written: location to store number of bytes written or %NULL.
856  *                 The value here stored does not include the trailing 0
857  *                 byte. 
858  * @error: location to store the error occuring, or %NULL to ignore
859  *         errors. Any of the errors in #GConvertError other than
860  *         %G_CONVERT_ERROR_NO_CONVERSION may occur.
861  *
862  * Convert a string from a 32-bit fixed width representation as UCS-4.
863  * to UTF-8. The result will be terminated with a 0 byte.
864  * 
865  * Return value: a pointer to a newly allocated UTF-8 string.
866  *               This value must be freed with g_free(). If an
867  *               error occurs, %NULL will be returned and
868  *               @error set.
869  **/
870 gchar *
871 g_ucs4_to_utf8 (const gunichar *str,
872                 glong           len,              
873                 glong          *items_read,       
874                 glong          *items_written,    
875                 GError        **error)
876 {
877   gint result_length;
878   gchar *result = NULL;
879   gchar *p;
880   gint i;
881
882   result_length = 0;
883   for (i = 0; len < 0 || i < len ; i++)
884     {
885       if (!str[i])
886         break;
887
888       if (str[i] >= 0x80000000)
889         {
890           if (items_read)
891             *items_read = i;
892           
893           g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
894                        _("Character out of range for UTF-8"));
895           goto err_out;
896         }
897       
898       result_length += UTF8_LENGTH (str[i]);
899     }
900
901   result = g_malloc (result_length + 1);
902   p = result;
903
904   i = 0;
905   while (p < result + result_length)
906     p += g_unichar_to_utf8 (str[i++], p);
907   
908   *p = '\0';
909
910   if (items_written)
911     *items_written = p - result;
912
913  err_out:
914   if (items_read)
915     *items_read = i;
916
917   return result;
918 }
919
920 #define SURROGATE_VALUE(h,l) (((h) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000)
921
922 /**
923  * g_utf16_to_utf8:
924  * @str: a UTF-16 encoded string
925  * @len: the maximum length of @str to use. If < 0, then
926  *       the string is terminated with a 0 character.
927  * @items_read: location to store number of words read, or %NULL.
928  *              If %NULL, then %G_CONVERT_ERROR_PARTIAL_INPUT will be
929  *              returned in case @str contains a trailing partial
930  *              character. If an error occurs then the index of the
931  *              invalid input is stored here.
932  * @items_written: location to store number of bytes written, or %NULL.
933  *                 The value stored here does not include the trailing
934  *                 0 byte.
935  * @error: location to store the error occuring, or %NULL to ignore
936  *         errors. Any of the errors in #GConvertError other than
937  *         %G_CONVERT_ERROR_NO_CONVERSION may occur.
938  *
939  * Convert a string from UTF-16 to UTF-8. The result will be
940  * terminated with a 0 byte.
941  * 
942  * Return value: a pointer to a newly allocated UTF-8 string.
943  *               This value must be freed with g_free(). If an
944  *               error occurs, %NULL will be returned and
945  *               @error set.
946  **/
947 gchar *
948 g_utf16_to_utf8 (const gunichar2  *str,
949                  glong             len,              
950                  glong            *items_read,       
951                  glong            *items_written,    
952                  GError          **error)
953 {
954   /* This function and g_utf16_to_ucs4 are almost exactly identical - The lines that differ
955    * are marked.
956    */
957   const gunichar2 *in;
958   gchar *out;
959   gchar *result = NULL;
960   gint n_bytes;
961   gunichar high_surrogate;
962
963   g_return_val_if_fail (str != 0, NULL);
964
965   n_bytes = 0;
966   in = str;
967   high_surrogate = 0;
968   while ((len < 0 || in - str < len) && *in)
969     {
970       gunichar2 c = *in;
971       gunichar wc;
972
973       if (c >= 0xdc00 && c < 0xe000) /* low surrogate */
974         {
975           if (high_surrogate)
976             {
977               wc = SURROGATE_VALUE (high_surrogate, c);
978               high_surrogate = 0;
979             }
980           else
981             {
982               g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
983                            _("Invalid sequence in conversion input"));
984               goto err_out;
985             }
986         }
987       else
988         {
989           if (high_surrogate)
990             {
991               g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
992                            _("Invalid sequence in conversion input"));
993               goto err_out;
994             }
995
996           if (c >= 0xd800 && c < 0xdc00) /* high surrogate */
997             {
998               high_surrogate = c;
999               goto next1;
1000             }
1001           else
1002             wc = c;
1003         }
1004
1005       /********** DIFFERENT for UTF8/UCS4 **********/
1006       n_bytes += UTF8_LENGTH (wc);
1007
1008     next1:
1009       in++;
1010     }
1011
1012   if (high_surrogate && !items_read)
1013     {
1014       g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT,
1015                    _("Partial character sequence at end of input"));
1016       goto err_out;
1017     }
1018   
1019   /* At this point, everything is valid, and we just need to convert
1020    */
1021   /********** DIFFERENT for UTF8/UCS4 **********/
1022   result = g_malloc (n_bytes + 1);
1023   
1024   high_surrogate = 0;
1025   out = result;
1026   in = str;
1027   while (out < result + n_bytes)
1028     {
1029       gunichar2 c = *in;
1030       gunichar wc;
1031
1032       if (c >= 0xdc00 && c < 0xe000) /* low surrogate */
1033         {
1034           wc = SURROGATE_VALUE (high_surrogate, c);
1035           high_surrogate = 0;
1036         }
1037       else if (c >= 0xd800 && c < 0xdc00) /* high surrogate */
1038         {
1039           high_surrogate = c;
1040           goto next2;
1041         }
1042       else
1043         wc = c;
1044
1045       /********** DIFFERENT for UTF8/UCS4 **********/
1046       out += g_unichar_to_utf8 (wc, out);
1047
1048     next2:
1049       in++;
1050     }
1051   
1052   /********** DIFFERENT for UTF8/UCS4 **********/
1053   *out = '\0';
1054
1055   if (items_written)
1056     /********** DIFFERENT for UTF8/UCS4 **********/
1057     *items_written = out - result;
1058
1059  err_out:
1060   if (items_read)
1061     *items_read = in - str;
1062
1063   return result;
1064 }
1065
1066 /**
1067  * g_utf16_to_ucs4:
1068  * @str: a UTF-16 encoded string
1069  * @len: the maximum length of @str to use. If < 0, then
1070  *       the string is terminated with a 0 character.
1071  * @items_read: location to store number of words read, or %NULL.
1072  *              If %NULL, then %G_CONVERT_ERROR_PARTIAL_INPUT will be
1073  *              returned in case @str contains a trailing partial
1074  *              character. If an error occurs then the index of the
1075  *              invalid input is stored here.
1076  * @items_written: location to store number of characters written, or %NULL.
1077  *                 The value stored here does not include the trailing
1078  *                 0 character.
1079  * @error: location to store the error occuring, or %NULL to ignore
1080  *         errors. Any of the errors in #GConvertError other than
1081  *         %G_CONVERT_ERROR_NO_CONVERSION may occur.
1082  *
1083  * Convert a string from UTF-16 to UCS-4. The result will be
1084  * terminated with a 0 character.
1085  * 
1086  * Return value: a pointer to a newly allocated UCS-4 string.
1087  *               This value must be freed with g_free(). If an
1088  *               error occurs, %NULL will be returned and
1089  *               @error set.
1090  **/
1091 gunichar *
1092 g_utf16_to_ucs4 (const gunichar2  *str,
1093                  glong             len,              
1094                  glong            *items_read,       
1095                  glong            *items_written,    
1096                  GError          **error)
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 != 0, 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 += sizeof (gunichar);
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 + 4);
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       *(gunichar *)out = wc;
1188       out += sizeof (gunichar);
1189
1190     next2:
1191       in++;
1192     }
1193
1194   /********** DIFFERENT for UTF8/UCS4 **********/
1195   *(gunichar *)out = 0;
1196
1197   if (items_written)
1198     /********** DIFFERENT for UTF8/UCS4 **********/
1199     *items_written = (out - result) / sizeof (gunichar);
1200
1201  err_out:
1202   if (items_read)
1203     *items_read = in - str;
1204
1205   return (gunichar *)result;
1206 }
1207
1208 /**
1209  * g_utf8_to_utf16:
1210  * @str: a UTF-8 encoded string
1211  * @len: the maximum length of @str to use. If < 0, then
1212  *       the string is %NULL terminated.
1213  
1214  * @items_read: location to store number of bytes read, or %NULL.
1215  *              If %NULL, then %G_CONVERT_ERROR_PARTIAL_INPUT will be
1216  *              returned in case @str contains a trailing partial
1217  *              character. If an error occurs then the index of the
1218  *              invalid input is stored here.
1219  * @items_written: location to store number of words written, or %NULL.
1220  *                 The value stored here does not include the trailing
1221  *                 0 word.
1222  * @error: location to store the error occuring, or %NULL to ignore
1223  *         errors. Any of the errors in #GConvertError other than
1224  *         %G_CONVERT_ERROR_NO_CONVERSION may occur.
1225  *
1226  * Convert a string from UTF-8 to UTF-16. A 0 word will be
1227  * added to the result after the converted text.
1228  * 
1229  * Return value: a pointer to a newly allocated UTF-16 string.
1230  *               This value must be freed with g_free(). If an
1231  *               error occurs, %NULL will be returned and
1232  *               @error set.
1233  **/
1234 gunichar2 *
1235 g_utf8_to_utf16 (const gchar *str,
1236                  glong        len,              
1237                  glong       *items_read,       
1238                  glong       *items_written,    
1239                  GError     **error)
1240 {
1241   gunichar2 *result = NULL;
1242   gint n16;
1243   const gchar *in;
1244   gint i;
1245
1246   g_return_val_if_fail (str != NULL, NULL);
1247
1248   in = str;
1249   n16 = 0;
1250   while ((len < 0 || str + len - in > 0) && *in)
1251     {
1252       gunichar wc = g_utf8_get_char_extended (in, str + len - in);
1253       if (wc & 0x80000000)
1254         {
1255           if (wc == (gunichar)-2)
1256             {
1257               if (items_read)
1258                 break;
1259               else
1260                 g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT,
1261                              _("Partial character sequence at end of input"));
1262             }
1263           else
1264             g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1265                          _("Invalid byte sequence in conversion input"));
1266
1267           goto err_out;
1268         }
1269
1270       if (wc < 0xd800)
1271         n16 += 1;
1272       else if (wc < 0xe000)
1273         {
1274           g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1275                        _("Invalid sequence in conversion input"));
1276
1277           goto err_out;
1278         }
1279       else if (wc < 0x10000)
1280         n16 += 1;
1281       else if (wc < 0x110000)
1282         n16 += 2;
1283       else
1284         {
1285           g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1286                        _("Character out of range for UTF-16"));
1287
1288           goto err_out;
1289         }
1290       
1291       in = g_utf8_next_char (in);
1292     }
1293
1294   result = g_new (gunichar2, n16 + 1);
1295   
1296   in = str;
1297   for (i = 0; i < n16;)
1298     {
1299       gunichar wc = g_utf8_get_char (in);
1300
1301       if (wc < 0x10000)
1302         {
1303           result[i++] = wc;
1304         }
1305       else
1306         {
1307           result[i++] = (wc - 0x10000) / 0x400 + 0xd800;
1308           result[i++] = (wc - 0x10000) % 0x400 + 0xdc00;
1309         }
1310       
1311       in = g_utf8_next_char (in);
1312     }
1313
1314   result[i] = 0;
1315
1316   if (items_written)
1317     *items_written = n16;
1318
1319  err_out:
1320   if (items_read)
1321     *items_read = in - str;
1322   
1323   return result;
1324 }
1325
1326 /**
1327  * g_ucs4_to_utf16:
1328  * @str: a UCS-4 encoded string
1329  * @len: the maximum length of @str to use. If < 0, then
1330  *       the string is terminated with a zero character.
1331  * @items_read: location to store number of bytes read, or %NULL.
1332  *              If an error occurs then the index of the invalid input
1333  *              is stored here.
1334  * @items_written: location to store number of words written, or %NULL.
1335  *                 The value stored here does not include the trailing
1336  *                 0 word.
1337  * @error: location to store the error occuring, or %NULL to ignore
1338  *         errors. Any of the errors in #GConvertError other than
1339  *         %G_CONVERT_ERROR_NO_CONVERSION may occur.
1340  *
1341  * Convert a string from UCS-4 to UTF-16. A 0 word will be
1342  * added to the result after the converted text.
1343  * 
1344  * Return value: a pointer to a newly allocated UTF-16 string.
1345  *               This value must be freed with g_free(). If an
1346  *               error occurs, %NULL will be returned and
1347  *               @error set.
1348  **/
1349 gunichar2 *
1350 g_ucs4_to_utf16 (const gunichar  *str,
1351                  glong            len,              
1352                  glong           *items_read,       
1353                  glong           *items_written,    
1354                  GError         **error)
1355 {
1356   gunichar2 *result = NULL;
1357   gint n16;
1358   gint i, j;
1359
1360   n16 = 0;
1361   i = 0;
1362   while ((len < 0 || i < len) && str[i])
1363     {
1364       gunichar wc = str[i];
1365
1366       if (wc < 0xd800)
1367         n16 += 1;
1368       else if (wc < 0xe000)
1369         {
1370           g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1371                        _("Invalid sequence in conversion input"));
1372
1373           goto err_out;
1374         }
1375       else if (wc < 0x10000)
1376         n16 += 1;
1377       else if (wc < 0x110000)
1378         n16 += 2;
1379       else
1380         {
1381           g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1382                        _("Character out of range for UTF-16"));
1383
1384           goto err_out;
1385         }
1386
1387       i++;
1388     }
1389   
1390   result = g_new (gunichar2, n16 + 1);
1391   
1392   for (i = 0, j = 0; j < n16; i++)
1393     {
1394       gunichar wc = str[i];
1395
1396       if (wc < 0x10000)
1397         {
1398           result[j++] = wc;
1399         }
1400       else
1401         {
1402           result[j++] = (wc - 0x10000) / 0x400 + 0xd800;
1403           result[j++] = (wc - 0x10000) % 0x400 + 0xdc00;
1404         }
1405     }
1406   result[j] = 0;
1407
1408   if (items_written)
1409     *items_written = n16;
1410   
1411  err_out:
1412   if (items_read)
1413     *items_read = i;
1414   
1415   return result;
1416 }
1417
1418 /**
1419  * g_utf8_validate:
1420  * @str: a pointer to character data
1421  * @max_len: max bytes to validate, or -1 to go until nul
1422  * @end: return location for end of valid data
1423  * 
1424  * Validates UTF-8 encoded text. @str is the text to validate;
1425  * if @str is nul-terminated, then @max_len can be -1, otherwise
1426  * @max_len should be the number of bytes to validate.
1427  * If @end is non-%NULL, then the end of the valid range
1428  * will be stored there (i.e. the address of the first invalid byte
1429  * if some bytes were invalid, or the end of the text being validated
1430  * otherwise).
1431  *
1432  * Returns TRUE if all of @str was valid. Many GLib and GTK+
1433  * routines <emphasis>require</emphasis> valid UTF8 as input;
1434  * so data read from a file or the network should be checked
1435  * with g_utf8_validate() before doing anything else with it.
1436  * 
1437  * Return value: TRUE if the text was valid UTF-8.
1438  **/
1439 gboolean
1440 g_utf8_validate (const gchar  *str,
1441                  gssize        max_len,    
1442                  const gchar **end)
1443 {
1444
1445   const gchar *p;
1446
1447   g_return_val_if_fail (str != NULL, FALSE);
1448   
1449   if (end)
1450     *end = str;
1451   
1452   p = str;
1453   
1454   while ((max_len < 0 || (p - str) < max_len) && *p)
1455     {
1456       int i, mask = 0, len;
1457       gunichar result;
1458       unsigned char c = (unsigned char) *p;
1459       
1460       UTF8_COMPUTE (c, mask, len);
1461
1462       if (len == -1)
1463         break;
1464
1465       /* check that the expected number of bytes exists in str */
1466       if (max_len >= 0 &&
1467           ((max_len - (p - str)) < len))
1468         break;
1469         
1470       UTF8_GET (result, p, i, mask, len);
1471
1472       if (UTF8_LENGTH (result) != len) /* Check for overlong UTF-8 */
1473         break;
1474
1475       if (result == (gunichar)-1)
1476         break;
1477
1478       if (!UNICODE_VALID (result))
1479         break;
1480       
1481       p += len;
1482     }
1483
1484   if (end)
1485     *end = p;
1486
1487   /* See that we covered the entire length if a length was
1488    * passed in, or that we ended on a nul if not
1489    */
1490   if (max_len >= 0 &&
1491       p != (str + max_len))
1492     return FALSE;
1493   else if (max_len < 0 &&
1494            *p != '\0')
1495     return FALSE;
1496   else
1497     return TRUE;
1498 }
1499
1500 /**
1501  * g_unichar_validate:
1502  * @ch: a Unicode character
1503  * 
1504  * Checks whether @ch is a valid Unicode character. Some possible
1505  * integer values of @ch will not be valid. 0 is considered a valid
1506  * character, though it's normally a string terminator.
1507  * 
1508  * Return value: %TRUE if @ch is a valid Unicode character
1509  **/
1510 gboolean
1511 g_unichar_validate (gunichar ch)
1512 {
1513   return UNICODE_VALID (ch);
1514 }