void idn_testsuite_assertucs4string(idn_testsuite_t ctx, const unsigned long *gotten, const unsigned long *expected, const char *file, int lineno) { char *expected_hex = NULL; char *gotten_hex = NULL; char *msg; assert(ctx != NULL && gotten != NULL && expected != NULL && file != NULL); if (idn_testsuite_getstatus(ctx) != idn_teststatus_pass) return; if (idn_ucs4_strcmp(expected, gotten) == 0) return; idn_testsuite_setstatus(ctx, idn_teststatus_fail); msg = (char *)malloc(idn_ucs4_strlen(expected) * 8 + idn_ucs4_strlen(gotten) * 8 + 32); expected_hex = make_hex_ucs4string(expected); gotten_hex = make_hex_ucs4string(gotten); if (msg == NULL || expected_hex == NULL || gotten_hex == NULL) { msg = ""; } else { sprintf(msg, "`%s' expected, but got `%s'", expected_hex, gotten_hex); } put_failure_message(ctx, msg, file, lineno); free(msg); free(expected_hex); free(gotten_hex); }
static void labellist_undo(labellist_t label) { size_t length; length = idn_ucs4_strlen(label->undo_name) + 1; memcpy(label->name, label->undo_name, sizeof(long) * length); }
static idn_result_t label_localmap(idn_resconf_t ctx, labellist_t label) { const unsigned long *from; const unsigned long *tld; unsigned long *to = NULL; size_t to_length; idn_mapselector_t local_mapper; idn_result_t r; from = labellist_getname(label); tld = labellist_gettldname(label); TRACE(("res localmap(label=\"%s\", tld=\"%s\")\n", idn__debug_ucs4xstring(from, 50), idn__debug_ucs4xstring(tld, 50))); local_mapper = idn_resconf_getlocalmapselector(ctx); if (local_mapper == NULL) { r = idn_success; goto ret; } if (tld == from) tld = idn_mapselector_getdefaulttld(); to_length = idn_ucs4_strlen(from) + 1 + 15; /* 15 for margin */ 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_mapselector_map2(local_mapper, from, tld, 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 localmap(): success (label=\"%s\")\n", idn__debug_ucs4xstring(labellist_getname(label), 50))); } else { TRACE(("res localmap(): %s\n", idn_result_tostring(r))); } if (local_mapper != NULL) idn_mapselector_destroy(local_mapper); free(to); return (r); }
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); }
unsigned long * idn_ucs4_strdup(const unsigned long *str) { size_t length = idn_ucs4_strlen(str); unsigned long *dupstr; dupstr = (unsigned long *)malloc(sizeof(*str) * (length + 1)); if (dupstr == NULL) return NULL; memcpy(dupstr, str, sizeof(*str) * (length + 1)); return dupstr; }
static idn_result_t label_normalize(idn_resconf_t ctx, labellist_t label) { const unsigned long *from; unsigned long *to = NULL; size_t to_length; idn_normalizer_t normalizer; idn_result_t r; from = labellist_getname(label); TRACE(("res normalzie(label=\"%s\")\n", idn__debug_ucs4xstring(from, 50))); normalizer = idn_resconf_getnormalizer(ctx); if (normalizer == NULL) { r = idn_success; goto ret; } to_length = idn_ucs4_strlen(from) + 1 + 15; /* 15 for margin */ 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_normalizer_normalize(normalizer, 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 normalize(): success (label=\"%s\")\n", idn__debug_ucs4xstring(labellist_getname(label), 50))); } else { TRACE(("res normalize(): %s\n", idn_result_tostring(r))); } if (normalizer != NULL) idn_normalizer_destroy(normalizer); free(to); return (r); }
static idn_result_t label_localdecodecheck(idn_resconf_t ctx, labellist_t label) { idn_converter_t local_converter = NULL; const unsigned long *from; char *to = NULL; size_t to_length; idn_result_t r; from = labellist_getname(label); to_length = idn_ucs4_strlen(from) + 1 + 15; /* 15 for margin */ TRACE(("res ucs4tolocal_check(label=\"%s\")\n", idn__debug_ucs4xstring(from, 50))); local_converter = idn_resconf_getlocalconverter(ctx); if (local_converter == NULL) { r = idn_success; goto ret; } for (;;) { char *new_buffer; new_buffer = (char *)realloc(to, to_length); if (new_buffer == NULL) { r = idn_nomemory; goto ret; } to = new_buffer; r = idn_converter_convfromucs4(local_converter, from, to, to_length); if (r == idn_success) break; else if (r == idn_nomapping) { r = label_idnencode_ace(ctx, label); if (r != idn_success) goto ret; break; } else if (r != idn_buffer_overflow) { goto ret; } to_length *= 2; } r = idn_success; ret: TRACE(("res ucs4tolocal_check(): %s\n", idn_result_tostring(r))); if (local_converter != NULL) idn_converter_destroy(local_converter); free(to); return (r); }
static idn_result_t labellist_getnamelist(labellist_t label, unsigned long *name, size_t name_length) { static const unsigned long dot_string[] = {0x002e, 0x0000}; /* "." */ size_t length; labellist_t l; for (l = label, length = 0; l != NULL; l = l->next) length += idn_ucs4_strlen(l->name) + 1; /* name + `.' */ length++; /* for NUL */ if (name_length < length) return (idn_buffer_overflow); *name = '\0'; for (l = label; l != NULL; l = l->next) { idn_ucs4_strcat(name, l->name); name += idn_ucs4_strlen(name); if (l->dot_followed) idn_ucs4_strcat(name, dot_string); } return (idn_success); }
static idn_result_t labellist_setname(labellist_t label, const unsigned long *name) { unsigned long *new_name; size_t length, new_length; length = idn_ucs4_strlen(name) + 1; new_length = length + 15; /* add 15 for margin */ if (label->name_length < new_length) { new_name = (unsigned long *) realloc(label->name, sizeof(long) * new_length); if (new_name == NULL) return (idn_nomemory); label->name = new_name; label->name_length = new_length; } memcpy(label->name, name, sizeof(long) * length); return (idn_success); }
static idn_result_t label_lencheck_ace(idn_resconf_t ctx, labellist_t label) { const unsigned long *name; size_t name_length; idn_result_t r; name = labellist_getname(label); name_length = idn_ucs4_strlen(name); TRACE(("res lencheck(label=\"%s\")\n", idn__debug_ucs4xstring(name, 50))); if (name_length == 0 || name_length > MAX_LABEL_LENGTH) { r = idn_invalid_length; goto ret; } r = idn_success; ret: TRACE(("res lencheck(): %s\n", idn_result_tostring(r))); return (r); }
static char * make_hex_ucs4string(const unsigned long *string) { static const char hex[] = {"0123456789abcdef"}; char *hex_string; const unsigned long *src; char *dst; hex_string = (char *)malloc((idn_ucs4_strlen(string)) * 8 + 1); if (hex_string == NULL) return NULL; for (src = string, dst = hex_string; *src != '\0'; src++) { if (0x20 <= *src && *src <= 0x7e && *src != '\\') { *dst++ = *src; } else if (*src <= UCS4_MAX) { *dst++ = '\\'; *dst++ = 'u'; if (*src >= 0x100000) { *dst++ = hex[(*src >> 20) & 0x0f]; } if (*src >= 0x10000) { *dst++ = hex[(*src >> 16) & 0x0f]; }
idn_result_t idn_normalizer_normalize(idn_normalizer_t ctx, const unsigned long *from, unsigned long *to, size_t tolen) { idn_result_t r; unsigned long *src, *dst; unsigned long *buffers[2] = {NULL, NULL}; size_t buflen[2] = {0, 0}; size_t dstlen; int idx; int i; assert(scheme_hash != NULL); assert(ctx != NULL && from != NULL && to != NULL); TRACE(("idn_normalizer_normalize(from=\"%s\", tolen=%d)\n", idn__debug_ucs4xstring(from, 50), (int)tolen)); if (ctx->nschemes <= 0) { if (tolen < idn_ucs4_strlen(from) + 1) { r = idn_buffer_overflow; goto ret; } idn_ucs4_strcpy(to, from); r = idn_success; goto ret; } /* * Normalize. */ src = (void *)from; dstlen = idn_ucs4_strlen(from) + 1; i = 0; while (i < ctx->nschemes) { TRACE(("idn_normalizer_normalize(): normalize %s\n", ctx->schemes[i]->name)); /* * Choose destination area to restore the result of a mapping. */ if (i + 1 == ctx->nschemes) { dst = to; dstlen = tolen; } else { if (src == buffers[0]) idx = 1; else idx = 0; if (buflen[idx] < dstlen) { void *newbuf; newbuf = realloc(buffers[idx], sizeof(long) * dstlen); if (newbuf == NULL) { r = idn_nomemory; goto ret; } buffers[idx] = (unsigned long *)newbuf; buflen[idx] = dstlen; } dst = buffers[idx]; dstlen = buflen[idx]; } /* * Perform i-th normalization scheme. * If buffer size is not enough, we double it and try again. */ r = (ctx->schemes[i]->proc)(src, dst, dstlen); if (r == idn_buffer_overflow && dst != to) { dstlen *= 2; continue; } if (r != idn_success) goto ret; src = dst; i++; } r = idn_success; ret: free(buffers[0]); free(buffers[1]); if (r == idn_success) { TRACE(("idn_normalizer_normalize(): success (to=\"%s\")\n", idn__debug_ucs4xstring(to, 50))); } else { TRACE(("idn_normalizer_normalize(): %s\n", idn_result_tostring(r))); } return (r); }
static idn_result_t roundtrip_check(idn_converter_t ctx, const unsigned long *from, const char *to) { /* * One problem with iconv() convertion is that * iconv() doesn't signal an error if the input * string contains characters which are valid but * do not have mapping to the output codeset. * (the behavior of iconv() for that case is defined as * `implementation dependent') * One way to check this case is to perform round-trip * conversion and see if it is same as the original string. */ idn_result_t r; unsigned long *back; unsigned long backbuf[256]; size_t fromlen; size_t backlen; TRACE(("idn_converter_convert: round-trip checking (from=\"%s\")\n", idn__debug_ucs4xstring(from, 50))); /* Allocate enough buffer. */ fromlen = idn_ucs4_strlen(from) + 1; if (fromlen * sizeof(*back) <= sizeof(backbuf)) { backlen = sizeof(backbuf); back = backbuf; } else { backlen = fromlen; back = (unsigned long *)malloc(backlen * sizeof(*back)); if (back == NULL) return (idn_nomemory); } /* * Perform backward conversion. */ r = idn_converter_convtoucs4(ctx, to, back, backlen); switch (r) { case idn_success: if (memcmp(back, from, sizeof(*from) * fromlen) != 0) r = idn_nomapping; break; case idn_invalid_encoding: case idn_buffer_overflow: r = idn_nomapping; break; default: break; } if (back != backbuf) free(back); if (r != idn_success) { TRACE(("round-trip check failed: %s\n", idn_result_tostring(r))); } return (r); }
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); }
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); }