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
selective_encode(idn_resconf_t conf,idn_action_t actions,char * from,char * to,int tolen)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
selective_decode(idn_resconf_t conf,idn_action_t actions,char * from,char * to,int tolen)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
set_defaults(idn_resconf_t conf)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
load_conf_file(idn_resconf_t conf,const char * file)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
set_encoding_alias(const char * encoding_alias)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
set_localcode(idn_resconf_t conf,const char * code)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
set_idncode(idn_resconf_t conf,const char * code)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
set_delimitermapper(idn_resconf_t conf,unsigned long * delimiters,int ndelimiters)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
set_localmapper(idn_resconf_t conf,char ** mappers,int nmappers)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
set_nameprep(idn_resconf_t conf,char * version)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
set_mapper(idn_resconf_t conf,char ** mappers,int nmappers)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
set_normalizer(idn_resconf_t conf,char ** normalizers,int nnormalizer)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
set_prohibit_checkers(idn_resconf_t conf,char ** prohibits,int nprohibits)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
set_unassigned_checkers(idn_resconf_t conf,char ** unassigns,int nunassigns)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
errormsg(const char * fmt,...)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
strbuf_init(idnconv_strbuf_t * buf)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
strbuf_reset(idnconv_strbuf_t * buf)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 *
strbuf_get(idnconv_strbuf_t * buf)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
strbuf_size(idnconv_strbuf_t * buf)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 *
strbuf_copy(idnconv_strbuf_t * buf,const char * str)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 *
strbuf_append(idnconv_strbuf_t * buf,const char * str)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 *
strbuf_alloc(idnconv_strbuf_t * buf,size_t size)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 *
strbuf_double(idnconv_strbuf_t * buf)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 *
strbuf_getline(idnconv_strbuf_t * buf,FILE * fp)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