1 /* $NetBSD: mapper.c,v 1.4 2014/12/10 04:37:55 christos Exp $ */
4 static char *rcsid
= "Id: mapper.c,v 1.1 2003/06/04 00:25:55 marka Exp ";
8 * Copyright (c) 2001,2002 Japan Network Information Center.
11 * By using this file, you agree to the terms and conditions set forth bellow.
13 * LICENSE TERMS AND CONDITIONS
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.
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.
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.
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."
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
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.
56 #include <idn/result.h>
57 #include <idn/assert.h>
58 #include <idn/logmacro.h>
59 #include <idn/mapper.h>
60 #include <idn/strhash.h>
61 #include <idn/debug.h>
66 * Type for mapping scheme.
71 idn_mapper_createproc_t create
;
72 idn_mapper_destroyproc_t destroy
;
73 idn_mapper_mapproc_t map
;
78 * Standard mapping schemes.
80 static const map_scheme_t nameprep_scheme
= {
83 idn_nameprep_createproc
,
84 idn_nameprep_destroyproc
,
89 static const map_scheme_t filemap_scheme
= {
92 idn__filemapper_createproc
,
93 idn__filemapper_destroyproc
,
94 idn__filemapper_mapproc
,
98 static const map_scheme_t
*standard_map_schemes
[] = {
105 * Hash table for mapping schemes.
107 static idn__strhash_t scheme_hash
= NULL
;
110 * Mapper object type.
115 map_scheme_t
*schemes
;
119 #define MAPPER_INITIAL_SCHEME_SIZE 1
122 idn_mapper_initialize(void) {
124 map_scheme_t
**scheme
;
126 TRACE(("idn_mapper_initialize()\n"));
128 if (scheme_hash
!= NULL
) {
129 r
= idn_success
; /* already initialized */
133 r
= idn__strhash_create(&scheme_hash
);
134 if (r
!= idn_success
)
137 for (scheme
= (map_scheme_t
**)standard_map_schemes
;
138 *scheme
!= NULL
; scheme
++) {
139 r
= idn__strhash_put(scheme_hash
, (*scheme
)->prefix
, *scheme
);
140 if (r
!= idn_success
)
146 if (r
!= idn_success
&& scheme_hash
!= NULL
) {
147 idn__strhash_destroy(scheme_hash
, NULL
);
150 TRACE(("idn_mapper_initialize(): %s\n", idn_result_tostring(r
)));
155 idn_mapper_create(idn_mapper_t
*ctxp
) {
156 idn_mapper_t ctx
= NULL
;
159 assert(scheme_hash
!= NULL
);
160 assert(ctxp
!= NULL
);
162 TRACE(("idn_mapper_create()\n"));
164 ctx
= (idn_mapper_t
) malloc(sizeof(struct idn_mapper
));
170 ctx
->schemes
= (map_scheme_t
*) malloc(sizeof(map_scheme_t
)
171 * MAPPER_INITIAL_SCHEME_SIZE
);
172 if (ctx
->schemes
== NULL
) {
178 ctx
->scheme_size
= MAPPER_INITIAL_SCHEME_SIZE
;
179 ctx
->reference_count
= 1;
184 if (r
!= idn_success
) {
189 TRACE(("idn_mapper_create(): %s\n", idn_result_tostring(r
)));
194 idn_mapper_destroy(idn_mapper_t ctx
) {
197 assert(scheme_hash
!= NULL
);
200 TRACE(("idn_mapper_destroy()\n"));
202 ctx
->reference_count
--;
203 if (ctx
->reference_count
<= 0) {
204 TRACE(("idn_mapper_destroy(): the object is destroyed\n"));
205 for (i
= 0; i
< ctx
->nschemes
; i
++)
206 ctx
->schemes
[i
].destroy(ctx
->schemes
[i
].context
);
210 TRACE(("idn_mapper_destroy(): "
211 "update reference count (%d->%d)\n",
212 ctx
->reference_count
+ 1, ctx
->reference_count
));
217 idn_mapper_incrref(idn_mapper_t ctx
) {
218 assert(ctx
!= NULL
&& scheme_hash
!= NULL
);
220 TRACE(("idn_mapper_incrref()\n"));
221 TRACE(("idn_mapper_incrref: update reference count (%d->%d)\n",
222 ctx
->reference_count
, ctx
->reference_count
+ 1));
224 ctx
->reference_count
++;
228 idn_mapper_add(idn_mapper_t ctx
, const char *scheme_name
) {
230 map_scheme_t
*scheme
;
231 const char *scheme_prefix
;
232 const char *scheme_parameter
;
233 void *scheme_context
= NULL
;
234 char static_buffer
[128]; /* large enough */
235 char *buffer
= static_buffer
;
237 assert(scheme_hash
!= NULL
);
240 TRACE(("idn_mapper_add(scheme_name=%s)\n",
241 idn__debug_xstring(scheme_name
, 50)));
244 * Split `scheme_name' into `scheme_prefix' and `scheme_parameter'.
246 scheme_parameter
= strchr(scheme_name
, ':');
247 if (scheme_parameter
== NULL
) {
248 scheme_prefix
= scheme_name
;
250 ptrdiff_t scheme_prefixlen
;
252 scheme_prefixlen
= scheme_parameter
- scheme_name
;
253 if (scheme_prefixlen
+ 1 > sizeof(static_buffer
)) {
254 buffer
= (char *) malloc(scheme_prefixlen
+ 1);
255 if (buffer
== NULL
) {
260 memcpy(buffer
, scheme_name
, scheme_prefixlen
);
261 *(buffer
+ scheme_prefixlen
) = '\0';
262 scheme_prefix
= buffer
;
269 if (idn__strhash_get(scheme_hash
, scheme_prefix
, (void **)&scheme
)
271 ERROR(("idn_mapper_add(): invalid scheme name \"%-.30s\"\n",
273 r
= idn_invalid_name
;
276 if (scheme_parameter
== NULL
) {
277 if (scheme
->parameter
!= NULL
)
278 scheme_parameter
= scheme
->parameter
;
280 scheme_parameter
= scheme
->prefix
;
286 assert(ctx
->nschemes
<= ctx
->scheme_size
);
288 if (ctx
->nschemes
== ctx
->scheme_size
) {
289 map_scheme_t
*new_schemes
;
291 new_schemes
= (map_scheme_t
*) realloc(ctx
->schemes
,
292 sizeof(map_scheme_t
) * ctx
->scheme_size
* 2);
293 if (new_schemes
== NULL
) {
297 ctx
->schemes
= new_schemes
;
298 ctx
->scheme_size
*= 2;
301 r
= scheme
->create(scheme_parameter
, &scheme_context
);
302 if (r
!= idn_success
)
305 memcpy(ctx
->schemes
+ ctx
->nschemes
, scheme
, sizeof(map_scheme_t
));
306 ctx
->schemes
[ctx
->nschemes
].context
= scheme_context
;
310 if (r
!= idn_success
)
311 free(scheme_context
);
312 if (buffer
!= static_buffer
)
314 TRACE(("idn_mapper_add(): %s\n", idn_result_tostring(r
)));
319 idn_mapper_addall(idn_mapper_t ctx
, const char **scheme_names
, int nschemes
) {
323 assert(scheme_hash
!= NULL
);
324 assert(ctx
!= NULL
&& scheme_names
!= NULL
);
326 TRACE(("idn_mapper_addall(nschemes=%d)\n", nschemes
));
328 for (i
= 0; i
< nschemes
; i
++) {
329 r
= idn_mapper_add(ctx
, (const char *)*scheme_names
);
330 if (r
!= idn_success
)
337 TRACE(("idn_mapper_addall(): %s\n", idn_result_tostring(r
)));
342 idn_mapper_map(idn_mapper_t ctx
, const unsigned long *from
,
343 unsigned long *to
, size_t tolen
) {
345 unsigned long *src
, *dst
;
346 unsigned long *buffers
[2] = {NULL
, NULL
};
347 size_t buflen
[2] = {0, 0};
352 assert(scheme_hash
!= NULL
);
353 assert(ctx
!= NULL
&& from
!= NULL
&& to
!= NULL
);
355 TRACE(("idn_mapper_map(from=\"%s\", tolen=%d)\n",
356 idn__debug_ucs4xstring(from
, 50), (int)tolen
));
358 if (ctx
->nschemes
<= 0) {
359 if (tolen
< idn_ucs4_strlen(from
) + 1) {
360 r
= idn_buffer_overflow
;
363 idn_ucs4_strcpy(to
, from
);
372 dstlen
= idn_ucs4_strlen(from
) + 1;
375 while (i
< ctx
->nschemes
) {
376 TRACE(("idn_mapper_map(): map %s\n", ctx
->schemes
[i
].prefix
));
379 * Choose destination area to restore the result of a mapping.
381 if (i
+ 1 == ctx
->nschemes
) {
386 if (src
== buffers
[0])
391 if (buflen
[idx
] < dstlen
) {
394 newbuf
= realloc(buffers
[idx
],
395 sizeof(long) * dstlen
);
396 if (newbuf
== NULL
) {
400 buffers
[idx
] = (unsigned long *)newbuf
;
401 buflen
[idx
] = dstlen
;
405 dstlen
= buflen
[idx
];
409 * Perform i-th map scheme.
410 * If buffer size is not enough, we double it and try again.
412 r
= (ctx
->schemes
[i
].map
)(ctx
->schemes
[i
].context
, src
, dst
,
414 if (r
== idn_buffer_overflow
&& dst
!= to
) {
418 if (r
!= idn_success
)
429 if (r
== idn_success
) {
430 TRACE(("idn_mapper_map(): success (to=\"%s\")\n",
431 idn__debug_ucs4xstring(to
, 50)));
433 TRACE(("idn_mapper_map(): %s\n", idn_result_tostring(r
)));
439 idn_mapper_register(const char *prefix
,
440 idn_mapper_createproc_t create
,
441 idn_mapper_destroyproc_t destroy
,
442 idn_mapper_mapproc_t map
) {
444 map_scheme_t
*scheme
= NULL
;
446 assert(scheme_hash
!= NULL
);
447 assert(prefix
!= NULL
&& create
!= NULL
&& destroy
!= NULL
&&
450 TRACE(("idn_mapper_register(prefix=%s)\n", prefix
));
452 scheme
= (map_scheme_t
*) malloc(sizeof(map_scheme_t
));
453 if (scheme
== NULL
) {
458 scheme
->prefix
= (char *) malloc(strlen(prefix
) + 1);
459 if (scheme
->prefix
== NULL
) {
464 strcpy(scheme
->prefix
, prefix
);
465 scheme
->parameter
= NULL
;
466 scheme
->create
= create
;
467 scheme
->destroy
= destroy
;
470 r
= idn__strhash_put(scheme_hash
, prefix
, scheme
);
471 if (r
!= idn_success
)
476 if (r
!= idn_success
) {
478 free(scheme
->prefix
);
482 TRACE(("idn_mapper_register(): %s\n", idn_result_tostring(r
)));