1 /* $NetBSD: converter.c,v 1.4 2014/12/10 04:37:55 christos Exp $ */
4 static char *rcsid
= "Id: converter.c,v 1.1 2003/06/04 00:25:51 marka Exp ";
8 * Copyright (c) 2000,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.
62 #include <idn/result.h>
63 #include <idn/assert.h>
64 #include <idn/logmacro.h>
65 #include <idn/converter.h>
66 #include <idn/aliaslist.h>
67 #include <idn/strhash.h>
68 #include <idn/debug.h>
70 #include <idn/punycode.h>
74 #ifndef IDN_UTF8_ENCODING_NAME
75 #define IDN_UTF8_ENCODING_NAME "UTF-8" /* by IANA */
77 #ifndef IDN_RACE_ENCODING_NAME
78 #define IDN_RACE_ENCODING_NAME "RACE"
80 #ifndef IDN_AMCACEZ_ENCODING_NAME
81 #define IDN_AMCACEZ_ENCODING_NAME "AMC-ACE-Z"
83 #ifndef IDN_PUNYCODE_ENCODING_NAME
84 #define IDN_PUNYCODE_ENCODING_NAME "Punycode"
87 #define MAX_RECURSE 20
91 #define IDNKEY_IDNKIT "Software\\JPNIC\\IDN"
92 #define IDNVAL_ALIASFILE "AliasFile"
96 #ifndef IDN_RESCONF_DIR
97 #define IDN_RESCONF_DIR "/etc"
99 #define IDN_ALIAS_FILE IDN_RESCONF_DIR "/idnalias.conf"
104 idn_converter_openproc_t openfromucs4
;
105 idn_converter_openproc_t opentoucs4
;
106 idn_converter_convfromucs4proc_t convfromucs4
;
107 idn_converter_convtoucs4proc_t convtoucs4
;
108 idn_converter_closeproc_t close
;
112 struct idn_converter
{
113 char *local_encoding_name
;
114 converter_ops_t
*ops
;
116 int opened_convfromucs4
;
117 int opened_convtoucs4
;
122 static idn__strhash_t encoding_name_hash
;
123 static idn__aliaslist_t encoding_alias_list
;
125 static idn_result_t
register_standard_encoding(void);
126 static idn_result_t
roundtrip_check(idn_converter_t ctx
,
127 const unsigned long *from
,
131 converter_none_open(idn_converter_t ctx
, void **privdata
);
133 converter_none_close(idn_converter_t ctx
, void *privdata
);
135 converter_none_convfromucs4(idn_converter_t ctx
,
137 const unsigned long *from
,
138 char *to
, size_t tolen
);
140 converter_none_convtoucs4(idn_converter_t ctx
,
141 void *privdata
, const char *from
,
142 unsigned long *to
, size_t tolen
);
144 #ifndef WITHOUT_ICONV
146 converter_iconv_openfromucs4(idn_converter_t ctx
, void **privdata
);
148 converter_iconv_opentoucs4(idn_converter_t ctx
, void **privdata
);
150 converter_iconv_close(idn_converter_t ctx
, void *privdata
);
152 converter_iconv_convfromucs4(idn_converter_t ctx
,
154 const unsigned long *from
,
155 char *to
, size_t tolen
);
157 converter_iconv_convtoucs4(idn_converter_t ctx
,
160 unsigned long *to
, size_t tolen
);
163 iconv_initialize_privdata(void **privdata
);
165 iconv_finalize_privdata(void *privdata
);
167 static char * get_system_aliasfile(void);
168 static int file_exist(const char *filename
);
170 #endif /* !WITHOUT_ICONV */
174 converter_uescape_convfromucs4(idn_converter_t ctx
,
176 const unsigned long *from
,
177 char *to
, size_t tolen
);
179 converter_uescape_convtoucs4(idn_converter_t ctx
,
186 static converter_ops_t none_converter_ops
= {
189 converter_none_convfromucs4
,
190 converter_none_convtoucs4
,
191 converter_none_close
,
195 #ifndef WITHOUT_ICONV
196 static converter_ops_t iconv_converter_ops
= {
197 converter_iconv_openfromucs4
,
198 converter_iconv_opentoucs4
,
199 converter_iconv_convfromucs4
,
200 converter_iconv_convtoucs4
,
201 converter_iconv_close
,
211 idn_converter_initialize(void) {
214 idn__aliaslist_t list
;
215 #ifndef WITHOUT_ICONV
219 TRACE(("idn_converter_initialize()\n"));
221 if (encoding_name_hash
== NULL
) {
222 if ((r
= idn__strhash_create(&hash
)) != idn_success
)
224 encoding_name_hash
= hash
;
225 r
= register_standard_encoding();
227 if (encoding_alias_list
== NULL
) {
228 if ((r
= idn__aliaslist_create(&list
)) != idn_success
)
230 encoding_alias_list
= list
;
231 #ifndef WITHOUT_ICONV
232 fname
= get_system_aliasfile();
233 if (fname
!= NULL
&& file_exist(fname
))
234 idn_converter_aliasfile(fname
);
240 TRACE(("idn_converter_initialize(): %s\n", idn_result_tostring(r
)));
244 #ifndef WITHOUT_ICONV
246 get_system_aliasfile() {
248 static char alias_path
[500]; /* a good longer than MAX_PATH */
250 if (idn__util_getregistrystring(idn__util_hkey_localmachine
,
252 alias_path
, sizeof(alias_path
))) {
258 return (IDN_ALIAS_FILE
);
263 file_exist(const char *filename
) {
266 if ((fp
= fopen(filename
, "r")) == NULL
)
274 idn_converter_create(const char *name
, idn_converter_t
*ctxp
, int flags
) {
275 const char *realname
;
280 assert(name
!= NULL
&& ctxp
!= NULL
);
282 TRACE(("idn_converter_create(%s)\n", name
));
284 realname
= idn_converter_getrealname(name
);
286 if (strcmp(name
, realname
) != 0) {
287 TRACE(("idn_converter_create: realname=%s\n", realname
));
293 /* Allocate memory for a converter context and the name. */
294 ctx
= malloc(sizeof(struct idn_converter
) + strlen(realname
) + 1);
300 ctx
->local_encoding_name
= (char *)(ctx
+ 1);
301 (void)strcpy(ctx
->local_encoding_name
, realname
);
303 ctx
->reference_count
= 1;
304 ctx
->opened_convfromucs4
= 0;
305 ctx
->opened_convtoucs4
= 0;
306 ctx
->private_data
= NULL
;
308 assert(encoding_name_hash
!= NULL
);
310 if (strcmp(realname
, IDN_UTF8_ENCODING_NAME
) == 0) {
311 /* No conversion needed */
312 ctx
->ops
= &none_converter_ops
;
313 } else if ((r
= idn__strhash_get(encoding_name_hash
, realname
, &v
))
315 /* Special converter found */
316 ctx
->ops
= (converter_ops_t
*)v
;
322 r
= idn_invalid_name
;
325 ctx
->ops
= &iconv_converter_ops
;
329 if ((flags
& IDN_CONVERTER_DELAYEDOPEN
) == 0) {
330 r
= (ctx
->ops
->openfromucs4
)(ctx
, &(ctx
->private_data
));
331 if (r
!= idn_success
) {
332 WARNING(("idn_converter_create(): open failed "
338 ctx
->opened_convfromucs4
= 1;
340 r
= (*ctx
->ops
->opentoucs4
)(ctx
, &(ctx
->private_data
));
341 if (r
!= idn_success
) {
342 WARNING(("idn_converter_create(): open failed "
348 ctx
->opened_convtoucs4
= 1;
354 TRACE(("idn_converter_create(): %s\n", idn_result_tostring(r
)));
359 idn_converter_destroy(idn_converter_t ctx
) {
362 TRACE(("idn_converter_destroy(ctx=%s)\n", ctx
->local_encoding_name
));
364 ctx
->reference_count
--;
365 if (ctx
->reference_count
<= 0) {
366 TRACE(("idn_converter_destroy(): the object is destroyed\n"));
367 (void)(*ctx
->ops
->close
)(ctx
, ctx
->private_data
);
370 TRACE(("idn_converter_destroy(): "
371 "update reference count (%d->%d)\n",
372 ctx
->reference_count
+ 1, ctx
->reference_count
));
377 idn_converter_incrref(idn_converter_t ctx
) {
380 TRACE(("idn_converter_incrref(ctx=%s)\n", ctx
->local_encoding_name
));
381 TRACE(("idn_converter_incrref: update reference count (%d->%d)\n",
382 ctx
->reference_count
, ctx
->reference_count
+ 1));
384 ctx
->reference_count
++;
388 idn_converter_localencoding(idn_converter_t ctx
) {
390 TRACE(("idn_converter_localencoding(ctx=%s)\n",
391 ctx
->local_encoding_name
));
392 return (ctx
->local_encoding_name
);
396 idn_converter_encodingtype(idn_converter_t ctx
) {
400 TRACE(("idn_converter_encodingtype(ctx=%s)\n",
401 ctx
->local_encoding_name
));
403 encoding_type
= ctx
->ops
->encoding_type
;
404 TRACE(("idn_converter_encodingtype(): %d\n", encoding_type
));
405 return (encoding_type
);
409 idn_converter_isasciicompatible(idn_converter_t ctx
) {
413 TRACE(("idn_converter_isasciicompatible(ctx=%s)\n",
414 ctx
->local_encoding_name
));
416 iscompat
= (ctx
->ops
->encoding_type
!= IDN_NONACE
);
417 TRACE(("idn_converter_isasciicompatible(): %d\n", iscompat
));
422 idn_converter_convfromucs4(idn_converter_t ctx
, const unsigned long *from
,
423 char *to
, size_t tolen
) {
426 assert(ctx
!= NULL
&& from
!= NULL
&& to
!= NULL
);
428 TRACE(("idn_converter_convfromucs4(ctx=%s, from=\"%s\", tolen=%d)\n",
429 ctx
->local_encoding_name
, idn__debug_ucs4xstring(from
, 50),
432 if (!ctx
->opened_convfromucs4
) {
433 r
= (*ctx
->ops
->openfromucs4
)(ctx
, &(ctx
->private_data
));
434 if (r
!= idn_success
)
436 ctx
->opened_convfromucs4
= 1;
439 r
= (*ctx
->ops
->convfromucs4
)(ctx
, ctx
->private_data
, from
, to
, tolen
);
440 if (r
!= idn_success
)
442 if ((ctx
->flags
& IDN_CONVERTER_RTCHECK
) != 0) {
443 r
= roundtrip_check(ctx
, from
, to
);
444 if (r
!= idn_success
)
450 if (r
== idn_success
) {
451 TRACE(("idn_converter_convfromucs4(): success (to=\"%s\")\n",
452 idn__debug_xstring(to
, 50)));
454 TRACE(("idn_converter_convfromucs4(): %s\n",
455 idn_result_tostring(r
)));
461 idn_converter_convtoucs4(idn_converter_t ctx
, const char *from
,
462 unsigned long *to
, size_t tolen
) {
465 assert(ctx
!= NULL
&& from
!= NULL
&& to
!= NULL
);
467 TRACE(("idn_converter_convtoucs4(ctx=%s, from=\"%s\", tolen=%d)\n",
468 ctx
->local_encoding_name
, idn__debug_xstring(from
, 50),
471 if (!ctx
->opened_convtoucs4
) {
472 r
= (*ctx
->ops
->opentoucs4
)(ctx
, &(ctx
->private_data
));
473 if (r
!= idn_success
)
475 ctx
->opened_convtoucs4
= 1;
478 r
= (*ctx
->ops
->convtoucs4
)(ctx
, ctx
->private_data
, from
, to
, tolen
);
480 if (r
== idn_success
) {
481 TRACE(("idn_converter_convtoucs4(): success (to=\"%s\")\n",
482 idn__debug_ucs4xstring(to
, 50)));
484 TRACE(("idn_converter_convtoucs4(): %s\n",
485 idn_result_tostring(r
)));
491 * Encoding registration.
495 idn_converter_register(const char *name
,
496 idn_converter_openproc_t openfromucs4
,
497 idn_converter_openproc_t opentoucs4
,
498 idn_converter_convfromucs4proc_t convfromucs4
,
499 idn_converter_convtoucs4proc_t convtoucs4
,
500 idn_converter_closeproc_t close
,
502 converter_ops_t
*ops
;
505 assert(name
!= NULL
&& convfromucs4
!= NULL
&& convtoucs4
!= NULL
);
507 TRACE(("idn_converter_register(name=%s)\n", name
));
509 if ((ops
= malloc(sizeof(*ops
))) == NULL
) {
514 if (openfromucs4
== NULL
)
515 openfromucs4
= converter_none_open
;
516 if (opentoucs4
== NULL
)
517 opentoucs4
= converter_none_open
;
519 close
= converter_none_close
;
521 ops
->openfromucs4
= openfromucs4
;
522 ops
->opentoucs4
= opentoucs4
;
523 ops
->convfromucs4
= convfromucs4
;
524 ops
->convtoucs4
= convtoucs4
;
526 ops
->encoding_type
= encoding_type
;
528 r
= idn__strhash_put(encoding_name_hash
, name
, ops
);
529 if (r
!= idn_success
) {
536 TRACE(("idn_converter_register(): %s\n", idn_result_tostring(r
)));
541 register_standard_encoding(void) {
544 r
= idn_converter_register(IDN_PUNYCODE_ENCODING_NAME
,
547 idn__punycode_encode
,
548 idn__punycode_decode
,
549 converter_none_close
,
551 if (r
!= idn_success
)
555 r
= idn_converter_register(IDN_AMCACEZ_ENCODING_NAME
,
558 idn__punycode_encode
,
559 idn__punycode_decode
,
560 converter_none_close
,
562 if (r
!= idn_success
)
565 r
= idn_converter_register(IDN_RACE_ENCODING_NAME
,
570 converter_none_close
,
572 if (r
!= idn_success
)
574 #endif /* IDN_EXTRA_ACE */
577 /* This is convenient for debug. Not useful for other purposes. */
578 r
= idn_converter_register("U-escape",
581 converter_uescape_convfromucs4
,
582 converter_uescape_convtoucs4
,
585 if (r
!= idn_success
)
593 * Encoding alias support.
596 idn_converter_addalias(const char *alias_name
, const char *real_name
,
600 assert(alias_name
!= NULL
&& real_name
!= NULL
);
602 TRACE(("idn_converter_addalias(alias_name=%s,real_name=%s)\n",
603 alias_name
, real_name
));
605 if (strlen(alias_name
) == 0 || strlen(real_name
) == 0) {
606 return idn_invalid_syntax
;
609 if (strcmp(alias_name
, real_name
) == 0) {
614 if (encoding_alias_list
== NULL
) {
615 WARNING(("idn_converter_addalias(): the module is not "
621 r
= idn__aliaslist_additem(encoding_alias_list
, alias_name
, real_name
,
624 TRACE(("idn_converter_addalias(): %s\n", idn_result_tostring(r
)));
629 idn_converter_aliasfile(const char *path
) {
632 assert(path
!= NULL
);
634 TRACE(("idn_converter_aliasfile(path=%s)\n", path
));
636 if (encoding_alias_list
== NULL
) {
637 WARNING(("idn_converter_aliasfile(): the module is not "
639 return (idn_failure
);
642 r
= idn__aliaslist_aliasfile(encoding_alias_list
, path
);
644 TRACE(("idn_converter_aliasfile(): %s\n", idn_result_tostring(r
)));
649 idn_converter_resetalias(void) {
650 idn__aliaslist_t list
;
653 TRACE(("idn_converter_resetalias()\n"));
655 if (encoding_alias_list
== NULL
) {
656 WARNING(("idn_converter_resetalias(): the module is not "
658 return (idn_failure
);
661 list
= encoding_alias_list
;
662 encoding_alias_list
= NULL
;
663 idn__aliaslist_destroy(list
);
665 r
= idn__aliaslist_create(&list
);
666 encoding_alias_list
= list
;
668 TRACE(("idn_converter_resetalias(): %s\n", idn_result_tostring(r
)));
673 idn_converter_getrealname(const char *name
) {
677 TRACE(("idn_converter_getrealname()\n"));
679 assert(name
!= NULL
);
681 if (encoding_alias_list
== NULL
) {
682 WARNING(("idn_converter_getrealname(): the module is not "
687 r
= idn__aliaslist_find(encoding_alias_list
, name
, &realname
);
688 if (r
!= idn_success
) {
699 roundtrip_check(idn_converter_t ctx
, const unsigned long *from
, const char *to
)
702 * One problem with iconv() convertion is that
703 * iconv() doesn't signal an error if the input
704 * string contains characters which are valid but
705 * do not have mapping to the output codeset.
706 * (the behavior of iconv() for that case is defined as
707 * `implementation dependent')
708 * One way to check this case is to perform round-trip
709 * conversion and see if it is same as the original string.
713 unsigned long backbuf
[256];
717 TRACE(("idn_converter_convert: round-trip checking (from=\"%s\")\n",
718 idn__debug_ucs4xstring(from
, 50)));
720 /* Allocate enough buffer. */
721 fromlen
= idn_ucs4_strlen(from
) + 1;
722 if (fromlen
* sizeof(*back
) <= sizeof(backbuf
)) {
723 backlen
= sizeof(backbuf
);
727 back
= (unsigned long *)malloc(backlen
* sizeof(*back
));
729 return (idn_nomemory
);
733 * Perform backward conversion.
735 r
= idn_converter_convtoucs4(ctx
, to
, back
, backlen
);
738 if (memcmp(back
, from
, sizeof(*from
) * fromlen
) != 0)
741 case idn_invalid_encoding
:
742 case idn_buffer_overflow
:
752 if (r
!= idn_success
) {
753 TRACE(("round-trip check failed: %s\n",
754 idn_result_tostring(r
)));
761 * Identity conversion (or, no conversion at all).
765 converter_none_open(idn_converter_t ctx
, void **privdata
) {
768 return (idn_success
);
772 converter_none_close(idn_converter_t ctx
, void *privdata
) {
775 return (idn_success
);
779 converter_none_convfromucs4(idn_converter_t ctx
, void *privdata
,
780 const unsigned long *from
, char *to
, size_t tolen
) {
781 assert(ctx
!= NULL
&& from
!= NULL
&& to
!= NULL
);
783 return idn_ucs4_ucs4toutf8(from
, to
, tolen
);
787 converter_none_convtoucs4(idn_converter_t ctx
, void *privdata
,
788 const char *from
, unsigned long *to
, size_t tolen
) {
789 assert(ctx
!= NULL
&& from
!= NULL
&& to
!= NULL
);
791 return idn_ucs4_utf8toucs4(from
, to
, tolen
);
794 #ifndef WITHOUT_ICONV
797 * Conversion using iconv() interface.
801 converter_iconv_openfromucs4(idn_converter_t ctx
, void **privdata
) {
807 r
= iconv_initialize_privdata(privdata
);
808 if (r
!= idn_success
)
811 ictxp
= (iconv_t
*)*privdata
;
812 *ictxp
= iconv_open(ctx
->local_encoding_name
, IDN_UTF8_ENCODING_NAME
);
813 if (*ictxp
== (iconv_t
)(-1)) {
818 return (idn_nomemory
);
820 return (idn_invalid_name
);
822 WARNING(("iconv_open failed with errno %d\n", errno
));
823 return (idn_failure
);
827 return (idn_success
);
831 converter_iconv_opentoucs4(idn_converter_t ctx
, void **privdata
) {
837 r
= iconv_initialize_privdata(privdata
);
838 if (r
!= idn_success
)
841 ictxp
= (iconv_t
*)*privdata
+ 1;
842 *ictxp
= iconv_open(IDN_UTF8_ENCODING_NAME
, ctx
->local_encoding_name
);
843 if (*ictxp
== (iconv_t
)(-1)) {
848 return (idn_nomemory
);
850 return (idn_invalid_name
);
852 WARNING(("iconv_open failed with errno %d\n", errno
));
853 return (idn_failure
);
857 return (idn_success
);
861 iconv_initialize_privdata(void **privdata
) {
862 if (*privdata
== NULL
) {
863 *privdata
= malloc(sizeof(iconv_t
) * 2);
864 if (*privdata
== NULL
)
865 return (idn_nomemory
);
866 *((iconv_t
*)*privdata
) = (iconv_t
)(-1);
867 *((iconv_t
*)*privdata
+ 1) = (iconv_t
)(-1);
870 return (idn_success
);
874 iconv_finalize_privdata(void *privdata
) {
877 if (privdata
!= NULL
) {
878 ictxp
= (iconv_t
*)privdata
;
879 if (*ictxp
!= (iconv_t
)(-1))
883 if (*ictxp
!= (iconv_t
)(-1))
890 converter_iconv_close(idn_converter_t ctx
, void *privdata
) {
893 iconv_finalize_privdata(privdata
);
895 return (idn_success
);
899 converter_iconv_convfromucs4(idn_converter_t ctx
, void *privdata
,
900 const unsigned long *from
, char *to
,
904 size_t utf8size
= 256; /* large enough */
909 char *inbuf
, *outbuf
;
911 assert(ctx
!= NULL
&& from
!= NULL
&& to
!= NULL
);
914 r
= idn_buffer_overflow
; /* need space for NUL */
919 * UCS4 -> UTF-8 conversion.
921 utf8
= (char *)malloc(utf8size
);
928 r
= idn_ucs4_ucs4toutf8(from
, utf8
, utf8size
);
929 if (r
== idn_buffer_overflow
) {
933 new_utf8
= (char *)realloc(utf8
, utf8size
);
934 if (new_utf8
== NULL
) {
940 } else if (r
!= idn_success
) {
944 ictx
= ((iconv_t
*)privdata
)[0];
947 * Reset internal state.
949 * The following code should work according to the SUSv2 spec,
950 * but causes segmentation fault with Solaris 2.6.
951 * So.. a work-around.
953 * (void)iconv(ictx, (const char **)NULL, (size_t *)NULL,
954 * (char **)NULL, (size_t *)NULL);
959 (void)iconv(ictx
, (const char **)NULL
, &inleft
, &outbuf
, &outleft
);
961 inleft
= strlen(utf8
);
963 outleft
= tolen
- 1; /* reserve space for terminating NUL */
964 sz
= iconv(ictx
, (const char **)&inbuf
, &inleft
, &to
, &outleft
);
966 if (sz
== (size_t)(-1) || inleft
> 0) {
971 * We already checked the validity of the input
972 * string. So we assume a mapping error.
977 r
= idn_buffer_overflow
;
980 WARNING(("iconv failed with errno %d\n", errno
));
987 * For UTF-8 -> local conversion, append a sequence of
991 sz
= iconv(ictx
, (const char **)NULL
, &inleft
, &to
, &outleft
);
992 if (sz
== (size_t)(-1)) {
996 r
= idn_invalid_encoding
;
999 r
= idn_buffer_overflow
;
1002 WARNING(("iconv failed with errno %d\n", errno
));
1017 converter_iconv_convtoucs4(idn_converter_t ctx
, void *privdata
,
1018 const char *from
, unsigned long *to
, size_t tolen
) {
1021 size_t utf8size
= 256; /* large enough */
1026 const char *from_ptr
;
1029 assert(ctx
!= NULL
&& from
!= NULL
&& to
!= NULL
);
1032 r
= idn_buffer_overflow
; /* need space for NUL */
1035 ictx
= ((iconv_t
*)privdata
)[1];
1036 utf8
= (char *)malloc(utf8size
);
1044 * Reset internal state.
1049 (void)iconv(ictx
, (const char **)NULL
, &inleft
, &outbuf
, &outleft
);
1052 inleft
= strlen(from
);
1054 outleft
= utf8size
- 1; /* reserve space for terminating NUL */
1055 sz
= iconv(ictx
, (const char **)&from_ptr
, &inleft
, &outbuf
, &outleft
);
1057 if (sz
== (size_t)(-1) || inleft
> 0) {
1064 * We assume all the characters in the local
1065 * codeset are included in UCS. This means mapping
1066 * error is not possible, so the input string must
1067 * have some problem.
1069 r
= idn_invalid_encoding
;
1073 new_utf8
= (char *)realloc(utf8
, utf8size
);
1074 if (new_utf8
== NULL
) {
1081 WARNING(("iconv failed with errno %d\n", errno
));
1089 * UTF-8 -> UCS4 conversion.
1091 r
= idn_ucs4_utf8toucs4(utf8
, to
, tolen
);
1098 #endif /* !WITHOUT_ICONV */
1102 * Conversion to/from unicode escape string.
1103 * Arbitrary UCS-4 character can be specified by a special sequence
1105 * where XXXXX denotes any hexadecimal string up to FFFFFFFF.
1106 * This is designed for debugging.
1110 converter_uescape_convfromucs4(idn_converter_t ctx
, void *privdata
,
1111 const unsigned long *from
, char *to
,
1116 while (*from
!= '\0') {
1121 r
= idn_buffer_overflow
;
1126 } else if (v
<= 0xffffffff) {
1130 (void)sprintf(tmp
, "\\u{%lx}", v
);
1133 r
= idn_buffer_overflow
;
1136 (void)memcpy(to
, tmp
, len
);
1140 r
= idn_invalid_encoding
;
1146 r
= idn_buffer_overflow
;
1151 return (idn_success
);
1154 if (r
!= idn_buffer_overflow
) {
1155 WARNING(("idn_uescape_convfromucs4(): %s\n",
1156 idn_result_tostring(r
)));
1162 converter_uescape_convtoucs4(idn_converter_t ctx
, void *privdata
,
1163 const char *from
, unsigned long *to
, size_t tolen
)
1166 size_t fromlen
= strlen(from
);
1168 while (*from
!= '\0') {
1170 r
= idn_buffer_overflow
;
1173 if (strncmp(from
, "\\u{", 3) == 0 ||
1174 strncmp(from
, "\\U{", 3) == 0) {
1179 v
= strtoul(from
+ 3, &end
, 16);
1180 ullen
= end
- (from
+ 3);
1181 if (*end
== '}' && ullen
> 1 && ullen
< 8) {
1191 int c
= *(unsigned char *)from
;
1211 if (width
== 0 || width
> fromlen
) {
1212 r
= idn_invalid_encoding
;
1216 memcpy(buf
, from
, width
);
1218 r
= idn_ucs4_utf8toucs4(buf
, to
, tolen
);
1219 if (r
!= idn_success
) {
1220 r
= idn_invalid_encoding
;
1231 r
= idn_buffer_overflow
;
1236 return (idn_success
);
1239 if (r
!= idn_buffer_overflow
) {
1240 WARNING(("idn_uescape_convtoucs4(): %s\n",
1241 idn_result_tostring(r
)));