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