Imported new UTF-8 routines from my 1.1 tree.
[silc.git] / lib / silcutil / silcstringprep.c
1 /*
2
3   silcstringprep.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2004 - 2005 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19
20 #include "silcincludes.h"
21 #include "silcstringprep.h"
22 #include <stringprep.h>
23
24 /* We use GNU Libidn which has stringprep to do the magic.  Only bad thing
25    is that its interface is idiotic.  We have our own API here in case
26    we'll implement it ourselves later. */
27
28 /* Prohibited characters as defined by the protocol in Appendix B */
29 const Stringprep_table_element silc_appendix_b[] =
30 {
31   {0x000021}, {0x00002A}, {0x00002C}, {0x00003F}, {0x000040},
32   {0x0000A2, 0x0000A9},
33   {0x0000AC}, {0x0000AE}, {0x0000AF}, {0x0000B0}, {0x0000B1}, {0x0000B4},
34   {0x0000B6}, {0x0000B8}, {0x0000D7}, {0x0000F7},
35   {0x0002C2, 0x0002C5}, {0x0002D2, 0x0002FF},
36   {0x000374}, {0x000375}, {0x000384}, {0x000385}, {0x0003F6}, {0x000482},
37   {0x00060E}, {0x00060F}, {0x0006E9}, {0x0006FD}, {0x0006FE}, {0x0009F2},
38   {0x0009F3}, {0x0009FA}, {0x000AF1}, {0x000B70},
39   {0x000BF3, 0x000BFA}, {0x000E3F},
40   {0x000F01, 0x000F03}, {0x000F13, 0x000F17}, {0x000F1A, 0x000F1F},
41   {0x000F34}, {0x000F36}, {0x000F38}, {0x000FBE}, {0x000FBF},
42   {0x000FC0, 0x000FC5}, {0x000FC7, 0x000FCF}, {0x0017DB}, {0x001940},
43   {0x0019E0, 0x0019FF}, {0x001FBD}, {0x001FBF, 0x001FC1},
44   {0x001FCD, 0x001FCF}, {0x001FDD, 0x001FDF}, {0x001FED, 0x001FEF},
45   {0x001FFD}, {0x001FFE}, {0x002044}, {0x002052}, {0x00207A, 0x00207C},
46   {0x00208A, 0x00208C}, {0x0020A0, 0x0020B1}, {0x002100, 0x00214F},
47   {0x002150, 0x00218F}, {0x002190, 0x0021FF}, {0x002200, 0x0022FF},
48   {0x002300, 0x0023FF}, {0x002400, 0x00243F}, {0x002440, 0x00245F},
49   {0x002460, 0x0024FF}, {0x002500, 0x00257F}, {0x002580, 0x00259F},
50   {0x0025A0, 0x0025FF}, {0x002600, 0x0026FF}, {0x002700, 0x0027BF},
51   {0x0027C0, 0x0027EF}, {0x0027F0, 0x0027FF}, {0x002800, 0x0028FF},
52   {0x002900, 0x00297F}, {0x002980, 0x0029FF}, {0x002A00, 0x002AFF},
53   {0x002B00, 0x002BFF}, {0x002E9A}, {0x002EF4, 0x002EFF},
54   {0x002FF0, 0x002FFF}, {0x00303B, 0x00303D}, {0x003040},
55   {0x003095, 0x003098}, {0x00309F, 0x0030A0}, {0x0030FF, 0x003104},
56   {0x00312D, 0x003130}, {0x00318F}, {0x0031B8, 0x0031FF},
57   {0x00321D, 0x00321F}, {0x003244, 0x00325F}, {0x00327C, 0x00327E},
58   {0x0032B1, 0x0032BF}, {0x0032CC, 0x0032CF}, {0x0032FF},
59   {0x003377, 0x00337A}, {0x0033DE, 0x0033DF}, {0x0033FF},
60   {0x004DB6, 0x004DFF},
61   {0x009FA6, 0x009FFF}, {0x00A48D, 0x00A48F}, {0x00A4A2, 0x00A4A3},
62   {0x00A4B4}, {0x00A4C1}, {0x00A4C5}, {0x00A4C7, 0x00ABFF},
63   {0x00D7A4, 0x00D7FF}, {0x00FA2E, 0x00FAFF}, {0x00FFE0, 0x00FFEE},
64   {0x00FFFC}, {0x010000, 0x01007F}, {0x010080, 0x0100FF},
65   {0x010100, 0x01013F}, {0x01D000, 0x01D0FF}, {0x01D100, 0x01D1FF},
66   {0x01D300, 0x01D35F}, {0x01D400, 0x01D7FF},
67   {0x0E0100, 0x0E01EF},
68   {0}
69 };
70
71 /* Default SILC Identifier String profile defined by the protocol */
72 const Stringprep_profile stringprep_silc_identifier_prep[] =
73 {
74   {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_1},
75   {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_2},
76   {STRINGPREP_NFKC, 0, 0},
77   {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_1_1},
78   {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_1_2},
79   {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_1},
80   {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_2},
81   {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_3},
82   {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_4},
83   {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_5},
84   {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_6},
85   {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_7},
86   {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_8},
87   {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_9},
88   {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_9},
89   {STRINGPREP_PROHIBIT_TABLE, 0, silc_appendix_b},
90   {STRINGPREP_UNASSIGNED_TABLE, ~STRINGPREP_NO_UNASSIGNED,
91    stringprep_rfc3454_A_1},
92   {0}
93 };
94
95 /* Prepares string according to the profile */
96
97 SilcStringprepStatus
98 silc_stringprep(const unsigned char *bin, SilcUInt32 bin_len,
99                 SilcStringEncoding bin_encoding,
100                 const char *profile_name,
101                 SilcStringprepFlags flags,
102                 unsigned char **out, SilcUInt32 *out_len,
103                 SilcStringEncoding out_encoding)
104 {
105   Stringprep_profile_flags f = 0;
106   const Stringprep_profile *profile;
107   unsigned char *utf8s;
108   SilcUInt32 utf8s_len;
109   int ret;
110
111   if (!bin || !bin_len || !profile_name)
112     return SILC_STRINGPREP_ERR;
113
114   /* Convert string to UTF-8 */
115   utf8s_len = silc_utf8_encoded_len(bin, bin_len, bin_encoding);
116   if (!utf8s_len)
117     return SILC_STRINGPREP_ERR_ENCODING;
118   utf8s = silc_calloc(utf8s_len + 1, sizeof(*utf8s));
119   if (!utf8s)
120     return SILC_STRINGPREP_ERR_OUT_OF_MEMORY;
121   silc_utf8_encode(bin, bin_len, bin_encoding, utf8s, utf8s_len);
122
123   /* Check profile. */
124   if (!strcmp(profile_name, SILC_IDENTIFIER_PREP))
125     profile = stringprep_silc_identifier_prep;
126   else
127     return SILC_STRINGPREP_ERR_UNSUP_PROFILE;
128
129   /* Translate flags */
130   if (!(flags & SILC_STRINGPREP_ALLOW_UNASSIGNED))
131     f |= STRINGPREP_NO_UNASSIGNED;
132
133   /* Prepare */
134   ret = stringprep((char *)utf8s, utf8s_len, f, profile);
135   switch (ret) {
136   case STRINGPREP_OK:
137     ret = SILC_STRINGPREP_OK;
138     break;
139
140   case STRINGPREP_CONTAINS_UNASSIGNED:
141     ret = SILC_STRINGPREP_ERR_UNASSIGNED;
142     break;
143
144   case STRINGPREP_CONTAINS_PROHIBITED:
145     ret = SILC_STRINGPREP_ERR_PROHIBITED;
146     break;
147
148   case STRINGPREP_BIDI_BOTH_L_AND_RAL:
149     ret = SILC_STRINGPREP_ERR_BIDI_RAL_WITH_L;
150     break;
151
152   case STRINGPREP_BIDI_LEADTRAIL_NOT_RAL:
153     ret = SILC_STRINGPREP_ERR_BIDI_RAL;
154     break;
155
156   case STRINGPREP_BIDI_CONTAINS_PROHIBITED:
157     ret = SILC_STRINGPREP_ERR_BIDI_PROHIBITED;
158     break;
159
160   case STRINGPREP_UNKNOWN_PROFILE:
161     ret = SILC_STRINGPREP_ERR_UNSUP_PROFILE;
162     break;
163
164   case STRINGPREP_MALLOC_ERROR:
165     ret = SILC_STRINGPREP_ERR_OUT_OF_MEMORY;
166     break;
167
168   default:
169     ret = SILC_STRINGPREP_ERR;
170     break;
171   }
172
173   /* Convert to desired output character encoding */
174   if (ret == SILC_STRINGPREP_OK) {
175     if (out && out_len) {
176       if (out_encoding != SILC_STRING_UTF8) {
177         *out_len = silc_utf8_decoded_len(utf8s, strlen(utf8s), out_encoding);
178         if (*out_len) {
179           *out = silc_calloc(*out_len + 1, sizeof(**out));
180           if (*out) {
181             silc_utf8_decode(utf8s, strlen(utf8s), out_encoding, *out,
182                              *out_len);
183           } else {
184             ret = SILC_STRINGPREP_ERR_OUT_OF_MEMORY;
185           }
186         } else {
187           ret = SILC_STRINGPREP_ERR_ENCODING;
188         }
189       } else {
190         *out_len = strlen(utf8s);
191         *out = silc_memdup(utf8s, *out_len);
192       }
193     }
194   }
195
196   silc_free(utf8s);
197
198   return (SilcStringprepStatus)ret;
199 }