*** empty log message ***
[libidn.git] / stringprep.c
blob17920a9cbe1e4c64b1b1d5cb03e9da17a536cd14
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 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
26 #include <stdio.h>
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #if HAVE_STRING_H
30 # if !STDC_HEADERS && HAVE_MEMORY_H
31 # include <memory.h>
32 # endif
33 # include <string.h>
34 #endif
35 #if HAVE_STRINGS_H
36 # include <strings.h>
37 #endif
38 #if HAVE_INTTYPES_H
39 # include <inttypes.h>
40 #else
41 # if HAVE_STDINT_H
42 # include <stdint.h>
43 # endif
44 #endif
45 #if HAVE_SYS_TYPES_H
46 #include <sys/types.h>
47 #endif
49 #include <stringprep.h>
50 #include <stringprep_generic.h>
52 #define DBG 0
54 static int
55 stringprep_find_character_in_table (long ucs4,
56 struct stringprep_table_element *table)
58 int i;
60 for (i = 0; table[i].start; i++)
61 if (ucs4 >= table[i].start &&
62 ucs4 <= (table[i].end ? table[i].end : table[i].start))
63 return i;
65 return -1;
68 static int
69 stringprep_find_string_in_table (long *ucs4,
70 int ucs4len,
71 int *tablepos,
72 struct stringprep_table_element *table)
74 int j, pos;
76 for (j = 0; j < ucs4len; j++)
77 if ((pos = stringprep_find_character_in_table (ucs4[j], table)) != -1)
79 if (tablepos)
80 *tablepos = pos;
81 return j;
84 return -1;
87 static int
88 stringprep_apply_table_to_string (long *ucs4,
89 int *ucs4len,
90 int maxucs4len,
91 struct stringprep_table_element *table)
93 int i;
94 int pos, maplen;
96 #if DBG
97 printf ("in: ");
98 for (i = 0; i < *ucs4len; i++)
99 printf ("U+%06x ", ucs4[i]);
100 printf ("\n");
101 #endif
103 if ((pos =
104 stringprep_find_string_in_table (ucs4, *ucs4len, &i, table)) != -1)
106 #if DBG
107 printf ("hit %06x %06x-%06x\n", ucs4[pos], table[i].start,
108 table[i].end);
109 #endif
111 for (maplen = 0; table[i].map[maplen]; maplen++)
114 if (*ucs4len - 1 + maplen >= maxucs4len)
115 return STRINGPREP_TOO_SMALL_BUFFER;
117 memmove (&ucs4[pos + maplen], &ucs4[pos + 1],
118 *ucs4len * sizeof (uint32_t) - (&ucs4[pos + 1] - ucs4));
119 memcpy (&ucs4[pos], table[i].map, sizeof (uint32_t) * maplen);
120 *ucs4len = *ucs4len - 1 + maplen;
123 #if DBG
124 printf ("out: ");
125 for (i = 0; i < *ucs4len; i++)
126 printf ("U+%06x ", ucs4[i]);
127 printf ("\n");
128 #endif
130 return STRINGPREP_OK;
134 stringprep (char *in, int maxlen, int flags, stringprep_profile * profile)
136 int i;
137 int rc;
138 char *p = 0;
139 long *q = 0;
140 long *ucs4;
141 int ucs4len;
142 int maxucs4len;
144 ucs4 = stringprep_utf8_to_ucs4_fast (in, -1, &ucs4len);
145 maxucs4len = 4 * ucs4len + 10;
146 ucs4 = realloc (ucs4, 1 + maxucs4len * sizeof (long));
147 if (!ucs4)
149 rc = STRINGPREP_MALLOC_ERROR;
150 goto done;
153 for (i = 0; profile[i].flags || profile[i].table; i++)
155 if (!profile[i].table && profile[i].flags == ~STRINGPREP_NO_NFKC &&
156 !(flags & STRINGPREP_NO_NFKC))
159 q = stringprep_ucs4_nfkc_normalize (ucs4, ucs4len);
161 if (!q)
163 rc = STRINGPREP_NFKC_FAILED;
164 goto done;
167 for (ucs4len = 0; ucs4[ucs4len]; ucs4len++)
170 free (ucs4);
171 ucs4 = q;
172 q = 0;
174 continue;
176 else if (profile[i].flags & STRINGPREP_INVERT_MAGIC)
178 if (flags & (~profile[i].flags))
179 continue;
181 else
183 if (profile[i].flags != 0 && !(flags & profile[i].flags))
184 continue;
187 if (!profile[i].table)
188 continue; /* this indicates an error in the profile ... */
190 rc = stringprep_apply_table_to_string
191 (ucs4, &ucs4len, maxucs4len, profile[i].table);
192 if (rc != STRINGPREP_OK)
193 goto done;
196 if (!(flags & STRINGPREP_NO_BIDI))
198 int done_prohibited = 0;
199 int done_ral = 0;
200 int done_l = 0;
201 int contains_ral = 0;
202 int contains_l = 0;
204 for (i = 0; profile[i].flags || profile[i].table; i++)
205 if (profile[i].flags == STRINGPREP_BIDI_PROHIBITED_MASK)
207 done_prohibited = 1;
208 rc = stringprep_apply_table_to_string
209 (ucs4, &ucs4len, maxucs4len, profile[i].table);
210 if (rc != STRINGPREP_OK)
211 goto done;
213 else if (profile[i].flags == STRINGPREP_BIDI_RAL_MASK)
215 done_ral = 1;
216 contains_ral = stringprep_find_string_in_table
217 (ucs4, ucs4len, 0, profile[i].table) != -1;
219 else if (profile[i].flags == STRINGPREP_BIDI_L_MASK)
221 done_l = 1;
222 contains_l = stringprep_find_string_in_table
223 (ucs4, ucs4len, 0, profile[i].table) != -1;
226 if (!done_prohibited || !done_ral || !done_l)
228 rc = STRINGPREP_BIDI_NOT_IN_PROFILE;
229 goto done;
232 if (contains_ral && contains_l)
234 rc = STRINGPREP_BIDI_BOTH_L_AND_RAL;
235 goto done;
238 if (contains_ral &&
239 (!stringprep_find_character_in_table (ucs4[0],
240 profile[i].table) ||
241 !stringprep_find_character_in_table (ucs4[ucs4len],
242 profile[i].table)))
244 rc = STRINGPREP_BIDI_LEADTRAIL_NOT_RAL;
245 goto done;
249 p = stringprep_ucs4_to_utf8 (ucs4, ucs4len, 0, 0);
251 if (strlen (p) >= maxlen)
253 rc = STRINGPREP_TOO_SMALL_BUFFER;
254 goto done;
257 strcpy (in, p);
259 rc = STRINGPREP_OK;
261 done:
262 if (p)
263 free (p);
264 if (q)
265 free (q);
266 if (ucs4)
267 free (ucs4);
268 return rc;