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