1 /* $NetBSD: util.c,v 1.4 2014/12/10 04:37:56 christos Exp $ */ 2 3 #ifndef lint 4 static char *rcsid = "Id: util.c,v 1.1 2003/06/04 00:27:08 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 <stdio.h> 53 #include <stddef.h> 54 #include <stdlib.h> 55 #include <stdarg.h> 56 #include <string.h> 57 #include <ctype.h> 58 #include <errno.h> 59 60 #include <idn/resconf.h> 61 #include <idn/converter.h> 62 #include <idn/res.h> 63 #include <idn/utf8.h> 64 65 #include "util.h" 66 #include "selectiveencode.h" 67 68 extern int line_number; 69 70 idn_result_t 71 selective_encode(idn_resconf_t conf, idn_action_t actions, 72 char *from, char *to, int tolen) 73 { 74 for (;;) { 75 int len; 76 char *region_start, *region_end; 77 idn_result_t r; 78 char save; 79 80 /* 81 * Find the region that needs conversion. 82 */ 83 r = idn_selectiveencode_findregion(from, ®ion_start, 84 ®ion_end); 85 if (r == idn_notfound) { 86 /* 87 * Not found. Just copy the whole thing. 88 */ 89 if (tolen <= strlen(from)) 90 return (idn_buffer_overflow); 91 (void)strcpy(to, from); 92 return (idn_success); 93 } else if (r != idn_success) { 94 /* This should not happen.. */ 95 errormsg("internal error at line %d: %s\n", 96 line_number, idn_result_tostring(r)); 97 return (r); 98 } 99 100 /* 101 * We have found a region to convert. 102 * First, copy the prefix part verbatim. 103 */ 104 len = region_start - from; 105 if (tolen < len) { 106 errormsg("internal buffer overflow at line %d\n", 107 line_number); 108 return (idn_buffer_overflow); 109 } 110 (void)memcpy(to, from, len); 111 to += len; 112 tolen -= len; 113 114 /* 115 * Terminate the region with NUL. 116 */ 117 save = *region_end; 118 *region_end = '\0'; 119 120 /* 121 * Encode the region. 122 */ 123 r = idn_res_encodename(conf, actions, region_start, to, tolen); 124 125 /* 126 * Restore character. 127 */ 128 *region_end = save; 129 130 if (r != idn_success) 131 return (r); 132 133 len = strlen(to); 134 to += len; 135 tolen -= len; 136 137 from = region_end; 138 } 139 } 140 141 idn_result_t 142 selective_decode(idn_resconf_t conf, idn_action_t actions, 143 char *from, char *to, int tolen) 144 { 145 char *domain_name; 146 char *ignored_chunk; 147 char save; 148 int len; 149 idn_result_t r; 150 151 /* 152 * While `*from' points to a character in a string which may be 153 * a domain name, `domain_name' refers to the beginning of the 154 * domain name. 155 */ 156 domain_name = NULL; 157 158 /* 159 * We ignore chunks matching to the regular expression: 160 * [\-\.][0-9A-Za-z\-\.]* 161 * 162 * While `*from' points to a character in such a chunk, 163 * `ignored_chunk' refers to the beginning of the chunk. 164 */ 165 ignored_chunk = NULL; 166 167 for (;;) { 168 if (*from == '-') { 169 /* 170 * We don't recognize `.-' as a part of domain name. 171 */ 172 if (domain_name != NULL) { 173 if (*(from - 1) == '.') { 174 ignored_chunk = domain_name; 175 domain_name = NULL; 176 } 177 } else if (ignored_chunk == NULL) { 178 ignored_chunk = from; 179 } 180 181 } else if (*from == '.') { 182 /* 183 * We don't recognize `-.' nor `..' as a part of 184 * domain name. 185 */ 186 if (domain_name != NULL) { 187 if (*(from - 1) == '-' || *(from - 1) == '.') { 188 ignored_chunk = domain_name; 189 domain_name = NULL; 190 } 191 } else if (ignored_chunk == NULL) { 192 ignored_chunk = from; 193 } 194 195 } else if (('a' <= *from && *from <= 'z') || 196 ('A' <= *from && *from <= 'Z') || 197 ('0' <= *from && *from <= '9')) { 198 if (ignored_chunk == NULL && domain_name == NULL) 199 domain_name = from; 200 201 } else { 202 if (ignored_chunk != NULL) { 203 /* 204 * `from' reaches the end of the ignored chunk. 205 * Copy the chunk to `to'. 206 */ 207 len = from - ignored_chunk; 208 if (tolen < len) 209 return (idn_buffer_overflow); 210 (void)memcpy(to, ignored_chunk, len); 211 to += len; 212 tolen -= len; 213 214 } else if (domain_name != NULL) { 215 /* 216 * `from' reaches the end of the domain name. 217 * Decode the domain name, and copy the result 218 * to `to'. 219 */ 220 save = *from; 221 *from = '\0'; 222 r = idn_res_decodename(conf, actions, 223 domain_name, to, tolen); 224 *from = save; 225 226 if (r == idn_success) { 227 len = strlen(to); 228 } else if (r == idn_invalid_encoding) { 229 len = from - domain_name; 230 if (tolen < len) 231 return (idn_buffer_overflow); 232 (void)memcpy(to, domain_name, len); 233 } else { 234 return (r); 235 } 236 to += len; 237 tolen -= len; 238 } 239 240 /* 241 * Copy a character `*from' to `to'. 242 */ 243 if (tolen < 1) 244 return (idn_buffer_overflow); 245 *to = *from; 246 to++; 247 tolen--; 248 249 domain_name = NULL; 250 ignored_chunk = NULL; 251 252 if (*from == '\0') 253 break; 254 } 255 256 from++; 257 } 258 259 return (idn_success); 260 } 261 262 void 263 set_defaults(idn_resconf_t conf) { 264 idn_result_t r; 265 266 if ((r = idn_resconf_setdefaults(conf)) != idn_success) { 267 errormsg("error setting default configuration: %s\n", 268 idn_result_tostring(r)); 269 exit(1); 270 } 271 } 272 273 void 274 load_conf_file(idn_resconf_t conf, const char *file) { 275 idn_result_t r; 276 277 if ((r = idn_resconf_loadfile(conf, file)) != idn_success) { 278 errormsg("error reading configuration file: %s\n", 279 idn_result_tostring(r)); 280 exit(1); 281 } 282 } 283 284 void 285 set_encoding_alias(const char *encoding_alias) { 286 idn_result_t r; 287 288 if ((r = idn_converter_resetalias()) != idn_success) { 289 errormsg("cannot reset alias information: %s\n", 290 idn_result_tostring(r)); 291 exit(1); 292 } 293 294 if ((r = idn_converter_aliasfile(encoding_alias)) != idn_success) { 295 errormsg("cannot read alias file %s: %s\n", 296 encoding_alias, idn_result_tostring(r)); 297 exit(1); 298 } 299 } 300 301 void 302 set_localcode(idn_resconf_t conf, const char *code) { 303 idn_result_t r; 304 305 r = idn_resconf_setlocalconvertername(conf, code, 306 IDN_CONVERTER_RTCHECK); 307 if (r != idn_success) { 308 errormsg("cannot create converter for codeset %s: %s\n", 309 code, idn_result_tostring(r)); 310 exit(1); 311 } 312 } 313 314 void 315 set_idncode(idn_resconf_t conf, const char *code) { 316 idn_result_t r; 317 318 r = idn_resconf_setidnconvertername(conf, code, 319 IDN_CONVERTER_RTCHECK); 320 if (r != idn_success) { 321 errormsg("cannot create converter for codeset %s: %s\n", 322 code, idn_result_tostring(r)); 323 exit(1); 324 } 325 } 326 327 void 328 set_delimitermapper(idn_resconf_t conf, unsigned long *delimiters, 329 int ndelimiters) { 330 idn_result_t r; 331 332 r = idn_resconf_addalldelimitermapucs(conf, delimiters, ndelimiters); 333 if (r != idn_success) { 334 errormsg("cannot add delimiter: %s\n", 335 idn_result_tostring(r)); 336 exit(1); 337 } 338 } 339 340 void 341 set_localmapper(idn_resconf_t conf, char **mappers, int nmappers) { 342 idn_result_t r; 343 344 /* Add mapping. */ 345 r = idn_resconf_addalllocalmapselectornames(conf, 346 IDN_MAPSELECTOR_DEFAULTTLD, 347 (const char **)mappers, 348 nmappers); 349 if (r != idn_success) { 350 errormsg("cannot add local map: %s\n", 351 idn_result_tostring(r)); 352 exit(1); 353 } 354 } 355 356 void 357 set_nameprep(idn_resconf_t conf, char *version) { 358 idn_result_t r; 359 360 r = idn_resconf_setnameprepversion(conf, version); 361 if (r != idn_success) { 362 errormsg("error setting nameprep %s: %s\n", 363 version, idn_result_tostring(r)); 364 exit(1); 365 } 366 } 367 368 void 369 set_mapper(idn_resconf_t conf, char **mappers, int nmappers) { 370 idn_result_t r; 371 372 /* Configure mapper. */ 373 r = idn_resconf_addallmappernames(conf, (const char **)mappers, 374 nmappers); 375 if (r != idn_success) { 376 errormsg("cannot add nameprep map: %s\n", 377 idn_result_tostring(r)); 378 exit(1); 379 } 380 } 381 382 void 383 set_normalizer(idn_resconf_t conf, char **normalizers, int nnormalizer) { 384 idn_result_t r; 385 386 r = idn_resconf_addallnormalizernames(conf, 387 (const char **)normalizers, 388 nnormalizer); 389 if (r != idn_success) { 390 errormsg("cannot add normalizer: %s\n", 391 idn_result_tostring(r)); 392 exit(1); 393 } 394 } 395 396 void 397 set_prohibit_checkers(idn_resconf_t conf, char **prohibits, int nprohibits) { 398 idn_result_t r; 399 400 r = idn_resconf_addallprohibitcheckernames(conf, 401 (const char **)prohibits, 402 nprohibits); 403 if (r != idn_success) { 404 errormsg("cannot add prohibit checker: %s\n", 405 idn_result_tostring(r)); 406 exit(1); 407 } 408 } 409 410 void 411 set_unassigned_checkers(idn_resconf_t conf, char **unassigns, int nunassigns) { 412 idn_result_t r; 413 414 r = idn_resconf_addallunassignedcheckernames(conf, 415 (const char **)unassigns, 416 nunassigns); 417 if (r != idn_success) { 418 errormsg("cannot add unassigned checker: %s\n", 419 idn_result_tostring(r)); 420 exit(1); 421 } 422 } 423 424 void 425 errormsg(const char *fmt, ...) { 426 va_list args; 427 428 va_start(args, fmt); 429 vfprintf(stderr, fmt, args); 430 va_end(args); 431 } 432 433 434 /* 435 * Dynamic Stirng Buffer Utility 436 */ 437 438 void 439 strbuf_init(idnconv_strbuf_t *buf) { 440 /* 441 * Initialize the given string buffer. 442 * Caller must allocate the structure (idnconv_strbuf_t) 443 * as an automatic variable or by malloc(). 444 */ 445 buf->str = buf->local_buf; 446 buf->str[0] = '\0'; 447 buf->size = sizeof(buf->local_buf); 448 } 449 450 void 451 strbuf_reset(idnconv_strbuf_t *buf) { 452 /* 453 * Reset the given string buffer. 454 * Free memory allocated by this utility, and 455 * re-initialize. 456 */ 457 if (buf->str != NULL && buf->str != buf->local_buf) { 458 free(buf->str); 459 } 460 strbuf_init(buf); 461 } 462 463 char * 464 strbuf_get(idnconv_strbuf_t *buf) { 465 /* 466 * Get the pointer of the buffer. 467 */ 468 return (buf->str); 469 } 470 471 size_t 472 strbuf_size(idnconv_strbuf_t *buf) { 473 /* 474 * Get the allocated size of the buffer. 475 */ 476 return (buf->size); 477 } 478 479 char * 480 strbuf_copy(idnconv_strbuf_t *buf, const char *str) { 481 /* 482 * Copy STR to BUF. 483 */ 484 size_t len = strlen(str); 485 486 if (strbuf_alloc(buf, len + 1) == NULL) 487 return (NULL); 488 strcpy(buf->str, str); 489 return (buf->str); 490 } 491 492 char * 493 strbuf_append(idnconv_strbuf_t *buf, const char *str) { 494 /* 495 * Append STR to the end of BUF. 496 */ 497 size_t len1 = strlen(buf->str); 498 size_t len2 = strlen(str); 499 char *p; 500 #define MARGIN 50 501 502 p = strbuf_alloc(buf, len1 + len2 + 1 + MARGIN); 503 if (p != NULL) 504 strcpy(buf->str + len1, str); 505 return (p); 506 } 507 508 char * 509 strbuf_alloc(idnconv_strbuf_t *buf, size_t size) { 510 /* 511 * Reallocate the buffer of BUF if needed 512 * so that BUF can hold SIZE bytes of data at least. 513 */ 514 char *p; 515 516 if (buf->size >= size) 517 return (buf->str); 518 if (buf->str == buf->local_buf) { 519 if ((p = malloc(size)) == NULL) 520 return (NULL); 521 memcpy(p, buf->local_buf, sizeof(buf->local_buf)); 522 } else { 523 if ((p = realloc(buf->str, size)) == NULL) 524 return (NULL); 525 } 526 buf->str = p; 527 buf->size = size; 528 return (buf->str); 529 } 530 531 char * 532 strbuf_double(idnconv_strbuf_t *buf) { 533 /* 534 * Double the size of the buffer of BUF. 535 */ 536 return (strbuf_alloc(buf, buf->size * 2)); 537 } 538 539 char * 540 strbuf_getline(idnconv_strbuf_t *buf, FILE *fp) { 541 /* 542 * Read a line from FP. 543 */ 544 char s[256]; 545 546 buf->str[0] = '\0'; 547 while (fgets(s, sizeof(s), fp) != NULL) { 548 if (strbuf_append(buf, s) == NULL) 549 return (NULL); 550 if (strlen(s) < sizeof(s) - 1 || s[sizeof(s) - 2] == '\n') 551 return (buf->str); 552 } 553 if (buf->str[0] != '\0') 554 return (buf->str); 555 return (NULL); 556 } 557