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