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