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, &region_start,
84 						   &region_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