Made g_utf8_find_prev_char able to return the first character of a string.
[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,
332                 const gchar *src,
333                 gsize        n)
334 {
335   const gchar *s = src;
336   while (n && *s)
337     {
338       s = g_utf8_next_char(s);
339       n--;
340     }
341   strncpy(dest, src, s - src);
342   dest[s - src] = 0;
343   return dest;
344 }
345
346 static gboolean
347 g_utf8_get_charset_internal (char **a)
348 {
349   char *charset = getenv("CHARSET");
350
351   if (charset && a && ! *a)
352     *a = charset;
353
354   if (charset && strstr (charset, "UTF-8"))
355       return TRUE;
356
357 #ifdef HAVE_CODESET
358   charset = nl_langinfo(CODESET);
359   if (charset)
360     {
361       if (a && ! *a)
362         *a = charset;
363       if (strcmp (charset, "UTF-8") == 0)
364         return TRUE;
365     }
366 #endif
367   
368 #if 0 /* #ifdef _NL_CTYPE_CODESET_NAME */
369   charset = nl_langinfo (_NL_CTYPE_CODESET_NAME);
370   if (charset)
371     {
372       if (a && ! *a)
373         *a = charset;
374       if (strcmp (charset, "UTF-8") == 0)
375         return TRUE;
376     }
377 #endif
378
379 #ifdef G_PLATFORM_WIN32
380   if (a && ! *a)
381     {
382       static char codepage[10];
383       
384       sprintf (codepage, "CP%d", GetACP ());
385       *a = codepage;
386       /* What about codepage 1200? Is that UTF-8? */
387       return FALSE;
388     }
389 #else
390   if (a && ! *a) 
391     *a = "US-ASCII";
392 #endif
393
394   /* Assume this for compatibility at present.  */
395   return FALSE;
396 }
397
398 static int utf8_locale_cache = -1;
399 static char *utf8_charset_cache = NULL;
400
401 /**
402  * g_get_charset:
403  * @charset: return location for character set name
404  * 
405  * Obtains the character set for the current locale; you might use
406  * this character set as an argument to g_convert(), to convert from
407  * the current locale's encoding to some other encoding. (Frequently
408  * g_locale_to_utf8() and g_locale_from_utf8() are nice shortcuts,
409  * though.)
410  *
411  * The return value is %TRUE if the locale's encoding is UTF-8, in that
412  * case you can perhaps avoid calling g_convert().
413  *
414  * The string returned in @charset is not allocated, and should not be
415  * freed.
416  * 
417  * Return value: %TRUE if the returned charset is UTF-8
418  **/
419 gboolean
420 g_get_charset (G_CONST_RETURN char **charset) 
421 {
422   if (utf8_locale_cache != -1)
423     {
424       if (charset)
425         *charset = utf8_charset_cache;
426       return utf8_locale_cache;
427     }
428   utf8_locale_cache = g_utf8_get_charset_internal (&utf8_charset_cache);
429   if (charset) 
430     *charset = utf8_charset_cache;
431   return utf8_locale_cache;
432 }
433
434 /* unicode_strchr */
435
436 /**
437  * g_unichar_to_utf8:
438  * @c: a ISO10646 character code
439  * @outbuf: output buffer, must have at least 6 bytes of space.
440  *       If %NULL, the length will be computed and returned
441  *       and nothing will be written to @out.
442  * 
443  * Convert a single character to utf8
444  * 
445  * Return value: number of bytes written
446  **/
447 int
448 g_unichar_to_utf8 (gunichar c,
449                    gchar   *outbuf)
450 {
451   guint len = 0;    
452   int first;
453   int i;
454
455   if (c < 0x80)
456     {
457       first = 0;
458       len = 1;
459     }
460   else if (c < 0x800)
461     {
462       first = 0xc0;
463       len = 2;
464     }
465   else if (c < 0x10000)
466     {
467       first = 0xe0;
468       len = 3;
469     }
470    else if (c < 0x200000)
471     {
472       first = 0xf0;
473       len = 4;
474     }
475   else if (c < 0x4000000)
476     {
477       first = 0xf8;
478       len = 5;
479     }
480   else
481     {
482       first = 0xfc;
483       len = 6;
484     }
485
486   if (outbuf)
487     {
488       for (i = len - 1; i > 0; --i)
489         {
490           outbuf[i] = (c & 0x3f) | 0x80;
491           c >>= 6;
492         }
493       outbuf[0] = c | first;
494     }
495
496   return len;
497 }
498
499 /**
500  * g_utf8_strchr:
501  * @p: a nul-terminated utf-8 string
502  * @p_len: the maximum length of p
503  * @c: a iso-10646 character
504  * 
505  * Find the leftmost occurence of the given iso-10646 character
506  * in a UTF-8 string, while limiting the search to p_len bytes.
507  * If len is -1, allow unbounded search.
508  * 
509  * Return value: NULL if the string does not contain the character, otherwise, a
510  *               a pointer to the start of the leftmost of the character in the string.
511  **/
512 gchar *
513 g_utf8_strchr (const char *p,
514                gssize      p_len,
515                gunichar    c)
516 {
517   gchar ch[10];
518
519   gint len = g_unichar_to_utf8 (c, ch);
520   ch[len] = '\0';
521   
522   return g_strstr_len (p, p_len, ch);
523 }
524
525
526 /**
527  * g_utf8_strrchr:
528  * @p: a nul-terminated utf-8 string
529  * @p_len: the maximum length of p
530  * @c: a iso-10646 character/
531  * 
532  * Find the rightmost occurence of the given iso-10646 character
533  * in a UTF-8 string, while limiting the search to p_len bytes.
534  * If len is -1, allow unbounded search.
535  * 
536  * Return value: NULL if the string does not contain the character, otherwise, a
537  *               a pointer to the start of the rightmost of the character in the string.
538  **/
539 gchar *
540 g_utf8_strrchr (const char *p,
541                 gssize      p_len,
542                 gunichar    c)
543 {
544   gchar ch[10];
545
546   gint len = g_unichar_to_utf8 (c, ch);
547   ch[len] = '\0';
548   
549   return g_strrstr_len (p, p_len, ch);
550 }
551
552
553 /* Like g_utf8_get_char, but take a maximum length
554  * and return (gunichar)-2 on incomplete trailing character
555  */
556 static inline gunichar
557 g_utf8_get_char_extended (const  gchar *p,
558                           gssize max_len)  
559 {
560   guint i, len;
561   gunichar wc = (guchar) *p;
562
563   if (wc < 0x80)
564     {
565       return wc;
566     }
567   else if (wc < 0xc0)
568     {
569       return (gunichar)-1;
570     }
571   else if (wc < 0xe0)
572     {
573       len = 2;
574       wc &= 0x1f;
575     }
576   else if (wc < 0xf0)
577     {
578       len = 3;
579       wc &= 0x0f;
580     }
581   else if (wc < 0xf8)
582     {
583       len = 4;
584       wc &= 0x07;
585     }
586   else if (wc < 0xfc)
587     {
588       len = 5;
589       wc &= 0x03;
590     }
591   else if (wc < 0xfe)
592     {
593       len = 6;
594       wc &= 0x01;
595     }
596   else
597     {
598       return (gunichar)-1;
599     }
600   
601   if (max_len >= 0 && len > max_len)
602     {
603       for (i = 1; i < max_len; i++)
604         {
605           if ((((guchar *)p)[i] & 0xc0) != 0x80)
606             return (gunichar)-1;
607         }
608       return (gunichar)-2;
609     }
610
611   for (i = 1; i < len; ++i)
612     {
613       gunichar ch = ((guchar *)p)[i];
614       
615       if ((ch & 0xc0) != 0x80)
616         {
617           if (ch)
618             return (gunichar)-1;
619           else
620             return (gunichar)-2;
621         }
622
623       wc <<= 6;
624       wc |= (ch & 0x3f);
625     }
626
627   if (UTF8_LENGTH(wc) != len)
628     return (gunichar)-1;
629   
630   return wc;
631 }
632
633 /**
634  * g_utf8_get_char_validated:
635  * @p: a pointer to unicode character encoded as UTF-8
636  * @max_len: the maximum number of bytes to read, or -1, for no maximum.
637  * 
638  * Convert a sequence of bytes encoded as UTF-8 to a unicode character.
639  * This function checks for incomplete characters, for invalid characters
640  * such as characters that are out of the range of Unicode, and for
641  * overlong encodings of valid characters.
642  * 
643  * Return value: the resulting character. If @p points to a partial
644  *    sequence at the end of a string that could begin a valid character,
645  *    returns (gunichar)-2; otherwise, if @p does not point to a valid
646  *    UTF-8 encoded unicode character, returns (gunichar)-1.
647  **/
648 gunichar
649 g_utf8_get_char_validated (const  gchar *p,
650                            gssize max_len)
651 {
652   gunichar result = g_utf8_get_char_extended (p, max_len);
653
654   if (result & 0x80000000)
655     return result;
656   else if (!UNICODE_VALID (result))
657     return (gunichar)-1;
658   else
659     return result;
660 }
661
662 /**
663  * g_utf8_to_ucs4_fast:
664  * @str: a UTF-8 encoded string
665  * @len: the maximum length of @str to use. If < 0, then
666  *       the string is %NULL terminated.
667  * @items_written: location to store the number of characters in the
668  *                 result, or %NULL.
669  *
670  * Convert a string from UTF-8 to a 32-bit fixed width
671  * representation as UCS-4, assuming valid UTF-8 input.
672  * This function is roughly twice as fast as g_utf8_to_ucs4()
673  * but does no error checking on the input.
674  * 
675  * Return value: a pointer to a newly allocated UCS-4 string.
676  *               This value must be freed with g_free()
677  **/
678 gunichar *
679 g_utf8_to_ucs4_fast (const gchar *str,
680                      glong        len,              
681                      glong       *items_written)    
682 {
683   gint j, charlen;
684   gunichar *result;
685   gint n_chars, i;
686   const gchar *p;
687
688   g_return_val_if_fail (str != NULL, NULL);
689
690   p = str;
691   n_chars = 0;
692   if (len < 0)
693     {
694       while (*p)
695         {
696           p = g_utf8_next_char (p);
697           ++n_chars;
698         }
699     }
700   else
701     {
702       while (p < str + len && *p)
703         {
704           p = g_utf8_next_char (p);
705           ++n_chars;
706         }
707     }
708   
709   result = g_new (gunichar, n_chars + 1);
710   
711   p = str;
712   for (i=0; i < n_chars; i++)
713     {
714       gunichar wc = ((unsigned char *)p)[0];
715
716       if (wc < 0x80)
717         {
718           result[i] = wc;
719           p++;
720         }
721       else
722         { 
723           if (wc < 0xe0)
724             {
725               charlen = 2;
726               wc &= 0x1f;
727             }
728           else if (wc < 0xf0)
729             {
730               charlen = 3;
731               wc &= 0x0f;
732             }
733           else if (wc < 0xf8)
734             {
735               charlen = 4;
736               wc &= 0x07;
737             }
738           else if (wc < 0xfc)
739             {
740               charlen = 5;
741               wc &= 0x03;
742             }
743           else
744             {
745               charlen = 6;
746               wc &= 0x01;
747             }
748
749           for (j = 1; j < charlen; j++)
750             {
751               wc <<= 6;
752               wc |= ((unsigned char *)p)[j] & 0x3f;
753             }
754
755           result[i] = wc;
756           p += charlen;
757         }
758     }
759   result[i] = 0;
760
761   if (items_written)
762     *items_written = i;
763
764   return result;
765 }
766
767 /**
768  * g_utf8_to_ucs4:
769  * @str: a UTF-8 encoded string
770  * @len: the maximum length of @str to use. If < 0, then
771  *       the string is %NULL terminated.
772  * @items_read: location to store number of bytes read, or %NULL.
773  *              If %NULL, then %G_CONVERT_ERROR_PARTIAL_INPUT will be
774  *              returned in case @str contains a trailing partial
775  *              character. If an error occurs then the index of the
776  *              invalid input is stored here.
777  * @items_written: location to store number of characters written or %NULL.
778  *                 The value here stored does not include the trailing 0
779  *                 character. 
780  * @error: location to store the error occuring, or %NULL to ignore
781  *         errors. Any of the errors in #GConvertError other than
782  *         %G_CONVERT_ERROR_NO_CONVERSION may occur.
783  *
784  * Convert a string from UTF-8 to a 32-bit fixed width
785  * representation as UCS-4. A trailing 0 will be added to the
786  * string after the converted text.
787  * 
788  * Return value: a pointer to a newly allocated UCS-4 string.
789  *               This value must be freed with g_free(). If an
790  *               error occurs, %NULL will be returned and
791  *               @error set.
792  **/
793 gunichar *
794 g_utf8_to_ucs4 (const gchar *str,
795                 glong        len,             
796                 glong       *items_read,      
797                 glong       *items_written,   
798                 GError     **error)
799 {
800   gunichar *result = NULL;
801   gint n_chars, i;
802   const gchar *in;
803   
804   in = str;
805   n_chars = 0;
806   while ((len < 0 || str + len - in > 0) && *in)
807     {
808       gunichar wc = g_utf8_get_char_extended (in, str + len - in);
809       if (wc & 0x80000000)
810         {
811           if (wc == (gunichar)-2)
812             {
813               if (items_read)
814                 break;
815               else
816                 g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT,
817                              _("Partial character sequence at end of input"));
818             }
819           else
820             g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
821                          _("Invalid byte sequence in conversion input"));
822
823           goto err_out;
824         }
825
826       n_chars++;
827
828       in = g_utf8_next_char (in);
829     }
830
831   result = g_new (gunichar, n_chars + 1);
832   
833   in = str;
834   for (i=0; i < n_chars; i++)
835     {
836       result[i] = g_utf8_get_char (in);
837       in = g_utf8_next_char (in);
838     }
839   result[i] = 0;
840
841   if (items_written)
842     *items_written = n_chars;
843
844  err_out:
845   if (items_read)
846     *items_read = in - str;
847
848   return result;
849 }
850
851 /**
852  * g_ucs4_to_utf8:
853  * @str: a UCS-4 encoded string
854  * @len: the maximum length of @str to use. If < 0, then
855  *       the string is %NULL terminated.
856  * @items_read: location to store number of characters read read, or %NULL.
857  * @items_written: location to store number of bytes written or %NULL.
858  *                 The value here stored does not include the trailing 0
859  *                 byte. 
860  * @error: location to store the error occuring, or %NULL to ignore
861  *         errors. Any of the errors in #GConvertError other than
862  *         %G_CONVERT_ERROR_NO_CONVERSION may occur.
863  *
864  * Convert a string from a 32-bit fixed width representation as UCS-4.
865  * to UTF-8. The result will be terminated with a 0 byte.
866  * 
867  * Return value: a pointer to a newly allocated UTF-8 string.
868  *               This value must be freed with g_free(). If an
869  *               error occurs, %NULL will be returned and
870  *               @error set.
871  **/
872 gchar *
873 g_ucs4_to_utf8 (const gunichar *str,
874                 glong           len,              
875                 glong          *items_read,       
876                 glong          *items_written,    
877                 GError        **error)
878 {
879   gint result_length;
880   gchar *result = NULL;
881   gchar *p;
882   gint i;
883
884   result_length = 0;
885   for (i = 0; len < 0 || i < len ; i++)
886     {
887       if (!str[i])
888         break;
889
890       if (str[i] >= 0x80000000)
891         {
892           if (items_read)
893             *items_read = i;
894           
895           g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
896                        _("Character out of range for UTF-8"));
897           goto err_out;
898         }
899       
900       result_length += UTF8_LENGTH (str[i]);
901     }
902
903   result = g_malloc (result_length + 1);
904   p = result;
905
906   i = 0;
907   while (p < result + result_length)
908     p += g_unichar_to_utf8 (str[i++], p);
909   
910   *p = '\0';
911
912   if (items_written)
913     *items_written = p - result;
914
915  err_out:
916   if (items_read)
917     *items_read = i;
918
919   return result;
920 }
921
922 #define SURROGATE_VALUE(h,l) (((h) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000)
923
924 /**
925  * g_utf16_to_utf8:
926  * @str: a UTF-16 encoded string
927  * @len: the maximum length of @str to use. If < 0, then
928  *       the string is terminated with a 0 character.
929  * @items_read: location to store number of words read, or %NULL.
930  *              If %NULL, then %G_CONVERT_ERROR_PARTIAL_INPUT will be
931  *              returned in case @str contains a trailing partial
932  *              character. If an error occurs then the index of the
933  *              invalid input is stored here.
934  * @items_written: location to store number of bytes written, or %NULL.
935  *                 The value stored here does not include the trailing
936  *                 0 byte.
937  * @error: location to store the error occuring, or %NULL to ignore
938  *         errors. Any of the errors in #GConvertError other than
939  *         %G_CONVERT_ERROR_NO_CONVERSION may occur.
940  *
941  * Convert a string from UTF-16 to UTF-8. The result will be
942  * terminated with a 0 byte.
943  * 
944  * Return value: a pointer to a newly allocated UTF-8 string.
945  *               This value must be freed with g_free(). If an
946  *               error occurs, %NULL will be returned and
947  *               @error set.
948  **/
949 gchar *
950 g_utf16_to_utf8 (const gunichar2  *str,
951                  glong             len,              
952                  glong            *items_read,       
953                  glong            *items_written,    
954                  GError          **error)
955 {
956   /* This function and g_utf16_to_ucs4 are almost exactly identical - The lines that differ
957    * are marked.
958    */
959   const gunichar2 *in;
960   gchar *out;
961   gchar *result = NULL;
962   gint n_bytes;
963   gunichar high_surrogate;
964
965   g_return_val_if_fail (str != 0, NULL);
966
967   n_bytes = 0;
968   in = str;
969   high_surrogate = 0;
970   while ((len < 0 || in - str < len) && *in)
971     {
972       gunichar2 c = *in;
973       gunichar wc;
974
975       if (c >= 0xdc00 && c < 0xe000) /* low surrogate */
976         {
977           if (high_surrogate)
978             {
979               wc = SURROGATE_VALUE (high_surrogate, c);
980               high_surrogate = 0;
981             }
982           else
983             {
984               g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
985                            _("Invalid sequence in conversion input"));
986               goto err_out;
987             }
988         }
989       else
990         {
991           if (high_surrogate)
992             {
993               g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
994                            _("Invalid sequence in conversion input"));
995               goto err_out;
996             }
997
998           if (c >= 0xd800 && c < 0xdc00) /* high surrogate */
999             {
1000               high_surrogate = c;
1001               goto next1;
1002             }
1003           else
1004             wc = c;
1005         }
1006
1007       /********** DIFFERENT for UTF8/UCS4 **********/
1008       n_bytes += UTF8_LENGTH (wc);
1009
1010     next1:
1011       in++;
1012     }
1013
1014   if (high_surrogate && !items_read)
1015     {
1016       g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT,
1017                    _("Partial character sequence at end of input"));
1018       goto err_out;
1019     }
1020   
1021   /* At this point, everything is valid, and we just need to convert
1022    */
1023   /********** DIFFERENT for UTF8/UCS4 **********/
1024   result = g_malloc (n_bytes + 1);
1025   
1026   high_surrogate = 0;
1027   out = result;
1028   in = str;
1029   while (out < result + n_bytes)
1030     {
1031       gunichar2 c = *in;
1032       gunichar wc;
1033
1034       if (c >= 0xdc00 && c < 0xe000) /* low surrogate */
1035         {
1036           wc = SURROGATE_VALUE (high_surrogate, c);
1037           high_surrogate = 0;
1038         }
1039       else if (c >= 0xd800 && c < 0xdc00) /* high surrogate */
1040         {
1041           high_surrogate = c;
1042           goto next2;
1043         }
1044       else
1045         wc = c;
1046
1047       /********** DIFFERENT for UTF8/UCS4 **********/
1048       out += g_unichar_to_utf8 (wc, out);
1049
1050     next2:
1051       in++;
1052     }
1053   
1054   /********** DIFFERENT for UTF8/UCS4 **********/
1055   *out = '\0';
1056
1057   if (items_written)
1058     /********** DIFFERENT for UTF8/UCS4 **********/
1059     *items_written = out - result;
1060
1061  err_out:
1062   if (items_read)
1063     *items_read = in - str;
1064
1065   return result;
1066 }
1067
1068 /**
1069  * g_utf16_to_ucs4:
1070  * @str: a UTF-16 encoded string
1071  * @len: the maximum length of @str to use. If < 0, then
1072  *       the string is terminated with a 0 character.
1073  * @items_read: location to store number of words read, or %NULL.
1074  *              If %NULL, then %G_CONVERT_ERROR_PARTIAL_INPUT will be
1075  *              returned in case @str contains a trailing partial
1076  *              character. If an error occurs then the index of the
1077  *              invalid input is stored here.
1078  * @items_written: location to store number of characters written, or %NULL.
1079  *                 The value stored here does not include the trailing
1080  *                 0 character.
1081  * @error: location to store the error occuring, or %NULL to ignore
1082  *         errors. Any of the errors in #GConvertError other than
1083  *         %G_CONVERT_ERROR_NO_CONVERSION may occur.
1084  *
1085  * Convert a string from UTF-16 to UCS-4. The result will be
1086  * terminated with a 0 character.
1087  * 
1088  * Return value: a pointer to a newly allocated UCS-4 string.
1089  *               This value must be freed with g_free(). If an
1090  *               error occurs, %NULL will be returned and
1091  *               @error set.
1092  **/
1093 gunichar *
1094 g_utf16_to_ucs4 (const gunichar2  *str,
1095                  glong             len,              
1096                  glong            *items_read,       
1097                  glong            *items_written,    
1098                  GError          **error)
1099 {
1100   const gunichar2 *in;
1101   gchar *out;
1102   gchar *result = NULL;
1103   gint n_bytes;
1104   gunichar high_surrogate;
1105
1106   g_return_val_if_fail (str != 0, NULL);
1107
1108   n_bytes = 0;
1109   in = str;
1110   high_surrogate = 0;
1111   while ((len < 0 || in - str < len) && *in)
1112     {
1113       gunichar2 c = *in;
1114       gunichar wc;
1115
1116       if (c >= 0xdc00 && c < 0xe000) /* low surrogate */
1117         {
1118           if (high_surrogate)
1119             {
1120               wc = SURROGATE_VALUE (high_surrogate, c);
1121               high_surrogate = 0;
1122             }
1123           else
1124             {
1125               g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1126                            _("Invalid sequence in conversion input"));
1127               goto err_out;
1128             }
1129         }
1130       else
1131         {
1132           if (high_surrogate)
1133             {
1134               g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1135                            _("Invalid sequence in conversion input"));
1136               goto err_out;
1137             }
1138
1139           if (c >= 0xd800 && c < 0xdc00) /* high surrogate */
1140             {
1141               high_surrogate = c;
1142               goto next1;
1143             }
1144           else
1145             wc = c;
1146         }
1147
1148       /********** DIFFERENT for UTF8/UCS4 **********/
1149       n_bytes += sizeof (gunichar);
1150
1151     next1:
1152       in++;
1153     }
1154
1155   if (high_surrogate && !items_read)
1156     {
1157       g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT,
1158                    _("Partial character sequence at end of input"));
1159       goto err_out;
1160     }
1161   
1162   /* At this point, everything is valid, and we just need to convert
1163    */
1164   /********** DIFFERENT for UTF8/UCS4 **********/
1165   result = g_malloc (n_bytes + 4);
1166   
1167   high_surrogate = 0;
1168   out = result;
1169   in = str;
1170   while (out < result + n_bytes)
1171     {
1172       gunichar2 c = *in;
1173       gunichar wc;
1174
1175       if (c >= 0xdc00 && c < 0xe000) /* low surrogate */
1176         {
1177           wc = SURROGATE_VALUE (high_surrogate, c);
1178           high_surrogate = 0;
1179         }
1180       else if (c >= 0xd800 && c < 0xdc00) /* high surrogate */
1181         {
1182           high_surrogate = c;
1183           goto next2;
1184         }
1185       else
1186         wc = c;
1187
1188       /********** DIFFERENT for UTF8/UCS4 **********/
1189       *(gunichar *)out = wc;
1190       out += sizeof (gunichar);
1191
1192     next2:
1193       in++;
1194     }
1195
1196   /********** DIFFERENT for UTF8/UCS4 **********/
1197   *(gunichar *)out = 0;
1198
1199   if (items_written)
1200     /********** DIFFERENT for UTF8/UCS4 **********/
1201     *items_written = (out - result) / sizeof (gunichar);
1202
1203  err_out:
1204   if (items_read)
1205     *items_read = in - str;
1206
1207   return (gunichar *)result;
1208 }
1209
1210 /**
1211  * g_utf8_to_utf16:
1212  * @str: a UTF-8 encoded string
1213  * @len: the maximum length of @str to use. If < 0, then
1214  *       the string is %NULL terminated.
1215  
1216  * @items_read: location to store number of bytes read, or %NULL.
1217  *              If %NULL, then %G_CONVERT_ERROR_PARTIAL_INPUT will be
1218  *              returned in case @str contains a trailing partial
1219  *              character. If an error occurs then the index of the
1220  *              invalid input is stored here.
1221  * @items_written: location to store number of words written, or %NULL.
1222  *                 The value stored here does not include the trailing
1223  *                 0 word.
1224  * @error: location to store the error occuring, or %NULL to ignore
1225  *         errors. Any of the errors in #GConvertError other than
1226  *         %G_CONVERT_ERROR_NO_CONVERSION may occur.
1227  *
1228  * Convert a string from UTF-8 to UTF-16. A 0 word will be
1229  * added to the result after the converted text.
1230  * 
1231  * Return value: a pointer to a newly allocated UTF-16 string.
1232  *               This value must be freed with g_free(). If an
1233  *               error occurs, %NULL will be returned and
1234  *               @error set.
1235  **/
1236 gunichar2 *
1237 g_utf8_to_utf16 (const gchar *str,
1238                  glong        len,              
1239                  glong       *items_read,       
1240                  glong       *items_written,    
1241                  GError     **error)
1242 {
1243   gunichar2 *result = NULL;
1244   gint n16;
1245   const gchar *in;
1246   gint i;
1247
1248   g_return_val_if_fail (str != NULL, NULL);
1249
1250   in = str;
1251   n16 = 0;
1252   while ((len < 0 || str + len - in > 0) && *in)
1253     {
1254       gunichar wc = g_utf8_get_char_extended (in, str + len - in);
1255       if (wc & 0x80000000)
1256         {
1257           if (wc == (gunichar)-2)
1258             {
1259               if (items_read)
1260                 break;
1261               else
1262                 g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT,
1263                              _("Partial character sequence at end of input"));
1264             }
1265           else
1266             g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1267                          _("Invalid byte sequence in conversion input"));
1268
1269           goto err_out;
1270         }
1271
1272       if (wc < 0xd800)
1273         n16 += 1;
1274       else if (wc < 0xe000)
1275         {
1276           g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1277                        _("Invalid sequence in conversion input"));
1278
1279           goto err_out;
1280         }
1281       else if (wc < 0x10000)
1282         n16 += 1;
1283       else if (wc < 0x110000)
1284         n16 += 2;
1285       else
1286         {
1287           g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1288                        _("Character out of range for UTF-16"));
1289
1290           goto err_out;
1291         }
1292       
1293       in = g_utf8_next_char (in);
1294     }
1295
1296   result = g_new (gunichar2, n16 + 1);
1297   
1298   in = str;
1299   for (i = 0; i < n16;)
1300     {
1301       gunichar wc = g_utf8_get_char (in);
1302
1303       if (wc < 0x10000)
1304         {
1305           result[i++] = wc;
1306         }
1307       else
1308         {
1309           result[i++] = (wc - 0x10000) / 0x400 + 0xd800;
1310           result[i++] = (wc - 0x10000) % 0x400 + 0xdc00;
1311         }
1312       
1313       in = g_utf8_next_char (in);
1314     }
1315
1316   result[i] = 0;
1317
1318   if (items_written)
1319     *items_written = n16;
1320
1321  err_out:
1322   if (items_read)
1323     *items_read = in - str;
1324   
1325   return result;
1326 }
1327
1328 /**
1329  * g_ucs4_to_utf16:
1330  * @str: a UCS-4 encoded string
1331  * @len: the maximum length of @str to use. If < 0, then
1332  *       the string is terminated with a zero character.
1333  * @items_read: location to store number of bytes read, or %NULL.
1334  *              If an error occurs then the index of the invalid input
1335  *              is stored here.
1336  * @items_written: location to store number of words written, or %NULL.
1337  *                 The value stored here does not include the trailing
1338  *                 0 word.
1339  * @error: location to store the error occuring, or %NULL to ignore
1340  *         errors. Any of the errors in #GConvertError other than
1341  *         %G_CONVERT_ERROR_NO_CONVERSION may occur.
1342  *
1343  * Convert a string from UCS-4 to UTF-16. A 0 word will be
1344  * added to the result after the converted text.
1345  * 
1346  * Return value: a pointer to a newly allocated UTF-16 string.
1347  *               This value must be freed with g_free(). If an
1348  *               error occurs, %NULL will be returned and
1349  *               @error set.
1350  **/
1351 gunichar2 *
1352 g_ucs4_to_utf16 (const gunichar  *str,
1353                  glong            len,              
1354                  glong           *items_read,       
1355                  glong           *items_written,    
1356                  GError         **error)
1357 {
1358   gunichar2 *result = NULL;
1359   gint n16;
1360   gint i, j;
1361
1362   n16 = 0;
1363   i = 0;
1364   while ((len < 0 || i < len) && str[i])
1365     {
1366       gunichar wc = str[i];
1367
1368       if (wc < 0xd800)
1369         n16 += 1;
1370       else if (wc < 0xe000)
1371         {
1372           g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1373                        _("Invalid sequence in conversion input"));
1374
1375           goto err_out;
1376         }
1377       else if (wc < 0x10000)
1378         n16 += 1;
1379       else if (wc < 0x110000)
1380         n16 += 2;
1381       else
1382         {
1383           g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1384                        _("Character out of range for UTF-16"));
1385
1386           goto err_out;
1387         }
1388
1389       i++;
1390     }
1391   
1392   result = g_new (gunichar2, n16 + 1);
1393   
1394   for (i = 0, j = 0; j < n16; i++)
1395     {
1396       gunichar wc = str[i];
1397
1398       if (wc < 0x10000)
1399         {
1400           result[j++] = wc;
1401         }
1402       else
1403         {
1404           result[j++] = (wc - 0x10000) / 0x400 + 0xd800;
1405           result[j++] = (wc - 0x10000) % 0x400 + 0xdc00;
1406         }
1407     }
1408   result[j] = 0;
1409
1410   if (items_written)
1411     *items_written = n16;
1412   
1413  err_out:
1414   if (items_read)
1415     *items_read = i;
1416   
1417   return result;
1418 }
1419
1420 /**
1421  * g_utf8_validate:
1422  * @str: a pointer to character data
1423  * @max_len: max bytes to validate, or -1 to go until nul
1424  * @end: return location for end of valid data
1425  * 
1426  * Validates UTF-8 encoded text. @str is the text to validate;
1427  * if @str is nul-terminated, then @max_len can be -1, otherwise
1428  * @max_len should be the number of bytes to validate.
1429  * If @end is non-%NULL, then the end of the valid range
1430  * will be stored there (i.e. the address of the first invalid byte
1431  * if some bytes were invalid, or the end of the text being validated
1432  * otherwise).
1433  *
1434  * Returns TRUE if all of @str was valid. Many GLib and GTK+
1435  * routines <emphasis>require</emphasis> valid UTF8 as input;
1436  * so data read from a file or the network should be checked
1437  * with g_utf8_validate() before doing anything else with it.
1438  * 
1439  * Return value: TRUE if the text was valid UTF-8.
1440  **/
1441 gboolean
1442 g_utf8_validate (const gchar  *str,
1443                  gssize        max_len,    
1444                  const gchar **end)
1445 {
1446
1447   const gchar *p;
1448
1449   g_return_val_if_fail (str != NULL, FALSE);
1450   
1451   if (end)
1452     *end = str;
1453   
1454   p = str;
1455   
1456   while ((max_len < 0 || (p - str) < max_len) && *p)
1457     {
1458       int i, mask = 0, len;
1459       gunichar result;
1460       unsigned char c = (unsigned char) *p;
1461       
1462       UTF8_COMPUTE (c, mask, len);
1463
1464       if (len == -1)
1465         break;
1466
1467       /* check that the expected number of bytes exists in str */
1468       if (max_len >= 0 &&
1469           ((max_len - (p - str)) < len))
1470         break;
1471         
1472       UTF8_GET (result, p, i, mask, len);
1473
1474       if (UTF8_LENGTH (result) != len) /* Check for overlong UTF-8 */
1475         break;
1476
1477       if (result == (gunichar)-1)
1478         break;
1479
1480       if (!UNICODE_VALID (result))
1481         break;
1482       
1483       p += len;
1484     }
1485
1486   if (end)
1487     *end = p;
1488
1489   /* See that we covered the entire length if a length was
1490    * passed in, or that we ended on a nul if not
1491    */
1492   if (max_len >= 0 &&
1493       p != (str + max_len))
1494     return FALSE;
1495   else if (max_len < 0 &&
1496            *p != '\0')
1497     return FALSE;
1498   else
1499     return TRUE;
1500 }
1501
1502 /**
1503  * g_unichar_validate:
1504  * @ch: a Unicode character
1505  * 
1506  * Checks whether @ch is a valid Unicode character. Some possible
1507  * integer values of @ch will not be valid. 0 is considered a valid
1508  * character, though it's normally a string terminator.
1509  * 
1510  * Return value: %TRUE if @ch is a valid Unicode character
1511  **/
1512 gboolean
1513 g_unichar_validate (gunichar ch)
1514 {
1515   return UNICODE_VALID (ch);
1516 }