source: psi/trunk/iris/libidn/stringprep.c@ 59

Last change on this file since 59 was 2, checked in by dmik, 19 years ago

Imported original Psi 0.10 sources from Affinix

File size: 12.4 KB
Line 
1/* stringprep.c Core stringprep implementation.
2 * Copyright (C) 2002, 2003 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 "internal.h"
23
24static ssize_t
25stringprep_find_character_in_table (my_uint32_t ucs4,
26 Stringprep_table_element * table)
27{
28 ssize_t i;
29
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;
34
35 return -1;
36}
37
38static ssize_t
39stringprep_find_string_in_table (my_uint32_t * ucs4,
40 size_t ucs4len,
41 size_t * tablepos,
42 Stringprep_table_element * table)
43{
44 size_t j;
45 ssize_t pos;
46
47 for (j = 0; j < ucs4len; j++)
48 if ((pos = stringprep_find_character_in_table (ucs4[j], table)) != -1)
49 {
50 if (tablepos)
51 *tablepos = pos;
52 return j;
53 }
54
55 return -1;
56}
57
58static int
59stringprep_apply_table_to_string (my_uint32_t * ucs4,
60 size_t * ucs4len,
61 size_t maxucs4len,
62 Stringprep_table_element * table,
63 const char *tablename)
64{
65 ssize_t pos;
66 size_t i, maplen;
67
68 while ((pos = stringprep_find_string_in_table (ucs4, *ucs4len,
69 &i, table)) != -1)
70 {
71 for (maplen = STRINGPREP_MAX_MAP_CHARS;
72 maplen > 0 && table[i].map[maplen - 1] == 0; maplen--)
73 ;
74
75 if (*ucs4len - 1 + maplen >= maxucs4len)
76 return STRINGPREP_TOO_SMALL_BUFFER;
77
78 memmove (&ucs4[pos + maplen], &ucs4[pos + 1],
79 *ucs4len * sizeof (my_uint32_t) - (&ucs4[pos + 1] - ucs4));
80 memcpy (&ucs4[pos], table[i].map, sizeof (my_uint32_t) * maplen);
81 *ucs4len = *ucs4len - 1 + maplen;
82 }
83
84 return STRINGPREP_OK;
85}
86
87#define INVERTED(x) ((x) & ((~0UL) >> 1))
88#define UNAPPLICAPLEFLAGS(flags, profileflags) \
89 ((!INVERTED(profileflags) && !(profileflags & flags) && profileflags) || \
90 ( INVERTED(profileflags) && (profileflags & flags)))
91
92/**
93 * stringprep:
94 * @in: input/ouput array with string to prepare.
95 * @maxlen: maximum length of input/output array.
96 * @flags: optional stringprep profile flags.
97 * @profile: pointer to stringprep profile to use.
98 *
99 * Prepare the input UTF-8 string according to the stringprep profile.
100 * Normally application programmers use stringprep profile macros such
101 * as stringprep_nameprep(), stringprep_kerberos5() etc instead of
102 * calling this function directly.
103 *
104 * Since the stringprep operation can expand the string, @maxlen
105 * indicate how large the buffer holding the string is. The @flags
106 * are one of Stringprep_profile_flags, or 0. The profile indicates
107 * processing details specific to that profile. Your application can
108 * define new profiles, possibly re-using the generic stringprep
109 * tables that always will be part of the library.
110 *
111 * Note that you must convert strings entered in the systems locale
112 * into UTF-8 before using this function.
113 *
114 * Return value: Returns 0 iff successful, or an error code.
115 **/
116int
117stringprep (char *in,
118 size_t maxlen,
119 Stringprep_profile_flags flags, Stringprep_profile * profile)
120{
121 size_t i, j;
122 ssize_t k;
123 int rc;
124 char *p = 0;
125 my_uint32_t *q = 0;
126 my_uint32_t *ucs4;
127 size_t ucs4len, maxucs4len;
128
129 ucs4 = stringprep_utf8_to_ucs4 (in, -1, &ucs4len);
130 maxucs4len = 4 * ucs4len + 10; /* XXX */
131 ucs4 = realloc (ucs4, 1 + maxucs4len * sizeof (my_uint32_t));
132 if (!ucs4)
133 {
134 rc = STRINGPREP_MALLOC_ERROR;
135 goto done;
136 }
137
138 for (i = 0; profile[i].operation; i++)
139 {
140 switch (profile[i].operation)
141 {
142 case STRINGPREP_NFKC:
143 if (UNAPPLICAPLEFLAGS (flags, profile[i].flags))
144 {
145 break;
146 }
147
148 if (flags & STRINGPREP_NO_NFKC && !profile[i].flags)
149 {
150 /* Profile requires NFKC, but callee asked for no NFKC. */
151 rc = STRINGPREP_FLAG_ERROR;
152 goto done;
153 }
154
155 q = stringprep_ucs4_nfkc_normalize (ucs4, ucs4len);
156
157 if (!q)
158 {
159 rc = STRINGPREP_NFKC_FAILED;
160 goto done;
161 }
162
163 for (j = 0; q[j]; j++)
164 ;
165
166 free (ucs4);
167 ucs4 = q;
168 ucs4len = j;
169 q = 0;
170 break;
171
172 case STRINGPREP_PROHIBIT_TABLE:
173 k = stringprep_find_string_in_table (ucs4, ucs4len,
174 NULL, profile[i].table);
175 if (k != -1)
176 {
177 rc = STRINGPREP_CONTAINS_PROHIBITED;
178 goto done;
179 }
180 break;
181
182 case STRINGPREP_UNASSIGNED_TABLE:
183 if (UNAPPLICAPLEFLAGS (flags, profile[i].flags))
184 break;
185 if (flags & STRINGPREP_NO_UNASSIGNED)
186 {
187 k = stringprep_find_string_in_table
188 (ucs4, ucs4len, NULL, profile[i].table);
189 if (k != -1)
190 {
191 rc = STRINGPREP_CONTAINS_UNASSIGNED;
192 goto done;
193 }
194 }
195 break;
196
197 case STRINGPREP_MAP_TABLE:
198 if (UNAPPLICAPLEFLAGS (flags, profile[i].flags))
199 break;
200 rc = stringprep_apply_table_to_string
201 (ucs4, &ucs4len, maxucs4len, profile[i].table, profile[i].name);
202 if (rc != STRINGPREP_OK)
203 goto done;
204 break;
205
206 case STRINGPREP_BIDI_PROHIBIT_TABLE:
207 case STRINGPREP_BIDI_RAL_TABLE:
208 case STRINGPREP_BIDI_L_TABLE:
209 break;
210
211 case STRINGPREP_BIDI:
212 {
213 int done_prohibited = 0;
214 int done_ral = 0;
215 int done_l = 0;
216 int contains_ral = -1;
217 int contains_l = -1;
218
219 for (j = 0; profile[j].operation; j++)
220 if (profile[j].operation == STRINGPREP_BIDI_PROHIBIT_TABLE)
221 {
222 done_prohibited = 1;
223 k = stringprep_find_string_in_table (ucs4, ucs4len,
224 NULL,
225 profile[j].table);
226 if (k != -1)
227 {
228 rc = STRINGPREP_BIDI_CONTAINS_PROHIBITED;
229 goto done;
230 }
231 }
232 else if (profile[j].operation == STRINGPREP_BIDI_RAL_TABLE)
233 {
234 done_ral = 1;
235 if (stringprep_find_string_in_table
236 (ucs4, ucs4len, NULL, profile[j].table) != -1)
237 contains_ral = j;
238 }
239 else if (profile[j].operation == STRINGPREP_BIDI_L_TABLE)
240 {
241 done_l = 1;
242 if (stringprep_find_string_in_table
243 (ucs4, ucs4len, NULL, profile[j].table) != -1)
244 contains_l = j;
245 }
246
247 if (!done_prohibited || !done_ral || !done_l)
248 {
249 rc = STRINGPREP_PROFILE_ERROR;
250 goto done;
251 }
252
253 if (contains_ral != -1 && contains_l != -1)
254 {
255 rc = STRINGPREP_BIDI_BOTH_L_AND_RAL;
256 goto done;
257 }
258
259 if (contains_ral != -1)
260 {
261 if (!(stringprep_find_character_in_table
262 (ucs4[0], profile[contains_ral].table) != -1 &&
263 stringprep_find_character_in_table
264 (ucs4[ucs4len - 1], profile[contains_ral].table) != -1))
265 {
266 rc = STRINGPREP_BIDI_LEADTRAIL_NOT_RAL;
267 goto done;
268 }
269 }
270 }
271 break;
272
273 default:
274 rc = STRINGPREP_PROFILE_ERROR;
275 goto done;
276 break;
277 }
278 }
279
280 p = stringprep_ucs4_to_utf8 (ucs4, ucs4len, 0, 0);
281
282 if (strlen (p) >= maxlen)
283 {
284 rc = STRINGPREP_TOO_SMALL_BUFFER;
285 goto done;
286 }
287
288 strcpy (in, p); /* flawfinder: ignore */
289
290 rc = STRINGPREP_OK;
291
292done:
293 if (p)
294 free (p);
295 if (q)
296 free (q);
297 if (ucs4)
298 free (ucs4);
299 return rc;
300}
301
302/**
303 * stringprep_profile:
304 * @in: input/ouput array with string to prepare.
305 * @out: output variable with newly allocate string.
306 * @flags: optional stringprep profile flags.
307 * @profile: name of stringprep profile to use.
308 *
309 * Prepare the input UTF-8 string according to the stringprep profile.
310 * Normally application programmers use stringprep profile macros such
311 * as stringprep_nameprep(), stringprep_kerberos5() etc instead of
312 * calling this function directly.
313 *
314 * Note that you must convert strings entered in the systems locale
315 * into UTF-8 before using this function.
316 *
317 * The output @out variable must be deallocated by the caller.
318 *
319 * Return value: Returns 0 iff successful, or an error code.
320 **/
321int
322stringprep_profile (char *in,
323 char **out, char *profile, Stringprep_profile_flags flags)
324{
325 Stringprep_profiles *p;
326 char *str;
327 size_t len;
328 int rc;
329
330 for (p = &stringprep_profiles[0]; p->name; p++)
331 if (strcmp (p->name, profile) == 0)
332 break;
333
334 if (!p || !p->name || !p->tables)
335 return STRINGPREP_UNKNOWN_PROFILE;
336
337 len = strlen (in) + BUFSIZ;
338 str = (char *) malloc (len);
339 if (str == NULL)
340 return STRINGPREP_MALLOC_ERROR;
341
342 strcpy (str, in);
343
344 rc = stringprep (str, len, flags, p->tables);
345
346 if (rc == STRINGPREP_OK)
347 *out = str;
348 else
349 free (str);
350
351 return rc;
352}
353
354/**
355 * STRINGPREP_VERSION
356 *
357 * String defined via CPP denoting the header file version number.
358 * Used together with stringprep_check_version() to verify header file
359 * and run-time library consistency.
360 */
361
362/**
363 * STRINGPREP_MAX_MAP_CHARS
364 *
365 * Maximum number of code points that can replace a single code point,
366 * during stringprep mapping.
367 */
368
369/**
370 * Stringprep_rc
371 *
372 * Enumerated return codes of stringprep(), stringprep_profile()
373 * functions (and macros using those functions). The value 0 is
374 * guaranteed to always correspond to success.
375 */
376
377/**
378 * Stringprep_profile_flags:
379 * @STRINGPREP_NO_NFKC: Disable the NFKC normalization, as well as
380 * selecting the non-NFKC case folding tables. Usually the profile
381 * specifies BIDI and NFKC settings, and applications should not
382 * override it unless in special situations.
383 * @STRINGPREP_NO_BIDI: Disable the BIDI step. Usually the profile
384 * specifies BIDI and NFKC settings, and applications should not
385 * override it unless in special situations.
386 * @STRINGPREP_NO_UNASSIGNED: Make the library return with an error if
387 * string contains unassigned characters according to profile.
388 *
389 * Stringprep profile flags.
390 */
391
392/**
393 * Stringprep_profile_steps:
394 *
395 * Various steps in the stringprep algorithm. You really want to
396 * study the source code to understand this one. Only useful if you
397 * want to add another profile.
398 */
399
400/**
401 * stringprep_nameprep:
402 * @in: input/ouput array with string to prepare.
403 * @maxlen: maximum length of input/output array.
404 *
405 * Prepare the input UTF-8 string according to the nameprep profile.
406 * The AllowUnassigned flag is true, use
407 * stringprep_nameprep_no_unassigned() for false AllowUnassigned.
408 * Returns 0 iff successful, or an error code.
409 **/
410
411/**
412 * stringprep_nameprep_no_unassigned:
413 * @in: input/ouput array with string to prepare.
414 * @maxlen: maximum length of input/output array.
415 *
416 * Prepare the input UTF-8 string according to the nameprep profile.
417 * The AllowUnassigned flag is false, use stringprep_nameprep() for
418 * true AllowUnassigned. Returns 0 iff successful, or an error code.
419 **/
420
421/**
422 * stringprep_iscsi:
423 * @in: input/ouput array with string to prepare.
424 * @maxlen: maximum length of input/output array.
425 *
426 * Prepare the input UTF-8 string according to the draft iSCSI
427 * stringprep profile. Returns 0 iff successful, or an error code.
428 **/
429
430/**
431 * stringprep_kerberos5:
432 * @in: input/ouput array with string to prepare.
433 * @maxlen: maximum length of input/output array.
434 *
435 * Prepare the input UTF-8 string according to the draft Kerberos5
436 * stringprep profile. Returns 0 iff successful, or an error code.
437 **/
438
439/**
440 * stringprep_plain:
441 * @in: input/ouput array with string to prepare.
442 * @maxlen: maximum length of input/output array.
443 *
444 * Prepare the input UTF-8 string according to the draft SASL
445 * ANONYMOUS profile. Returns 0 iff successful, or an error code.
446 **/
447
448/**
449 * stringprep_xmpp_nodeprep:
450 * @in: input/ouput array with string to prepare.
451 * @maxlen: maximum length of input/output array.
452 *
453 * Prepare the input UTF-8 string according to the draft XMPP node
454 * identifier profile. Returns 0 iff successful, or an error code.
455 **/
456
457/**
458 * stringprep_xmpp_resourceprep:
459 * @in: input/ouput array with string to prepare.
460 * @maxlen: maximum length of input/output array.
461 *
462 * Prepare the input UTF-8 string according to the draft XMPP resource
463 * identifier profile. Returns 0 iff successful, or an error code.
464 **/
465
466/**
467 * stringprep_generic:
468 * @in: input/ouput array with string to prepare.
469 * @maxlen: maximum length of input/output array.
470 *
471 * Prepare the input UTF-8 string according to a hypotetical "generic"
472 * stringprep profile. This is mostly used for debugging or when
473 * constructing new stringprep profiles. Returns 0 iff successful, or
474 * an error code.
475 **/
Note: See TracBrowser for help on using the repository browser.