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); }
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); }