1 : /*
2 : * Copyright (c) 2001,2002 Japan Network Information Center.
3 : * All rights reserved.
4 : *
5 : * By using this file, you agree to the terms and conditions set forth bellow.
6 : *
7 : * LICENSE TERMS AND CONDITIONS
8 : *
9 : * The following License Terms and Conditions apply, unless a different
10 : * license is obtained from Japan Network Information Center ("JPNIC"),
11 : * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda,
12 : * Chiyoda-ku, Tokyo 101-0047, Japan.
13 : *
14 : * 1. Use, Modification and Redistribution (including distribution of any
15 : * modified or derived work) in source and/or binary forms is permitted
16 : * under this License Terms and Conditions.
17 : *
18 : * 2. Redistribution of source code must retain the copyright notices as they
19 : * appear in each source code file, this License Terms and Conditions.
20 : *
21 : * 3. Redistribution in binary form must reproduce the Copyright Notice,
22 : * this License Terms and Conditions, in the documentation and/or other
23 : * materials provided with the distribution. For the purposes of binary
24 : * distribution the "Copyright Notice" refers to the following language:
25 : * "Copyright (c) 2000-2002 Japan Network Information Center. All rights reserved."
26 : *
27 : * 4. The name of JPNIC may not be used to endorse or promote products
28 : * derived from this Software without specific prior written approval of
29 : * JPNIC.
30 : *
31 : * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC
32 : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
34 : * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JPNIC BE LIABLE
35 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
36 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
38 : * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
39 : * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
40 : * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41 : * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
42 : */
43 :
44 :
45 : #include <stdlib.h>
46 : #include <string.h>
47 :
48 : #include "nsIDNKitInterface.h"
49 :
50 : #define UCS_MAX 0x7fffffff
51 : #define UNICODE_MAX 0x10ffff
52 :
53 :
54 : /*
55 : * Load NAMEPREP compiled tables.
56 : */
57 : #include "nameprepdata.c"
58 :
59 : /*
60 : * Define mapping/checking functions for each version of the draft.
61 : */
62 :
63 : #define VERSION id11
64 : #include "nameprep_template.c"
65 : #undef VERSION
66 :
67 : typedef const char *(*nameprep_mapproc)(PRUint32 v);
68 : typedef int (*nameprep_checkproc)(PRUint32 v);
69 : typedef idn_biditype_t (*nameprep_biditypeproc)(PRUint32 v);
70 :
71 : static struct idn_nameprep {
72 : char *version;
73 : nameprep_mapproc map_proc;
74 : nameprep_checkproc prohibited_proc;
75 : nameprep_checkproc unassigned_proc;
76 : nameprep_biditypeproc biditype_proc;
77 : } nameprep_versions[] = {
78 : #define MAKE_NAMEPREP_HANDLE(version, id) \
79 : { version, \
80 : compose_sym2(nameprep_map_, id), \
81 : compose_sym2(nameprep_prohibited_, id), \
82 : compose_sym2(nameprep_unassigned_, id), \
83 : compose_sym2(nameprep_biditype_, id), }
84 : MAKE_NAMEPREP_HANDLE("nameprep-11", id11),
85 : { NULL, NULL, NULL, NULL, NULL },
86 : };
87 :
88 : static idn_result_t idn_nameprep_check(nameprep_checkproc proc,
89 : const PRUint32 *str,
90 : const PRUint32 **found);
91 :
92 : idn_result_t
93 1419 : idn_nameprep_create(const char *version, idn_nameprep_t *handlep) {
94 : idn_nameprep_t handle;
95 :
96 : assert(handlep != NULL);
97 :
98 : TRACE(("idn_nameprep_create(version=%-.50s)\n",
99 : version == NULL ? "<NULL>" : version));
100 :
101 1419 : if (version == NULL)
102 1419 : version = IDN_NAMEPREP_CURRENT;
103 :
104 : /*
105 : * Lookup table for the specified version. Since the number of
106 : * versions won't be large (I don't want see draft-23 or such :-),
107 : * simple linear search is OK.
108 : */
109 1419 : for (handle = nameprep_versions; handle->version != NULL; handle++) {
110 1419 : if (strcmp(handle->version, version) == 0) {
111 1419 : *handlep = handle;
112 1419 : return (idn_success);
113 : }
114 : }
115 0 : return (idn_notfound);
116 : }
117 :
118 : void
119 1416 : idn_nameprep_destroy(idn_nameprep_t handle) {
120 : assert(handle != NULL);
121 :
122 : TRACE(("idn_nameprep_destroy()\n"));
123 :
124 : /* Nothing to do. */
125 1416 : }
126 :
127 : idn_result_t
128 567 : idn_nameprep_map(idn_nameprep_t handle, const PRUint32 *from,
129 : PRUint32 *to, size_t tolen) {
130 : assert(handle != NULL && from != NULL && to != NULL);
131 :
132 : TRACE(("idn_nameprep_map(ctx=%s, from=\"%s\")\n",
133 : handle->version, idn__debug_ucs4xstring(from, 50)));
134 :
135 4598 : while (*from != '\0') {
136 3464 : PRUint32 v = *from;
137 : const char *mapped;
138 :
139 3464 : if (v > UCS_MAX) {
140 : /* This cannot happen, but just in case.. */
141 0 : return (idn_invalid_codepoint);
142 3464 : } else if (v > UNICODE_MAX) {
143 : /* No mapping is possible. */
144 0 : mapped = NULL;
145 : } else {
146 : /* Try mapping. */
147 3464 : mapped = (*handle->map_proc)(v);
148 : }
149 :
150 3464 : if (mapped == NULL) {
151 : /* No mapping. Just copy verbatim. */
152 3464 : if (tolen < 1)
153 0 : return (idn_buffer_overflow);
154 3464 : *to++ = v;
155 3464 : tolen--;
156 : } else {
157 : const unsigned char *mappeddata;
158 : size_t mappedlen;
159 :
160 0 : mappeddata = (const unsigned char *)mapped + 1;
161 0 : mappedlen = *mapped;
162 :
163 0 : if (tolen < (mappedlen + 3) / 4)
164 0 : return (idn_buffer_overflow);
165 0 : tolen -= (mappedlen + 3) / 4;
166 0 : while (mappedlen >= 4) {
167 0 : *to = *mappeddata++;
168 0 : *to |= *mappeddata++ << 8;
169 0 : *to |= *mappeddata++ << 16;
170 0 : *to |= *mappeddata++ << 24;
171 0 : mappedlen -= 4;
172 0 : to++;
173 : }
174 0 : if (mappedlen > 0) {
175 0 : *to = *mappeddata++;
176 0 : *to |= (mappedlen >= 2) ?
177 0 : *mappeddata++ << 8: 0;
178 0 : *to |= (mappedlen >= 3) ?
179 0 : *mappeddata++ << 16: 0;
180 0 : to++;
181 : }
182 : }
183 3464 : from++;
184 : }
185 567 : if (tolen == 0)
186 0 : return (idn_buffer_overflow);
187 567 : *to = '\0';
188 567 : return (idn_success);
189 : }
190 :
191 : idn_result_t
192 567 : idn_nameprep_isprohibited(idn_nameprep_t handle, const PRUint32 *str,
193 : const PRUint32 **found) {
194 : assert(handle != NULL && str != NULL && found != NULL);
195 :
196 : TRACE(("idn_nameprep_isprohibited(ctx=%s, str=\"%s\")\n",
197 : handle->version, idn__debug_ucs4xstring(str, 50)));
198 :
199 567 : return (idn_nameprep_check(handle->prohibited_proc, str, found));
200 : }
201 :
202 : idn_result_t
203 16 : idn_nameprep_isunassigned(idn_nameprep_t handle, const PRUint32 *str,
204 : const PRUint32 **found) {
205 : assert(handle != NULL && str != NULL && found != NULL);
206 :
207 : TRACE(("idn_nameprep_isunassigned(handle->version, str=\"%s\")\n",
208 : handle->version, idn__debug_ucs4xstring(str, 50)));
209 :
210 16 : return (idn_nameprep_check(handle->unassigned_proc, str, found));
211 : }
212 :
213 : static idn_result_t
214 583 : idn_nameprep_check(nameprep_checkproc proc, const PRUint32 *str,
215 : const PRUint32 **found) {
216 : PRUint32 v;
217 :
218 4645 : while (*str != '\0') {
219 3497 : v = *str;
220 :
221 3497 : if (v > UCS_MAX) {
222 : /* This cannot happen, but just in case.. */
223 0 : return (idn_invalid_codepoint);
224 3497 : } else if (v > UNICODE_MAX) {
225 : /* It is invalid.. */
226 0 : *found = str;
227 0 : return (idn_success);
228 3497 : } else if ((*proc)(v)) {
229 18 : *found = str;
230 18 : return (idn_success);
231 : }
232 3479 : str++;
233 : }
234 565 : *found = NULL;
235 565 : return (idn_success);
236 : }
237 :
238 : idn_result_t
239 552 : idn_nameprep_isvalidbidi(idn_nameprep_t handle, const PRUint32 *str,
240 : const PRUint32 **found) {
241 : PRUint32 v;
242 : idn_biditype_t first_char;
243 : idn_biditype_t last_char;
244 : int found_r_al;
245 :
246 : assert(handle != NULL && str != NULL && found != NULL);
247 :
248 : TRACE(("idn_nameprep_isvalidbidi(ctx=%s, str=\"%s\")\n",
249 : handle->version, idn__debug_ucs4xstring(str, 50)));
250 :
251 552 : if (*str == '\0') {
252 0 : *found = NULL;
253 0 : return (idn_success);
254 : }
255 :
256 : /*
257 : * check first character's type and initialize variables.
258 : */
259 552 : found_r_al = 0;
260 552 : if (*str > UCS_MAX) {
261 : /* This cannot happen, but just in case.. */
262 0 : return (idn_invalid_codepoint);
263 552 : } else if (*str > UNICODE_MAX) {
264 : /* It is invalid.. */
265 0 : *found = str;
266 0 : return (idn_success);
267 : }
268 552 : first_char = last_char = (*(handle->biditype_proc))(*str);
269 552 : if (first_char == idn_biditype_r_al) {
270 50 : found_r_al = 1;
271 : }
272 552 : str++;
273 :
274 : /*
275 : * see whether string is valid or not.
276 : */
277 3904 : while (*str != '\0') {
278 2802 : v = *str;
279 :
280 2802 : if (v > UCS_MAX) {
281 : /* This cannot happen, but just in case.. */
282 0 : return (idn_invalid_codepoint);
283 2802 : } else if (v > UNICODE_MAX) {
284 : /* It is invalid.. */
285 0 : *found = str;
286 0 : return (idn_success);
287 : } else {
288 2802 : last_char = (*(handle->biditype_proc))(v);
289 2802 : if (found_r_al && last_char == idn_biditype_l) {
290 1 : *found = str;
291 1 : return (idn_success);
292 : }
293 2801 : if (first_char != idn_biditype_r_al && last_char == idn_biditype_r_al) {
294 1 : *found = str;
295 1 : return (idn_success);
296 : }
297 2800 : if (last_char == idn_biditype_r_al) {
298 228 : found_r_al = 1;
299 : }
300 : }
301 2800 : str++;
302 : }
303 :
304 550 : if (found_r_al) {
305 49 : if (last_char != idn_biditype_r_al) {
306 1 : *found = str - 1;
307 1 : return (idn_success);
308 : }
309 : }
310 :
311 549 : *found = NULL;
312 549 : return (idn_success);
313 : }
314 :
315 : idn_result_t
316 0 : idn_nameprep_createproc(const char *parameter, void **handlep) {
317 0 : return idn_nameprep_create(parameter, (idn_nameprep_t *)handlep);
318 : }
319 :
320 : void
321 0 : idn_nameprep_destroyproc(void *handle) {
322 0 : idn_nameprep_destroy((idn_nameprep_t)handle);
323 0 : }
324 :
325 : idn_result_t
326 0 : idn_nameprep_mapproc(void *handle, const PRUint32 *from,
327 : PRUint32 *to, size_t tolen) {
328 0 : return idn_nameprep_map((idn_nameprep_t)handle, from, to, tolen);
329 : }
330 :
331 : idn_result_t
332 0 : idn_nameprep_prohibitproc(void *handle, const PRUint32 *str,
333 : const PRUint32 **found) {
334 0 : return idn_nameprep_isprohibited((idn_nameprep_t)handle, str, found);
335 : }
336 :
337 : idn_result_t
338 0 : idn_nameprep_unassignedproc(void *handle, const PRUint32 *str,
339 : const PRUint32 **found) {
340 0 : return idn_nameprep_isunassigned((idn_nameprep_t)handle, str, found);
341 : }
342 :
343 : idn_result_t
344 0 : idn_nameprep_bidiproc(void *handle, const PRUint32 *str,
345 : const PRUint32 **found) {
346 0 : return idn_nameprep_isvalidbidi((idn_nameprep_t)handle, str, found);
347 : }
|