Added SILC Thread Queue API
[silc.git] / lib / contrib / nfkc.c
1 /* nfkc.c       Unicode normalization utilities.
2  * Copyright (C) 2002, 2003, 2004, 2005  Simon Josefsson
3  *
4  * This file is part of GNU Libidn.
5  *
6  * GNU Libidn 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.1 of the License, or (at your option) any later version.
10  *
11  * GNU Libidn 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 GNU Libidn; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "stringprep.h"
26
27 /* This file contains functions from GLIB, including gutf8.c and
28  * gunidecomp.c, all licensed under LGPL and copyright hold by:
29  *
30  *  Copyright (C) 1999, 2000 Tom Tromey
31  *  Copyright 2000 Red Hat, Inc.
32  */
33
34 /* Hacks to make syncing with GLIB code easier. */
35 #define gboolean int
36 #define gchar char
37 #define guchar unsigned char
38 #define glong long
39 #define gint int
40 #define guint unsigned int
41 #define gushort unsigned short
42 #define gint16 int16_t
43 #define guint16 uint16_t
44 #define gunichar uint32_t
45 #define gsize size_t
46 #define gssize ssize_t
47 #define g_malloc malloc
48 #define g_free free
49 #define GError void
50 #define g_set_error(a,b,c,d) ((void) 0)
51 #define g_new(struct_type, n_structs)                                   \
52   ((struct_type *) g_malloc (((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
53 #  if defined (__GNUC__) && !defined (__STRICT_ANSI__) && !defined (__cplusplus)
54 #    define G_STMT_START        (void)(
55 #    define G_STMT_END          )
56 #  else
57 #    if (defined (sun) || defined (__sun__))
58 #      define G_STMT_START      if (1)
59 #      define G_STMT_END        else (void)0
60 #    else
61 #      define G_STMT_START      do
62 #      define G_STMT_END        while (0)
63 #    endif
64 #  endif
65 #define g_return_val_if_fail(expr,val)          G_STMT_START{ (void)0; }G_STMT_END
66 #define G_N_ELEMENTS(arr)               (sizeof (arr) / sizeof ((arr)[0]))
67 #define TRUE 1
68 #define FALSE 0
69
70 /* Code from GLIB gunicode.h starts here. */
71
72 typedef enum
73 {
74   G_NORMALIZE_DEFAULT,
75   G_NORMALIZE_NFD = G_NORMALIZE_DEFAULT,
76   G_NORMALIZE_DEFAULT_COMPOSE,
77   G_NORMALIZE_NFC = G_NORMALIZE_DEFAULT_COMPOSE,
78   G_NORMALIZE_ALL,
79   G_NORMALIZE_NFKD = G_NORMALIZE_ALL,
80   G_NORMALIZE_ALL_COMPOSE,
81   G_NORMALIZE_NFKC = G_NORMALIZE_ALL_COMPOSE
82 }
83 GNormalizeMode;
84
85 /* Code from GLIB gutf8.c starts here. */
86
87 #define UTF8_COMPUTE(Char, Mask, Len)           \
88   if (Char < 128)                               \
89     {                                           \
90       Len = 1;                                  \
91       Mask = 0x7f;                              \
92     }                                           \
93   else if ((Char & 0xe0) == 0xc0)               \
94     {                                           \
95       Len = 2;                                  \
96       Mask = 0x1f;                              \
97     }                                           \
98   else if ((Char & 0xf0) == 0xe0)               \
99     {                                           \
100       Len = 3;                                  \
101       Mask = 0x0f;                              \
102     }                                           \
103   else if ((Char & 0xf8) == 0xf0)               \
104     {                                           \
105       Len = 4;                                  \
106       Mask = 0x07;                              \
107     }                                           \
108   else if ((Char & 0xfc) == 0xf8)               \
109     {                                           \
110       Len = 5;                                  \
111       Mask = 0x03;                              \
112     }                                           \
113   else if ((Char & 0xfe) == 0xfc)               \
114     {                                           \
115       Len = 6;                                  \
116       Mask = 0x01;                              \
117     }                                           \
118   else                                          \
119     Len = -1;
120
121 #define UTF8_LENGTH(Char)                       \
122   ((Char) < 0x80 ? 1 :                          \
123    ((Char) < 0x800 ? 2 :                        \
124     ((Char) < 0x10000 ? 3 :                     \
125      ((Char) < 0x200000 ? 4 :                   \
126       ((Char) < 0x4000000 ? 5 : 6)))))
127
128
129 #define UTF8_GET(Result, Chars, Count, Mask, Len)       \
130   (Result) = (Chars)[0] & (Mask);                       \
131   for ((Count) = 1; (Count) < (Len); ++(Count))         \
132     {                                                   \
133       if (((Chars)[(Count)] & 0xc0) != 0x80)            \
134         {                                               \
135           (Result) = -1;                                \
136           break;                                        \
137         }                                               \
138       (Result) <<= 6;                                   \
139       (Result) |= ((Chars)[(Count)] & 0x3f);            \
140     }
141
142 #define UNICODE_VALID(Char)                     \
143   ((Char) < 0x110000 &&                         \
144    (((Char) & 0xFFFFF800) != 0xD800) &&         \
145    ((Char) < 0xFDD0 || (Char) > 0xFDEF) &&      \
146    ((Char) & 0xFFFE) != 0xFFFE)
147
148
149 static const gchar utf8_skip_data[256] = {
150   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,
151   1, 1, 1, 1, 1, 1, 1,
152   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,
153   1, 1, 1, 1, 1, 1, 1,
154   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,
155   1, 1, 1, 1, 1, 1, 1,
156   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,
157   1, 1, 1, 1, 1, 1, 1,
158   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,
159   1, 1, 1, 1, 1, 1, 1,
160   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,
161   1, 1, 1, 1, 1, 1, 1,
162   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,
163   2, 2, 2, 2, 2, 2, 2,
164   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,
165   5, 5, 5, 6, 6, 1, 1
166 };
167
168 static const gchar *const g_utf8_skip = utf8_skip_data;
169
170 #define g_utf8_next_char(p) (char *)((p) + g_utf8_skip[*(guchar *)(p)])
171
172 /*
173  * g_utf8_strlen:
174  * @p: pointer to the start of a UTF-8 encoded string.
175  * @max: the maximum number of bytes to examine. If @max
176  *       is less than 0, then the string is assumed to be
177  *       nul-terminated. If @max is 0, @p will not be examined and
178  *       may be %NULL.
179  *
180  * Returns the length of the string in characters.
181  *
182  * Return value: the length of the string in characters
183  **/
184 static glong
185 g_utf8_strlen (const gchar * p, gssize max)
186 {
187   glong len = 0;
188   const gchar *start = p;
189   g_return_val_if_fail (p != NULL || max == 0, 0);
190
191   if (max < 0)
192     {
193       while (*p)
194         {
195           p = g_utf8_next_char (p);
196           ++len;
197         }
198     }
199   else
200     {
201       if (max == 0 || !*p)
202         return 0;
203
204       p = g_utf8_next_char (p);
205
206       while (p - start < max && *p)
207         {
208           ++len;
209           p = g_utf8_next_char (p);
210         }
211
212       /* only do the last len increment if we got a complete
213        * char (don't count partial chars)
214        */
215       if (p - start == max)
216         ++len;
217     }
218
219   return len;
220 }
221
222 /*
223  * g_utf8_get_char:
224  * @p: a pointer to Unicode character encoded as UTF-8
225  *
226  * Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
227  * If @p does not point to a valid UTF-8 encoded character, results are
228  * undefined. If you are not sure that the bytes are complete
229  * valid Unicode characters, you should use g_utf8_get_char_validated()
230  * instead.
231  *
232  * Return value: the resulting character
233  **/
234 static 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_unichar_to_utf8:
251  * @c: a ISO10646 character code
252  * @outbuf: output buffer, must have at least 6 bytes of space.
253  *       If %NULL, the length will be computed and returned
254  *       and nothing will be written to @outbuf.
255  *
256  * Converts a single character to UTF-8.
257  *
258  * Return value: number of bytes written
259  **/
260 static int
261 g_unichar_to_utf8 (gunichar c, gchar * outbuf)
262 {
263   guint len = 0;
264   int first;
265   int i;
266
267   if (c < 0x80)
268     {
269       first = 0;
270       len = 1;
271     }
272   else if (c < 0x800)
273     {
274       first = 0xc0;
275       len = 2;
276     }
277   else if (c < 0x10000)
278     {
279       first = 0xe0;
280       len = 3;
281     }
282   else if (c < 0x200000)
283     {
284       first = 0xf0;
285       len = 4;
286     }
287   else if (c < 0x4000000)
288     {
289       first = 0xf8;
290       len = 5;
291     }
292   else
293     {
294       first = 0xfc;
295       len = 6;
296     }
297
298   if (outbuf)
299     {
300       for (i = len - 1; i > 0; --i)
301         {
302           outbuf[i] = (c & 0x3f) | 0x80;
303           c >>= 6;
304         }
305       outbuf[0] = c | first;
306     }
307
308   return len;
309 }
310
311 /*
312  * g_utf8_to_ucs4_fast:
313  * @str: a UTF-8 encoded string
314  * @len: the maximum length of @str to use. If @len < 0, then
315  *       the string is nul-terminated.
316  * @items_written: location to store the number of characters in the
317  *                 result, or %NULL.
318  *
319  * Convert a string from UTF-8 to a 32-bit fixed width
320  * representation as UCS-4, assuming valid UTF-8 input.
321  * This function is roughly twice as fast as g_utf8_to_ucs4()
322  * but does no error checking on the input.
323  *
324  * Return value: a pointer to a newly allocated UCS-4 string.
325  *               This value must be freed with g_free().
326  **/
327 static gunichar *
328 g_utf8_to_ucs4_fast (const gchar * str, glong len, glong * items_written)
329 {
330   gint j, charlen;
331   gunichar *result;
332   gint n_chars, i;
333   const gchar *p;
334
335   g_return_val_if_fail (str != NULL, NULL);
336
337   p = str;
338   n_chars = 0;
339   if (len < 0)
340     {
341       while (*p)
342         {
343           p = g_utf8_next_char (p);
344           ++n_chars;
345         }
346     }
347   else
348     {
349       while (p < str + len && *p)
350         {
351           p = g_utf8_next_char (p);
352           ++n_chars;
353         }
354     }
355
356   result = g_new (gunichar, n_chars + 1);
357   if (!result)
358     return NULL;
359
360   p = str;
361   for (i = 0; i < n_chars; i++)
362     {
363       gunichar wc = ((unsigned char *) p)[0];
364
365       if (wc < 0x80)
366         {
367           result[i] = wc;
368           p++;
369         }
370       else
371         {
372           if (wc < 0xe0)
373             {
374               charlen = 2;
375               wc &= 0x1f;
376             }
377           else if (wc < 0xf0)
378             {
379               charlen = 3;
380               wc &= 0x0f;
381             }
382           else if (wc < 0xf8)
383             {
384               charlen = 4;
385               wc &= 0x07;
386             }
387           else if (wc < 0xfc)
388             {
389               charlen = 5;
390               wc &= 0x03;
391             }
392           else
393             {
394               charlen = 6;
395               wc &= 0x01;
396             }
397
398           for (j = 1; j < charlen; j++)
399             {
400               wc <<= 6;
401               wc |= ((unsigned char *) p)[j] & 0x3f;
402             }
403
404           result[i] = wc;
405           p += charlen;
406         }
407     }
408   result[i] = 0;
409
410   if (items_written)
411     *items_written = i;
412
413   return result;
414 }
415
416 /*
417  * g_ucs4_to_utf8:
418  * @str: a UCS-4 encoded string
419  * @len: the maximum length of @str to use. If @len < 0, then
420  *       the string is terminated with a 0 character.
421  * @items_read: location to store number of characters read read, or %NULL.
422  * @items_written: location to store number of bytes written or %NULL.
423  *                 The value here stored does not include the trailing 0
424  *                 byte.
425  * @error: location to store the error occuring, or %NULL to ignore
426  *         errors. Any of the errors in #GConvertError other than
427  *         %G_CONVERT_ERROR_NO_CONVERSION may occur.
428  *
429  * Convert a string from a 32-bit fixed width representation as UCS-4.
430  * to UTF-8. The result will be terminated with a 0 byte.
431  *
432  * Return value: a pointer to a newly allocated UTF-8 string.
433  *               This value must be freed with g_free(). If an
434  *               error occurs, %NULL will be returned and
435  *               @error set.
436  **/
437 static gchar *
438 g_ucs4_to_utf8 (const gunichar * str,
439                 glong len,
440                 glong * items_read, glong * items_written, GError ** error)
441 {
442   gint result_length;
443   gchar *result = NULL;
444   gchar *p;
445   gint i;
446
447   result_length = 0;
448   for (i = 0; len < 0 || i < len; i++)
449     {
450       if (!str[i])
451         break;
452
453       if (str[i] >= 0x80000000)
454         {
455           if (items_read)
456             *items_read = i;
457
458           g_set_error (error, G_CONVERT_ERROR,
459                        G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
460                        _("Character out of range for UTF-8"));
461           goto err_out;
462         }
463
464       result_length += UTF8_LENGTH (str[i]);
465     }
466
467   result = g_malloc (result_length + 1);
468   if (!result)
469     return NULL;
470   p = result;
471
472   i = 0;
473   while (p < result + result_length)
474     p += g_unichar_to_utf8 (str[i++], p);
475
476   *p = '\0';
477
478   if (items_written)
479     *items_written = p - result;
480
481 err_out:
482   if (items_read)
483     *items_read = i;
484
485   return result;
486 }
487
488 /* Code from GLIB gunidecomp.c starts here. */
489
490 #include "gunidecomp.h"
491 #include "gunicomp.h"
492
493 #define CC_PART1(Page, Char) \
494   ((combining_class_table_part1[Page] >= G_UNICODE_MAX_TABLE_INDEX) \
495    ? (combining_class_table_part1[Page] - G_UNICODE_MAX_TABLE_INDEX) \
496    : (cclass_data[combining_class_table_part1[Page]][Char]))
497
498 #define CC_PART2(Page, Char) \
499   ((combining_class_table_part2[Page] >= G_UNICODE_MAX_TABLE_INDEX) \
500    ? (combining_class_table_part2[Page] - G_UNICODE_MAX_TABLE_INDEX) \
501    : (cclass_data[combining_class_table_part2[Page]][Char]))
502
503 #define COMBINING_CLASS(Char) \
504   (((Char) <= G_UNICODE_LAST_CHAR_PART1) \
505    ? CC_PART1 ((Char) >> 8, (Char) & 0xff) \
506    : (((Char) >= 0xe0000 && (Char) <= G_UNICODE_LAST_CHAR) \
507       ? CC_PART2 (((Char) - 0xe0000) >> 8, (Char) & 0xff) \
508       : 0))
509
510 /* constants for hangul syllable [de]composition */
511 #define SBase 0xAC00
512 #define LBase 0x1100
513 #define VBase 0x1161
514 #define TBase 0x11A7
515 #define LCount 19
516 #define VCount 21
517 #define TCount 28
518 #define NCount (VCount * TCount)
519 #define SCount (LCount * NCount)
520
521 /*
522  * g_unicode_canonical_ordering:
523  * @string: a UCS-4 encoded string.
524  * @len: the maximum length of @string to use.
525  *
526  * Computes the canonical ordering of a string in-place.
527  * This rearranges decomposed characters in the string
528  * according to their combining classes.  See the Unicode
529  * manual for more information.
530  **/
531 static void
532 g_unicode_canonical_ordering (gunichar * string, gsize len)
533 {
534   gsize i;
535   int swap = 1;
536
537   while (swap)
538     {
539       int last;
540       swap = 0;
541       last = COMBINING_CLASS (string[0]);
542       for (i = 0; i < len - 1; ++i)
543         {
544           int next = COMBINING_CLASS (string[i + 1]);
545           if (next != 0 && last > next)
546             {
547               gsize j;
548               /* Percolate item leftward through string.  */
549               for (j = i + 1; j > 0; --j)
550                 {
551                   gunichar t;
552                   if (COMBINING_CLASS (string[j - 1]) <= next)
553                     break;
554                   t = string[j];
555                   string[j] = string[j - 1];
556                   string[j - 1] = t;
557                   swap = 1;
558                 }
559               /* We're re-entering the loop looking at the old
560                  character again.  */
561               next = last;
562             }
563           last = next;
564         }
565     }
566 }
567
568 /* http://www.unicode.org/unicode/reports/tr15/#Hangul
569  * r should be null or have sufficient space. Calling with r == NULL will
570  * only calculate the result_len; however, a buffer with space for three
571  * characters will always be big enough. */
572 static void
573 decompose_hangul (gunichar s, gunichar * r, gsize * result_len)
574 {
575   gint SIndex = s - SBase;
576
577   /* not a hangul syllable */
578   if (SIndex < 0 || SIndex >= SCount)
579     {
580       if (r)
581         r[0] = s;
582       *result_len = 1;
583     }
584   else
585     {
586       gunichar L = LBase + SIndex / NCount;
587       gunichar V = VBase + (SIndex % NCount) / TCount;
588       gunichar T = TBase + SIndex % TCount;
589
590       if (r)
591         {
592           r[0] = L;
593           r[1] = V;
594         }
595
596       if (T != TBase)
597         {
598           if (r)
599             r[2] = T;
600           *result_len = 3;
601         }
602       else
603         *result_len = 2;
604     }
605 }
606
607 /* returns a pointer to a null-terminated UTF-8 string */
608 static const gchar *
609 find_decomposition (gunichar ch, gboolean compat)
610 {
611   int start = 0;
612   int end = G_N_ELEMENTS (decomp_table);
613
614   if (ch >= decomp_table[start].ch && ch <= decomp_table[end - 1].ch)
615     {
616       while (TRUE)
617         {
618           int half = (start + end) / 2;
619           if (ch == decomp_table[half].ch)
620             {
621               int offset;
622
623               if (compat)
624                 {
625                   offset = decomp_table[half].compat_offset;
626                   if (offset == G_UNICODE_NOT_PRESENT_OFFSET)
627                     offset = decomp_table[half].canon_offset;
628                 }
629               else
630                 {
631                   offset = decomp_table[half].canon_offset;
632                   if (offset == G_UNICODE_NOT_PRESENT_OFFSET)
633                     return NULL;
634                 }
635
636               return &(decomp_expansion_string[offset]);
637             }
638           else if (half == start)
639             break;
640           else if (ch > decomp_table[half].ch)
641             start = half;
642           else
643             end = half;
644         }
645     }
646
647   return NULL;
648 }
649
650 /* L,V => LV and LV,T => LVT  */
651 static gboolean
652 combine_hangul (gunichar a, gunichar b, gunichar * result)
653 {
654   gint LIndex = a - LBase;
655   gint SIndex = a - SBase;
656
657   gint VIndex = b - VBase;
658   gint TIndex = b - TBase;
659
660   if (0 <= LIndex && LIndex < LCount && 0 <= VIndex && VIndex < VCount)
661     {
662       *result = SBase + (LIndex * VCount + VIndex) * TCount;
663       return TRUE;
664     }
665   else if (0 <= SIndex && SIndex < SCount && (SIndex % TCount) == 0
666            && 0 <= TIndex && TIndex <= TCount)
667     {
668       *result = a + TIndex;
669       return TRUE;
670     }
671
672   return FALSE;
673 }
674
675 #define CI(Page, Char) \
676   ((compose_table[Page] >= G_UNICODE_MAX_TABLE_INDEX) \
677    ? (compose_table[Page] - G_UNICODE_MAX_TABLE_INDEX) \
678    : (compose_data[compose_table[Page]][Char]))
679
680 #define COMPOSE_INDEX(Char) \
681      ((((Char) >> 8) > (COMPOSE_TABLE_LAST)) ? 0 : CI((Char) >> 8, (Char) & 0xff))
682
683 static gboolean
684 combine (gunichar a, gunichar b, gunichar * result)
685 {
686   gushort index_a, index_b;
687
688   if (combine_hangul (a, b, result))
689     return TRUE;
690
691   index_a = COMPOSE_INDEX (a);
692
693   if (index_a >= COMPOSE_FIRST_SINGLE_START && index_a < COMPOSE_SECOND_START)
694     {
695       if (b == compose_first_single[index_a - COMPOSE_FIRST_SINGLE_START][0])
696         {
697           *result =
698             compose_first_single[index_a - COMPOSE_FIRST_SINGLE_START][1];
699           return TRUE;
700         }
701       else
702         return FALSE;
703     }
704
705   index_b = COMPOSE_INDEX (b);
706
707   if (index_b >= COMPOSE_SECOND_SINGLE_START)
708     {
709       if (a ==
710           compose_second_single[index_b - COMPOSE_SECOND_SINGLE_START][0])
711         {
712           *result =
713             compose_second_single[index_b - COMPOSE_SECOND_SINGLE_START][1];
714           return TRUE;
715         }
716       else
717         return FALSE;
718     }
719
720   if (index_a >= COMPOSE_FIRST_START && index_a < COMPOSE_FIRST_SINGLE_START
721       && index_b >= COMPOSE_SECOND_START
722       && index_b < COMPOSE_SECOND_SINGLE_START)
723     {
724       gunichar res =
725         compose_array[index_a - COMPOSE_FIRST_START][index_b -
726                                                      COMPOSE_SECOND_START];
727
728       if (res)
729         {
730           *result = res;
731           return TRUE;
732         }
733     }
734
735   return FALSE;
736 }
737
738 static gunichar *
739 _g_utf8_normalize_wc (const gchar * str, gssize max_len, GNormalizeMode mode)
740 {
741   gsize n_wc;
742   gunichar *wc_buffer;
743   const char *p;
744   gsize last_start;
745   gboolean do_compat = (mode == G_NORMALIZE_NFKC || mode == G_NORMALIZE_NFKD);
746   gboolean do_compose = (mode == G_NORMALIZE_NFC || mode == G_NORMALIZE_NFKC);
747
748   n_wc = 0;
749   p = str;
750   while ((max_len < 0 || p < str + max_len) && *p)
751     {
752       const gchar *decomp;
753       gunichar wc = g_utf8_get_char (p);
754
755       if (wc >= 0xac00 && wc <= 0xd7af)
756         {
757           gsize result_len;
758           decompose_hangul (wc, NULL, &result_len);
759           n_wc += result_len;
760         }
761       else
762         {
763           decomp = find_decomposition (wc, do_compat);
764
765           if (decomp)
766             n_wc += g_utf8_strlen (decomp, -1);
767           else
768             n_wc++;
769         }
770
771       p = g_utf8_next_char (p);
772     }
773
774   wc_buffer = g_new (gunichar, n_wc + 1);
775   if (!wc_buffer)
776     return NULL;
777
778   last_start = 0;
779   n_wc = 0;
780   p = str;
781   while ((max_len < 0 || p < str + max_len) && *p)
782     {
783       gunichar wc = g_utf8_get_char (p);
784       const gchar *decomp;
785       int cc;
786       gsize old_n_wc = n_wc;
787
788       if (wc >= 0xac00 && wc <= 0xd7af)
789         {
790           gsize result_len;
791           decompose_hangul (wc, wc_buffer + n_wc, &result_len);
792           n_wc += result_len;
793         }
794       else
795         {
796           decomp = find_decomposition (wc, do_compat);
797
798           if (decomp)
799             {
800               const char *pd;
801               for (pd = decomp; *pd != '\0'; pd = g_utf8_next_char (pd))
802                 wc_buffer[n_wc++] = g_utf8_get_char (pd);
803             }
804           else
805             wc_buffer[n_wc++] = wc;
806         }
807
808       if (n_wc > 0)
809         {
810           cc = COMBINING_CLASS (wc_buffer[old_n_wc]);
811
812           if (cc == 0)
813             {
814               g_unicode_canonical_ordering (wc_buffer + last_start,
815                                             n_wc - last_start);
816               last_start = old_n_wc;
817             }
818         }
819
820       p = g_utf8_next_char (p);
821     }
822
823   if (n_wc > 0)
824     {
825       g_unicode_canonical_ordering (wc_buffer + last_start,
826                                     n_wc - last_start);
827       last_start = n_wc;
828     }
829
830   wc_buffer[n_wc] = 0;
831
832   /* All decomposed and reordered */
833
834   if (do_compose && n_wc > 0)
835     {
836       gsize i, j;
837       int last_cc = 0;
838       last_start = 0;
839
840       for (i = 0; i < n_wc; i++)
841         {
842           int cc = COMBINING_CLASS (wc_buffer[i]);
843
844           if (i > 0 &&
845               (last_cc == 0 || last_cc != cc) &&
846               combine (wc_buffer[last_start], wc_buffer[i],
847                        &wc_buffer[last_start]))
848             {
849               for (j = i + 1; j < n_wc; j++)
850                 wc_buffer[j - 1] = wc_buffer[j];
851               n_wc--;
852               i--;
853
854               if (i == last_start)
855                 last_cc = 0;
856               else
857                 last_cc = COMBINING_CLASS (wc_buffer[i - 1]);
858
859               continue;
860             }
861
862           if (cc == 0)
863             last_start = i;
864
865           last_cc = cc;
866         }
867     }
868
869   wc_buffer[n_wc] = 0;
870
871   return wc_buffer;
872 }
873
874 /*
875  * g_utf8_normalize:
876  * @str: a UTF-8 encoded string.
877  * @len: length of @str, in bytes, or -1 if @str is nul-terminated.
878  * @mode: the type of normalization to perform.
879  *
880  * Converts a string into canonical form, standardizing
881  * such issues as whether a character with an accent
882  * is represented as a base character and combining
883  * accent or as a single precomposed character. You
884  * should generally call g_utf8_normalize() before
885  * comparing two Unicode strings.
886  *
887  * The normalization mode %G_NORMALIZE_DEFAULT only
888  * standardizes differences that do not affect the
889  * text content, such as the above-mentioned accent
890  * representation. %G_NORMALIZE_ALL also standardizes
891  * the "compatibility" characters in Unicode, such
892  * as SUPERSCRIPT THREE to the standard forms
893  * (in this case DIGIT THREE). Formatting information
894  * may be lost but for most text operations such
895  * characters should be considered the same.
896  * For example, g_utf8_collate() normalizes
897  * with %G_NORMALIZE_ALL as its first step.
898  *
899  * %G_NORMALIZE_DEFAULT_COMPOSE and %G_NORMALIZE_ALL_COMPOSE
900  * are like %G_NORMALIZE_DEFAULT and %G_NORMALIZE_ALL,
901  * but returned a result with composed forms rather
902  * than a maximally decomposed form. This is often
903  * useful if you intend to convert the string to
904  * a legacy encoding or pass it to a system with
905  * less capable Unicode handling.
906  *
907  * Return value: a newly allocated string, that is the
908  *   normalized form of @str.
909  **/
910 static gchar *
911 g_utf8_normalize (const gchar * str, gssize len, GNormalizeMode mode)
912 {
913   gunichar *result_wc = _g_utf8_normalize_wc (str, len, mode);
914   gchar *result;
915
916   result = g_ucs4_to_utf8 (result_wc, -1, NULL, NULL, NULL);
917   g_free (result_wc);
918
919   return result;
920 }
921
922 /* Public Libidn API starts here. */
923
924 /**
925  * stringprep_utf8_to_unichar:
926  * @p: a pointer to Unicode character encoded as UTF-8
927  *
928  * Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
929  * If @p does not point to a valid UTF-8 encoded character, results are
930  * undefined.
931  *
932  * Return value: the resulting character.
933  **/
934 uint32_t
935 stringprep_utf8_to_unichar (const char *p)
936 {
937   return g_utf8_get_char (p);
938 }
939
940 /**
941  * stringprep_unichar_to_utf8:
942  * @c: a ISO10646 character code
943  * @outbuf: output buffer, must have at least 6 bytes of space.
944  *       If %NULL, the length will be computed and returned
945  *       and nothing will be written to @outbuf.
946  *
947  * Converts a single character to UTF-8.
948  *
949  * Return value: number of bytes written.
950  **/
951 int
952 stringprep_unichar_to_utf8 (uint32_t c, char *outbuf)
953 {
954   return g_unichar_to_utf8 (c, outbuf);
955 }
956
957 /**
958  * stringprep_utf8_to_ucs4:
959  * @str: a UTF-8 encoded string
960  * @len: the maximum length of @str to use. If @len < 0, then
961  *       the string is nul-terminated.
962  * @items_written: location to store the number of characters in the
963  *                 result, or %NULL.
964  *
965  * Convert a string from UTF-8 to a 32-bit fixed width
966  * representation as UCS-4, assuming valid UTF-8 input.
967  * This function does no error checking on the input.
968  *
969  * Return value: a pointer to a newly allocated UCS-4 string.
970  *               This value must be freed with free().
971  **/
972 uint32_t *
973 stringprep_utf8_to_ucs4 (const char *str, ssize_t len, size_t * items_written)
974 {
975   return g_utf8_to_ucs4_fast (str, (glong) len, (glong *) items_written);
976 }
977
978 /**
979  * stringprep_ucs4_to_utf8:
980  * @str: a UCS-4 encoded string
981  * @len: the maximum length of @str to use. If @len < 0, then
982  *       the string is terminated with a 0 character.
983  * @items_read: location to store number of characters read read, or %NULL.
984  * @items_written: location to store number of bytes written or %NULL.
985  *                 The value here stored does not include the trailing 0
986  *                 byte.
987  *
988  * Convert a string from a 32-bit fixed width representation as UCS-4.
989  * to UTF-8. The result will be terminated with a 0 byte.
990  *
991  * Return value: a pointer to a newly allocated UTF-8 string.
992  *               This value must be freed with free(). If an
993  *               error occurs, %NULL will be returned and
994  *               @error set.
995  **/
996 char *
997 stringprep_ucs4_to_utf8 (const uint32_t * str, ssize_t len,
998                          size_t * items_read, size_t * items_written)
999 {
1000   return g_ucs4_to_utf8 (str, len, (glong *) items_read,
1001                          (glong *) items_written, NULL);
1002 }
1003
1004 /**
1005  * stringprep_utf8_nfkc_normalize:
1006  * @str: a UTF-8 encoded string.
1007  * @len: length of @str, in bytes, or -1 if @str is nul-terminated.
1008  *
1009  * Converts a string into canonical form, standardizing
1010  * such issues as whether a character with an accent
1011  * is represented as a base character and combining
1012  * accent or as a single precomposed character.
1013  *
1014  * The normalization mode is NFKC (ALL COMPOSE).  It standardizes
1015  * differences that do not affect the text content, such as the
1016  * above-mentioned accent representation. It standardizes the
1017  * "compatibility" characters in Unicode, such as SUPERSCRIPT THREE to
1018  * the standard forms (in this case DIGIT THREE). Formatting
1019  * information may be lost but for most text operations such
1020  * characters should be considered the same. It returns a result with
1021  * composed forms rather than a maximally decomposed form.
1022  *
1023  * Return value: a newly allocated string, that is the
1024  *   NFKC normalized form of @str.
1025  **/
1026 char *
1027 stringprep_utf8_nfkc_normalize (const char *str, ssize_t len)
1028 {
1029   return g_utf8_normalize (str, len, G_NORMALIZE_NFKC);
1030 }
1031
1032 /**
1033  * stringprep_ucs4_nfkc_normalize:
1034  * @str: a Unicode string.
1035  * @len: length of @str array, or -1 if @str is nul-terminated.
1036  *
1037  * Converts UCS4 string into UTF-8 and runs
1038  * stringprep_utf8_nfkc_normalize().
1039  *
1040  * Return value: a newly allocated Unicode string, that is the NFKC
1041  *   normalized form of @str.
1042  **/
1043 uint32_t *
1044 stringprep_ucs4_nfkc_normalize (uint32_t * str, ssize_t len)
1045 {
1046   char *p;
1047   uint32_t *result_wc;
1048
1049   p = stringprep_ucs4_to_utf8 (str, len, 0, 0);
1050   result_wc = _g_utf8_normalize_wc (p, -1, G_NORMALIZE_NFKC);
1051   free (p);
1052
1053   return result_wc;
1054 }