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