*** empty log message ***
[libidn.git] / stringprep.c
blob22e2c004455249c040e8b79cdd3aecb1c6e2a0e3
1 /* stringprep.c Core stringprep implementation.
2 * Copyright (C) 2002, 2003 Simon Josefsson
4 * This file is part of GNU Libidn.
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.
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.
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
22 #include "internal.h"
24 static int
25 stringprep_find_character_in_table (unsigned long ucs4,
26 Stringprep_table_element * table)
28 int i;
30 for (i = 0; table[i].start; i++)
31 if (ucs4 >= table[i].start &&
32 ucs4 <= (table[i].end ? table[i].end : table[i].start))
33 return i;
35 return -1;
38 static ssize_t
39 stringprep_find_string_in_table (unsigned long *ucs4,
40 size_t ucs4len,
41 int *tablepos,
42 Stringprep_table_element * table)
44 size_t j;
45 int pos;
47 for (j = 0; j < ucs4len; j++)
48 if ((pos = stringprep_find_character_in_table (ucs4[j], table)) != -1)
50 if (tablepos)
51 *tablepos = pos;
52 return j;
55 return -1;
58 static int
59 stringprep_apply_table_to_string (unsigned long *ucs4,
60 size_t *ucs4len,
61 size_t maxucs4len,
62 Stringprep_table_element * table,
63 const char *tablename)
65 int i;
66 ssize_t pos;
67 size_t maplen;
69 while ((pos = stringprep_find_string_in_table
70 (ucs4, *ucs4len, &i, table)) != -1)
72 for(maplen = STRINGPREP_MAX_MAP_CHARS;
73 maplen > 0 && table[i].map[maplen-1] == 0;
74 maplen--)
77 if (*ucs4len - 1 + maplen >= maxucs4len)
78 return STRINGPREP_TOO_SMALL_BUFFER;
80 memmove (&ucs4[pos + maplen], &ucs4[pos + 1],
81 *ucs4len * sizeof (unsigned long) - (&ucs4[pos + 1] - ucs4));
82 memcpy (&ucs4[pos], table[i].map, sizeof (unsigned long) * maplen);
83 *ucs4len = *ucs4len - 1 + maplen;
86 return STRINGPREP_OK;
89 #define INVERTED(x) ((x) & ((~0UL) >> 1))
90 #define UNAPPLICAPLEFLAGS(flags, profileflags) \
91 ((!INVERTED(profileflags) && !(profileflags & flags) && profileflags) || \
92 ( INVERTED(profileflags) && (profileflags & flags)))
94 /**
95 * stringprep:
96 * @in: input/ouput array with string to prepare.
97 * @maxlen: maximum length of input/output array.
98 * @flags: optional stringprep profile flags.
99 * @profile: pointer to stringprep profile to use.
101 * Prepare the input UTF-8 string according to the stringprep profile.
102 * Normally application programmers use stringprep profile macros such
103 * as stringprep_nameprep(), stringprep_kerberos5() etc instead of
104 * calling this function directly.
106 * Since the stringprep operation can expand the string, @maxlen
107 * indicate how large the buffer holding the string is. The @flags
108 * are one of Stringprep_profile_flags, or 0. The profile indicates
109 * processing details, see the profile header files, such as
110 * stringprep_generic.h and stringprep_nameprep.h for two examples.
111 * Your application can define new profiles, possibly re-using the
112 * generic stringprep tables that always will be part of the library.
113 * Note that you must convert strings entered in the systems locale
114 * into UTF-8 before using this function.
116 * Return value: Returns 0 iff successful, or an error code.
119 stringprep (char *in, size_t maxlen, int flags, Stringprep_profile * profile)
121 int i, j;
122 int rc;
123 char *p = 0;
124 unsigned long *q = 0;
125 unsigned long *ucs4;
126 size_t ucs4len, maxucs4len;
128 ucs4 = stringprep_utf8_to_ucs4 (in, -1, &ucs4len);
129 maxucs4len = 4 * ucs4len + 10; /* XXX */
130 ucs4 = realloc (ucs4, 1 + maxucs4len * sizeof (unsigned long));
131 if (!ucs4)
133 rc = STRINGPREP_MALLOC_ERROR;
134 goto done;
137 for (i = 0; profile[i].operation; i++)
139 switch (profile[i].operation)
141 case STRINGPREP_NFKC:
142 if (UNAPPLICAPLEFLAGS (flags, profile[i].flags))
144 break;
147 if (flags & STRINGPREP_NO_NFKC && !profile[i].flags)
149 /* Profile requires NFKC, but callee asked for no NFKC. */
150 rc = STRINGPREP_FLAG_ERROR;
151 goto done;
154 q = stringprep_ucs4_nfkc_normalize (ucs4, ucs4len);
156 if (!q)
158 rc = STRINGPREP_NFKC_FAILED;
159 goto done;
162 for (j = 0; q[j]; j++)
165 free (ucs4);
166 ucs4 = q;
167 ucs4len = j;
168 q = 0;
169 break;
171 case STRINGPREP_PROHIBIT_TABLE:
172 j = stringprep_find_string_in_table (ucs4, ucs4len,
173 NULL, profile[i].table);
174 if (j != -1)
176 rc = STRINGPREP_CONTAINS_PROHIBITED;
177 goto done;
179 break;
181 case STRINGPREP_UNASSIGNED_TABLE:
182 if (UNAPPLICAPLEFLAGS (flags, profile[i].flags))
183 break;
184 if (flags & STRINGPREP_NO_UNASSIGNED)
186 j = stringprep_find_string_in_table
187 (ucs4, ucs4len, NULL, profile[i].table);
188 if (j != -1)
190 rc = STRINGPREP_CONTAINS_UNASSIGNED;
191 goto done;
194 break;
196 case STRINGPREP_MAP_TABLE:
197 if (UNAPPLICAPLEFLAGS (flags, profile[i].flags))
198 break;
199 rc = stringprep_apply_table_to_string
200 (ucs4, &ucs4len, maxucs4len, profile[i].table, profile[i].name);
201 if (rc != STRINGPREP_OK)
202 goto done;
203 break;
205 case STRINGPREP_BIDI_PROHIBIT_TABLE:
206 case STRINGPREP_BIDI_RAL_TABLE:
207 case STRINGPREP_BIDI_L_TABLE:
208 break;
210 case STRINGPREP_BIDI:
212 int done_prohibited = 0;
213 int done_ral = 0;
214 int done_l = 0;
215 int contains_ral = -1;
216 int contains_l = -1;
217 int k;
219 for (j = 0; profile[j].operation; j++)
220 if (profile[j].operation == STRINGPREP_BIDI_PROHIBIT_TABLE)
222 done_prohibited = 1;
223 k = stringprep_find_string_in_table (ucs4, ucs4len,
224 NULL, profile[j].table);
225 if (k != -1)
227 rc = STRINGPREP_BIDI_CONTAINS_PROHIBITED;
228 goto done;
231 else if (profile[j].operation == STRINGPREP_BIDI_RAL_TABLE)
233 done_ral = 1;
234 if (stringprep_find_string_in_table
235 (ucs4, ucs4len, NULL, profile[j].table) != -1)
236 contains_ral = j;
238 else if (profile[j].operation == STRINGPREP_BIDI_L_TABLE)
240 done_l = 1;
241 if (stringprep_find_string_in_table
242 (ucs4, ucs4len, NULL, profile[j].table) != -1)
243 contains_l = j;
246 if (!done_prohibited || !done_ral || !done_l)
248 rc = STRINGPREP_PROFILE_ERROR;
249 goto done;
252 if (contains_ral != -1 && contains_l != -1)
254 rc = STRINGPREP_BIDI_BOTH_L_AND_RAL;
255 goto done;
258 if (contains_ral != -1)
260 if (!(stringprep_find_character_in_table
261 (ucs4[0], profile[contains_ral].table) != -1 &&
262 stringprep_find_character_in_table
263 (ucs4[ucs4len - 1], profile[contains_ral].table) != -1))
265 rc = STRINGPREP_BIDI_LEADTRAIL_NOT_RAL;
266 goto done;
270 break;
272 default:
273 rc = STRINGPREP_PROFILE_ERROR;
274 goto done;
275 break;
279 p = stringprep_ucs4_to_utf8 (ucs4, ucs4len, 0, 0);
281 if (strlen (p) >= maxlen)
283 rc = STRINGPREP_TOO_SMALL_BUFFER;
284 goto done;
287 strcpy (in, p); /* flawfinder: ignore */
289 rc = STRINGPREP_OK;
291 done:
292 if (p)
293 free (p);
294 if (q)
295 free (q);
296 if (ucs4)
297 free (ucs4);
298 return rc;
302 * stringprep_profile:
303 * @in: input/ouput array with string to prepare.
304 * @out: output variable with newly allocate string.
305 * @flags: optional stringprep profile flags.
306 * @profile: name of stringprep profile to use.
308 * Prepare the input UTF-8 string according to the stringprep profile.
309 * Normally application programmers use stringprep profile macros such
310 * as stringprep_nameprep(), stringprep_kerberos5() etc instead of
311 * calling this function directly.
313 * Note that you must convert strings entered in the systems locale
314 * into UTF-8 before using this function.
316 * The output @out variable must be deallocated by the caller.
318 * Return value: Returns 0 iff successful, or an error code.
321 stringprep_profile (char *in, char **out, char *profile, int flags)
323 Stringprep_profiles *p;
324 char *str;
325 size_t len;
326 int rc;
328 for (p = &stringprep_profiles[0]; p->name; p++)
329 if (strcmp(p->name, profile) == 0)
330 break;
332 if (!p || !p->name || !p->tables)
333 return STRINGPREP_UNKNOWN_PROFILE;
335 len = strlen(in) + BUFSIZ;
336 str = (char*) malloc(len);
337 if (str == NULL)
338 return STRINGPREP_MALLOC_ERROR;
340 strcpy(str, in);
342 rc = stringprep (str, len, flags, p->tables);
344 if (rc == STRINGPREP_OK)
345 *out = str;
346 else
347 free(str);
349 return rc;