Add nameprep vector.
[libidn.git] / stringprep.c
blobf80f2943364dc125366c89eee0d9903de69a1408
1 /* stringprep.c library implementing IETF stringprep specification
2 * Copyright (C) 2002 Simon Josefsson
4 * This file is part of libstringprep.
6 * Libstringprep 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.
11 * Libstringprep 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.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with libstringprep; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "internal.h"
24 #define DBG 0
26 static int
27 stringprep_find_character_in_table (long ucs4,
28 Stringprep_table_element * table)
30 int i;
32 for (i = 0; table[i].start; i++)
33 if (ucs4 >= table[i].start &&
34 ucs4 <= (table[i].end ? table[i].end : table[i].start))
35 return i;
37 return -1;
40 static int
41 stringprep_find_string_in_table (long *ucs4,
42 int ucs4len,
43 int *tablepos,
44 Stringprep_table_element * table)
46 int j, pos;
48 for (j = 0; j < ucs4len; j++)
49 if ((pos = stringprep_find_character_in_table (ucs4[j], table)) != -1)
51 if (tablepos)
52 *tablepos = pos;
53 return j;
56 return -1;
59 static int
60 stringprep_apply_table_to_string (long *ucs4,
61 int *ucs4len,
62 int maxucs4len,
63 Stringprep_table_element * table)
65 int i;
66 int pos, maplen;
68 if ((pos =
69 stringprep_find_string_in_table (ucs4, *ucs4len, &i, table)) != -1)
71 #if DBG
72 printf ("hit %06lx %06lx-%06lx\n", ucs4[pos], table[i].start,
73 table[i].end);
74 #endif
76 for (maplen = 0; table[i].map[maplen]; maplen++)
79 if (*ucs4len - 1 + maplen >= maxucs4len)
80 return STRINGPREP_TOO_SMALL_BUFFER;
82 memmove (&ucs4[pos + maplen], &ucs4[pos + 1],
83 *ucs4len * sizeof (uint32_t) - (&ucs4[pos + 1] - ucs4));
84 memcpy (&ucs4[pos], table[i].map, sizeof (uint32_t) * maplen);
85 *ucs4len = *ucs4len - 1 + maplen;
88 return STRINGPREP_OK;
91 #define INVERTED(x) ((x) & ((~0UL) >> 1))
92 #define UNAPPLICAPLEFLAGS(flags, profileflags) \
93 ((!INVERTED(profileflags) && !(profileflags & flags) && profileflags) || \
94 ( INVERTED(profileflags) && (profileflags & flags)))
96 int
97 stringprep (char *in, int maxlen, int flags, Stringprep_profile * profile)
99 int i;
100 int rc;
101 char *p = 0;
102 long *q = 0;
103 long *ucs4;
104 int ucs4len;
105 int maxucs4len;
107 ucs4 = stringprep_utf8_to_ucs4 (in, -1, &ucs4len);
108 maxucs4len = 4 * ucs4len + 10;
109 ucs4 = realloc (ucs4, 1 + maxucs4len * sizeof (long));
110 if (!ucs4)
112 rc = STRINGPREP_MALLOC_ERROR;
113 goto done;
116 #if DBG
118 int j;
119 printf ("\t;; in: ");
120 for (j = 0; j < ucs4len; j++)
121 printf ("U+%06lx ", ucs4[j]);
122 printf ("\n");
124 #endif
126 for (i = 0; profile[i].operation; i++)
128 switch (profile[i].operation)
130 case STRINGPREP_NFKC:
131 if (UNAPPLICAPLEFLAGS (flags, profile[i].flags))
132 break;
133 if (flags & STRINGPREP_NO_NFKC && !profile[i].flags)
135 /* Profile requires NFKC, but callee asked for no NFKC. */
136 rc = STRINGPREP_FLAG_ERROR;
137 goto done;
140 q = stringprep_ucs4_nfkc_normalize (ucs4, ucs4len);
142 if (!q)
144 rc = STRINGPREP_NFKC_FAILED;
145 goto done;
148 for (ucs4len = 0; ucs4[ucs4len]; ucs4len++)
151 free (ucs4);
152 ucs4 = q;
153 q = 0;
154 break;
156 case STRINGPREP_PROHIBIT_TABLE:
157 if (stringprep_find_string_in_table
158 (ucs4, ucs4len, NULL, profile[i].table) != -1)
160 rc = STRINGPREP_CONTAINS_PROHIBITED;
161 goto done;
163 break;
165 case STRINGPREP_UNASSIGNED_TABLE:
166 if (UNAPPLICAPLEFLAGS (flags, profile[i].flags))
167 break;
168 if (flags & STRINGPREP_NO_UNASSIGNED)
169 if (stringprep_find_string_in_table
170 (ucs4, ucs4len, NULL, profile[i].table) != -1)
172 rc = STRINGPREP_CONTAINS_UNASSIGNED;
173 goto done;
175 break;
177 case STRINGPREP_MAP_TABLE:
178 if (UNAPPLICAPLEFLAGS (flags, profile[i].flags))
179 break;
180 rc = stringprep_apply_table_to_string
181 (ucs4, &ucs4len, maxucs4len, profile[i].table);
182 if (rc != STRINGPREP_OK)
183 goto done;
184 break;
186 case STRINGPREP_BIDI_PROHIBIT_TABLE:
187 case STRINGPREP_BIDI_RAL_TABLE:
188 case STRINGPREP_BIDI_L_TABLE:
189 break;
191 case STRINGPREP_BIDI:
193 int done_prohibited = 0;
194 int done_ral = 0;
195 int done_l = 0;
196 int contains_ral = -1;
197 int contains_l = -1;
198 int j;
200 for (j = 0; profile[j].operation; j++)
201 if (profile[j].operation == STRINGPREP_BIDI_PROHIBIT_TABLE)
203 done_prohibited = 1;
204 if (stringprep_find_string_in_table
205 (ucs4, ucs4len, NULL, profile[j].table) != -1)
206 return STRINGPREP_BIDI_CONTAINS_PROHIBITED;
208 else if (profile[j].operation == STRINGPREP_BIDI_RAL_TABLE)
210 done_ral = 1;
211 if (stringprep_find_string_in_table
212 (ucs4, ucs4len, NULL, profile[j].table) != -1)
213 contains_ral = j;
215 else if (profile[j].operation == STRINGPREP_BIDI_L_TABLE)
217 done_l = 1;
218 if (stringprep_find_string_in_table
219 (ucs4, ucs4len, NULL, profile[j].table) != -1)
220 contains_l = j;
223 if (!done_prohibited || !done_ral || !done_l)
225 rc = STRINGPREP_PROFILE_ERROR;
226 goto done;
229 if (contains_ral != -1 && contains_l != -1)
231 rc = STRINGPREP_BIDI_BOTH_L_AND_RAL;
232 goto done;
235 if (contains_ral != -1)
236 if (!(stringprep_find_character_in_table
237 (ucs4[0], profile[contains_ral].table) != -1 &&
238 stringprep_find_character_in_table
239 (ucs4[ucs4len - 1], profile[contains_ral].table) != -1))
241 rc = STRINGPREP_BIDI_LEADTRAIL_NOT_RAL;
242 goto done;
245 break;
247 default:
248 rc = STRINGPREP_PROFILE_ERROR;
249 goto done;
250 break;
252 #if DBG
254 int j;
255 printf ("\t;; %5s: ", profile[i].name ? profile[i].name : "<NONAME>");
256 for (j = 0; j < ucs4len; j++)
257 printf ("U+%06lx ", ucs4[j]);
258 printf ("\n");
260 #endif
263 p = stringprep_ucs4_to_utf8 (ucs4, ucs4len, 0, 0);
265 if (strlen (p) >= maxlen)
267 rc = STRINGPREP_TOO_SMALL_BUFFER;
268 goto done;
271 strcpy (in, p);
273 rc = STRINGPREP_OK;
275 done:
276 if (p)
277 free (p);
278 if (q)
279 free (q);
280 if (ucs4)
281 free (ucs4);
282 return rc;