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