1#ifndef lint 2static char *rcsid = "$Id: checker.c,v 1.1 2003/06/04 00:25:49 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 <stddef.h> 51#include <stdlib.h> 52#include <string.h> 53 54#include <idn/result.h> 55#include <idn/assert.h> 56#include <idn/logmacro.h> 57#include <idn/checker.h> 58#include <idn/strhash.h> 59#include <idn/debug.h> 60 61/* 62 * Type for checking scheme. 63 */ 64typedef struct { 65 char *prefix; 66 char *parameter; 67 idn_checker_createproc_t create; 68 idn_checker_destroyproc_t destroy; 69 idn_checker_lookupproc_t lookup; 70 void *context; 71} check_scheme_t; 72 73/* 74 * Standard checking schemes. 75 */ 76static const check_scheme_t rfc3491_prohibit_scheme = { 77 "prohibit#RFC3491", 78 "RFC3491", 79 idn_nameprep_createproc, 80 idn_nameprep_destroyproc, 81 idn_nameprep_prohibitproc, 82 NULL, 83}; 84 85static const check_scheme_t rfc3491_unasigned_scheme = { 86 "unassigned#RFC3491", 87 "RFC3491", 88 idn_nameprep_createproc, 89 idn_nameprep_destroyproc, 90 idn_nameprep_unassignedproc, 91 NULL, 92}; 93 94static const check_scheme_t rfc3491_bidi_scheme = { 95 "bidi#RFC3491", 96 "RFC3491", 97 idn_nameprep_createproc, 98 idn_nameprep_destroyproc, 99 idn_nameprep_bidiproc, 100 NULL, 101}; 102 103static const check_scheme_t filecheck_prohibit_scheme = { 104 "prohibit#fileset", 105 NULL, 106 idn__filechecker_createproc, 107 idn__filechecker_destroyproc, 108 idn__filechecker_lookupproc, 109 NULL, 110}; 111 112static const check_scheme_t filecheck_unassigned_scheme = { 113 "unassigned#fileset", 114 NULL, 115 idn__filechecker_createproc, 116 idn__filechecker_destroyproc, 117 idn__filechecker_lookupproc, 118 NULL, 119}; 120 121static const check_scheme_t *standard_check_schemes[] = { 122 &rfc3491_unasigned_scheme, 123 &rfc3491_prohibit_scheme, 124 &rfc3491_bidi_scheme, 125 &filecheck_prohibit_scheme, 126 &filecheck_unassigned_scheme, 127 NULL, 128}; 129 130/* 131 * Hash table for checking schemes. 132 */ 133static idn__strhash_t scheme_hash = NULL; 134 135/* 136 * Mapper object type. 137 */ 138struct idn_checker { 139 int nschemes; 140 int scheme_size; 141 check_scheme_t *schemes; 142 int reference_count; 143}; 144 145#define MAPPER_INITIAL_SCHEME_SIZE 1 146 147idn_result_t 148idn_checker_initialize(void) { 149 idn_result_t r; 150 check_scheme_t **scheme; 151 152 TRACE(("idn_checker_initialize()\n")); 153 154 if (scheme_hash != NULL) { 155 r = idn_success; /* already initialized */ 156 goto ret; 157 } 158 159 r = idn__strhash_create(&scheme_hash); 160 if (r != idn_success) { 161 goto ret; 162 } 163 164 for (scheme = (check_scheme_t **)standard_check_schemes; 165 *scheme != NULL; scheme++) { 166 r = idn__strhash_put(scheme_hash, (*scheme)->prefix, *scheme); 167 if (r != idn_success) 168 goto ret; 169 } 170 171 r = idn_success; 172ret: 173 if (r != idn_success) { 174 if (scheme_hash != NULL) { 175 idn__strhash_destroy(scheme_hash, NULL); 176 scheme_hash = NULL; 177 } 178 } 179 TRACE(("idn_checker_initialize(): %s\n", idn_result_tostring(r))); 180 return (r); 181} 182 183idn_result_t 184idn_checker_create(idn_checker_t *ctxp) { 185 idn_checker_t ctx = NULL; 186 idn_result_t r; 187 188 assert(scheme_hash != NULL); 189 assert(ctxp != NULL); 190 191 TRACE(("idn_checker_create()\n")); 192 193 ctx = (idn_checker_t) malloc(sizeof(struct idn_checker)); 194 if (ctx == NULL) { 195 r = idn_nomemory; 196 goto ret; 197 } 198 199 ctx->schemes = (check_scheme_t *) malloc(sizeof(check_scheme_t) 200 * MAPPER_INITIAL_SCHEME_SIZE); 201 if (ctx->schemes == NULL) { 202 r = idn_nomemory; 203 goto ret; 204 } 205 206 ctx->nschemes = 0; 207 ctx->scheme_size = MAPPER_INITIAL_SCHEME_SIZE; 208 ctx->reference_count = 1; 209 *ctxp = ctx; 210 r = idn_success; 211ret: 212 if (r != idn_success) { 213 if (ctx != NULL) 214 free(ctx->schemes); 215 free(ctx); 216 } 217 TRACE(("idn_checker_create(): %s\n", idn_result_tostring(r))); 218 return (r); 219} 220 221void 222idn_checker_destroy(idn_checker_t ctx) { 223 int i; 224 225 assert(scheme_hash != NULL); 226 assert(ctx != NULL); 227 228 TRACE(("idn_checker_destroy()\n")); 229 230 ctx->reference_count--; 231 if (ctx->reference_count <= 0) { 232 TRACE(("idn_checker_destroy(): the object is destroyed\n")); 233 for (i = 0; i < ctx->nschemes; i++) 234 ctx->schemes[i].destroy(ctx->schemes[i].context); 235 free(ctx->schemes); 236 free(ctx); 237 } else { 238 TRACE(("idn_checker_destroy(): " 239 "update reference count (%d->%d)\n", 240 ctx->reference_count + 1, ctx->reference_count)); 241 } 242} 243 244void 245idn_checker_incrref(idn_checker_t ctx) { 246 assert(ctx != NULL && scheme_hash != NULL); 247 248 TRACE(("idn_checker_incrref()\n")); 249 TRACE(("idn_checker_incrref: update reference count (%d->%d)\n", 250 ctx->reference_count, ctx->reference_count + 1)); 251 252 ctx->reference_count++; 253} 254 255idn_result_t 256idn_checker_add(idn_checker_t ctx, const char *scheme_name) { 257 idn_result_t r; 258 check_scheme_t *scheme; 259 const char *scheme_prefix; 260 const char *scheme_parameter; 261 void *scheme_context = NULL; 262 char *buffer = NULL; 263 264 assert(scheme_hash != NULL); 265 assert(ctx != NULL); 266 267 TRACE(("idn_checker_add(scheme_name=%s)\n", 268 idn__debug_xstring(scheme_name, 50))); 269 270 /* 271 * Split `scheme_name' into `scheme_prefix' and `scheme_parameter'. 272 */ 273 scheme_parameter = strchr(scheme_name, ':'); 274 if (scheme_parameter == NULL) { 275 scheme_prefix = scheme_name; 276 scheme_parameter = NULL; 277 } else { 278 ptrdiff_t scheme_prefixlen; 279 280 scheme_prefixlen = scheme_parameter - scheme_name; 281 buffer = (char *) malloc(scheme_prefixlen + 1); 282 if (buffer == NULL) { 283 r = idn_nomemory; 284 goto ret; 285 } 286 memcpy(buffer, scheme_name, scheme_prefixlen); 287 *(buffer + scheme_prefixlen) = '\0'; 288 scheme_prefix = buffer; 289 scheme_parameter++; 290 } 291 292 /* 293 * Find a scheme. 294 */ 295 if (idn__strhash_get(scheme_hash, scheme_prefix, (void **)&scheme) 296 != idn_success) { 297 ERROR(("idn_checker_add(): invalid scheme \"%-.30s\"\n", 298 scheme_name)); 299 r = idn_invalid_name; 300 goto ret; 301 } 302 if (scheme_parameter == NULL && scheme->parameter != NULL) 303 scheme_parameter = scheme->parameter; 304 305 /* 306 * Add the scheme. 307 */ 308 assert(ctx->nschemes <= ctx->scheme_size); 309 310 if (ctx->nschemes == ctx->scheme_size) { 311 check_scheme_t *new_schemes; 312 313 new_schemes = (check_scheme_t *) realloc(ctx->schemes, 314 sizeof(check_scheme_t) * ctx->scheme_size * 2); 315 if (new_schemes == NULL) { 316 r = idn_nomemory; 317 goto ret; 318 } 319 ctx->schemes = new_schemes; 320 ctx->scheme_size *= 2; 321 } 322 323 r = scheme->create(scheme_parameter, &scheme_context); 324 if (r != idn_success) 325 goto ret; 326 327 memcpy(ctx->schemes + ctx->nschemes, scheme, sizeof(check_scheme_t)); 328 ctx->schemes[ctx->nschemes].context = scheme_context; 329 ctx->nschemes++; 330 r = idn_success; 331 332ret: 333 free(buffer); 334 if (r != idn_success) 335 free(scheme_context); 336 TRACE(("idn_checker_add(): %s\n", idn_result_tostring(r))); 337 return (r); 338} 339 340idn_result_t 341idn_checker_addall(idn_checker_t ctx, const char **scheme_names, 342 int nschemes) { 343 idn_result_t r; 344 int i; 345 346 assert(scheme_hash != NULL); 347 assert(ctx != NULL && scheme_names != NULL); 348 349 TRACE(("idn_checker_addall(nschemes=%d)\n", nschemes)); 350 351 for (i = 0; i < nschemes; i++) { 352 r = idn_checker_add(ctx, (const char *)*scheme_names); 353 if (r != idn_success) 354 goto ret; 355 scheme_names++; 356 } 357 358 r = idn_success; 359ret: 360 TRACE(("idn_checker_addall(): %s\n", idn_result_tostring(r))); 361 return (r); 362} 363 364idn_result_t 365idn_checker_lookup(idn_checker_t ctx, const unsigned long *ucs4, 366 const unsigned long **found) { 367 idn_result_t r; 368 int i; 369 370 assert(scheme_hash != NULL); 371 assert(ctx != NULL && ucs4 != NULL && found != NULL); 372 373 TRACE(("idn_checker_lookup(ucs4=\"%s\")\n", 374 idn__debug_ucs4xstring(ucs4, 50))); 375 376 /* 377 * Lookup. 378 */ 379 *found = NULL; 380 381 for (i = 0; i < ctx->nschemes; i++) { 382 TRACE(("idn_checker_lookup(): lookup %s\n", 383 ctx->schemes[i].prefix)); 384 385 r = (ctx->schemes[i].lookup)(ctx->schemes[i].context, ucs4, 386 found); 387 if (r != idn_success) 388 goto ret; 389 if (*found != NULL) 390 break; 391 } 392 393 r = idn_success; 394ret: 395 if (*found == NULL) { 396 TRACE(("idn_checker_lookup(): %s (not found)\n", 397 idn_result_tostring(r))); 398 } else { 399 TRACE(("idn_checker_lookup(): %s (found \\x%04lx)\n", 400 idn_result_tostring(r), **found)); 401 } 402 return (r); 403} 404 405idn_result_t 406idn_checker_register(const char *prefix, 407 idn_checker_createproc_t create, 408 idn_checker_destroyproc_t destroy, 409 idn_checker_lookupproc_t lookup) { 410 idn_result_t r; 411 check_scheme_t *scheme = NULL; 412 413 assert(scheme_hash != NULL); 414 assert(prefix != NULL && create != NULL && destroy != NULL && 415 lookup != NULL); 416 417 TRACE(("idn_checker_register(prefix=%s)\n", prefix)); 418 419 scheme = (check_scheme_t *) malloc(sizeof(check_scheme_t)); 420 if (scheme == NULL) { 421 r = idn_nomemory; 422 goto ret; 423 } 424 425 scheme->prefix = (char *) malloc(strlen(prefix) + 1); 426 if (scheme->prefix == NULL) { 427 r = idn_nomemory; 428 goto ret; 429 } 430 431 strcpy(scheme->prefix, prefix); 432 scheme->parameter = NULL; 433 scheme->create = create; 434 scheme->destroy = destroy; 435 scheme->lookup = lookup; 436 437 r = idn__strhash_put(scheme_hash, prefix, scheme); 438ret: 439 if (r != idn_success) { 440 if (scheme != NULL) 441 free(scheme->prefix); 442 free(scheme); 443 } 444 TRACE(("idn_checker_register(): %s\n", idn_result_tostring(r))); 445 return (r); 446} 447