xref: /minix3/external/bsd/bind/dist/contrib/idn/idnkit-1.0-src/lib/mapper.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
1*00b67f09SDavid van Moolenbroek /*	$NetBSD: mapper.c,v 1.4 2014/12/10 04:37:55 christos Exp $	*/
2*00b67f09SDavid van Moolenbroek 
3*00b67f09SDavid van Moolenbroek #ifndef lint
4*00b67f09SDavid van Moolenbroek static char *rcsid = "Id: mapper.c,v 1.1 2003/06/04 00:25:55 marka Exp ";
5*00b67f09SDavid van Moolenbroek #endif
6*00b67f09SDavid van Moolenbroek 
7*00b67f09SDavid van Moolenbroek /*
8*00b67f09SDavid van Moolenbroek  * Copyright (c) 2001,2002 Japan Network Information Center.
9*00b67f09SDavid van Moolenbroek  * All rights reserved.
10*00b67f09SDavid van Moolenbroek  *
11*00b67f09SDavid van Moolenbroek  * By using this file, you agree to the terms and conditions set forth bellow.
12*00b67f09SDavid van Moolenbroek  *
13*00b67f09SDavid van Moolenbroek  * 			LICENSE TERMS AND CONDITIONS
14*00b67f09SDavid van Moolenbroek  *
15*00b67f09SDavid van Moolenbroek  * The following License Terms and Conditions apply, unless a different
16*00b67f09SDavid van Moolenbroek  * license is obtained from Japan Network Information Center ("JPNIC"),
17*00b67f09SDavid van Moolenbroek  * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda,
18*00b67f09SDavid van Moolenbroek  * Chiyoda-ku, Tokyo 101-0047, Japan.
19*00b67f09SDavid van Moolenbroek  *
20*00b67f09SDavid van Moolenbroek  * 1. Use, Modification and Redistribution (including distribution of any
21*00b67f09SDavid van Moolenbroek  *    modified or derived work) in source and/or binary forms is permitted
22*00b67f09SDavid van Moolenbroek  *    under this License Terms and Conditions.
23*00b67f09SDavid van Moolenbroek  *
24*00b67f09SDavid van Moolenbroek  * 2. Redistribution of source code must retain the copyright notices as they
25*00b67f09SDavid van Moolenbroek  *    appear in each source code file, this License Terms and Conditions.
26*00b67f09SDavid van Moolenbroek  *
27*00b67f09SDavid van Moolenbroek  * 3. Redistribution in binary form must reproduce the Copyright Notice,
28*00b67f09SDavid van Moolenbroek  *    this License Terms and Conditions, in the documentation and/or other
29*00b67f09SDavid van Moolenbroek  *    materials provided with the distribution.  For the purposes of binary
30*00b67f09SDavid van Moolenbroek  *    distribution the "Copyright Notice" refers to the following language:
31*00b67f09SDavid van Moolenbroek  *    "Copyright (c) 2000-2002 Japan Network Information Center.  All rights reserved."
32*00b67f09SDavid van Moolenbroek  *
33*00b67f09SDavid van Moolenbroek  * 4. The name of JPNIC may not be used to endorse or promote products
34*00b67f09SDavid van Moolenbroek  *    derived from this Software without specific prior written approval of
35*00b67f09SDavid van Moolenbroek  *    JPNIC.
36*00b67f09SDavid van Moolenbroek  *
37*00b67f09SDavid van Moolenbroek  * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC
38*00b67f09SDavid van Moolenbroek  *    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
39*00b67f09SDavid van Moolenbroek  *    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
40*00b67f09SDavid van Moolenbroek  *    PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL JPNIC BE LIABLE
41*00b67f09SDavid van Moolenbroek  *    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42*00b67f09SDavid van Moolenbroek  *    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
43*00b67f09SDavid van Moolenbroek  *    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
44*00b67f09SDavid van Moolenbroek  *    BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
45*00b67f09SDavid van Moolenbroek  *    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
46*00b67f09SDavid van Moolenbroek  *    OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
47*00b67f09SDavid van Moolenbroek  *    ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
48*00b67f09SDavid van Moolenbroek  */
49*00b67f09SDavid van Moolenbroek 
50*00b67f09SDavid van Moolenbroek #include <config.h>
51*00b67f09SDavid van Moolenbroek 
52*00b67f09SDavid van Moolenbroek #include <stddef.h>
53*00b67f09SDavid van Moolenbroek #include <stdlib.h>
54*00b67f09SDavid van Moolenbroek #include <string.h>
55*00b67f09SDavid van Moolenbroek 
56*00b67f09SDavid van Moolenbroek #include <idn/result.h>
57*00b67f09SDavid van Moolenbroek #include <idn/assert.h>
58*00b67f09SDavid van Moolenbroek #include <idn/logmacro.h>
59*00b67f09SDavid van Moolenbroek #include <idn/mapper.h>
60*00b67f09SDavid van Moolenbroek #include <idn/strhash.h>
61*00b67f09SDavid van Moolenbroek #include <idn/debug.h>
62*00b67f09SDavid van Moolenbroek #include <idn/util.h>
63*00b67f09SDavid van Moolenbroek #include <idn/ucs4.h>
64*00b67f09SDavid van Moolenbroek 
65*00b67f09SDavid van Moolenbroek /*
66*00b67f09SDavid van Moolenbroek  * Type for mapping scheme.
67*00b67f09SDavid van Moolenbroek  */
68*00b67f09SDavid van Moolenbroek typedef struct {
69*00b67f09SDavid van Moolenbroek 	char *prefix;
70*00b67f09SDavid van Moolenbroek 	char *parameter;
71*00b67f09SDavid van Moolenbroek 	idn_mapper_createproc_t create;
72*00b67f09SDavid van Moolenbroek 	idn_mapper_destroyproc_t destroy;
73*00b67f09SDavid van Moolenbroek 	idn_mapper_mapproc_t map;
74*00b67f09SDavid van Moolenbroek 	void *context;
75*00b67f09SDavid van Moolenbroek } map_scheme_t;
76*00b67f09SDavid van Moolenbroek 
77*00b67f09SDavid van Moolenbroek /*
78*00b67f09SDavid van Moolenbroek  * Standard mapping schemes.
79*00b67f09SDavid van Moolenbroek  */
80*00b67f09SDavid van Moolenbroek static const map_scheme_t nameprep_scheme = {
81*00b67f09SDavid van Moolenbroek 	"RFC3491",
82*00b67f09SDavid van Moolenbroek 	NULL,
83*00b67f09SDavid van Moolenbroek 	idn_nameprep_createproc,
84*00b67f09SDavid van Moolenbroek 	idn_nameprep_destroyproc,
85*00b67f09SDavid van Moolenbroek 	idn_nameprep_mapproc,
86*00b67f09SDavid van Moolenbroek 	NULL,
87*00b67f09SDavid van Moolenbroek };
88*00b67f09SDavid van Moolenbroek 
89*00b67f09SDavid van Moolenbroek static const map_scheme_t filemap_scheme = {
90*00b67f09SDavid van Moolenbroek 	"filemap",
91*00b67f09SDavid van Moolenbroek 	"",
92*00b67f09SDavid van Moolenbroek 	idn__filemapper_createproc,
93*00b67f09SDavid van Moolenbroek 	idn__filemapper_destroyproc,
94*00b67f09SDavid van Moolenbroek 	idn__filemapper_mapproc,
95*00b67f09SDavid van Moolenbroek 	NULL,
96*00b67f09SDavid van Moolenbroek };
97*00b67f09SDavid van Moolenbroek 
98*00b67f09SDavid van Moolenbroek static const map_scheme_t *standard_map_schemes[] = {
99*00b67f09SDavid van Moolenbroek 	&nameprep_scheme,
100*00b67f09SDavid van Moolenbroek 	&filemap_scheme,
101*00b67f09SDavid van Moolenbroek 	NULL,
102*00b67f09SDavid van Moolenbroek };
103*00b67f09SDavid van Moolenbroek 
104*00b67f09SDavid van Moolenbroek /*
105*00b67f09SDavid van Moolenbroek  * Hash table for mapping schemes.
106*00b67f09SDavid van Moolenbroek  */
107*00b67f09SDavid van Moolenbroek static idn__strhash_t scheme_hash = NULL;
108*00b67f09SDavid van Moolenbroek 
109*00b67f09SDavid van Moolenbroek /*
110*00b67f09SDavid van Moolenbroek  * Mapper object type.
111*00b67f09SDavid van Moolenbroek  */
112*00b67f09SDavid van Moolenbroek struct idn_mapper {
113*00b67f09SDavid van Moolenbroek 	int nschemes;
114*00b67f09SDavid van Moolenbroek 	int scheme_size;
115*00b67f09SDavid van Moolenbroek 	map_scheme_t *schemes;
116*00b67f09SDavid van Moolenbroek 	int reference_count;
117*00b67f09SDavid van Moolenbroek };
118*00b67f09SDavid van Moolenbroek 
119*00b67f09SDavid van Moolenbroek #define MAPPER_INITIAL_SCHEME_SIZE	1
120*00b67f09SDavid van Moolenbroek 
121*00b67f09SDavid van Moolenbroek idn_result_t
idn_mapper_initialize(void)122*00b67f09SDavid van Moolenbroek idn_mapper_initialize(void) {
123*00b67f09SDavid van Moolenbroek 	idn_result_t r;
124*00b67f09SDavid van Moolenbroek 	map_scheme_t **scheme;
125*00b67f09SDavid van Moolenbroek 
126*00b67f09SDavid van Moolenbroek 	TRACE(("idn_mapper_initialize()\n"));
127*00b67f09SDavid van Moolenbroek 
128*00b67f09SDavid van Moolenbroek 	if (scheme_hash != NULL) {
129*00b67f09SDavid van Moolenbroek 		r = idn_success;	/* already initialized */
130*00b67f09SDavid van Moolenbroek 		goto ret;
131*00b67f09SDavid van Moolenbroek 	}
132*00b67f09SDavid van Moolenbroek 
133*00b67f09SDavid van Moolenbroek 	r = idn__strhash_create(&scheme_hash);
134*00b67f09SDavid van Moolenbroek 	if (r != idn_success)
135*00b67f09SDavid van Moolenbroek 		goto ret;
136*00b67f09SDavid van Moolenbroek 
137*00b67f09SDavid van Moolenbroek 	for (scheme = (map_scheme_t **)standard_map_schemes;
138*00b67f09SDavid van Moolenbroek 		*scheme != NULL; scheme++) {
139*00b67f09SDavid van Moolenbroek 		r = idn__strhash_put(scheme_hash, (*scheme)->prefix, *scheme);
140*00b67f09SDavid van Moolenbroek 		if (r != idn_success)
141*00b67f09SDavid van Moolenbroek 			goto ret;
142*00b67f09SDavid van Moolenbroek 	}
143*00b67f09SDavid van Moolenbroek 
144*00b67f09SDavid van Moolenbroek 	r = idn_success;
145*00b67f09SDavid van Moolenbroek ret:
146*00b67f09SDavid van Moolenbroek 	if (r != idn_success && scheme_hash != NULL) {
147*00b67f09SDavid van Moolenbroek 		idn__strhash_destroy(scheme_hash, NULL);
148*00b67f09SDavid van Moolenbroek 		scheme_hash = NULL;
149*00b67f09SDavid van Moolenbroek 	}
150*00b67f09SDavid van Moolenbroek 	TRACE(("idn_mapper_initialize(): %s\n", idn_result_tostring(r)));
151*00b67f09SDavid van Moolenbroek 	return (r);
152*00b67f09SDavid van Moolenbroek }
153*00b67f09SDavid van Moolenbroek 
154*00b67f09SDavid van Moolenbroek idn_result_t
idn_mapper_create(idn_mapper_t * ctxp)155*00b67f09SDavid van Moolenbroek idn_mapper_create(idn_mapper_t *ctxp) {
156*00b67f09SDavid van Moolenbroek 	idn_mapper_t ctx = NULL;
157*00b67f09SDavid van Moolenbroek 	idn_result_t r;
158*00b67f09SDavid van Moolenbroek 
159*00b67f09SDavid van Moolenbroek 	assert(scheme_hash != NULL);
160*00b67f09SDavid van Moolenbroek 	assert(ctxp != NULL);
161*00b67f09SDavid van Moolenbroek 
162*00b67f09SDavid van Moolenbroek 	TRACE(("idn_mapper_create()\n"));
163*00b67f09SDavid van Moolenbroek 
164*00b67f09SDavid van Moolenbroek 	ctx = (idn_mapper_t) malloc(sizeof(struct idn_mapper));
165*00b67f09SDavid van Moolenbroek 	if (ctx == NULL) {
166*00b67f09SDavid van Moolenbroek 		r = idn_nomemory;
167*00b67f09SDavid van Moolenbroek 		goto ret;
168*00b67f09SDavid van Moolenbroek 	}
169*00b67f09SDavid van Moolenbroek 
170*00b67f09SDavid van Moolenbroek 	ctx->schemes = (map_scheme_t *) malloc(sizeof(map_scheme_t)
171*00b67f09SDavid van Moolenbroek 		 * MAPPER_INITIAL_SCHEME_SIZE);
172*00b67f09SDavid van Moolenbroek 	if (ctx->schemes == NULL) {
173*00b67f09SDavid van Moolenbroek 		r = idn_nomemory;
174*00b67f09SDavid van Moolenbroek 		goto ret;
175*00b67f09SDavid van Moolenbroek 	}
176*00b67f09SDavid van Moolenbroek 
177*00b67f09SDavid van Moolenbroek 	ctx->nschemes = 0;
178*00b67f09SDavid van Moolenbroek 	ctx->scheme_size = MAPPER_INITIAL_SCHEME_SIZE;
179*00b67f09SDavid van Moolenbroek 	ctx->reference_count = 1;
180*00b67f09SDavid van Moolenbroek 	*ctxp = ctx;
181*00b67f09SDavid van Moolenbroek 	r = idn_success;
182*00b67f09SDavid van Moolenbroek 
183*00b67f09SDavid van Moolenbroek ret:
184*00b67f09SDavid van Moolenbroek 	if (r != idn_success) {
185*00b67f09SDavid van Moolenbroek 		if (ctx != NULL)
186*00b67f09SDavid van Moolenbroek 			free(ctx->schemes);
187*00b67f09SDavid van Moolenbroek 		free(ctx);
188*00b67f09SDavid van Moolenbroek 	}
189*00b67f09SDavid van Moolenbroek 	TRACE(("idn_mapper_create(): %s\n", idn_result_tostring(r)));
190*00b67f09SDavid van Moolenbroek 	return (r);
191*00b67f09SDavid van Moolenbroek }
192*00b67f09SDavid van Moolenbroek 
193*00b67f09SDavid van Moolenbroek void
idn_mapper_destroy(idn_mapper_t ctx)194*00b67f09SDavid van Moolenbroek idn_mapper_destroy(idn_mapper_t ctx) {
195*00b67f09SDavid van Moolenbroek 	int i;
196*00b67f09SDavid van Moolenbroek 
197*00b67f09SDavid van Moolenbroek 	assert(scheme_hash != NULL);
198*00b67f09SDavid van Moolenbroek 	assert(ctx != NULL);
199*00b67f09SDavid van Moolenbroek 
200*00b67f09SDavid van Moolenbroek 	TRACE(("idn_mapper_destroy()\n"));
201*00b67f09SDavid van Moolenbroek 
202*00b67f09SDavid van Moolenbroek 	ctx->reference_count--;
203*00b67f09SDavid van Moolenbroek 	if (ctx->reference_count <= 0) {
204*00b67f09SDavid van Moolenbroek 		TRACE(("idn_mapper_destroy(): the object is destroyed\n"));
205*00b67f09SDavid van Moolenbroek 		for (i = 0; i < ctx->nschemes; i++)
206*00b67f09SDavid van Moolenbroek 			ctx->schemes[i].destroy(ctx->schemes[i].context);
207*00b67f09SDavid van Moolenbroek 		free(ctx->schemes);
208*00b67f09SDavid van Moolenbroek 		free(ctx);
209*00b67f09SDavid van Moolenbroek 	} else {
210*00b67f09SDavid van Moolenbroek 		TRACE(("idn_mapper_destroy(): "
211*00b67f09SDavid van Moolenbroek 		       "update reference count (%d->%d)\n",
212*00b67f09SDavid van Moolenbroek 		       ctx->reference_count + 1, ctx->reference_count));
213*00b67f09SDavid van Moolenbroek 	}
214*00b67f09SDavid van Moolenbroek }
215*00b67f09SDavid van Moolenbroek 
216*00b67f09SDavid van Moolenbroek void
idn_mapper_incrref(idn_mapper_t ctx)217*00b67f09SDavid van Moolenbroek idn_mapper_incrref(idn_mapper_t ctx) {
218*00b67f09SDavid van Moolenbroek 	assert(ctx != NULL && scheme_hash != NULL);
219*00b67f09SDavid van Moolenbroek 
220*00b67f09SDavid van Moolenbroek 	TRACE(("idn_mapper_incrref()\n"));
221*00b67f09SDavid van Moolenbroek 	TRACE(("idn_mapper_incrref: update reference count (%d->%d)\n",
222*00b67f09SDavid van Moolenbroek 		ctx->reference_count, ctx->reference_count + 1));
223*00b67f09SDavid van Moolenbroek 
224*00b67f09SDavid van Moolenbroek 	ctx->reference_count++;
225*00b67f09SDavid van Moolenbroek }
226*00b67f09SDavid van Moolenbroek 
227*00b67f09SDavid van Moolenbroek idn_result_t
idn_mapper_add(idn_mapper_t ctx,const char * scheme_name)228*00b67f09SDavid van Moolenbroek idn_mapper_add(idn_mapper_t ctx, const char *scheme_name) {
229*00b67f09SDavid van Moolenbroek 	idn_result_t r;
230*00b67f09SDavid van Moolenbroek 	map_scheme_t *scheme;
231*00b67f09SDavid van Moolenbroek 	const char *scheme_prefix;
232*00b67f09SDavid van Moolenbroek 	const char *scheme_parameter;
233*00b67f09SDavid van Moolenbroek 	void *scheme_context = NULL;
234*00b67f09SDavid van Moolenbroek 	char static_buffer[128];	/* large enough */
235*00b67f09SDavid van Moolenbroek 	char *buffer = static_buffer;
236*00b67f09SDavid van Moolenbroek 
237*00b67f09SDavid van Moolenbroek 	assert(scheme_hash != NULL);
238*00b67f09SDavid van Moolenbroek 	assert(ctx != NULL);
239*00b67f09SDavid van Moolenbroek 
240*00b67f09SDavid van Moolenbroek 	TRACE(("idn_mapper_add(scheme_name=%s)\n",
241*00b67f09SDavid van Moolenbroek 		idn__debug_xstring(scheme_name, 50)));
242*00b67f09SDavid van Moolenbroek 
243*00b67f09SDavid van Moolenbroek 	/*
244*00b67f09SDavid van Moolenbroek 	 * Split `scheme_name' into `scheme_prefix' and `scheme_parameter'.
245*00b67f09SDavid van Moolenbroek 	 */
246*00b67f09SDavid van Moolenbroek 	scheme_parameter = strchr(scheme_name, ':');
247*00b67f09SDavid van Moolenbroek 	if (scheme_parameter == NULL) {
248*00b67f09SDavid van Moolenbroek 		scheme_prefix = scheme_name;
249*00b67f09SDavid van Moolenbroek 	} else {
250*00b67f09SDavid van Moolenbroek 		ptrdiff_t scheme_prefixlen;
251*00b67f09SDavid van Moolenbroek 
252*00b67f09SDavid van Moolenbroek 		scheme_prefixlen = scheme_parameter - scheme_name;
253*00b67f09SDavid van Moolenbroek 		if (scheme_prefixlen + 1 > sizeof(static_buffer)) {
254*00b67f09SDavid van Moolenbroek 			buffer = (char *) malloc(scheme_prefixlen + 1);
255*00b67f09SDavid van Moolenbroek 			if (buffer == NULL) {
256*00b67f09SDavid van Moolenbroek 				r = idn_nomemory;
257*00b67f09SDavid van Moolenbroek 				goto ret;
258*00b67f09SDavid van Moolenbroek 			}
259*00b67f09SDavid van Moolenbroek 		}
260*00b67f09SDavid van Moolenbroek 		memcpy(buffer, scheme_name, scheme_prefixlen);
261*00b67f09SDavid van Moolenbroek 		*(buffer + scheme_prefixlen) = '\0';
262*00b67f09SDavid van Moolenbroek 		scheme_prefix = buffer;
263*00b67f09SDavid van Moolenbroek 		scheme_parameter++;
264*00b67f09SDavid van Moolenbroek 	}
265*00b67f09SDavid van Moolenbroek 
266*00b67f09SDavid van Moolenbroek 	/*
267*00b67f09SDavid van Moolenbroek 	 * Find a scheme.
268*00b67f09SDavid van Moolenbroek 	 */
269*00b67f09SDavid van Moolenbroek 	if (idn__strhash_get(scheme_hash, scheme_prefix, (void **)&scheme)
270*00b67f09SDavid van Moolenbroek 		!= idn_success) {
271*00b67f09SDavid van Moolenbroek 		ERROR(("idn_mapper_add(): invalid scheme name \"%-.30s\"\n",
272*00b67f09SDavid van Moolenbroek 		       scheme_prefix));
273*00b67f09SDavid van Moolenbroek 		r = idn_invalid_name;
274*00b67f09SDavid van Moolenbroek 		goto ret;
275*00b67f09SDavid van Moolenbroek 	}
276*00b67f09SDavid van Moolenbroek 	if (scheme_parameter == NULL) {
277*00b67f09SDavid van Moolenbroek 		if (scheme->parameter != NULL)
278*00b67f09SDavid van Moolenbroek 			scheme_parameter = scheme->parameter;
279*00b67f09SDavid van Moolenbroek 		else
280*00b67f09SDavid van Moolenbroek 			scheme_parameter = scheme->prefix;
281*00b67f09SDavid van Moolenbroek 	}
282*00b67f09SDavid van Moolenbroek 
283*00b67f09SDavid van Moolenbroek 	/*
284*00b67f09SDavid van Moolenbroek 	 * Add the scheme.
285*00b67f09SDavid van Moolenbroek 	 */
286*00b67f09SDavid van Moolenbroek 	assert(ctx->nschemes <= ctx->scheme_size);
287*00b67f09SDavid van Moolenbroek 
288*00b67f09SDavid van Moolenbroek 	if (ctx->nschemes == ctx->scheme_size) {
289*00b67f09SDavid van Moolenbroek 		map_scheme_t *new_schemes;
290*00b67f09SDavid van Moolenbroek 
291*00b67f09SDavid van Moolenbroek 		new_schemes = (map_scheme_t *) realloc(ctx->schemes,
292*00b67f09SDavid van Moolenbroek 			sizeof(map_scheme_t) * ctx->scheme_size * 2);
293*00b67f09SDavid van Moolenbroek 		if (new_schemes == NULL) {
294*00b67f09SDavid van Moolenbroek 			r = idn_nomemory;
295*00b67f09SDavid van Moolenbroek 			goto ret;
296*00b67f09SDavid van Moolenbroek 		}
297*00b67f09SDavid van Moolenbroek 		ctx->schemes = new_schemes;
298*00b67f09SDavid van Moolenbroek 		ctx->scheme_size *= 2;
299*00b67f09SDavid van Moolenbroek 	}
300*00b67f09SDavid van Moolenbroek 
301*00b67f09SDavid van Moolenbroek 	r = scheme->create(scheme_parameter, &scheme_context);
302*00b67f09SDavid van Moolenbroek 	if (r != idn_success)
303*00b67f09SDavid van Moolenbroek 		goto ret;
304*00b67f09SDavid van Moolenbroek 
305*00b67f09SDavid van Moolenbroek 	memcpy(ctx->schemes + ctx->nschemes, scheme, sizeof(map_scheme_t));
306*00b67f09SDavid van Moolenbroek 	ctx->schemes[ctx->nschemes].context = scheme_context;
307*00b67f09SDavid van Moolenbroek 	ctx->nschemes++;
308*00b67f09SDavid van Moolenbroek 	r = idn_success;
309*00b67f09SDavid van Moolenbroek ret:
310*00b67f09SDavid van Moolenbroek 	if (r != idn_success)
311*00b67f09SDavid van Moolenbroek 		free(scheme_context);
312*00b67f09SDavid van Moolenbroek 	if (buffer != static_buffer)
313*00b67f09SDavid van Moolenbroek 		free(buffer);
314*00b67f09SDavid van Moolenbroek 	TRACE(("idn_mapper_add(): %s\n", idn_result_tostring(r)));
315*00b67f09SDavid van Moolenbroek 	return (r);
316*00b67f09SDavid van Moolenbroek }
317*00b67f09SDavid van Moolenbroek 
318*00b67f09SDavid van Moolenbroek idn_result_t
idn_mapper_addall(idn_mapper_t ctx,const char ** scheme_names,int nschemes)319*00b67f09SDavid van Moolenbroek idn_mapper_addall(idn_mapper_t ctx, const char **scheme_names, int nschemes) {
320*00b67f09SDavid van Moolenbroek 	idn_result_t r;
321*00b67f09SDavid van Moolenbroek 	int i;
322*00b67f09SDavid van Moolenbroek 
323*00b67f09SDavid van Moolenbroek 	assert(scheme_hash != NULL);
324*00b67f09SDavid van Moolenbroek 	assert(ctx != NULL && scheme_names != NULL);
325*00b67f09SDavid van Moolenbroek 
326*00b67f09SDavid van Moolenbroek 	TRACE(("idn_mapper_addall(nschemes=%d)\n", nschemes));
327*00b67f09SDavid van Moolenbroek 
328*00b67f09SDavid van Moolenbroek 	for (i = 0; i < nschemes; i++) {
329*00b67f09SDavid van Moolenbroek 		r = idn_mapper_add(ctx, (const char *)*scheme_names);
330*00b67f09SDavid van Moolenbroek 		if (r != idn_success)
331*00b67f09SDavid van Moolenbroek 			goto ret;
332*00b67f09SDavid van Moolenbroek 		scheme_names++;
333*00b67f09SDavid van Moolenbroek 	}
334*00b67f09SDavid van Moolenbroek 
335*00b67f09SDavid van Moolenbroek 	r = idn_success;
336*00b67f09SDavid van Moolenbroek ret:
337*00b67f09SDavid van Moolenbroek 	TRACE(("idn_mapper_addall(): %s\n", idn_result_tostring(r)));
338*00b67f09SDavid van Moolenbroek 	return (r);
339*00b67f09SDavid van Moolenbroek }
340*00b67f09SDavid van Moolenbroek 
341*00b67f09SDavid van Moolenbroek idn_result_t
idn_mapper_map(idn_mapper_t ctx,const unsigned long * from,unsigned long * to,size_t tolen)342*00b67f09SDavid van Moolenbroek idn_mapper_map(idn_mapper_t ctx, const unsigned long *from,
343*00b67f09SDavid van Moolenbroek 	       unsigned long *to, size_t tolen) {
344*00b67f09SDavid van Moolenbroek 	idn_result_t r;
345*00b67f09SDavid van Moolenbroek 	unsigned long *src, *dst;
346*00b67f09SDavid van Moolenbroek 	unsigned long *buffers[2] = {NULL, NULL};
347*00b67f09SDavid van Moolenbroek 	size_t buflen[2] = {0, 0};
348*00b67f09SDavid van Moolenbroek 	size_t dstlen;
349*00b67f09SDavid van Moolenbroek 	int idx;
350*00b67f09SDavid van Moolenbroek 	int i;
351*00b67f09SDavid van Moolenbroek 
352*00b67f09SDavid van Moolenbroek 	assert(scheme_hash != NULL);
353*00b67f09SDavid van Moolenbroek 	assert(ctx != NULL && from != NULL && to != NULL);
354*00b67f09SDavid van Moolenbroek 
355*00b67f09SDavid van Moolenbroek 	TRACE(("idn_mapper_map(from=\"%s\", tolen=%d)\n",
356*00b67f09SDavid van Moolenbroek 	       idn__debug_ucs4xstring(from, 50), (int)tolen));
357*00b67f09SDavid van Moolenbroek 
358*00b67f09SDavid van Moolenbroek 	if (ctx->nschemes <= 0) {
359*00b67f09SDavid van Moolenbroek 		if (tolen < idn_ucs4_strlen(from) + 1) {
360*00b67f09SDavid van Moolenbroek 			r = idn_buffer_overflow;
361*00b67f09SDavid van Moolenbroek 			goto ret;
362*00b67f09SDavid van Moolenbroek 		}
363*00b67f09SDavid van Moolenbroek 		idn_ucs4_strcpy(to, from);
364*00b67f09SDavid van Moolenbroek 		r = idn_success;
365*00b67f09SDavid van Moolenbroek 		goto ret;
366*00b67f09SDavid van Moolenbroek 	}
367*00b67f09SDavid van Moolenbroek 
368*00b67f09SDavid van Moolenbroek 	/*
369*00b67f09SDavid van Moolenbroek 	 * Map.
370*00b67f09SDavid van Moolenbroek 	 */
371*00b67f09SDavid van Moolenbroek 	src = (void *)from;
372*00b67f09SDavid van Moolenbroek 	dstlen = idn_ucs4_strlen(from) + 1;
373*00b67f09SDavid van Moolenbroek 
374*00b67f09SDavid van Moolenbroek 	i = 0;
375*00b67f09SDavid van Moolenbroek 	while (i < ctx->nschemes) {
376*00b67f09SDavid van Moolenbroek 		TRACE(("idn_mapper_map(): map %s\n", ctx->schemes[i].prefix));
377*00b67f09SDavid van Moolenbroek 
378*00b67f09SDavid van Moolenbroek 		/*
379*00b67f09SDavid van Moolenbroek 		 * Choose destination area to restore the result of a mapping.
380*00b67f09SDavid van Moolenbroek 		 */
381*00b67f09SDavid van Moolenbroek 		if (i + 1 == ctx->nschemes) {
382*00b67f09SDavid van Moolenbroek 			dst = to;
383*00b67f09SDavid van Moolenbroek 			dstlen = tolen;
384*00b67f09SDavid van Moolenbroek 
385*00b67f09SDavid van Moolenbroek 		} else {
386*00b67f09SDavid van Moolenbroek 			if (src == buffers[0])
387*00b67f09SDavid van Moolenbroek 				idx = 1;
388*00b67f09SDavid van Moolenbroek 			else
389*00b67f09SDavid van Moolenbroek 				idx = 0;
390*00b67f09SDavid van Moolenbroek 
391*00b67f09SDavid van Moolenbroek 			if (buflen[idx] < dstlen) {
392*00b67f09SDavid van Moolenbroek 				void *newbuf;
393*00b67f09SDavid van Moolenbroek 
394*00b67f09SDavid van Moolenbroek 				newbuf = realloc(buffers[idx],
395*00b67f09SDavid van Moolenbroek 						 sizeof(long) * dstlen);
396*00b67f09SDavid van Moolenbroek 				if (newbuf == NULL) {
397*00b67f09SDavid van Moolenbroek 					r = idn_nomemory;
398*00b67f09SDavid van Moolenbroek 					goto ret;
399*00b67f09SDavid van Moolenbroek 				}
400*00b67f09SDavid van Moolenbroek 				buffers[idx] = (unsigned long *)newbuf;
401*00b67f09SDavid van Moolenbroek 				buflen[idx] = dstlen;
402*00b67f09SDavid van Moolenbroek 			}
403*00b67f09SDavid van Moolenbroek 
404*00b67f09SDavid van Moolenbroek 			dst = buffers[idx];
405*00b67f09SDavid van Moolenbroek 			dstlen = buflen[idx];
406*00b67f09SDavid van Moolenbroek 		}
407*00b67f09SDavid van Moolenbroek 
408*00b67f09SDavid van Moolenbroek 		/*
409*00b67f09SDavid van Moolenbroek 		 * Perform i-th map scheme.
410*00b67f09SDavid van Moolenbroek 		 * If buffer size is not enough, we double it and try again.
411*00b67f09SDavid van Moolenbroek 		 */
412*00b67f09SDavid van Moolenbroek 		r = (ctx->schemes[i].map)(ctx->schemes[i].context, src, dst,
413*00b67f09SDavid van Moolenbroek 					  dstlen);
414*00b67f09SDavid van Moolenbroek 		if (r == idn_buffer_overflow && dst != to) {
415*00b67f09SDavid van Moolenbroek 			dstlen *= 2;
416*00b67f09SDavid van Moolenbroek 			continue;
417*00b67f09SDavid van Moolenbroek 		}
418*00b67f09SDavid van Moolenbroek 		if (r != idn_success)
419*00b67f09SDavid van Moolenbroek 			goto ret;
420*00b67f09SDavid van Moolenbroek 
421*00b67f09SDavid van Moolenbroek 		src = dst;
422*00b67f09SDavid van Moolenbroek 		i++;
423*00b67f09SDavid van Moolenbroek 	}
424*00b67f09SDavid van Moolenbroek 
425*00b67f09SDavid van Moolenbroek 	r = idn_success;
426*00b67f09SDavid van Moolenbroek ret:
427*00b67f09SDavid van Moolenbroek 	free(buffers[0]);
428*00b67f09SDavid van Moolenbroek 	free(buffers[1]);
429*00b67f09SDavid van Moolenbroek 	if (r == idn_success) {
430*00b67f09SDavid van Moolenbroek 		TRACE(("idn_mapper_map(): success (to=\"%s\")\n",
431*00b67f09SDavid van Moolenbroek 		       idn__debug_ucs4xstring(to, 50)));
432*00b67f09SDavid van Moolenbroek 	} else {
433*00b67f09SDavid van Moolenbroek 		TRACE(("idn_mapper_map(): %s\n", idn_result_tostring(r)));
434*00b67f09SDavid van Moolenbroek 	}
435*00b67f09SDavid van Moolenbroek 	return (r);
436*00b67f09SDavid van Moolenbroek }
437*00b67f09SDavid van Moolenbroek 
438*00b67f09SDavid van Moolenbroek idn_result_t
idn_mapper_register(const char * prefix,idn_mapper_createproc_t create,idn_mapper_destroyproc_t destroy,idn_mapper_mapproc_t map)439*00b67f09SDavid van Moolenbroek idn_mapper_register(const char *prefix,
440*00b67f09SDavid van Moolenbroek 		    idn_mapper_createproc_t create,
441*00b67f09SDavid van Moolenbroek 		    idn_mapper_destroyproc_t destroy,
442*00b67f09SDavid van Moolenbroek 		    idn_mapper_mapproc_t map) {
443*00b67f09SDavid van Moolenbroek 	idn_result_t r;
444*00b67f09SDavid van Moolenbroek 	map_scheme_t *scheme = NULL;
445*00b67f09SDavid van Moolenbroek 
446*00b67f09SDavid van Moolenbroek 	assert(scheme_hash != NULL);
447*00b67f09SDavid van Moolenbroek 	assert(prefix != NULL && create != NULL && destroy != NULL &&
448*00b67f09SDavid van Moolenbroek 		map != NULL);
449*00b67f09SDavid van Moolenbroek 
450*00b67f09SDavid van Moolenbroek 	TRACE(("idn_mapper_register(prefix=%s)\n", prefix));
451*00b67f09SDavid van Moolenbroek 
452*00b67f09SDavid van Moolenbroek 	scheme = (map_scheme_t *) malloc(sizeof(map_scheme_t));
453*00b67f09SDavid van Moolenbroek 	if (scheme == NULL) {
454*00b67f09SDavid van Moolenbroek 		r = idn_nomemory;
455*00b67f09SDavid van Moolenbroek 		goto ret;
456*00b67f09SDavid van Moolenbroek 	}
457*00b67f09SDavid van Moolenbroek 
458*00b67f09SDavid van Moolenbroek 	scheme->prefix = (char *) malloc(strlen(prefix) + 1);
459*00b67f09SDavid van Moolenbroek 	if (scheme->prefix == NULL) {
460*00b67f09SDavid van Moolenbroek 		r = idn_nomemory;
461*00b67f09SDavid van Moolenbroek 		goto ret;
462*00b67f09SDavid van Moolenbroek 	}
463*00b67f09SDavid van Moolenbroek 
464*00b67f09SDavid van Moolenbroek 	strcpy(scheme->prefix, prefix);
465*00b67f09SDavid van Moolenbroek 	scheme->parameter = NULL;
466*00b67f09SDavid van Moolenbroek 	scheme->create    = create;
467*00b67f09SDavid van Moolenbroek 	scheme->destroy   = destroy;
468*00b67f09SDavid van Moolenbroek 	scheme->map       = map;
469*00b67f09SDavid van Moolenbroek 
470*00b67f09SDavid van Moolenbroek 	r = idn__strhash_put(scheme_hash, prefix, scheme);
471*00b67f09SDavid van Moolenbroek 	if (r != idn_success)
472*00b67f09SDavid van Moolenbroek 		goto ret;
473*00b67f09SDavid van Moolenbroek 
474*00b67f09SDavid van Moolenbroek 	r = idn_success;
475*00b67f09SDavid van Moolenbroek ret:
476*00b67f09SDavid van Moolenbroek 	if (r != idn_success) {
477*00b67f09SDavid van Moolenbroek 		if (scheme != NULL)
478*00b67f09SDavid van Moolenbroek 			free(scheme->prefix);
479*00b67f09SDavid van Moolenbroek 		free(scheme);
480*00b67f09SDavid van Moolenbroek 	}
481*00b67f09SDavid van Moolenbroek 
482*00b67f09SDavid van Moolenbroek 	TRACE(("idn_mapper_register(): %s\n", idn_result_tostring(r)));
483*00b67f09SDavid van Moolenbroek 	return (r);
484*00b67f09SDavid van Moolenbroek }
485