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