static idn_result_t converter_none_convfromucs4(idn_converter_t ctx, void *privdata, const unsigned long *from, char *to, size_t tolen) { assert(ctx != NULL && from != NULL && to != NULL); return idn_ucs4_ucs4toutf8(from, to, tolen); }
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); }
static idn_result_t converter_iconv_convfromucs4(idn_converter_t ctx, void *privdata, const unsigned long *from, char *to, size_t tolen) { iconv_t ictx; char *utf8 = NULL; size_t utf8size = 256; /* large enough */ idn_result_t r; size_t sz; size_t inleft; size_t outleft; char *inbuf, *outbuf; assert(ctx != NULL && from != NULL && to != NULL); if (tolen <= 0) { r = idn_buffer_overflow; /* need space for NUL */ goto ret; } /* * UCS4 -> UTF-8 conversion. */ utf8 = (char *)malloc(utf8size); if (utf8 == NULL) { r = idn_nomemory; goto ret; } try_again: r = idn_ucs4_ucs4toutf8(from, utf8, utf8size); if (r == idn_buffer_overflow) { char *new_utf8; utf8size *= 2; new_utf8 = (char *)realloc(utf8, utf8size); if (new_utf8 == NULL) { r = idn_nomemory; goto ret; } utf8 = new_utf8; goto try_again; } else if (r != idn_success) { goto ret; } ictx = ((iconv_t *)privdata)[0]; /* * Reset internal state. * * The following code should work according to the SUSv2 spec, * but causes segmentation fault with Solaris 2.6. * So.. a work-around. * * (void)iconv(ictx, (const char **)NULL, (size_t *)NULL, * (char **)NULL, (size_t *)NULL); */ inleft = 0; outbuf = NULL; outleft = 0; (void)iconv(ictx, (const char **)NULL, &inleft, &outbuf, &outleft); inleft = strlen(utf8); inbuf = utf8; outleft = tolen - 1; /* reserve space for terminating NUL */ sz = iconv(ictx, (const char **)&inbuf, &inleft, &to, &outleft); if (sz == (size_t)(-1) || inleft > 0) { switch (errno) { case EILSEQ: case EINVAL: /* * We already checked the validity of the input * string. So we assume a mapping error. */ r = idn_nomapping; goto ret; case E2BIG: r = idn_buffer_overflow; goto ret; default: WARNING(("iconv failed with errno %d\n", errno)); r = idn_failure; goto ret; } } /* * For UTF-8 -> local conversion, append a sequence of * state reset. */ inleft = 0; sz = iconv(ictx, (const char **)NULL, &inleft, &to, &outleft); if (sz == (size_t)(-1)) { switch (errno) { case EILSEQ: case EINVAL: r = idn_invalid_encoding; goto ret; case E2BIG: r = idn_buffer_overflow; goto ret; default: WARNING(("iconv failed with errno %d\n", errno)); r = idn_failure; goto ret; } } *to = '\0'; r = idn_success; ret: free(utf8); 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_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); }
static idn_result_t label_idndecode(idn_resconf_t ctx, labellist_t label) { idn_converter_t idn_converter = NULL; const unsigned long *from; char *ascii_from = NULL; unsigned long *to = NULL; size_t from_length, to_length; idn_result_t r; from = labellist_getname(label); from_length = idn_ucs4_strlen(from) + 1; TRACE(("res idntoucs4(label=\"%s\")\n", idn__debug_ucs4xstring(from, 50))); idn_converter = idn_resconf_getidnconverter(ctx); if (idn_converter == NULL) { r = idn_success; goto ret; } for (;;) { char *new_buffer; new_buffer = (char *) realloc(ascii_from, from_length); if (new_buffer == NULL) { r = idn_nomemory; goto ret; } ascii_from = new_buffer; r = idn_ucs4_ucs4toutf8(from, ascii_from, from_length); if (r == idn_success) break; else if (r != idn_buffer_overflow) goto ret; from_length *= 2; } to = NULL; to_length = from_length; 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_converter_convtoucs4(idn_converter, ascii_from, to, to_length); if (r == idn_success) break; else if (r != idn_buffer_overflow) goto ret; to_length *= 2; } r = labellist_setname(label, to); ret: if (r == idn_success) { TRACE(("res idntoucs4(): success (label=\"%s\")\n", idn__debug_ucs4xstring(labellist_getname(label), 50))); } else { TRACE(("res idntoucs4(): %s\n", idn_result_tostring(r))); } if (idn_converter != NULL) idn_converter_destroy(idn_converter); free(to); free(ascii_from); 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); }