idn_result_t idn_decodename2(idn_action_t actions, const char *from, char *to, size_t tolen, const char *auxencoding) { idn_result_t r; assert(from != NULL && to != NULL); TRACE(("idn_decodename2(actions=%s, from=\"%s\", tolen=%d)\n", idn__res_actionstostring(actions), idn__debug_xstring(from, 50), (int)tolen)); if (!initialized && ((r = idn_nameinit(0)) != idn_success)) goto ret; r = idn_res_decodename2(default_conf, actions, from, to, tolen, auxencoding); ret: if (r == idn_success) { TRACE(("idn_decodename2(): success (to=\"%s\")\n", idn__debug_xstring(to, 50))); } else { TRACE(("idn_decodename2(): %s\n", idn_result_tostring(r))); } return (r); }
/* * Add an alias to 'ctx'. */ idn_result_t idn__langalias_add(idn__langalias_t ctx, const char *alias_name, const char *real_name) { idn_result_t r = idn_success; idn__langalias_entry_t new_entry = NULL; assert(ctx != NULL && alias_name != NULL && real_name != NULL); TRACE(("idn__langalias_add(alias=\"%s\", real=\"%s\")\n", idn__debug_xstring(alias_name), idn__debug_xstring(real_name))); new_entry = (idn__langalias_entry_t)malloc(sizeof(*new_entry)); if (new_entry == NULL) { r = idn_nomemory; goto ret; } new_entry->alias_name = NULL; new_entry->real_name = NULL; new_entry->next = NULL; new_entry->alias_name = idn__util_strdup(alias_name); if (new_entry->alias_name == NULL) { r = idn_nomemory; goto ret; } idn__util_asclower(new_entry->alias_name); new_entry->real_name = idn__util_strdup(real_name); if (new_entry->real_name == NULL) { r = idn_nomemory; goto ret; } idn__util_asclower(new_entry->real_name); r = idn__strhash8_put(ctx->hash, new_entry->alias_name, new_entry->real_name); if (r != idn_success) goto ret; if (ctx->entries_head == NULL) { ctx->entries_head = new_entry; ctx->entries_tail = new_entry; } else { ctx->entries_tail->next = new_entry; ctx->entries_tail = new_entry; } ret: TRACE(("idn__langalias_add(): %s\n", idn_result_tostring(r))); if (r != idn_success) { if (new_entry != NULL) { free(new_entry->alias_name); free(new_entry->real_name); free(new_entry); } } return (r); }
idn_result_t idn_converter_convtoucs4(idn_converter_t ctx, const char *from, unsigned long *to, size_t tolen) { idn_result_t r; assert(ctx != NULL && from != NULL && to != NULL); TRACE(("idn_converter_convtoucs4(ctx=%s, from=\"%s\", tolen=%d)\n", ctx->local_encoding_name, idn__debug_xstring(from, 50), (int)tolen)); if (!ctx->opened_convtoucs4) { r = (*ctx->ops->opentoucs4)(ctx, &(ctx->private_data)); if (r != idn_success) goto ret; ctx->opened_convtoucs4 = 1; } r = (*ctx->ops->convtoucs4)(ctx, ctx->private_data, from, to, tolen); ret: if (r == idn_success) { TRACE(("idn_converter_convtoucs4(): success (to=\"%s\")\n", idn__debug_ucs4xstring(to, 50))); } else { TRACE(("idn_converter_convtoucs4(): %s\n", idn_result_tostring(r))); } return (r); }
/* * Find a real name for 'alias_name'. */ const char * idn__langalias_find(idn__langalias_t ctx, const char *alias_name) { const char *real_name; const char *result; assert(ctx != NULL && alias_name != NULL); TRACE(("idn__langalias_find(alias=\"%s\")\n", idn__debug_xstring(alias_name))); real_name = idn__strhash8_get(ctx->hash, alias_name); result = (real_name != NULL) ? real_name : alias_name; TRACE(("idn__langalias_find(): success (real=\"%s\")\n", idn__debug_xstring(result))); return (result); }
idn_result_t mdn_decodename(int actions, const char *from, char *to, size_t tolen) { idn_result_t r; assert(from != NULL && to != NULL); TRACE(("idn_decodename(actions=%s, from=\"%s\", tolen=%d)\n", idn__res_actionstostring(actions), idn__debug_xstring(from, 50), (int)tolen)); if (!initialized && ((r = idn_nameinit(1)) != idn_success)) return (r); return (idn_res_decodename(default_conf, actions, from, to, tolen)); }
idn_result_t idn_selectiveencode_findregion(const char *s, char **startp, char **endp) { char *non_ascii; char *start, *end; assert(s != NULL && startp != NULL && endp != NULL); TRACE(("idn_selectiveencode_findregion(s=\"%s\")\n", idn__debug_xstring(s, 20))); /* * Scan the specified string looking for non-ascii character. */ if ((non_ascii = find_nonascii(s)) == NULL) return (idn_notfound); /* * Non-ascii character found. * Determine the region to encode. */ /* * First, we scan backwards to find the beginning of the region * that should be converted. */ start = non_ascii; while (start > s) { char *prev = idn_utf8_findfirstbyte(start - 1, s); if (is_domain_delimiter(*prev)) break; /* Found */ start = prev; } *startp = start; /* * Next we scan forwards looking for the end of the region. */ end = non_ascii + idn_utf8_mblen(non_ascii); while (!is_domain_delimiter(*end)) end += idn_utf8_mblen(end); *endp = end; return (idn_success); }
/* * Set the local encoding to 'name'. */ void idn__localencoding_setname(idn__localencoding_t ctx, const char *name) { idn_result_t r = idn_success; assert(ctx != NULL); TRACE(("idn__localencoding_setname(name=\"%s\")\n", idn__debug_xstring(name))); if (name == NULL) ctx->is_static = 0; else { idn__util_strcpy(ctx->name, sizeof(ctx->name), idn__encodingalias_find(aliases, name)); ctx->is_static = 1; } TRACE(("idn__localencoding_setname(): %s\n", idn_result_tostring(r))); }
const char * idn__localencoding_getname(idn__localencoding_t ctx) { const char *key = NULL; #ifdef WIN32 char cp_str[40]; /* enough */ #endif assert(ctx != NULL); TRACE(("idn__localencoding_getname()\n")); if (!ctx->is_static) { key = getenv(IDN_LOCALCS_ENV); #ifdef WIN32 if (key == NULL) { sprintf(cp_str, "CP%u", GetACP()); key = cp_str; } #endif #if defined(HAVE_NL_LANGINFO) && defined(CODESET) if (key == NULL) key = nl_langinfo(CODESET); #endif #ifdef HAVE_SETLOCALE if (key == NULL) key = setlocale(LC_CTYPE, NULL); #endif if (key == NULL) key = getenv("LC_ALL"); if (key == NULL) key = getenv("LC_CTYPE"); if (key == NULL) key = getenv("LANG"); if (key == NULL) key = getenv("LANG"); if (key == NULL) key = IDN__UTF8_ENCODINGNAME; idn__util_strcpy(ctx->name, sizeof(ctx->name), idn__encodingalias_find(aliases, key)); } TRACE(("idn__localencoding_getname(): success " "(name=\"%s\")\n", idn__debug_xstring(ctx->name))); return (ctx->name); }
/* * Perform UTF32 to UTF-8 to conversion. */ idn_result_t idn__res_utf32toutf8(idn_resconf_t ctx, const unsigned long *from, char **to) { idn_result_t r = idn_success; size_t tolen = 0; assert(ctx != NULL && from != NULL && to != NULL); TRACE(("idn__res_utf32toutf8(label=\"%s\")\n", idn__debug_utf32xstring(from))); *to = NULL; tolen = 256; /* may be large enough. */ for (;;) { void *new_to; new_to = realloc(*to, sizeof(**to) * tolen); if (new_to == NULL) { r = idn_nomemory; goto ret; } *to = (char *)new_to; r = idn__utf32_toutf8(from, *to, tolen); if (r == idn_success) break; else if (r != idn_buffer_overflow) goto ret; tolen *= 2; } ret: if (r == idn_success) { TRACE(("idn__res_utf32toutf8(): success (to=\"%s\")\n", idn__debug_xstring(*to))); } else { TRACE(("idn__res_utf32toutf8(): %s\n", idn_result_tostring(r))); free(*to); *to = NULL; } return (r); }
/* * Read an alias definition file and add aliases in it to 'ctx'. */ idn_result_t idn__langalias_addfromfile(idn__langalias_t ctx, const char *file) { idn_result_t r = idn_success; FILE *fp = NULL; int line_no; char line[200], alias[200], real[200]; assert(ctx != NULL && file != NULL); TRACE(("idn__langalias_addfromfile(file=\"%s\")\n", idn__debug_xstring(file))); fp = fopen(file, "r"); if (fp == NULL) { r = idn_nofile; goto ret; } for (line_no = 1; fgets(line, sizeof(line), fp) != NULL; line_no++) { unsigned char *p = (unsigned char *)line; while (isascii(*p) && isspace(*p)) p++; if (*p == '#' || *p == '\n' || *p == '\0') continue; if (sscanf((char *)p, "%s %s", alias, real) == 2) { r = idn__langalias_add(ctx, alias, real); if (r != idn_success) break; } else { INFO(("idn__langalias_addfromfile: syntax error, " "line %d\n",line_no)); r = idn_invalid_syntax; break; } } ret: TRACE(("idn__langalias_addfromfile(): %s\n", idn_result_tostring(r))); return (r); }
idn_result_t idn_converter_convfromucs4(idn_converter_t ctx, const unsigned long *from, char *to, size_t tolen) { idn_result_t r; assert(ctx != NULL && from != NULL && to != NULL); TRACE(("idn_converter_convfromucs4(ctx=%s, from=\"%s\", tolen=%d)\n", ctx->local_encoding_name, idn__debug_ucs4xstring(from, 50), (int)tolen)); if (!ctx->opened_convfromucs4) { r = (*ctx->ops->openfromucs4)(ctx, &(ctx->private_data)); if (r != idn_success) goto ret; ctx->opened_convfromucs4 = 1; } r = (*ctx->ops->convfromucs4)(ctx, ctx->private_data, from, to, tolen); if (r != idn_success) goto ret; if ((ctx->flags & IDN_CONVERTER_RTCHECK) != 0) { r = roundtrip_check(ctx, from, to); if (r != idn_success) goto ret; } r = idn_success; ret: if (r == idn_success) { TRACE(("idn_converter_convfromucs4(): success (to=\"%s\")\n", idn__debug_xstring(to, 50))); } else { TRACE(("idn_converter_convfromucs4(): %s\n", idn_result_tostring(r))); } return (r); }
idn_result_t idn_ucs4_ucs4toutf8(const unsigned long *ucs4, char *utf8, size_t tolen) { unsigned char *utf8p = (unsigned char *)utf8; unsigned long v; int width; int mask; int offset; idn_result_t r; TRACE(("idn_ucs4_ucs4toutf8(ucs4=\"%s\", tolen=%d)\n", idn__debug_ucs4xstring(ucs4, 50), (int)tolen)); while (*ucs4 != '\0') { v = *ucs4++; if (IS_SURROGATE_LOW(v) || IS_SURROGATE_HIGH(v)) { WARNING(("idn_ucs4_ucs4toutf8: UCS4 string contains " "surrogate pair\n")); r = idn_invalid_encoding; goto ret; } if (v < 0x80) { mask = 0; width = 1; } else if (v < 0x800) { mask = 0xc0; width = 2; } else if (v < 0x10000) { mask = 0xe0; width = 3; } else if (v < 0x200000) { mask = 0xf0; width = 4; } else if (v < 0x4000000) { mask = 0xf8; width = 5; } else if (v < 0x80000000) { mask = 0xfc; width = 6; } else { WARNING(("idn_ucs4_ucs4toutf8: invalid character\n")); r = idn_invalid_encoding; goto ret; } if (tolen < width) { r = idn_buffer_overflow; goto ret; } offset = 6 * (width - 1); *utf8p++ = (v >> offset) | mask; mask = 0x80; while (offset > 0) { offset -= 6; *utf8p++ = ((v >> offset) & 0x3f) | mask; } tolen -= width; } if (tolen < 1) { r = idn_buffer_overflow; goto ret; } *utf8p = '\0'; r = idn_success; ret: if (r == idn_success) { TRACE(("idn_ucs4_ucs4toutf8(): success (utf8=\"%s\")\n", idn__debug_xstring(utf8, 50))); } else { TRACE(("idn_ucs4_ucs4toutf8(): %s\n", idn_result_tostring(r))); } return (r); }
idn_result_t idn_ucs4_utf8toucs4(const char *utf8, unsigned long *ucs4, size_t tolen) { const unsigned char *utf8p = (const unsigned char *)utf8; unsigned long *ucs4p = ucs4; unsigned long v, min; unsigned char c; int width; int i; idn_result_t r; TRACE(("idn_ucs4_utf8toucs4(utf8=\"%s\", tolen=%d)\n", idn__debug_xstring(utf8, 50), (int)tolen)); while(*utf8p != '\0') { c = *utf8p++; if (c < 0x80) { v = c; min = 0; width = 1; } else if (c < 0xc0) { WARNING(("idn_ucs4_utf8toucs4: invalid character\n")); r = idn_invalid_encoding; goto ret; } else if (c < 0xe0) { v = c & 0x1f; min = 0x80; width = 2; } else if (c < 0xf0) { v = c & 0x0f; min = 0x800; width = 3; } else if (c < 0xf8) { v = c & 0x07; min = 0x10000; width = 4; } else if (c < 0xfc) { v = c & 0x03; min = 0x200000; width = 5; } else if (c < 0xfe) { v = c & 0x01; min = 0x4000000; width = 6; } else { WARNING(("idn_ucs4_utf8toucs4: invalid character\n")); r = idn_invalid_encoding; goto ret; } for (i = width - 1; i > 0; i--) { c = *utf8p++; if (c < 0x80 || 0xc0 <= c) { WARNING(("idn_ucs4_utf8toucs4: " "invalid character\n")); r = idn_invalid_encoding; goto ret; } v = (v << 6) | (c & 0x3f); } if (v < min) { WARNING(("idn_ucs4_utf8toucs4: invalid character\n")); r = idn_invalid_encoding; goto ret; } if (IS_SURROGATE_LOW(v) || IS_SURROGATE_HIGH(v)) { WARNING(("idn_ucs4_utf8toucs4: UTF-8 string contains " "surrogate pair\n")); r = idn_invalid_encoding; goto ret; } if (tolen < 1) { r = idn_buffer_overflow; goto ret; } tolen--; *ucs4p++ = v; } if (tolen < 1) { r = idn_buffer_overflow; goto ret; } *ucs4p = '\0'; r = idn_success; ret: if (r == idn_success) { TRACE(("idn_ucs4_utf8toucs4(): success (ucs4=\"%s\")\n", idn__debug_ucs4xstring(ucs4, 50))); } else { TRACE(("idn_ucs4_utf8toucs4(): %s\n", idn_result_tostring(r))); } return (r); }
idn_result_t idn__punycode_decode(idn_converter_t ctx, void *privdata, const char *from, unsigned long *to, size_t tolen) { unsigned long *to_org = to; unsigned long c, idx; size_t prefixlen = strlen(IDN_PUNYCODE_PREFIX); size_t fromlen; size_t uidx, fidx, ucslen; int first, bias; idn_result_t r; assert(ctx != NULL); TRACE(("idn__punycode_decode(from=\"%s\", tolen=%d)\n", idn__debug_xstring(from, 50), (int)tolen)); if (!idn__util_asciihaveaceprefix(from, IDN_PUNYCODE_PREFIX)) { if (*from == '\0') { r = idn_ucs4_utf8toucs4(from, to, tolen); goto ret; } r = idn_invalid_encoding; goto ret; } from += prefixlen; fromlen = strlen(from); /* * Find the last delimiter, and copy the characters * before it verbatim. */ ucslen = 0; for (fidx = fromlen; fidx > 0; fidx--) { if (from[fidx - 1] == '-') { if (tolen < fidx) { r = idn_buffer_overflow; goto ret; } for (uidx = 0; uidx < fidx - 1; uidx++) { to[uidx] = from[uidx]; } ucslen = uidx; break; } } first = 1; bias = PUNYCODE_INITIAL_BIAS; c = PUNYCODE_INITIAL_N; idx = 0; while (fidx < fromlen) { int len; unsigned long delta; int i; len = punycode_getwc(from + fidx, fromlen - fidx, bias, &delta); if (len == 0) { r = idn_invalid_encoding; goto ret; } fidx += len; bias = punycode_update_bias(delta, ucslen + 1, first); first = 0; idx += delta; c += idx / (ucslen + 1); uidx = idx % (ucslen + 1); /* Insert 'c' at uidx. */ if (tolen-- <= 0) { r = idn_buffer_overflow; goto ret; } for (i = ucslen; i > uidx; i--) to[i] = to[i - 1]; to[uidx] = c; ucslen++; idx = uidx + 1; } /* Terminate with NUL. */ if (tolen <= 0) { r = idn_buffer_overflow; goto ret; } to[ucslen] = '\0'; r = idn_success; ret: if (r == idn_success) { TRACE(("idn__punycode_decode(): succcess (to=\"%s\")\n", idn__debug_ucs4xstring(to_org, 50))); } else { TRACE(("idn__punycode_decode(): %s\n", idn_result_tostring(r))); } return (r); }
idn_result_t idn_checker_add(idn_checker_t ctx, const char *scheme_name) { idn_result_t r; check_scheme_t *scheme; const char *scheme_prefix; const char *scheme_parameter; void *scheme_context = NULL; char *buffer = NULL; assert(scheme_hash != NULL); assert(ctx != NULL); TRACE(("idn_checker_add(scheme_name=%s)\n", idn__debug_xstring(scheme_name, 50))); /* * Split `scheme_name' into `scheme_prefix' and `scheme_parameter'. */ scheme_parameter = strchr(scheme_name, ':'); if (scheme_parameter == NULL) { scheme_prefix = scheme_name; scheme_parameter = NULL; } else { ptrdiff_t scheme_prefixlen; scheme_prefixlen = scheme_parameter - scheme_name; buffer = (char *) malloc(scheme_prefixlen + 1); if (buffer == NULL) { r = idn_nomemory; goto ret; } memcpy(buffer, scheme_name, scheme_prefixlen); *(buffer + scheme_prefixlen) = '\0'; scheme_prefix = buffer; scheme_parameter++; } /* * Find a scheme. */ if (idn__strhash_get(scheme_hash, scheme_prefix, (void **)&scheme) != idn_success) { ERROR(("idn_checker_add(): invalid scheme \"%-.30s\"\n", scheme_name)); r = idn_invalid_name; goto ret; } if (scheme_parameter == NULL && scheme->parameter != NULL) scheme_parameter = scheme->parameter; /* * Add the scheme. */ assert(ctx->nschemes <= ctx->scheme_size); if (ctx->nschemes == ctx->scheme_size) { check_scheme_t *new_schemes; new_schemes = (check_scheme_t *) realloc(ctx->schemes, sizeof(check_scheme_t) * ctx->scheme_size * 2); if (new_schemes == NULL) { r = idn_nomemory; goto ret; } ctx->schemes = new_schemes; ctx->scheme_size *= 2; } r = scheme->create(scheme_parameter, &scheme_context); if (r != idn_success) goto ret; memcpy(ctx->schemes + ctx->nschemes, scheme, sizeof(check_scheme_t)); ctx->schemes[ctx->nschemes].context = scheme_context; ctx->nschemes++; r = idn_success; ret: free(buffer); if (r != idn_success) free(scheme_context); TRACE(("idn_checker_add(): %s\n", idn_result_tostring(r))); return (r); }
idn_result_t idn__punycode_encode(idn_converter_t ctx, void *privdata, const unsigned long *from, char *to, size_t tolen) { char *to_org = to; unsigned long cur_code, next_code, delta; size_t prefixlen = strlen(IDN_PUNYCODE_PREFIX); size_t fromlen; size_t ucsdone; size_t toidx; int uidx, bias, first; idn_result_t r; assert(ctx != NULL); TRACE(("idn__punycode_encode(from=\"%s\", tolen=%d)\n", idn__debug_ucs4xstring(from, 50), (int)tolen)); if (*from == '\0') { r = idn_ucs4_ucs4toutf8(from, to, tolen); goto ret; } else if (idn__util_ucs4haveaceprefix(from, IDN_PUNYCODE_PREFIX)) { r = idn_prohibited; goto ret; } if (tolen < prefixlen) { r = idn_buffer_overflow; goto ret; } memcpy(to, IDN_PUNYCODE_PREFIX, prefixlen); to += prefixlen; tolen -= prefixlen; fromlen = idn_ucs4_strlen(from); /* * If the input string is too long (actually too long to be sane), * return failure in order to prevent possible overflow. */ if (fromlen > PUNYCODE_MAXINPUT) { ERROR(("idn__punycode_encode(): " "the input string is too long to convert Punycode\n", idn__debug_ucs4xstring(from, 50))); r = idn_failure; goto ret; } ucsdone = 0; /* number of characters processed */ toidx = 0; /* * First, pick up basic code points and copy them to 'to'. */ for (uidx = 0; uidx < fromlen; uidx++) { if (from[uidx] < 0x80) { if (toidx >= tolen) { r = idn_buffer_overflow; goto ret; } to[toidx++] = from[uidx]; ucsdone++; } } /* * If there are any basic code points, output a delimiter * (hyphen-minus). */ if (toidx > 0) { if (toidx >= tolen) { r = idn_buffer_overflow; goto ret; } to[toidx++] = '-'; to += toidx; tolen -= toidx; } /* * Then encode non-basic characters. */ first = 1; cur_code = PUNYCODE_INITIAL_N; bias = PUNYCODE_INITIAL_BIAS; delta = 0; while (ucsdone < fromlen) { int limit = -1, rest; /* * Find the smallest code point equal to or greater * than 'cur_code'. Also remember the index of the * last occurence of the code point. */ for (next_code = MAX_UCS, uidx = fromlen - 1; uidx >= 0; uidx--) { if (from[uidx] >= cur_code && from[uidx] < next_code) { next_code = from[uidx]; limit = uidx; } } /* There must be such code point. */ assert(limit >= 0); delta += (next_code - cur_code) * (ucsdone + 1); cur_code = next_code; /* * Scan the input string again, and encode characters * whose code point is 'cur_code'. Use 'limit' to avoid * unnecessary scan. */ for (uidx = 0, rest = ucsdone; uidx <= limit; uidx++) { if (from[uidx] < cur_code) { delta++; rest--; } else if (from[uidx] == cur_code) { int sz = punycode_putwc(to, tolen, delta, bias); if (sz == 0) { r = idn_buffer_overflow; goto ret; } to += sz; tolen -= sz; ucsdone++; bias = punycode_update_bias(delta, ucsdone, first); delta = 0; first = 0; } } delta += rest + 1; cur_code++; } /* * Terminate with NUL. */ if (tolen <= 0) { r = idn_buffer_overflow; goto ret; } *to = '\0'; r = idn_success; ret: if (r == idn_success) { TRACE(("idn__punycode_encode(): succcess (to=\"%s\")\n", idn__debug_xstring(to_org, 50))); } else { TRACE(("idn__punycode_encode(): %s\n", idn_result_tostring(r))); } return (r); }
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); }
/* * Read a mapping definition file and add mappings in it to 'ctx'. */ idn_result_t idn__tldlocalmap_addfromfile(idn__tldlocalmap_t ctx, const char *tld, const char *file) { static const unsigned long default_map_tld[] = { '<', 'd', 'e', 'f', 'a', 'u', 'l', 't', '>', '\0' }; idn_result_t r = idn_success; unsigned long tld_utf32[IDN__TLDLOCALMAP_MAXTLDLENGTH + 1]; idn__tldlocalmap_entry_t new_entry = NULL; idn__foreignmap_t new_mapctx = NULL; assert(ctx != NULL && file != NULL); TRACE(("idn__tldlocalmap_addfromfile(tld=\"%s\", file=\"%s\")\n", idn__debug_xstring(tld), idn__debug_xstring(file))); if (tld != NULL && *tld == '.') tld++; if (tld != NULL && *tld == '\0') { r = idn_invalid_syntax; goto ret; } if (tld != NULL && strcmp(tld, "*") == 0) tld = NULL; new_entry = (idn__tldlocalmap_entry_t)malloc(sizeof(*new_entry)); if (new_entry == NULL) { r = idn_nomemory; goto ret; } new_entry->tld = NULL; new_entry->map = NULL; new_entry->next = NULL; r = idn__foreignmap_create(&new_mapctx); if (r != idn_success) goto ret; r = idn__foreignmap_addfromfile(new_mapctx, file); if (r != idn_success) goto ret; new_entry->map = new_mapctx; if (tld != NULL) { r = idn__utf32_fromutf8(tld, tld_utf32, IDN__TLDLOCALMAP_MAXTLDLENGTH + 1); if (r != idn_success) { r = idn_invalid_name; goto ret; } idn__utf32_asclower(tld_utf32); new_entry->tld = idn__utf32_strdup(tld_utf32); if (new_entry->tld == NULL) { r = idn_nomemory; goto ret; } r = idn__strhash32_put(ctx->hash, tld_utf32, new_entry); if (r != idn_success) goto ret; } else { new_entry->tld = idn__utf32_strdup(default_map_tld); if (new_entry->tld == NULL) { r = idn_nomemory; goto ret; } ctx->default_map = new_entry; } if (ctx->entries_head == NULL) { ctx->entries_head = new_entry; ctx->entries_tail = new_entry; } else { ctx->entries_tail->next = new_entry; ctx->entries_tail = new_entry; } ret: if (r == idn_success) { TRACE(("idn__tldlocalmap_addfromfile(): success " "(tld=\"%s\")\n", idn__debug_xstring(tld))); } else { TRACE(("idn__tldlocalmap_addfromfile(): %s\n", idn_result_tostring(r))); if (new_mapctx != NULL) idn__foreignmap_destroy(new_mapctx); if (new_entry != NULL) { free(new_entry->tld); free(new_entry); } } return (r); }
idn_result_t idn_res_decodename2(idn_resconf_t ctx, idn_action_t actions, const char *from, char *to, size_t tolen, const char *auxencoding) { #ifdef WITHOUT_ICONV return idn_failure; #else /* WITHOUT_ICONV */ idn_result_t r; idn_converter_t aux_converter = NULL; unsigned long *buffer_ucs4 = NULL; char *buffer_utf8 = NULL; size_t buffer_length; assert(ctx != NULL && from != NULL && to != NULL); TRACE(("idn_res_decodename2(actions=%s, from=\"%s\", tolen=%d, " "auxencoding=\"%s\")\n", idn__res_actionstostring(actions), idn__debug_xstring(from, 50), (int)tolen, (auxencoding != NULL) ? auxencoding : "<null>")); 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 (auxencoding == NULL || strcmp(auxencoding, IDN_UTF8_ENCODING_NAME) == 0 || strcmp(auxencoding, "UTF-8") == 0) { return idn_res_decodename(ctx, actions, from, to, tolen); } /* * Convert `from' to UCS4. */ r = idn_resconf_setauxidnconvertername(ctx, auxencoding, IDN_CONVERTER_DELAYEDOPEN); if (r != idn_success) { goto ret; } aux_converter = idn_resconf_getauxidnconverter(ctx); if (aux_converter == NULL) { r = idn_failure; goto ret; } buffer_length = tolen * 2; for (;;) { void *new_buffer; new_buffer = realloc(buffer_ucs4, sizeof(*buffer_ucs4) * buffer_length); if (new_buffer == NULL) { r = idn_nomemory; goto ret; } buffer_ucs4 = (unsigned long *)new_buffer; r = idn_converter_convtoucs4(aux_converter, from, buffer_ucs4, buffer_length); if (r == idn_success) break; else if (r != idn_buffer_overflow) goto ret; buffer_length *= 2; } if (*buffer_ucs4 == '\0') { if (tolen <= 0) { r = idn_buffer_overflow; goto ret; } *to = '\0'; r = idn_success; goto ret; } /* * Convert `buffer_ucs4' to UTF-8. */ buffer_length = tolen * 2; for (;;) { void *new_buffer; new_buffer = realloc(buffer_utf8, sizeof(*buffer_utf8) * buffer_length); if (new_buffer == NULL) { r = idn_nomemory; goto ret; } buffer_utf8 = (char *)new_buffer; r = idn_ucs4_ucs4toutf8(buffer_ucs4, buffer_utf8, buffer_length); if (r == idn_success) break; else if (r != idn_buffer_overflow) goto ret; buffer_length *= 2; } if (*buffer_utf8 == '\0') { if (tolen <= 0) { r = idn_buffer_overflow; goto ret; } *to = '\0'; r = idn_success; goto ret; } r = idn_res_decodename(ctx, actions, buffer_utf8, to, tolen); ret: if (r == idn_success) { TRACE(("idn_res_decodename2(): success (to=\"%s\")\n", idn__debug_xstring(to, 50))); } else { TRACE(("idn_res_decodename2(): %s\n", idn_result_tostring(r))); } free(buffer_ucs4); free(buffer_utf8); if (aux_converter != NULL) idn_converter_destroy(aux_converter); return (r); #endif /* WITHOUT_ICONV */ }
idn_result_t idn__race_decode(idn_converter_t ctx, void *privdata, const char *from, unsigned long *to, size_t tolen) { unsigned short *buf = NULL; size_t prefixlen = strlen(IDN_RACE_PREFIX); size_t fromlen; size_t buflen; idn_result_t r; assert(ctx != NULL); TRACE(("idn__race_decode(from=\"%s\", tolen=%d)\n", idn__debug_xstring(from, 50), (int)tolen)); if (!idn__util_asciihaveaceprefix(from, IDN_RACE_PREFIX)) { if (*from == '\0') { r = idn_ucs4_utf8toucs4(from, to, tolen); goto ret; } r = idn_invalid_encoding; goto ret; } from += prefixlen; fromlen = strlen(from); /* * Allocate sufficient buffer. */ buflen = fromlen + 1; buf = malloc(sizeof(*buf) * buflen); if (buf == NULL) { r = idn_nomemory; goto ret; } /* * Decode base32 and decompress. */ r = race_decode_decompress(from, buf, buflen); if (r != idn_success) goto ret; /* * Now 'buf' points the decompressed string, which must contain * UTF-16 characters. */ /* * Convert to UCS4. */ r = idn_ucs4_utf16toucs4(buf, to, tolen); if (r != idn_success) goto ret; ret: free(buf); if (r == idn_success) { TRACE(("idn__race_decode(): succcess (to=\"%s\")\n", idn__debug_ucs4xstring(to, 50))); } else { TRACE(("idn__race_decode(): %s\n", idn_result_tostring(r))); } return (r); }