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