Make sure ChangeLog is regenerated.
[libidn.git] / stringprep.c
blob3e1c9a0a42d513deaeb111dc0da9a39856fb4f42
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 while ((pos = stringprep_find_string_in_table
69 (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 (long) - (&ucs4[pos + 1] - ucs4));
84 memcpy (&ucs4[pos], table[i].map, sizeof (long) * 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)
207 rc = STRINGPREP_BIDI_CONTAINS_PROHIBITED;
208 goto done;
211 else if (profile[j].operation == STRINGPREP_BIDI_RAL_TABLE)
213 done_ral = 1;
214 if (stringprep_find_string_in_table
215 (ucs4, ucs4len, NULL, profile[j].table) != -1)
216 contains_ral = j;
218 else if (profile[j].operation == STRINGPREP_BIDI_L_TABLE)
220 done_l = 1;
221 if (stringprep_find_string_in_table
222 (ucs4, ucs4len, NULL, profile[j].table) != -1)
223 contains_l = j;
226 if (!done_prohibited || !done_ral || !done_l)
228 rc = STRINGPREP_PROFILE_ERROR;
229 goto done;
232 if (contains_ral != -1 && contains_l != -1)
234 rc = STRINGPREP_BIDI_BOTH_L_AND_RAL;
235 goto done;
238 if (contains_ral != -1)
239 if (!(stringprep_find_character_in_table
240 (ucs4[0], profile[contains_ral].table) != -1 &&
241 stringprep_find_character_in_table
242 (ucs4[ucs4len - 1], profile[contains_ral].table) != -1))
244 rc = STRINGPREP_BIDI_LEADTRAIL_NOT_RAL;
245 goto done;
248 break;
250 default:
251 rc = STRINGPREP_PROFILE_ERROR;
252 goto done;
253 break;
255 #if DBG
257 int j;
258 printf ("\t;; %5s: ", profile[i].name ? profile[i].name : "<NONAME>");
259 for (j = 0; j < ucs4len; j++)
260 printf ("U+%06lx ", ucs4[j]);
261 printf ("\n");
263 #endif
266 p = stringprep_ucs4_to_utf8 (ucs4, ucs4len, 0, 0);
268 if (strlen (p) >= maxlen)
270 rc = STRINGPREP_TOO_SMALL_BUFFER;
271 goto done;
274 strcpy (in, p); /* flawfinder: ignore */
276 rc = STRINGPREP_OK;
278 done:
279 if (p)
280 free (p);
281 if (q)
282 free (q);
283 if (ucs4)
284 free (ucs4);
285 return rc;