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