1 /* $NetBSD: res.c,v 1.4 2014/12/10 04:37:55 christos Exp $ */ 2 3 #ifndef lint 4 static char *rcsid = "Id: res.c,v 1.1 2003/06/04 00:26:10 marka Exp "; 5 #endif 6 7 /* 8 * Copyright (c) 2000,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 <stddef.h> 53 #include <stdlib.h> 54 #include <string.h> 55 56 #include <idn/result.h> 57 #include <idn/assert.h> 58 #include <idn/logmacro.h> 59 #include <idn/converter.h> 60 #include <idn/normalizer.h> 61 #include <idn/checker.h> 62 #include <idn/mapper.h> 63 #include <idn/mapselector.h> 64 #include <idn/delimitermap.h> 65 #include <idn/resconf.h> 66 #include <idn/res.h> 67 #include <idn/util.h> 68 #include <idn/debug.h> 69 #include <idn/ucs4.h> 70 71 #ifndef IDN_UTF8_ENCODING_NAME 72 #define IDN_UTF8_ENCODING_NAME "UTF-8" /* by IANA */ 73 #endif 74 75 #ifndef WITHOUT_ICONV 76 #define ENCODE_MASK \ 77 (IDN_LOCALCONV | IDN_DELIMMAP | IDN_LOCALMAP | IDN_MAP | \ 78 IDN_NORMALIZE | IDN_PROHCHECK | IDN_UNASCHECK | IDN_BIDICHECK | \ 79 IDN_ASCCHECK | IDN_IDNCONV | IDN_LENCHECK | IDN_ENCODE_QUERY | \ 80 IDN_UNDOIFERR) 81 #define DECODE_MASK \ 82 (IDN_DELIMMAP | IDN_MAP | IDN_NORMALIZE | IDN_PROHCHECK | \ 83 IDN_UNASCHECK | IDN_BIDICHECK | IDN_IDNCONV | IDN_ASCCHECK | \ 84 IDN_RTCHECK | IDN_LOCALCONV | IDN_DECODE_QUERY) 85 #else 86 #define ENCODE_MASK \ 87 (IDN_DELIMMAP | IDN_LOCALMAP | IDN_MAP | IDN_NORMALIZE | \ 88 IDN_PROHCHECK | IDN_UNASCHECK | IDN_BIDICHECK | IDN_ASCCHECK | \ 89 IDN_IDNCONV | IDN_LENCHECK | IDN_ENCODE_QUERY | IDN_UNDOIFERR) 90 #define DECODE_MASK \ 91 (IDN_DELIMMAP | IDN_MAP | IDN_NORMALIZE | IDN_PROHCHECK | \ 92 IDN_UNASCHECK | IDN_BIDICHECK | IDN_IDNCONV | IDN_ASCCHECK | \ 93 IDN_RTCHECK | IDN_DECODE_QUERY) 94 #endif 95 96 #define MAX_LABEL_LENGTH 63 97 98 /* 99 * label to convert. 100 */ 101 typedef struct labellist * labellist_t; 102 struct labellist { 103 unsigned long *name; 104 size_t name_length; 105 unsigned long *undo_name; 106 labellist_t next; 107 labellist_t previous; 108 int dot_followed; 109 }; 110 111 typedef idn_result_t (*res_insnproc_t)(idn_resconf_t ctx, 112 labellist_t label); 113 114 static void idn_res_initialize(void); 115 static idn_result_t copy_verbatim(const char *from, char *to, 116 size_t tolen); 117 static idn_result_t labellist_create(const unsigned long *name, 118 labellist_t *labelp); 119 static void labellist_destroy(labellist_t label); 120 static idn_result_t labellist_setname(labellist_t label, 121 const unsigned long *name); 122 static const unsigned long * 123 labellist_getname(labellist_t label); 124 static const unsigned long * 125 labellist_gettldname(labellist_t label); 126 static idn_result_t labellist_getnamelist(labellist_t label, 127 unsigned long *name, 128 size_t label_length); 129 static void labellist_undo(labellist_t label); 130 static labellist_t labellist_tail(labellist_t label); 131 static labellist_t labellist_previous(labellist_t label); 132 133 #ifndef WITHOUT_ICONV 134 static idn_result_t label_localdecodecheck(idn_resconf_t ctx, 135 labellist_t label); 136 #endif 137 static idn_result_t label_idnencode_ace(idn_resconf_t ctx, 138 labellist_t label); 139 static idn_result_t label_idndecode(idn_resconf_t ctx, labellist_t label); 140 static idn_result_t label_localmap(idn_resconf_t ctx, labellist_t label); 141 static idn_result_t label_map(idn_resconf_t ctx, labellist_t label); 142 static idn_result_t label_normalize(idn_resconf_t ctx, labellist_t label); 143 static idn_result_t label_prohcheck(idn_resconf_t ctx, labellist_t label); 144 static idn_result_t label_unascheck(idn_resconf_t ctx, labellist_t label); 145 static idn_result_t label_bidicheck(idn_resconf_t ctx, labellist_t label); 146 static idn_result_t label_asccheck(idn_resconf_t ctx, labellist_t label); 147 static idn_result_t label_lencheck_ace(idn_resconf_t ctx, 148 labellist_t label); 149 static idn_result_t label_lencheck_nonace(idn_resconf_t ctx, 150 labellist_t label); 151 static idn_result_t label_rtcheck(idn_resconf_t ctx, idn_action_t actions, 152 labellist_t label, 153 const unsigned long *original_name); 154 155 static int initialized; 156 static int enabled; 157 158 void 159 idn_res_enable(int on_off) { 160 if (!initialized) { 161 idn_res_initialize(); 162 } 163 164 if (on_off == 0) { 165 enabled = 0; 166 } else { 167 enabled = 1; 168 } 169 } 170 171 static void 172 idn_res_initialize(void) { 173 if (!initialized) { 174 char *value = getenv("IDN_DISABLE"); 175 176 if (value == NULL) { 177 enabled = 1; 178 } else { 179 enabled = 0; 180 } 181 initialized = 1; 182 } 183 } 184 185 idn_result_t 186 idn_res_encodename(idn_resconf_t ctx, idn_action_t actions, const char *from, 187 char *to, size_t tolen) { 188 idn_converter_t local_converter = NULL; 189 idn_converter_t idn_converter = NULL; 190 idn_delimitermap_t delimiter_mapper; 191 idn_result_t r; 192 labellist_t labels = NULL, l; 193 unsigned long *buffer = NULL; 194 size_t buffer_length; 195 int from_is_root; 196 int idn_is_ace; 197 198 assert(ctx != NULL && from != NULL && to != NULL); 199 200 TRACE(("idn_res_encodename(actions=%s, from=\"%s\", tolen=%d)\n", 201 idn__res_actionstostring(actions), 202 idn__debug_xstring(from, 50), (int)tolen)); 203 204 if (actions & ~ENCODE_MASK) { 205 WARNING(("idn_res_encodename: invalid actions 0x%x\n", 206 actions)); 207 r = idn_invalid_action; 208 goto ret; 209 } 210 211 if (!initialized) 212 idn_res_initialize(); 213 if (!enabled || actions == 0) { 214 r = copy_verbatim(from, to, tolen); 215 goto ret; 216 } else if (tolen <= 0) { 217 r = idn_buffer_overflow; 218 goto ret; 219 } 220 221 if (actions & IDN_ENCODE_QUERY) { 222 #ifndef WITHOUT_ICONV 223 actions |= (IDN_LOCALCONV | IDN_DELIMMAP | IDN_LOCALMAP | \ 224 IDN_MAP | IDN_NORMALIZE | IDN_PROHCHECK | \ 225 IDN_BIDICHECK | IDN_IDNCONV | IDN_LENCHECK); 226 #else 227 actions |= (IDN_DELIMMAP | IDN_LOCALMAP | IDN_MAP | \ 228 IDN_NORMALIZE | IDN_PROHCHECK | IDN_BIDICHECK | \ 229 IDN_IDNCONV | IDN_LENCHECK); 230 #endif 231 } 232 233 /* 234 * Convert `from' to UCS4. 235 */ 236 local_converter = idn_resconf_getlocalconverter(ctx); 237 #ifndef WITHOUT_ICONV 238 if (local_converter == NULL) { 239 r = idn_invalid_name; 240 goto ret; 241 } 242 #endif 243 244 idn_converter = idn_resconf_getidnconverter(ctx); 245 if (idn_converter != NULL && 246 idn_converter_isasciicompatible(idn_converter)) 247 idn_is_ace = 1; 248 else 249 idn_is_ace = 0; 250 251 buffer_length = tolen * 2; 252 253 for (;;) { 254 void *new_buffer; 255 256 new_buffer = realloc(buffer, sizeof(*buffer) * buffer_length); 257 if (new_buffer == NULL) { 258 r = idn_nomemory; 259 goto ret; 260 } 261 buffer = (unsigned long *)new_buffer; 262 263 if (actions & IDN_LOCALCONV) { 264 r = idn_converter_convtoucs4(local_converter, from, 265 buffer, buffer_length); 266 } else { 267 r = idn_ucs4_utf8toucs4(from, buffer, buffer_length); 268 } 269 if (r == idn_success) 270 break; 271 else if (r != idn_buffer_overflow) 272 goto ret; 273 274 buffer_length *= 2; 275 } 276 277 if (*buffer == '\0') { 278 if (tolen <= 0) { 279 r = idn_buffer_overflow; 280 goto ret; 281 } 282 *to = '\0'; 283 r = idn_success; 284 goto ret; 285 } 286 287 /* 288 * Delimiter map. 289 */ 290 if (actions & IDN_DELIMMAP) { 291 TRACE(("res delimitermap(name=\"%s\")\n", 292 idn__debug_ucs4xstring(buffer, 50))); 293 294 delimiter_mapper = idn_resconf_getdelimitermap(ctx); 295 if (delimiter_mapper != NULL) { 296 r = idn_delimitermap_map(delimiter_mapper, buffer, 297 buffer, buffer_length); 298 idn_delimitermap_destroy(delimiter_mapper); 299 if (r != idn_success) 300 goto ret; 301 } 302 TRACE(("res delimitermap(): success (name=\"%s\")\n", 303 idn__debug_ucs4xstring(buffer, 50))); 304 } 305 306 from_is_root = (buffer[0] == '.' && buffer[1] == '\0'); 307 308 /* 309 * Split the name into a list of labels. 310 */ 311 r = labellist_create(buffer, &labels); 312 if (r != idn_success) 313 goto ret; 314 315 /* 316 * Perform conversions and tests. 317 */ 318 for (l = labellist_tail(labels); l != NULL; 319 l = labellist_previous(l)) { 320 321 if (!idn__util_ucs4isasciirange(labellist_getname(l))) { 322 if (actions & IDN_LOCALMAP) { 323 r = label_localmap(ctx, l); 324 if (r != idn_success) 325 goto ret; 326 } 327 } 328 329 if (!idn__util_ucs4isasciirange(labellist_getname(l))) { 330 if (actions & IDN_MAP) { 331 r = label_map(ctx, l); 332 if (r != idn_success) 333 goto ret; 334 } 335 if (actions & IDN_NORMALIZE) { 336 r = label_normalize(ctx, l); 337 if (r != idn_success) 338 goto ret; 339 } 340 if (actions & IDN_PROHCHECK) { 341 r = label_prohcheck(ctx, l); 342 if (r == idn_prohibited && 343 (actions & IDN_UNDOIFERR)) { 344 labellist_undo(l); 345 continue; 346 } else if (r != idn_success) { 347 goto ret; 348 } 349 } 350 if (actions & IDN_UNASCHECK) { 351 r = label_unascheck(ctx, l); 352 if (r == idn_prohibited && 353 (actions & IDN_UNDOIFERR)) { 354 labellist_undo(l); 355 continue; 356 } else if (r != idn_success) { 357 goto ret; 358 } 359 } 360 if (actions & IDN_BIDICHECK) { 361 r = label_bidicheck(ctx, l); 362 if (r == idn_prohibited && 363 (actions & IDN_UNDOIFERR)) { 364 labellist_undo(l); 365 continue; 366 } else if (r != idn_success) { 367 goto ret; 368 } 369 } 370 } 371 372 if (actions & IDN_ASCCHECK) { 373 r = label_asccheck(ctx, l); 374 if (r == idn_prohibited && (actions & IDN_UNDOIFERR)) { 375 labellist_undo(l); 376 continue; 377 } else if (r != idn_success) { 378 goto ret; 379 } 380 } 381 382 if (!idn__util_ucs4isasciirange(labellist_getname(l))) { 383 if ((actions & IDN_IDNCONV) && idn_is_ace) { 384 r = label_idnencode_ace(ctx, l); 385 if (r != idn_success) 386 goto ret; 387 } 388 } 389 390 if (!from_is_root && (actions & IDN_LENCHECK)) { 391 if (idn_is_ace) 392 r = label_lencheck_ace(ctx, l); 393 else 394 r = label_lencheck_nonace(ctx, l); 395 if (r == idn_invalid_length && 396 (actions & IDN_UNDOIFERR)) { 397 labellist_undo(l); 398 continue; 399 } else if (r != idn_success) { 400 goto ret; 401 } 402 } 403 } 404 405 /* 406 * Concat a list of labels to a name. 407 */ 408 for (;;) { 409 void *new_buffer; 410 411 new_buffer = realloc(buffer, sizeof(*buffer) * buffer_length); 412 if (new_buffer == NULL) { 413 r = idn_nomemory; 414 goto ret; 415 } 416 buffer = (unsigned long *)new_buffer; 417 418 r = labellist_getnamelist(labels, buffer, buffer_length); 419 if (r == idn_success) 420 break; 421 else if (r != idn_buffer_overflow) 422 goto ret; 423 424 buffer_length *= 2; 425 } 426 427 if ((actions & IDN_IDNCONV) && idn_converter != NULL && !idn_is_ace) { 428 r = idn_converter_convfromucs4(idn_converter, buffer, to, 429 tolen); 430 } else { 431 r = idn_ucs4_ucs4toutf8(buffer, to, tolen); 432 } 433 434 ret: 435 if (r == idn_success) { 436 TRACE(("idn_res_encodename(): success (to=\"%s\")\n", 437 idn__debug_xstring(to, 50))); 438 } else { 439 TRACE(("idn_res_encodename(): %s\n", idn_result_tostring(r))); 440 } 441 free(buffer); 442 if (local_converter != NULL) 443 idn_converter_destroy(local_converter); 444 if (idn_converter != NULL) 445 idn_converter_destroy(idn_converter); 446 if (labels != NULL) 447 labellist_destroy(labels); 448 return (r); 449 } 450 451 idn_result_t 452 idn_res_decodename(idn_resconf_t ctx, idn_action_t actions, const char *from, 453 char *to, size_t tolen) { 454 idn_converter_t local_converter = NULL; 455 idn_converter_t idn_converter = NULL; 456 idn_delimitermap_t delimiter_mapper; 457 idn_result_t r; 458 labellist_t labels = NULL, l; 459 unsigned long *buffer = NULL; 460 unsigned long *saved_name = NULL; 461 size_t buffer_length; 462 int idn_is_ace; 463 464 assert(ctx != NULL && from != NULL && to != NULL); 465 466 TRACE(("idn_res_decodename(actions=%s, from=\"%s\", tolen=%d)\n", 467 idn__res_actionstostring(actions), 468 idn__debug_xstring(from, 50), (int)tolen)); 469 470 if (actions & ~DECODE_MASK) { 471 WARNING(("idn_res_decodename: invalid actions 0x%x\n", 472 actions)); 473 r = idn_invalid_action; 474 goto ret; 475 } 476 477 if (!initialized) 478 idn_res_initialize(); 479 if (!enabled || actions == 0) { 480 r = copy_verbatim(from, to, tolen); 481 goto ret; 482 } else if (tolen <= 0) { 483 r = idn_buffer_overflow; 484 goto ret; 485 } 486 487 if (actions & IDN_DECODE_QUERY) { 488 #ifndef WITHOUT_ICONV 489 actions |= (IDN_DELIMMAP | IDN_MAP | IDN_NORMALIZE | \ 490 IDN_PROHCHECK | IDN_BIDICHECK | IDN_IDNCONV | \ 491 IDN_RTCHECK | IDN_LOCALCONV); 492 #else 493 actions |= (IDN_DELIMMAP | IDN_MAP | IDN_NORMALIZE | \ 494 IDN_PROHCHECK | IDN_BIDICHECK | IDN_IDNCONV | \ 495 IDN_RTCHECK); 496 #endif 497 } 498 499 /* 500 * Convert `from' to UCS4. 501 */ 502 local_converter = idn_resconf_getlocalconverter(ctx); 503 #ifndef WITHOUT_ICONV 504 if (local_converter == NULL) { 505 r = idn_invalid_name; 506 goto ret; 507 } 508 #endif 509 510 idn_converter = idn_resconf_getidnconverter(ctx); 511 if (idn_converter != NULL && 512 idn_converter_isasciicompatible(idn_converter)) 513 idn_is_ace = 1; 514 else 515 idn_is_ace = 0; 516 517 buffer_length = tolen * 2; 518 519 TRACE(("res idndecode(name=\"%s\")\n", idn__debug_xstring(from, 50))); 520 521 for (;;) { 522 void *new_buffer; 523 524 new_buffer = realloc(buffer, sizeof(*buffer) * buffer_length); 525 if (new_buffer == NULL) { 526 r = idn_nomemory; 527 goto ret; 528 } 529 buffer = (unsigned long *)new_buffer; 530 531 if ((actions & IDN_IDNCONV) && 532 idn_converter != NULL && !idn_is_ace) { 533 r = idn_converter_convtoucs4(idn_converter, from, 534 buffer, buffer_length); 535 } else { 536 r = idn_ucs4_utf8toucs4(from, buffer, buffer_length); 537 } 538 if (r == idn_success) 539 break; 540 else if (r != idn_buffer_overflow) 541 goto ret; 542 543 buffer_length *= 2; 544 } 545 546 if (*buffer == '\0') { 547 if (tolen <= 0) { 548 r = idn_buffer_overflow; 549 goto ret; 550 } 551 *to = '\0'; 552 r = idn_success; 553 goto ret; 554 } 555 556 /* 557 * Delimiter map. 558 */ 559 if (actions & IDN_DELIMMAP) { 560 TRACE(("res delimitermap(name=\"%s\")\n", 561 idn__debug_ucs4xstring(buffer, 50))); 562 563 delimiter_mapper = idn_resconf_getdelimitermap(ctx); 564 if (delimiter_mapper != NULL) { 565 r = idn_delimitermap_map(delimiter_mapper, buffer, 566 buffer, buffer_length); 567 idn_delimitermap_destroy(delimiter_mapper); 568 if (r != idn_success) 569 goto ret; 570 } 571 TRACE(("res delimitermap(): success (name=\"%s\")\n", 572 idn__debug_ucs4xstring(buffer, 50))); 573 } 574 575 /* 576 * Split the name into a list of labels. 577 */ 578 r = labellist_create(buffer, &labels); 579 if (r != idn_success) 580 goto ret; 581 582 /* 583 * Perform conversions and tests. 584 */ 585 for (l = labellist_tail(labels); l != NULL; 586 l = labellist_previous(l)) { 587 588 free(saved_name); 589 saved_name = NULL; 590 591 if (!idn__util_ucs4isasciirange(labellist_getname(l))) { 592 if (actions & IDN_MAP) { 593 r = label_map(ctx, l); 594 if (r != idn_success) 595 goto ret; 596 } 597 if (actions & IDN_NORMALIZE) { 598 r = label_normalize(ctx, l); 599 if (r != idn_success) 600 goto ret; 601 } 602 if (actions & IDN_PROHCHECK) { 603 r = label_prohcheck(ctx, l); 604 if (r == idn_prohibited) { 605 labellist_undo(l); 606 continue; 607 } else if (r != idn_success) { 608 goto ret; 609 } 610 } 611 if (actions & IDN_UNASCHECK) { 612 r = label_unascheck(ctx, l); 613 if (r == idn_prohibited) { 614 labellist_undo(l); 615 continue; 616 } else if (r != idn_success) { 617 goto ret; 618 } 619 } 620 if (actions & IDN_BIDICHECK) { 621 r = label_bidicheck(ctx, l); 622 if (r == idn_prohibited) { 623 labellist_undo(l); 624 continue; 625 } else if (r != idn_success) { 626 goto ret; 627 } 628 } 629 } 630 631 if ((actions & IDN_IDNCONV) && idn_is_ace) { 632 saved_name = idn_ucs4_strdup(labellist_getname(l)); 633 if (saved_name == NULL) { 634 r = idn_nomemory; 635 goto ret; 636 } 637 r = label_idndecode(ctx, l); 638 if (r == idn_invalid_encoding) { 639 labellist_undo(l); 640 continue; 641 } else if (r != idn_success) { 642 goto ret; 643 } 644 } 645 if ((actions & IDN_RTCHECK) && saved_name != NULL) { 646 r = label_rtcheck(ctx, actions, l, saved_name); 647 if (r == idn_invalid_encoding) { 648 labellist_undo(l); 649 continue; 650 } else if (r != idn_success) { 651 goto ret; 652 } 653 } 654 655 #ifndef WITHOUT_ICONV 656 if (actions & IDN_LOCALCONV) { 657 r = label_localdecodecheck(ctx, l); 658 if (r != idn_success) 659 goto ret; 660 } 661 #endif 662 } 663 664 /* 665 * Concat a list of labels to a name. 666 */ 667 for (;;) { 668 void *new_buffer; 669 670 new_buffer = realloc(buffer, sizeof(*buffer) * buffer_length); 671 if (new_buffer == NULL) { 672 r = idn_nomemory; 673 goto ret; 674 } 675 buffer = (unsigned long *)new_buffer; 676 677 r = labellist_getnamelist(labels, buffer, buffer_length); 678 if (r == idn_success) 679 break; 680 else if (r != idn_buffer_overflow) 681 goto ret; 682 683 buffer_length *= 2; 684 } 685 686 if (actions & IDN_LOCALCONV) { 687 r = idn_converter_convfromucs4(local_converter, buffer, to, 688 tolen); 689 } else { 690 r = idn_ucs4_ucs4toutf8(buffer, to, tolen); 691 } 692 693 ret: 694 if (r == idn_success) { 695 TRACE(("idn_res_decodename(): success (to=\"%s\")\n", 696 idn__debug_xstring(to, 50))); 697 } else { 698 TRACE(("idn_res_decodename(): %s\n", idn_result_tostring(r))); 699 } 700 free(saved_name); 701 free(buffer); 702 if (local_converter != NULL) 703 idn_converter_destroy(local_converter); 704 if (idn_converter != NULL) 705 idn_converter_destroy(idn_converter); 706 if (labels != NULL) 707 labellist_destroy(labels); 708 return (r); 709 } 710 711 idn_result_t 712 idn_res_decodename2(idn_resconf_t ctx, idn_action_t actions, const char *from, 713 char *to, size_t tolen, const char *auxencoding) { 714 #ifdef WITHOUT_ICONV 715 return idn_failure; 716 717 #else /* WITHOUT_ICONV */ 718 idn_result_t r; 719 idn_converter_t aux_converter = NULL; 720 unsigned long *buffer_ucs4 = NULL; 721 char *buffer_utf8 = NULL; 722 size_t buffer_length; 723 724 assert(ctx != NULL && from != NULL && to != NULL); 725 726 TRACE(("idn_res_decodename2(actions=%s, from=\"%s\", tolen=%d, " 727 "auxencoding=\"%s\")\n", 728 idn__res_actionstostring(actions), 729 idn__debug_xstring(from, 50), (int)tolen, 730 (auxencoding != NULL) ? auxencoding : "<null>")); 731 732 if (!initialized) 733 idn_res_initialize(); 734 if (!enabled || actions == 0) { 735 r = copy_verbatim(from, to, tolen); 736 goto ret; 737 } else if (tolen <= 0) { 738 r = idn_buffer_overflow; 739 goto ret; 740 } 741 742 if (auxencoding == NULL || 743 strcmp(auxencoding, IDN_UTF8_ENCODING_NAME) == 0 || 744 strcmp(auxencoding, "UTF-8") == 0) { 745 return idn_res_decodename(ctx, actions, from, to, tolen); 746 } 747 748 /* 749 * Convert `from' to UCS4. 750 */ 751 r = idn_resconf_setauxidnconvertername(ctx, auxencoding, 752 IDN_CONVERTER_DELAYEDOPEN); 753 if (r != idn_success) { 754 goto ret; 755 } 756 757 aux_converter = idn_resconf_getauxidnconverter(ctx); 758 if (aux_converter == NULL) { 759 r = idn_failure; 760 goto ret; 761 } 762 763 buffer_length = tolen * 2; 764 for (;;) { 765 void *new_buffer; 766 767 new_buffer = realloc(buffer_ucs4, 768 sizeof(*buffer_ucs4) * buffer_length); 769 if (new_buffer == NULL) { 770 r = idn_nomemory; 771 goto ret; 772 } 773 buffer_ucs4 = (unsigned long *)new_buffer; 774 775 r = idn_converter_convtoucs4(aux_converter, from, 776 buffer_ucs4, 777 buffer_length); 778 if (r == idn_success) 779 break; 780 else if (r != idn_buffer_overflow) 781 goto ret; 782 783 buffer_length *= 2; 784 } 785 786 if (*buffer_ucs4 == '\0') { 787 if (tolen <= 0) { 788 r = idn_buffer_overflow; 789 goto ret; 790 } 791 *to = '\0'; 792 r = idn_success; 793 goto ret; 794 } 795 796 /* 797 * Convert `buffer_ucs4' to UTF-8. 798 */ 799 buffer_length = tolen * 2; 800 for (;;) { 801 void *new_buffer; 802 803 new_buffer = realloc(buffer_utf8, 804 sizeof(*buffer_utf8) * buffer_length); 805 if (new_buffer == NULL) { 806 r = idn_nomemory; 807 goto ret; 808 } 809 buffer_utf8 = (char *)new_buffer; 810 r = idn_ucs4_ucs4toutf8(buffer_ucs4, buffer_utf8, 811 buffer_length); 812 813 if (r == idn_success) 814 break; 815 else if (r != idn_buffer_overflow) 816 goto ret; 817 818 buffer_length *= 2; 819 } 820 821 if (*buffer_utf8 == '\0') { 822 if (tolen <= 0) { 823 r = idn_buffer_overflow; 824 goto ret; 825 } 826 *to = '\0'; 827 r = idn_success; 828 goto ret; 829 } 830 831 r = idn_res_decodename(ctx, actions, buffer_utf8, to, tolen); 832 833 ret: 834 if (r == idn_success) { 835 TRACE(("idn_res_decodename2(): success (to=\"%s\")\n", 836 idn__debug_xstring(to, 50))); 837 } else { 838 TRACE(("idn_res_decodename2(): %s\n", idn_result_tostring(r))); 839 } 840 free(buffer_ucs4); 841 free(buffer_utf8); 842 if (aux_converter != NULL) 843 idn_converter_destroy(aux_converter); 844 845 return (r); 846 847 #endif /* WITHOUT_ICONV */ 848 } 849 850 static idn_result_t 851 copy_verbatim(const char *from, char *to, size_t tolen) { 852 size_t fromlen = strlen(from); 853 854 if (fromlen + 1 > tolen) 855 return (idn_buffer_overflow); 856 (void)memcpy(to, from, fromlen + 1); 857 return (idn_success); 858 } 859 860 static idn_result_t 861 labellist_create(const unsigned long *name, labellist_t *labelp) { 862 size_t length, malloc_length; 863 labellist_t head_label = NULL; 864 labellist_t tail_label = NULL; 865 labellist_t new_label = NULL; 866 const unsigned long *endp = NULL; 867 idn_result_t r; 868 869 while (*name != '\0') { 870 for (endp = name; *endp != '.' && *endp != '\0'; endp++) 871 ; /* nothing to be done */ 872 length = (endp - name) + 1; 873 malloc_length = length + 15; /* add 15 for margin */ 874 875 new_label = (labellist_t) 876 malloc(sizeof(struct labellist)); 877 if (new_label == NULL) { 878 r = idn_nomemory; 879 goto ret; 880 } 881 if (head_label == NULL) 882 head_label = new_label; 883 884 new_label->name = NULL; 885 new_label->undo_name = NULL; 886 new_label->name_length = malloc_length; 887 new_label->next = NULL; 888 new_label->previous = NULL; 889 new_label->dot_followed = (*endp == '.'); 890 891 new_label->name = (unsigned long *) 892 malloc(sizeof(long) * malloc_length); 893 if (new_label->name == NULL) { 894 r = idn_nomemory; 895 goto ret; 896 } 897 memcpy(new_label->name, name, sizeof(long) * length); 898 *(new_label->name + length - 1) = '\0'; 899 900 new_label->undo_name = (unsigned long *) 901 malloc(sizeof(long) * malloc_length); 902 if (new_label->undo_name == NULL) { 903 r = idn_nomemory; 904 goto ret; 905 } 906 memcpy(new_label->undo_name, name, sizeof(long) * length); 907 *(new_label->undo_name + length - 1) = '\0'; 908 909 if (tail_label != NULL) { 910 tail_label->next = new_label; 911 new_label->previous = tail_label; 912 } 913 tail_label = new_label; 914 915 if (*endp == '.') 916 name = endp + 1; 917 else 918 name = endp; 919 } 920 921 *labelp = head_label; 922 r = idn_success; 923 924 ret: 925 if (r != idn_success) { 926 if (new_label != NULL) { 927 free(new_label->name); 928 free(new_label->undo_name); 929 free(new_label); 930 } 931 if (head_label != NULL) 932 labellist_destroy(head_label); 933 } 934 return (r); 935 } 936 937 938 static void 939 labellist_destroy(labellist_t label) { 940 labellist_t l, l_next; 941 942 for (l = label; l != NULL; l = l_next) { 943 l_next = l->next; 944 free(l->name); 945 free(l->undo_name); 946 free(l); 947 } 948 } 949 950 static idn_result_t 951 labellist_setname(labellist_t label, const unsigned long *name) { 952 unsigned long *new_name; 953 size_t length, new_length; 954 955 length = idn_ucs4_strlen(name) + 1; 956 new_length = length + 15; /* add 15 for margin */ 957 958 if (label->name_length < new_length) { 959 new_name = (unsigned long *) 960 realloc(label->name, sizeof(long) * new_length); 961 if (new_name == NULL) 962 return (idn_nomemory); 963 label->name = new_name; 964 label->name_length = new_length; 965 } 966 memcpy(label->name, name, sizeof(long) * length); 967 968 return (idn_success); 969 } 970 971 static const unsigned long * 972 labellist_getname(labellist_t label) { 973 return (label->name); 974 } 975 976 static const unsigned long * 977 labellist_gettldname(labellist_t label) { 978 labellist_t l; 979 980 if (label->previous == NULL && label->next == NULL && 981 !label->dot_followed) 982 return (idn_mapselector_getnotld()); 983 984 for (l = label; l->next != NULL; l = l->next) 985 ; /* nothing to be done */ 986 987 return (l->name); 988 } 989 990 static idn_result_t 991 labellist_getnamelist(labellist_t label, unsigned long *name, 992 size_t name_length) { 993 static const unsigned long dot_string[] = {0x002e, 0x0000}; /* "." */ 994 size_t length; 995 labellist_t l; 996 997 for (l = label, length = 0; l != NULL; l = l->next) 998 length += idn_ucs4_strlen(l->name) + 1; /* name + `.' */ 999 length++; /* for NUL */ 1000 1001 if (name_length < length) 1002 return (idn_buffer_overflow); 1003 1004 *name = '\0'; 1005 for (l = label; l != NULL; l = l->next) { 1006 idn_ucs4_strcat(name, l->name); 1007 name += idn_ucs4_strlen(name); 1008 if (l->dot_followed) 1009 idn_ucs4_strcat(name, dot_string); 1010 } 1011 return (idn_success); 1012 } 1013 1014 static void 1015 labellist_undo(labellist_t label) { 1016 size_t length; 1017 1018 length = idn_ucs4_strlen(label->undo_name) + 1; 1019 memcpy(label->name, label->undo_name, sizeof(long) * length); 1020 } 1021 1022 static labellist_t 1023 labellist_tail(labellist_t label) { 1024 labellist_t l; 1025 1026 if (label == NULL) 1027 return (NULL); 1028 for (l = label; l->next != NULL; l = l->next) 1029 ; /* nothing to be done */ 1030 return (l); 1031 } 1032 1033 static labellist_t 1034 labellist_previous(labellist_t label) { 1035 return (label->previous); 1036 } 1037 1038 #ifndef WITHOUT_ICONV 1039 1040 static idn_result_t 1041 label_localdecodecheck(idn_resconf_t ctx, labellist_t label) { 1042 idn_converter_t local_converter = NULL; 1043 const unsigned long *from; 1044 char *to = NULL; 1045 size_t to_length; 1046 idn_result_t r; 1047 1048 from = labellist_getname(label); 1049 to_length = idn_ucs4_strlen(from) + 1 + 15; /* 15 for margin */ 1050 TRACE(("res ucs4tolocal_check(label=\"%s\")\n", 1051 idn__debug_ucs4xstring(from, 50))); 1052 1053 local_converter = idn_resconf_getlocalconverter(ctx); 1054 if (local_converter == NULL) { 1055 r = idn_success; 1056 goto ret; 1057 } 1058 1059 for (;;) { 1060 char *new_buffer; 1061 1062 new_buffer = (char *)realloc(to, to_length); 1063 if (new_buffer == NULL) { 1064 r = idn_nomemory; 1065 goto ret; 1066 } 1067 to = new_buffer; 1068 r = idn_converter_convfromucs4(local_converter, from, to, 1069 to_length); 1070 if (r == idn_success) 1071 break; 1072 else if (r == idn_nomapping) { 1073 r = label_idnencode_ace(ctx, label); 1074 if (r != idn_success) 1075 goto ret; 1076 break; 1077 } else if (r != idn_buffer_overflow) { 1078 goto ret; 1079 } 1080 to_length *= 2; 1081 } 1082 1083 r = idn_success; 1084 ret: 1085 TRACE(("res ucs4tolocal_check(): %s\n", idn_result_tostring(r))); 1086 if (local_converter != NULL) 1087 idn_converter_destroy(local_converter); 1088 free(to); 1089 return (r); 1090 } 1091 1092 #endif /* !WITHOUT_ICONV */ 1093 1094 static idn_result_t 1095 label_idndecode(idn_resconf_t ctx, labellist_t label) { 1096 idn_converter_t idn_converter = NULL; 1097 const unsigned long *from; 1098 char *ascii_from = NULL; 1099 unsigned long *to = NULL; 1100 size_t from_length, to_length; 1101 idn_result_t r; 1102 1103 from = labellist_getname(label); 1104 from_length = idn_ucs4_strlen(from) + 1; 1105 TRACE(("res idntoucs4(label=\"%s\")\n", 1106 idn__debug_ucs4xstring(from, 50))); 1107 1108 idn_converter = idn_resconf_getidnconverter(ctx); 1109 if (idn_converter == NULL) { 1110 r = idn_success; 1111 goto ret; 1112 } 1113 1114 for (;;) { 1115 char *new_buffer; 1116 1117 new_buffer = (char *) realloc(ascii_from, from_length); 1118 if (new_buffer == NULL) { 1119 r = idn_nomemory; 1120 goto ret; 1121 } 1122 ascii_from = new_buffer; 1123 r = idn_ucs4_ucs4toutf8(from, ascii_from, from_length); 1124 if (r == idn_success) 1125 break; 1126 else if (r != idn_buffer_overflow) 1127 goto ret; 1128 from_length *= 2; 1129 } 1130 1131 to = NULL; 1132 to_length = from_length; 1133 1134 for (;;) { 1135 unsigned long *new_buffer; 1136 1137 new_buffer = (unsigned long *) 1138 realloc(to, sizeof(long) * to_length); 1139 if (new_buffer == NULL) { 1140 r = idn_nomemory; 1141 goto ret; 1142 } 1143 to = new_buffer; 1144 r = idn_converter_convtoucs4(idn_converter, ascii_from, to, 1145 to_length); 1146 if (r == idn_success) 1147 break; 1148 else if (r != idn_buffer_overflow) 1149 goto ret; 1150 to_length *= 2; 1151 } 1152 1153 r = labellist_setname(label, to); 1154 ret: 1155 if (r == idn_success) { 1156 TRACE(("res idntoucs4(): success (label=\"%s\")\n", 1157 idn__debug_ucs4xstring(labellist_getname(label), 1158 50))); 1159 } else { 1160 TRACE(("res idntoucs4(): %s\n", idn_result_tostring(r))); 1161 } 1162 if (idn_converter != NULL) 1163 idn_converter_destroy(idn_converter); 1164 free(to); 1165 free(ascii_from); 1166 return (r); 1167 } 1168 1169 static idn_result_t 1170 label_idnencode_ace(idn_resconf_t ctx, labellist_t label) { 1171 idn_converter_t idn_converter = NULL; 1172 const unsigned long *from; 1173 char *ascii_to = NULL; 1174 unsigned long *to = NULL; 1175 size_t to_length; 1176 idn_result_t r; 1177 1178 from = labellist_getname(label); 1179 TRACE(("res ucs4toidn(label=\"%s\")\n", 1180 idn__debug_ucs4xstring(from, 50))); 1181 1182 idn_converter = idn_resconf_getidnconverter(ctx); 1183 if (idn_converter == NULL) { 1184 r = idn_success; 1185 goto ret; 1186 } 1187 1188 ascii_to = NULL; 1189 to_length = idn_ucs4_strlen(from) * 4 + 16; /* add mergin */ 1190 1191 for (;;) { 1192 char *new_buffer; 1193 1194 new_buffer = (char *) realloc(ascii_to, to_length); 1195 if (new_buffer == NULL) { 1196 r = idn_nomemory; 1197 goto ret; 1198 } 1199 ascii_to = new_buffer; 1200 r = idn_converter_convfromucs4(idn_converter, from, ascii_to, 1201 to_length); 1202 if (r == idn_success) 1203 break; 1204 else if (r != idn_buffer_overflow) 1205 goto ret; 1206 to_length *= 2; 1207 } 1208 1209 for (;;) { 1210 unsigned long *new_buffer; 1211 1212 new_buffer = (unsigned long *) 1213 realloc(to, sizeof(long) * to_length); 1214 if (new_buffer == NULL) { 1215 r = idn_nomemory; 1216 goto ret; 1217 } 1218 to = new_buffer; 1219 r = idn_ucs4_utf8toucs4(ascii_to, to, to_length); 1220 if (r == idn_success) 1221 break; 1222 else if (r != idn_buffer_overflow) 1223 goto ret; 1224 to_length *= 2; 1225 } 1226 1227 if (r != idn_success) 1228 goto ret; 1229 1230 r = labellist_setname(label, to); 1231 ret: 1232 if (r == idn_success) { 1233 TRACE(("res ucs4toidn(): success (label=\"%s\")\n", 1234 idn__debug_ucs4xstring(labellist_getname(label), 1235 50))); 1236 } else { 1237 TRACE(("res ucs4toidn(): %s\n", idn_result_tostring(r))); 1238 } 1239 if (idn_converter != NULL) 1240 idn_converter_destroy(idn_converter); 1241 free(to); 1242 free(ascii_to); 1243 return (r); 1244 } 1245 1246 static idn_result_t 1247 label_localmap(idn_resconf_t ctx, labellist_t label) { 1248 const unsigned long *from; 1249 const unsigned long *tld; 1250 unsigned long *to = NULL; 1251 size_t to_length; 1252 idn_mapselector_t local_mapper; 1253 idn_result_t r; 1254 1255 from = labellist_getname(label); 1256 tld = labellist_gettldname(label); 1257 TRACE(("res localmap(label=\"%s\", tld=\"%s\")\n", 1258 idn__debug_ucs4xstring(from, 50), 1259 idn__debug_ucs4xstring(tld, 50))); 1260 1261 local_mapper = idn_resconf_getlocalmapselector(ctx); 1262 if (local_mapper == NULL) { 1263 r = idn_success; 1264 goto ret; 1265 } 1266 1267 if (tld == from) 1268 tld = idn_mapselector_getdefaulttld(); 1269 to_length = idn_ucs4_strlen(from) + 1 + 15; /* 15 for margin */ 1270 1271 for (;;) { 1272 unsigned long *new_buffer; 1273 1274 new_buffer = (unsigned long *) 1275 realloc(to, sizeof(long) * to_length); 1276 if (new_buffer == NULL) { 1277 r = idn_nomemory; 1278 goto ret; 1279 } 1280 to = new_buffer; 1281 r = idn_mapselector_map2(local_mapper, from, tld, to, 1282 to_length); 1283 if (r == idn_success) 1284 break; 1285 else if (r != idn_buffer_overflow) 1286 goto ret; 1287 to_length *= 2; 1288 } 1289 1290 r = labellist_setname(label, to); 1291 ret: 1292 if (r == idn_success) { 1293 TRACE(("res localmap(): success (label=\"%s\")\n", 1294 idn__debug_ucs4xstring(labellist_getname(label), 1295 50))); 1296 } else { 1297 TRACE(("res localmap(): %s\n", idn_result_tostring(r))); 1298 } 1299 if (local_mapper != NULL) 1300 idn_mapselector_destroy(local_mapper); 1301 free(to); 1302 return (r); 1303 } 1304 1305 static idn_result_t 1306 label_map(idn_resconf_t ctx, labellist_t label) { 1307 const unsigned long *from; 1308 unsigned long *to = NULL; 1309 size_t to_length; 1310 idn_mapper_t mapper; 1311 idn_result_t r; 1312 1313 from = labellist_getname(label); 1314 TRACE(("res map(label=\"%s\")\n", idn__debug_ucs4xstring(from, 50))); 1315 1316 mapper = idn_resconf_getmapper(ctx); 1317 if (mapper == NULL) { 1318 r = idn_success; 1319 goto ret; 1320 } 1321 to_length = idn_ucs4_strlen(from) + 1 + 15; /* 15 for margin */ 1322 1323 for (;;) { 1324 unsigned long *new_buffer; 1325 1326 new_buffer = (unsigned long *) 1327 realloc(to, sizeof(long) * to_length); 1328 if (new_buffer == NULL) { 1329 r = idn_nomemory; 1330 goto ret; 1331 } 1332 to = new_buffer; 1333 r = idn_mapper_map(mapper, from, to, to_length); 1334 if (r == idn_success) 1335 break; 1336 else if (r != idn_buffer_overflow) 1337 goto ret; 1338 to_length *= 2; 1339 } 1340 1341 r = labellist_setname(label, to); 1342 ret: 1343 if (r == idn_success) { 1344 TRACE(("res map(): success (label=\"%s\")\n", 1345 idn__debug_ucs4xstring(labellist_getname(label), 1346 50))); 1347 } else { 1348 TRACE(("res map(): %s\n", idn_result_tostring(r))); 1349 } 1350 if (mapper != NULL) 1351 idn_mapper_destroy(mapper); 1352 free(to); 1353 return (r); 1354 } 1355 1356 static idn_result_t 1357 label_normalize(idn_resconf_t ctx, labellist_t label) { 1358 const unsigned long *from; 1359 unsigned long *to = NULL; 1360 size_t to_length; 1361 idn_normalizer_t normalizer; 1362 idn_result_t r; 1363 1364 from = labellist_getname(label); 1365 TRACE(("res normalzie(label=\"%s\")\n", 1366 idn__debug_ucs4xstring(from, 50))); 1367 1368 normalizer = idn_resconf_getnormalizer(ctx); 1369 if (normalizer == NULL) { 1370 r = idn_success; 1371 goto ret; 1372 } 1373 to_length = idn_ucs4_strlen(from) + 1 + 15; /* 15 for margin */ 1374 1375 for (;;) { 1376 unsigned long *new_buffer; 1377 1378 new_buffer = (unsigned long *) 1379 realloc(to, sizeof(long) * to_length); 1380 if (new_buffer == NULL) { 1381 r = idn_nomemory; 1382 goto ret; 1383 } 1384 to = new_buffer; 1385 r = idn_normalizer_normalize(normalizer, from, to, to_length); 1386 if (r == idn_success) 1387 break; 1388 else if (r != idn_buffer_overflow) 1389 goto ret; 1390 to_length *= 2; 1391 } 1392 1393 r = labellist_setname(label, to); 1394 ret: 1395 if (r == idn_success) { 1396 TRACE(("res normalize(): success (label=\"%s\")\n", 1397 idn__debug_ucs4xstring(labellist_getname(label), 1398 50))); 1399 } else { 1400 TRACE(("res normalize(): %s\n", idn_result_tostring(r))); 1401 } 1402 if (normalizer != NULL) 1403 idn_normalizer_destroy(normalizer); 1404 free(to); 1405 return (r); 1406 } 1407 1408 static idn_result_t 1409 label_prohcheck(idn_resconf_t ctx, labellist_t label) { 1410 const unsigned long *name, *found; 1411 idn_checker_t prohibit_checker; 1412 idn_result_t r; 1413 1414 name = labellist_getname(label); 1415 TRACE(("res prohcheck(label=\"%s\")\n", 1416 idn__debug_ucs4xstring(name, 50))); 1417 1418 prohibit_checker = idn_resconf_getprohibitchecker(ctx); 1419 if (prohibit_checker == NULL) { 1420 r = idn_success; 1421 goto ret; 1422 } 1423 1424 r = idn_checker_lookup(prohibit_checker, name, &found); 1425 idn_checker_destroy(prohibit_checker); 1426 if (r == idn_success && found != NULL) 1427 r = idn_prohibited; 1428 1429 ret: 1430 TRACE(("res prohcheck(): %s\n", idn_result_tostring(r))); 1431 return (r); 1432 } 1433 1434 static idn_result_t 1435 label_unascheck(idn_resconf_t ctx, labellist_t label) { 1436 const unsigned long *name, *found; 1437 idn_checker_t unassigned_checker; 1438 idn_result_t r; 1439 1440 name = labellist_getname(label); 1441 TRACE(("res unascheck(label=\"%s\")\n", 1442 idn__debug_ucs4xstring(name, 50))); 1443 1444 unassigned_checker = idn_resconf_getunassignedchecker(ctx); 1445 if (unassigned_checker == NULL) { 1446 r = idn_success; 1447 goto ret; 1448 } 1449 1450 r = idn_checker_lookup(unassigned_checker, name, &found); 1451 idn_checker_destroy(unassigned_checker); 1452 if (r == idn_success && found != NULL) 1453 r = idn_prohibited; 1454 1455 ret: 1456 TRACE(("res unascheck(): %s\n", idn_result_tostring(r))); 1457 return (r); 1458 } 1459 1460 static idn_result_t 1461 label_bidicheck(idn_resconf_t ctx, labellist_t label) { 1462 const unsigned long *name, *found; 1463 idn_checker_t bidi_checker; 1464 idn_result_t r; 1465 1466 name = labellist_getname(label); 1467 TRACE(("res bidicheck(label=\"%s\")\n", 1468 idn__debug_ucs4xstring(name, 50))); 1469 1470 bidi_checker = idn_resconf_getbidichecker(ctx); 1471 if (bidi_checker == NULL) { 1472 r = idn_success; 1473 goto ret; 1474 } 1475 1476 r = idn_checker_lookup(bidi_checker, name, &found); 1477 idn_checker_destroy(bidi_checker); 1478 if (r == idn_success && found != NULL) 1479 r = idn_prohibited; 1480 1481 ret: 1482 TRACE(("res bidicheck(): %s\n", idn_result_tostring(r))); 1483 return (r); 1484 } 1485 1486 static idn_result_t 1487 label_asccheck(idn_resconf_t ctx, labellist_t label) { 1488 const unsigned long *name, *n; 1489 idn_result_t r; 1490 1491 name = labellist_getname(label); 1492 TRACE(("res asccheck(label=\"%s\")\n", 1493 idn__debug_ucs4xstring(name, 50))); 1494 1495 if (*name == '-') { 1496 r = idn_prohibited; 1497 goto ret; 1498 } 1499 1500 for (n = name; *n != '\0'; n++) { 1501 if (*n <= '\177') { 1502 if ((*n < '0' || *n > '9') && 1503 (*n < 'A' || *n > 'Z') && 1504 (*n < 'a' || *n > 'z') && 1505 *n != '-') { 1506 r = idn_prohibited; 1507 goto ret; 1508 } 1509 } 1510 } 1511 1512 if (n > name && *(n - 1) == '-') { 1513 r = idn_prohibited; 1514 goto ret; 1515 } 1516 1517 r = idn_success; 1518 ret: 1519 TRACE(("res asccheck(): %s\n", idn_result_tostring(r))); 1520 return (r); 1521 } 1522 1523 static idn_result_t 1524 label_lencheck_ace(idn_resconf_t ctx, labellist_t label) { 1525 const unsigned long *name; 1526 size_t name_length; 1527 idn_result_t r; 1528 1529 name = labellist_getname(label); 1530 name_length = idn_ucs4_strlen(name); 1531 TRACE(("res lencheck(label=\"%s\")\n", 1532 idn__debug_ucs4xstring(name, 50))); 1533 1534 if (name_length == 0 || name_length > MAX_LABEL_LENGTH) { 1535 r = idn_invalid_length; 1536 goto ret; 1537 } 1538 1539 r = idn_success; 1540 ret: 1541 TRACE(("res lencheck(): %s\n", idn_result_tostring(r))); 1542 return (r); 1543 } 1544 1545 static idn_result_t 1546 label_lencheck_nonace(idn_resconf_t ctx, labellist_t label) { 1547 idn_converter_t idn_converter; 1548 const unsigned long *from; 1549 size_t to_length; 1550 idn_result_t r; 1551 char *buffer = NULL; 1552 size_t buffer_length; 1553 1554 from = labellist_getname(label); 1555 TRACE(("res lencheck(label=\"%s\")\n", 1556 idn__debug_ucs4xstring(from, 50))); 1557 1558 buffer_length = idn_ucs4_strlen(from) * 4 + 16; /* 16 for margin */ 1559 idn_converter = idn_resconf_getidnconverter(ctx); 1560 1561 for (;;) { 1562 void *new_buffer; 1563 1564 new_buffer = realloc(buffer, sizeof(*buffer) * buffer_length); 1565 if (new_buffer == NULL) { 1566 r = idn_nomemory; 1567 goto ret; 1568 } 1569 buffer = (char *)new_buffer; 1570 1571 if (idn_converter != NULL) { 1572 r = idn_converter_convfromucs4(idn_converter, from, 1573 buffer, buffer_length); 1574 } else { 1575 r = idn_ucs4_ucs4toutf8(from, buffer, buffer_length); 1576 } 1577 if (r == idn_success) 1578 break; 1579 else if (r != idn_buffer_overflow) 1580 goto ret; 1581 1582 buffer_length *= 2; 1583 } 1584 1585 to_length = strlen(buffer); 1586 if (to_length == 0 || to_length > MAX_LABEL_LENGTH) { 1587 r = idn_invalid_length; 1588 goto ret; 1589 } 1590 1591 r = idn_success; 1592 ret: 1593 TRACE(("res lencheck(): %s\n", idn_result_tostring(r))); 1594 if (idn_converter != NULL) 1595 idn_converter_destroy(idn_converter); 1596 free(buffer); 1597 return (r); 1598 } 1599 1600 static idn_result_t 1601 label_rtcheck(idn_resconf_t ctx, idn_action_t actions, labellist_t label, 1602 const unsigned long *original_name) { 1603 labellist_t rt_label = NULL; 1604 const unsigned long *rt_name; 1605 const unsigned long *cur_name; 1606 idn_result_t r; 1607 1608 cur_name = labellist_getname(label); 1609 TRACE(("res rtcheck(label=\"%s\", org_label=\"%s\")\n", 1610 idn__debug_ucs4xstring(cur_name, 50), 1611 idn__debug_ucs4xstring(original_name, 50))); 1612 1613 r = labellist_create(cur_name, &rt_label); 1614 if (r != idn_success) 1615 goto ret; 1616 if (rt_label == NULL) { 1617 if (*original_name == '\0') 1618 r = idn_success; 1619 else 1620 r = idn_invalid_encoding; 1621 goto ret; 1622 } 1623 1624 if (!idn__util_ucs4isasciirange(labellist_getname(rt_label))) { 1625 r = label_map(ctx, rt_label); 1626 if (r != idn_success) 1627 goto ret; 1628 r = label_normalize(ctx, rt_label); 1629 if (r != idn_success) 1630 goto ret; 1631 r = label_prohcheck(ctx, rt_label); 1632 if (r != idn_success) 1633 goto ret; 1634 if (actions & IDN_UNASCHECK) { 1635 r = label_unascheck(ctx, rt_label); 1636 if (r != idn_success) 1637 goto ret; 1638 } 1639 r = label_bidicheck(ctx, rt_label); 1640 if (r != idn_success) 1641 goto ret; 1642 } 1643 1644 if (actions & IDN_ASCCHECK) { 1645 r = label_asccheck(ctx, rt_label); 1646 if (r != idn_success) 1647 goto ret; 1648 } 1649 if (!idn__util_ucs4isasciirange(labellist_getname(rt_label))) { 1650 r = label_idnencode_ace(ctx, rt_label); 1651 if (r != idn_success) 1652 goto ret; 1653 } 1654 r = label_lencheck_ace(ctx, rt_label); 1655 if (r != idn_success) 1656 goto ret; 1657 rt_name = labellist_getname(rt_label); 1658 1659 if (idn_ucs4_strcasecmp(rt_name, original_name) != 0) { 1660 TRACE(("res rtcheck(): round trip failed, org =\"%s\", rt=\"%s\"\n", 1661 idn__debug_ucs4xstring(original_name, 50), 1662 idn__debug_ucs4xstring(rt_name, 50))); 1663 r = idn_invalid_encoding; 1664 goto ret; 1665 } 1666 1667 r = idn_success; 1668 ret: 1669 if (r != idn_nomemory && r != idn_success) 1670 r = idn_invalid_encoding; 1671 TRACE(("res rtcheck(): %s\n", idn_result_tostring(r))); 1672 if (rt_label != NULL) 1673 labellist_destroy(rt_label); 1674 return (r); 1675 } 1676 1677 const char * 1678 idn__res_actionstostring(idn_action_t actions) { 1679 static char buf[100]; 1680 1681 buf[0] = '\0'; 1682 1683 if (actions == IDN_ENCODE_QUERY) 1684 strcpy(buf, "encode-query"); 1685 else if (actions == IDN_DECODE_QUERY) 1686 strcpy(buf, "decode-query"); 1687 else if (actions == IDN_ENCODE_APP) 1688 strcpy(buf, "encode-app"); 1689 else if (actions == IDN_DECODE_APP) 1690 strcpy(buf, "decode-app"); 1691 else if (actions == IDN_ENCODE_STORED) 1692 strcpy(buf, "encode-stored"); 1693 else if (actions == IDN_DECODE_STORED) 1694 strcpy(buf, "decode-stored"); 1695 else { 1696 if (actions & IDN_LOCALCONV) 1697 strcat(buf, "|localconv"); 1698 if (actions & IDN_DELIMMAP) 1699 strcat(buf, "|delimmap"); 1700 if (actions & IDN_LOCALMAP) 1701 strcat(buf, "|localmap"); 1702 1703 if (actions & IDN_MAP) 1704 strcat(buf, "|map"); 1705 if (actions & IDN_NORMALIZE) 1706 strcat(buf, "|normalize"); 1707 if (actions & IDN_PROHCHECK) 1708 strcat(buf, "|prohcheck"); 1709 if (actions & IDN_UNASCHECK) 1710 strcat(buf, "|unascheck"); 1711 if (actions & IDN_BIDICHECK) 1712 strcat(buf, "|bidicheck"); 1713 1714 if (actions & IDN_IDNCONV) 1715 strcat(buf, "|idnconv"); 1716 if (actions & IDN_ASCCHECK) 1717 strcat(buf, "|asccheck"); 1718 if (actions & IDN_LENCHECK) 1719 strcat(buf, "|lencheck"); 1720 if (actions & IDN_RTCHECK) 1721 strcat(buf, "|rtcheck"); 1722 } 1723 1724 if (buf[0] == '|') 1725 return (buf + 1); 1726 else 1727 return (buf); 1728 } 1729