1/*	$NetBSD: util.c,v 1.2.6.1 2012/06/06 18:18:09 bouyer Exp $	*/
2
3#ifndef lint
4static 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
68extern int		line_number;
69
70idn_result_t
71selective_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
141idn_result_t
142selective_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
262void
263set_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
273void
274load_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
284void
285set_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
301void
302set_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
314void
315set_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
327void
328set_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
340void
341set_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
356void
357set_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
368void
369set_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
382void
383set_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
396void
397set_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
410void
411set_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
424void
425errormsg(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
438void
439strbuf_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
450void
451strbuf_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
463char *
464strbuf_get(idnconv_strbuf_t *buf) {
465	/*
466	 * Get the pointer of the buffer.
467	 */
468	return (buf->str);
469}
470
471size_t
472strbuf_size(idnconv_strbuf_t *buf) {
473	/*
474	 * Get the allocated size of the buffer.
475	 */
476	return (buf->size);
477}
478
479char *
480strbuf_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
492char *
493strbuf_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
508char *
509strbuf_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
531char *
532strbuf_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
539char *
540strbuf_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