Exemple #1
0
idn_converter_t
idn_resconf_getalternateconverter(idn_resconf_t ctx) {
	assert(ctx != NULL);

	TRACE(("idn_resconf_getalternateconverter()\n"));

	return (idn_resconf_getidnconverter(ctx));
}
Exemple #2
0
static idn_result_t
label_lencheck_nonace(idn_resconf_t ctx, labellist_t label) {
	idn_converter_t idn_converter;
	const unsigned long *from;
	size_t to_length;
	idn_result_t r;
	char *buffer = NULL;
	size_t buffer_length;

	from = labellist_getname(label);
	TRACE(("res lencheck(label=\"%s\")\n",
	       idn__debug_ucs4xstring(from, 50)));

	buffer_length = idn_ucs4_strlen(from) * 4 + 16; /* 16 for margin */
	idn_converter = idn_resconf_getidnconverter(ctx);

	for (;;) {
		void *new_buffer;

		new_buffer = realloc(buffer, sizeof(*buffer) * buffer_length);
		if (new_buffer == NULL) {
			r = idn_nomemory;
			goto ret;
		}
		buffer = (char *)new_buffer;

		if (idn_converter != NULL) {
			r = idn_converter_convfromucs4(idn_converter, from,
						       buffer, buffer_length);
		} else {
			r = idn_ucs4_ucs4toutf8(from, buffer, buffer_length);
		}
		if (r == idn_success)
			break;
		else if (r != idn_buffer_overflow)
			goto ret;

		buffer_length *= 2;
	}

	to_length = strlen(buffer);
	if (to_length == 0 || to_length > MAX_LABEL_LENGTH) {
		r = idn_invalid_length;
		goto ret;
	}

	r = idn_success;
ret:
	TRACE(("res lencheck(): %s\n", idn_result_tostring(r)));
	if (idn_converter != NULL)
		idn_converter_destroy(idn_converter);
	free(buffer);
	return (r);
}
Exemple #3
0
static int decode_file (idn_resconf_t conf1, idn_resconf_t conf2, FILE * fp, int flags)
{
    idn_result_t r;

    idnconv_strbuf_t buf1, buf2;

    idn_action_t actions1, actions2;

    int nl_trimmed;

    int local_ace_hack, idn_ace_hack;

    idn_converter_t conv;

    /*
     * See if the input codeset is an ACE.
     */
    conv = idn_resconf_getidnconverter (conf1);
    if (conv != NULL && idn_converter_isasciicompatible (conv) && (flags & FLAG_SELECTIVE))
        idn_ace_hack = 1;
    else
        idn_ace_hack = 0;
    if (conv != NULL)
        idn_converter_destroy (conv);

    conv = idn_resconf_getlocalconverter (conf1);
    if (conv != NULL && idn_converter_isasciicompatible (conv) && (flags & FLAG_SELECTIVE))
        local_ace_hack = 1;
    else
        local_ace_hack = 0;
    if (conv != NULL)
        idn_converter_destroy (conv);

    actions1 = IDN_IDNCONV;

    if (local_ace_hack)
    {
        actions2 = IDN_IDNCONV;
        if (flags & FLAG_MAP)
            actions2 |= IDN_MAP;
        if (flags & FLAG_NORMALIZE)
            actions2 |= IDN_NORMALIZE;
        if (flags & FLAG_PROHIBITCHECK)
            actions2 |= IDN_PROHCHECK;
        if (flags & FLAG_UNASSIGNCHECK)
            actions2 |= IDN_UNASCHECK;
        if (flags & FLAG_BIDICHECK)
            actions2 |= IDN_BIDICHECK;
        if (flags & FLAG_ASCIICHECK)
            actions2 |= IDN_ASCCHECK;
        if (flags & FLAG_LENGTHCHECK)
            actions2 |= IDN_LENCHECK;
    }
    else
    {
        actions2 = IDN_LOCALCONV;
    }

    if (flags & FLAG_DELIMMAP)
        actions1 |= IDN_DELIMMAP;
    if (flags & FLAG_MAP)
        actions1 |= IDN_MAP;
    if (flags & FLAG_NORMALIZE)
        actions1 |= IDN_NORMALIZE;
    if (flags & FLAG_NORMALIZE)
        actions1 |= IDN_NORMALIZE;
    if (flags & FLAG_PROHIBITCHECK)
        actions1 |= IDN_PROHCHECK;
    if (flags & FLAG_UNASSIGNCHECK)
        actions1 |= IDN_UNASCHECK;
    if (flags & FLAG_BIDICHECK)
        actions1 |= IDN_BIDICHECK;
    if (flags & FLAG_ASCIICHECK)
        actions1 |= IDN_ASCCHECK;
    if (flags & FLAG_ROUNDTRIPCHECK)
        actions1 |= IDN_RTCHECK;

    strbuf_init (&buf1);
    strbuf_init (&buf2);
    line_number = 1;
    while (strbuf_getline (&buf1, fp) != NULL)
    {
        /*
         * Trim newline at the end.  This is needed for
         * those ascii-comatible encodings such as UTF-5 or RACE
         * not to try converting newlines, which will result
         * in `invalid encoding' error.
         */
        nl_trimmed = trim_newline (&buf1);

        /*
         * Treat input line as the string encoded in local
         * encoding and convert it to UTF-8 encoded string.
         */
        if (local_ace_hack)
        {
            if (strbuf_copy (&buf2, strbuf_get (&buf1)) == NULL)
                r = idn_nomemory;
            else
                r = idn_success;
        }
        else
        {
            r = convert_line (&buf1, &buf2, conf1, IDN_LOCALCONV, 0);
        }
        if (r != idn_success)
        {
            errormsg ("conversion failed at line %d: %s\n", line_number, idn_result_tostring (r));
            goto error;
        }

        /*
         * Convert internationalized domain names in the line.
         */
        if (idn_ace_hack)
        {
            r = convert_line (&buf2, &buf1, conf1, actions1, FLAG_REVERSE | FLAG_SELECTIVE);
        }
        else
        {
            r = convert_line (&buf2, &buf1, conf1, actions1, FLAG_REVERSE);
        }
        if (r != idn_success)
        {
            errormsg ("conversion failed at line %d: %s\n", line_number, idn_result_tostring (r));
            goto error;
        }
        if (!idn_utf8_isvalidstring (strbuf_get (&buf1)))
        {
            errormsg ("conversion to utf-8 failed at line %d\n", line_number);
            goto error;
        }

        /*
         * Perform round trip check and convert to the output
         * codeset.
         */
        if (local_ace_hack)
        {
            r = convert_line (&buf1, &buf2, conf2, actions2, FLAG_SELECTIVE);
        }
        else
        {
            r = convert_line (&buf1, &buf2, conf1, actions2, FLAG_REVERSE);
        }

        if (r != idn_success)
        {
            errormsg ("error in nameprep or output conversion "
                      "at line %d: %s\n", line_number, idn_result_tostring (r));
            goto error;
        }

        fputs (strbuf_get (&buf2), stdout);
        if (nl_trimmed)
            putc ('\n', stdout);

        if (flush_every_line)
            fflush (stdout);

        line_number++;
    }
    strbuf_reset (&buf1);
    strbuf_reset (&buf2);
    return (0);

  error:
    strbuf_reset (&buf1);
    strbuf_reset (&buf2);
    return (1);
}
Exemple #4
0
int main (int ac, char **av)
{
    char *cmd = *av;

    char *cname;

    unsigned long delimiters[MAX_DELIMITER];

    char *localmappers[MAX_LOCALMAPPER];

    char *nameprep_version = NULL;

    int ndelimiters = 0;

    int nlocalmappers = 0;

    char *in_code = NULL;

    char *out_code = NULL;

    char *resconf_file = NULL;

    int no_resconf = 0;

    char *encoding_alias = NULL;

    int flags = DEFAULT_FLAGS;

    FILE *fp;

    idn_result_t r;

    idn_resconf_t resconf1, resconf2;

    idn_converter_t conv;

    int exit_value;

#ifdef HAVE_SETLOCALE
    (void) setlocale (LC_ALL, "");
#endif

    /*
     * If the command name begins with 'r', reverse mode is assumed.
     */
    if ((cname = strrchr (cmd, '/')) != NULL)
        cname++;
    else
        cname = cmd;
    if (cname[0] == 'r')
        flags |= FLAG_REVERSE;

    ac--;
    av++;
    while (ac > 0 && **av == '-')
    {

#define OPT_MATCH(opt) (strcmp(*av, opt) == 0)
#define MUST_HAVE_ARG if (ac < 2) print_usage(cmd)
#define APPEND_LIST(array, size, item, what) \
    if (size >= (sizeof(array) / sizeof(array[0]))) { \
        errormsg("too many " what "\n"); \
        exit(1); \
    } \
    array[size++] = item; \
    ac--; av++

        if (OPT_MATCH ("-in") || OPT_MATCH ("-i"))
        {
            MUST_HAVE_ARG;
            in_code = av[1];
            ac--;
            av++;
        }
        else if (OPT_MATCH ("-out") || OPT_MATCH ("-o"))
        {
            MUST_HAVE_ARG;
            out_code = av[1];
            ac--;
            av++;
        }
        else if (OPT_MATCH ("-conf") || OPT_MATCH ("-c"))
        {
            MUST_HAVE_ARG;
            resconf_file = av[1];
            ac--;
            av++;
        }
        else if (OPT_MATCH ("-nameprep") || OPT_MATCH ("-n"))
        {
            MUST_HAVE_ARG;
            nameprep_version = av[1];
            ac--;
            av++;
        }
        else if (OPT_MATCH ("-noconf") || OPT_MATCH ("-C"))
        {
            no_resconf = 1;
        }
        else if (OPT_MATCH ("-reverse") || OPT_MATCH ("-r"))
        {
            flags |= FLAG_REVERSE;
        }
        else if (OPT_MATCH ("-nolocalmap") || OPT_MATCH ("-L"))
        {
            flags &= ~FLAG_LOCALMAP;
        }
        else if (OPT_MATCH ("-nonameprep") || OPT_MATCH ("-N"))
        {
            flags &= ~FLAG_NAMEPREP;
        }
        else if (OPT_MATCH ("-unassigncheck") || OPT_MATCH ("-u"))
        {
            flags |= FLAG_UNASSIGNCHECK;
        }
        else if (OPT_MATCH ("-nounassigncheck") || OPT_MATCH ("-U"))
        {
            flags &= ~FLAG_UNASSIGNCHECK;
        }
        else if (OPT_MATCH ("-nobidicheck") || OPT_MATCH ("-B"))
        {
            flags &= ~FLAG_BIDICHECK;
        }
        else if (OPT_MATCH ("-noasciicheck") || OPT_MATCH ("-A"))
        {
            flags &= ~FLAG_ASCIICHECK;
        }
        else if (OPT_MATCH ("-nolengthcheck"))
        {
            flags &= ~FLAG_LENGTHCHECK;
        }
        else if (OPT_MATCH ("-noroundtripcheck"))
        {
            flags &= ~FLAG_ROUNDTRIPCHECK;
        }
        else if (OPT_MATCH ("-whole") || OPT_MATCH ("-w"))
        {
            flags &= ~FLAG_SELECTIVE;
        }
        else if (OPT_MATCH ("-localmap"))
        {
            MUST_HAVE_ARG;
            APPEND_LIST (localmappers, nlocalmappers, av[1], "local maps");
        }
        else if (OPT_MATCH ("-delimiter"))
        {
            unsigned long v;

            MUST_HAVE_ARG;
            v = get_ucs (av[1]);
            APPEND_LIST (delimiters, ndelimiters, v, "delimiter maps");
        }
        else if (OPT_MATCH ("-alias") || OPT_MATCH ("-a"))
        {
            MUST_HAVE_ARG;
            encoding_alias = av[1];
            ac--;
            av++;
        }
        else if (OPT_MATCH ("-flush"))
        {
            flush_every_line = 1;
        }
        else if (OPT_MATCH ("-version") || OPT_MATCH ("-v"))
        {
            print_version ();
        }
        else
        {
            print_usage (cmd);
        }
#undef OPT_MATCH
#undef MUST_HAVE_ARG
#undef APPEND_LIST

        ac--;
        av++;
    }

    if (ac > 1)
        print_usage (cmd);

    /* Initialize. */
    if ((r = idn_resconf_initialize ()) != idn_success)
    {
        errormsg ("error initializing library\n");
        return (1);
    }

    /*
     * Create resource contexts.
     * `resconf1' and `resconf2' are almost the same but local and
     * IDN encodings are reversed.
     */
    resconf1 = NULL;
    resconf2 = NULL;
    if (idn_resconf_create (&resconf1) != idn_success || idn_resconf_create (&resconf2) != idn_success)
    {
        errormsg ("error initializing configuration contexts\n");
        return (1);
    }

    /* Load configuration file. */
    if (no_resconf)
    {
        set_defaults (resconf1);
        set_defaults (resconf2);
    }
    else
    {
        load_conf_file (resconf1, resconf_file);
        load_conf_file (resconf2, resconf_file);
    }

    /* Set encoding alias file. */
    if (encoding_alias != NULL)
        set_encoding_alias (encoding_alias);

    /* Set input codeset. */
    if (flags & FLAG_REVERSE)
    {
        if (in_code == NULL)
        {
            conv = idn_resconf_getidnconverter (resconf1);
            if (conv == NULL)
            {
                errormsg ("cannot get the IDN encoding.\n" "please specify an appropriate one " "with `-in' option.\n");
                exit (1);
            }
            idn_resconf_setlocalconverter (resconf2, conv);
            idn_converter_destroy (conv);
        }
        else
        {
            set_idncode (resconf1, in_code);
            set_localcode (resconf2, in_code);
        }
    }
    else
    {
        if (in_code == NULL)
        {
            conv = idn_resconf_getlocalconverter (resconf1);
            if (conv == NULL)
            {
                errormsg ("cannot get the local encoding.\n"
                          "please specify an appropriate one " "with `-in' option.\n");
                exit (1);
            }
            idn_resconf_setidnconverter (resconf2, conv);
            idn_converter_destroy (conv);
        }
        else
        {
            set_localcode (resconf1, in_code);
            set_idncode (resconf2, in_code);
        }
    }

    /* Set output codeset. */
    if (flags & FLAG_REVERSE)
    {
        if (out_code == NULL)
        {
            conv = idn_resconf_getlocalconverter (resconf1);
            if (conv == NULL)
            {
                errormsg ("cannot get the local encoding.\n"
                          "please specify an appropriate one " "with `-out' option.\n");
                exit (1);
            }
            idn_resconf_setidnconverter (resconf2, conv);
            idn_converter_destroy (conv);
        }
        else
        {
            set_localcode (resconf1, out_code);
            set_idncode (resconf2, out_code);
        }
    }
    else
    {
        if (out_code == NULL)
        {
            conv = idn_resconf_getidnconverter (resconf1);
            if (conv == NULL)
            {
                errormsg ("cannot get the IDN encoding.\n"
                          "please specify an appropriate one " "with `-out' option.\n");
                exit (1);
            }
            idn_resconf_setlocalconverter (resconf2, conv);
            idn_converter_destroy (conv);
        }
        else
        {
            set_idncode (resconf1, out_code);
            set_localcode (resconf2, out_code);
        }
    }

    /* Set delimiter map(s). */
    if (ndelimiters > 0)
    {
        set_delimitermapper (resconf1, delimiters, ndelimiters);
        set_delimitermapper (resconf2, delimiters, ndelimiters);
    }

    /* Set local map(s). */
    if (nlocalmappers > 0)
    {
        set_localmapper (resconf1, localmappers, nlocalmappers);
        set_localmapper (resconf2, localmappers, nlocalmappers);
    }

    /* Set NAMEPREP version. */
    if (nameprep_version != NULL)
    {
        set_nameprep (resconf1, nameprep_version);
        set_nameprep (resconf2, nameprep_version);
    }

    idn_res_enable (1);

    /* Open input file. */
    if (ac > 0)
    {
        if ((fp = fopen (av[0], "r")) == NULL)
        {
            errormsg ("cannot open file %s: %s\n", av[0], strerror (errno));
            return (1);
        }
    }
    else
    {
        fp = stdin;
    }

    /* Do the conversion. */
    if (flags & FLAG_REVERSE)
        exit_value = decode_file (resconf1, resconf2, fp, flags);
    else
        exit_value = encode_file (resconf1, resconf2, fp, flags);

    idn_resconf_destroy (resconf1);
    idn_resconf_destroy (resconf2);

    return exit_value;
}
Exemple #5
0
idn_result_t
idn_res_decodename(idn_resconf_t ctx, idn_action_t actions, const char *from,
		    char *to, size_t tolen) {
	idn_converter_t local_converter = NULL;
	idn_converter_t idn_converter = NULL;
	idn_delimitermap_t delimiter_mapper;
	idn_result_t r;
	labellist_t labels = NULL, l;
	unsigned long *buffer = NULL;
	unsigned long *saved_name = NULL;
	size_t buffer_length;
	int idn_is_ace;

	assert(ctx != NULL && from != NULL && to != NULL);

	TRACE(("idn_res_decodename(actions=%s, from=\"%s\", tolen=%d)\n",
		idn__res_actionstostring(actions),
		idn__debug_xstring(from, 50), (int)tolen));

	if (actions & ~DECODE_MASK) {
		WARNING(("idn_res_decodename: invalid actions 0x%x\n",
			 actions));
		r = idn_invalid_action;
		goto ret;
	}

	if (!initialized)
		idn_res_initialize();
	if (!enabled || actions == 0) {
		r = copy_verbatim(from, to, tolen);
		goto ret;
	} else if (tolen <= 0) {
		r = idn_buffer_overflow;
		goto ret;
	}

	if (actions & IDN_DECODE_QUERY) {
#ifndef WITHOUT_ICONV
		actions |= (IDN_DELIMMAP | IDN_MAP | IDN_NORMALIZE | \
			    IDN_PROHCHECK | IDN_BIDICHECK | IDN_IDNCONV | \
			    IDN_RTCHECK | IDN_LOCALCONV);
#else
		actions |= (IDN_DELIMMAP | IDN_MAP | IDN_NORMALIZE | \
			    IDN_PROHCHECK | IDN_BIDICHECK | IDN_IDNCONV | \
			    IDN_RTCHECK);
#endif
	}

	/*
	 * Convert `from' to UCS4.
	 */
	local_converter = idn_resconf_getlocalconverter(ctx);
#ifndef WITHOUT_ICONV
	if (local_converter == NULL) {
		r = idn_invalid_name;
		goto ret;
	}
#endif

	idn_converter = idn_resconf_getidnconverter(ctx);
	if (idn_converter != NULL &&
	    idn_converter_isasciicompatible(idn_converter))
		idn_is_ace = 1;
	else
		idn_is_ace = 0;

	buffer_length = tolen * 2;

	TRACE(("res idndecode(name=\"%s\")\n", idn__debug_xstring(from, 50)));

	for (;;) {
		void *new_buffer;

		new_buffer = realloc(buffer, sizeof(*buffer) * buffer_length);
		if (new_buffer == NULL) {
			r = idn_nomemory;
			goto ret;
		}
		buffer = (unsigned long *)new_buffer;

		if ((actions & IDN_IDNCONV) &&
		     idn_converter != NULL && !idn_is_ace) {
			r = idn_converter_convtoucs4(idn_converter, from,
						     buffer, buffer_length);
		} else {
			r = idn_ucs4_utf8toucs4(from, buffer, buffer_length);
		}
		if (r == idn_success)
			break;
		else if (r != idn_buffer_overflow)
			goto ret;

		buffer_length *= 2;
	}

	if (*buffer == '\0') {
		if (tolen <= 0) {
			r = idn_buffer_overflow;
			goto ret;
		}
		*to = '\0';
		r = idn_success;
		goto ret;
	}

	/*
	 * Delimiter map.
	 */
	if (actions & IDN_DELIMMAP) {
		TRACE(("res delimitermap(name=\"%s\")\n",
		       idn__debug_ucs4xstring(buffer, 50)));

		delimiter_mapper = idn_resconf_getdelimitermap(ctx);
		if (delimiter_mapper != NULL) {
			r = idn_delimitermap_map(delimiter_mapper, buffer,
						 buffer, buffer_length);
			idn_delimitermap_destroy(delimiter_mapper);
			if (r != idn_success)
				goto ret;
		}
		TRACE(("res delimitermap(): success (name=\"%s\")\n",
		       idn__debug_ucs4xstring(buffer, 50)));
	}

	/*
	 * Split the name into a list of labels.
	 */
	r = labellist_create(buffer, &labels);
	if (r != idn_success)
		goto ret;

	/*
	 * Perform conversions and tests.
	 */
	for (l = labellist_tail(labels); l != NULL;
	     l = labellist_previous(l)) {

		free(saved_name);
		saved_name = NULL;

		if (!idn__util_ucs4isasciirange(labellist_getname(l))) {
			if (actions & IDN_MAP) {
				r = label_map(ctx, l);
				if (r != idn_success)
					goto ret;
			}
			if (actions & IDN_NORMALIZE) {
				r = label_normalize(ctx, l);
				if (r != idn_success)
					goto ret;
			}
			if (actions & IDN_PROHCHECK) {
				r = label_prohcheck(ctx, l);
				if (r == idn_prohibited) {
					labellist_undo(l);
					continue;
				} else if (r != idn_success) {
					goto ret;
				}
			}
			if (actions & IDN_UNASCHECK) {
				r = label_unascheck(ctx, l);
				if (r == idn_prohibited) {
					labellist_undo(l);
					continue;
				} else if (r != idn_success) {
					goto ret;
				}
			}
			if (actions & IDN_BIDICHECK) {
				r = label_bidicheck(ctx, l);
				if (r == idn_prohibited) {
					labellist_undo(l);
					continue;
				} else if (r != idn_success) {
					goto ret;
				}
			}
		}

		if ((actions & IDN_IDNCONV) && idn_is_ace) {
			saved_name = idn_ucs4_strdup(labellist_getname(l));
			if (saved_name == NULL) {
				r = idn_nomemory;
				goto ret;
			}
			r = label_idndecode(ctx, l);
			if (r == idn_invalid_encoding) {
				labellist_undo(l);
				continue;
			} else if (r != idn_success) {
				goto ret;
			}
		}
		if ((actions & IDN_RTCHECK) && saved_name != NULL) {
			r = label_rtcheck(ctx, actions, l, saved_name);
			if (r == idn_invalid_encoding) {
				labellist_undo(l);
				continue;
			} else if (r != idn_success) {
				goto ret;
			}
		}

#ifndef WITHOUT_ICONV
		if (actions & IDN_LOCALCONV) {
			r = label_localdecodecheck(ctx, l);
			if (r != idn_success)
				goto ret;
		}
#endif
	}

	/*
	 * Concat a list of labels to a name.
	 */
	for (;;) {
		void *new_buffer;

		new_buffer = realloc(buffer, sizeof(*buffer) * buffer_length);
		if (new_buffer == NULL) {
			r = idn_nomemory;
			goto ret;
		}
		buffer = (unsigned long *)new_buffer;

		r = labellist_getnamelist(labels, buffer, buffer_length);
		if (r == idn_success)
			break;
		else if (r != idn_buffer_overflow)
			goto ret;

		buffer_length *= 2;
	}

	if (actions & IDN_LOCALCONV) {
		r = idn_converter_convfromucs4(local_converter, buffer, to,
					       tolen);
	} else {
		r = idn_ucs4_ucs4toutf8(buffer, to, tolen);
	}

ret:
	if (r == idn_success) {
		TRACE(("idn_res_decodename(): success (to=\"%s\")\n",
		       idn__debug_xstring(to, 50)));
	} else {
		TRACE(("idn_res_decodename(): %s\n", idn_result_tostring(r)));
	}
	free(saved_name);
	free(buffer);
	if (local_converter != NULL)
		idn_converter_destroy(local_converter);
	if (idn_converter != NULL)
		idn_converter_destroy(idn_converter);
	if (labels != NULL)
		labellist_destroy(labels);
	return (r);
}
Exemple #6
0
static idn_result_t
label_idnencode_ace(idn_resconf_t ctx, labellist_t label) {
	idn_converter_t idn_converter = NULL;
	const unsigned long *from;
	char *ascii_to = NULL;
	unsigned long *to = NULL;
	size_t to_length;
	idn_result_t r;

	from = labellist_getname(label);
	TRACE(("res ucs4toidn(label=\"%s\")\n",
	       idn__debug_ucs4xstring(from, 50)));

	idn_converter = idn_resconf_getidnconverter(ctx);
	if (idn_converter == NULL) {
		r = idn_success;
		goto ret;
	}

	ascii_to = NULL;
	to_length = idn_ucs4_strlen(from) * 4 + 16;  /* add mergin */

	for (;;) {
		char *new_buffer;

		new_buffer = (char *) realloc(ascii_to, to_length);
		if (new_buffer == NULL) {
			r = idn_nomemory;
			goto ret;
		}
		ascii_to = new_buffer;
		r = idn_converter_convfromucs4(idn_converter, from, ascii_to,
					       to_length);
		if (r == idn_success)
			break;
		else if (r != idn_buffer_overflow)
			goto ret;
		to_length *= 2;
	}

	for (;;) {
		unsigned long *new_buffer;

		new_buffer = (unsigned long *)
			     realloc(to, sizeof(long) * to_length);
		if (new_buffer == NULL) {
			r = idn_nomemory;
			goto ret;
		}
		to = new_buffer;
		r = idn_ucs4_utf8toucs4(ascii_to, to, to_length);
		if (r == idn_success)
			break;
		else if (r != idn_buffer_overflow)
			goto ret;
		to_length *= 2;
	}

	if (r != idn_success)
		goto ret;

	r = labellist_setname(label, to);
ret:
	if (r == idn_success) {
		TRACE(("res ucs4toidn(): success (label=\"%s\")\n",
		       idn__debug_ucs4xstring(labellist_getname(label),
					      50)));
	} else {
		TRACE(("res ucs4toidn(): %s\n", idn_result_tostring(r)));
	}
	if (idn_converter != NULL)
		idn_converter_destroy(idn_converter);
	free(to);
	free(ascii_to);
	return (r);
}