idn_result_t idn_decodename(idn_action_t 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(0)) != idn_success)) goto ret; r = idn_res_decodename(default_conf, actions, from, to, tolen); ret: if (r == idn_success) { TRACE(("idn_decodename(): success (to=\"%s\")\n", idn__debug_xstring(to, 50))); } else { TRACE(("idn_decodename(): %s\n", idn_result_tostring(r))); } return (r); }
static idn_result_t parse_idn_encoding(idn_resconf_t ctx, char *args, int lineno) { idn_result_t r; char *argv[MAX_CONF_LINE_ARGS + 1]; int argc; argc = split_args(args, argv, MAX_CONF_LINE_ARGS + 1); if (argc != 1) { ERROR(("libidnkit: wrong # of args for idn-encoding, " "line %d\n", lineno)); return (idn_invalid_syntax); } r = idn_converter_create(argv[0], &ctx->idn_converter, IDN_CONVERTER_DELAYEDOPEN | IDN_CONVERTER_RTCHECK); if (r != idn_success) { ERROR(("libidnkit: cannot create idn converter, %s, " "line %d\n", idn_result_tostring(r), lineno)); } return (r); }
static idn_result_t label_asccheck(idn_resconf_t ctx, labellist_t label) { const unsigned long *name, *n; idn_result_t r; name = labellist_getname(label); TRACE(("res asccheck(label=\"%s\")\n", idn__debug_ucs4xstring(name, 50))); if (*name == '-') { r = idn_prohibited; goto ret; } for (n = name; *n != '\0'; n++) { if (*n <= '\177') { if ((*n < '0' || *n > '9') && (*n < 'A' || *n > 'Z') && (*n < 'a' || *n > 'z') && *n != '-') { r = idn_prohibited; goto ret; } } } if (n > name && *(n - 1) == '-') { r = idn_prohibited; goto ret; } r = idn_success; ret: TRACE(("res asccheck(): %s\n", idn_result_tostring(r))); return (r); }
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); }
idn_result_t idn_converter_create(const char *name, idn_converter_t *ctxp, int flags) { const char *realname; idn_converter_t ctx; idn_result_t r; void *v; assert(name != NULL && ctxp != NULL); TRACE(("idn_converter_create(%s)\n", name)); realname = idn_converter_getrealname(name); #ifdef DEBUG if (strcmp(name, realname) != 0) { TRACE(("idn_converter_create: realname=%s\n", realname)); } #endif *ctxp = NULL; /* Allocate memory for a converter context and the name. */ ctx = malloc(sizeof(struct idn_converter) + strlen(realname) + 1); if (ctx == NULL) { r = idn_nomemory; goto ret; } ctx->local_encoding_name = (char *)(ctx + 1); (void)strcpy(ctx->local_encoding_name, realname); ctx->flags = flags; ctx->reference_count = 1; ctx->opened_convfromucs4 = 0; ctx->opened_convtoucs4 = 0; ctx->private_data = NULL; assert(encoding_name_hash != NULL); if (strcmp(realname, IDN_UTF8_ENCODING_NAME) == 0) { /* No conversion needed */ ctx->ops = &none_converter_ops; } else if ((r = idn__strhash_get(encoding_name_hash, realname, &v)) == idn_success) { /* Special converter found */ ctx->ops = (converter_ops_t *)v; } else { /* General case */ #ifdef WITHOUT_ICONV free(ctx); *ctxp = NULL; r = idn_invalid_name; goto ret; #else ctx->ops = &iconv_converter_ops; #endif } if ((flags & IDN_CONVERTER_DELAYEDOPEN) == 0) { r = (ctx->ops->openfromucs4)(ctx, &(ctx->private_data)); if (r != idn_success) { WARNING(("idn_converter_create(): open failed " "(ucs4->local)\n")); free(ctx); *ctxp = NULL; goto ret; } ctx->opened_convfromucs4 = 1; r = (*ctx->ops->opentoucs4)(ctx, &(ctx->private_data)); if (r != idn_success) { WARNING(("idn_converter_create(): open failed " "(local->ucs4)\n")); free(ctx); *ctxp = NULL; goto ret; } ctx->opened_convtoucs4 = 1; } *ctxp = ctx; r = idn_success; ret: TRACE(("idn_converter_create(): %s\n", idn_result_tostring(r))); return (r); }
static idn_result_t converter_uescape_convtoucs4(idn_converter_t ctx, void *privdata, const char *from, unsigned long *to, size_t tolen) { idn_result_t r; size_t fromlen = strlen(from); while (*from != '\0') { if (tolen <= 0) { r = idn_buffer_overflow; goto failure; } if (strncmp(from, "\\u{", 3) == 0 || strncmp(from, "\\U{", 3) == 0) { size_t ullen; unsigned long v; char *end; v = strtoul(from + 3, &end, 16); ullen = end - (from + 3); if (*end == '}' && ullen > 1 && ullen < 8) { *to = v; from = end + 1; fromlen -= ullen; } else { *to = '\\'; from++; fromlen--; } } else { int c = *(unsigned char *)from; size_t width; char buf[8]; if (c < 0x80) width = 1; else if (c < 0xc0) width = 0; else if (c < 0xe0) width = 2; else if (c < 0xf0) width = 3; else if (c < 0xf8) width = 4; else if (c < 0xfc) width = 5; else if (c < 0xfe) width = 6; else width = 0; if (width == 0 || width > fromlen) { r = idn_invalid_encoding; goto failure; } memcpy(buf, from, width); buf[width] = '\0'; r = idn_ucs4_utf8toucs4(buf, to, tolen); if (r != idn_success) { r = idn_invalid_encoding; goto failure; } from += width; fromlen -= width; } to++; tolen--; } if (tolen <= 0) { r = idn_buffer_overflow; goto failure; } *to = '\0'; return (idn_success); failure: if (r != idn_buffer_overflow) { WARNING(("idn_uescape_convtoucs4(): %s\n", idn_result_tostring(r))); } return (r); }
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_delimitermap_map(idn_delimitermap_t ctx, const unsigned long *from, unsigned long *to, size_t tolen) { /* default delimiters (label separators) from IDNA specification */ static const unsigned long default_delimiters[] = { 0x002e, /* full stop */ 0x3002, /* ideographic full stop */ 0xff0e, /* fullwidth full stop */ 0xff61, /* halfwidth ideographic full stop */ 0x0000 }; unsigned long *to_org = to; idn_result_t r; int i, j; int found; assert(ctx != NULL && from != NULL && to != NULL); TRACE(("idn_delimitermap_map(from=\"%s\", tolen=%d)\n", idn__debug_ucs4xstring(from, 50), (int)tolen)); /* * Map. */ while (*from != '\0') { found = 0; if (tolen < 1) { r = idn_buffer_overflow; goto ret; } for (j = 0; default_delimiters[j] != 0x0000; j++) { if (default_delimiters[j] == *from) { found = 1; break; } } if (!found) { for (i = 0; i < ctx->ndelimiters; i++) { if (ctx->delimiters[i] == *from) { found = 1; break; } } } if (found) *to = '.'; else *to = *from; from++; to++; tolen--; } if (tolen < 1) { r = idn_buffer_overflow; goto ret; } *to = '\0'; r = idn_success; ret: if (r == idn_success) { TRACE(("idn_delimitermap_map(): success (to=\"%s\")\n", idn__debug_ucs4xstring(to_org, 50))); } else { TRACE(("idn_delimitermap_map(): %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_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_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_rtcheck(idn_resconf_t ctx, idn_action_t actions, labellist_t label, const unsigned long *original_name) { labellist_t rt_label = NULL; const unsigned long *rt_name; const unsigned long *cur_name; idn_result_t r; cur_name = labellist_getname(label); TRACE(("res rtcheck(label=\"%s\", org_label=\"%s\")\n", idn__debug_ucs4xstring(cur_name, 50), idn__debug_ucs4xstring(original_name, 50))); r = labellist_create(cur_name, &rt_label); if (r != idn_success) goto ret; if (rt_label == NULL) { if (*original_name == '\0') r = idn_success; else r = idn_invalid_encoding; goto ret; } if (!idn__util_ucs4isasciirange(labellist_getname(rt_label))) { r = label_map(ctx, rt_label); if (r != idn_success) goto ret; r = label_normalize(ctx, rt_label); if (r != idn_success) goto ret; r = label_prohcheck(ctx, rt_label); if (r != idn_success) goto ret; if (actions & IDN_UNASCHECK) { r = label_unascheck(ctx, rt_label); if (r != idn_success) goto ret; } r = label_bidicheck(ctx, rt_label); if (r != idn_success) goto ret; } if (actions & IDN_ASCCHECK) { r = label_asccheck(ctx, rt_label); if (r != idn_success) goto ret; } if (!idn__util_ucs4isasciirange(labellist_getname(rt_label))) { r = label_idnencode_ace(ctx, rt_label); if (r != idn_success) goto ret; } r = label_lencheck_ace(ctx, rt_label); if (r != idn_success) goto ret; rt_name = labellist_getname(rt_label); if (idn_ucs4_strcasecmp(rt_name, original_name) != 0) { TRACE(("res rtcheck(): round trip failed, org =\"%s\", rt=\"%s\"\n", idn__debug_ucs4xstring(original_name, 50), idn__debug_ucs4xstring(rt_name, 50))); r = idn_invalid_encoding; goto ret; } r = idn_success; ret: if (r != idn_nomemory && r != idn_success) r = idn_invalid_encoding; TRACE(("res rtcheck(): %s\n", idn_result_tostring(r))); if (rt_label != NULL) labellist_destroy(rt_label); 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); }
/* * 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_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); }
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); }
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); }
static idn_result_t parse_nameprep(idn_resconf_t ctx, char *args, int lineno) { idn_result_t r; char *argv[MAX_CONF_LINE_ARGS + 1]; char scheme_name[MAX_CONF_LINE_LENGTH + 1]; int argc; argc = split_args(args, argv, MAX_CONF_LINE_ARGS + 1); if (argc != 1) { ERROR(("libidnkit: wrong # of args for nameprep, line %d\n", lineno)); return (idn_invalid_syntax); } /* * Set mapper. */ r = idn_mapper_create(&ctx->mapper); if (r != idn_success) { ERROR(("libidnkit: cannot create mapper, %s, line %d\n", idn_result_tostring(r), lineno)); return (r); } r = idn_mapper_add(ctx->mapper, argv[0]); if (r == idn_invalid_name) { ERROR(("libidnkit: map scheme unavailable \"%-.30s\", " "line %d\n", argv[0], lineno)); return (r); } else if (r != idn_success) { return (r); } /* * Set normalizer. */ r = idn_normalizer_create(&ctx->normalizer); if (r != idn_success) { ERROR(("libidnkit: cannot create normalizer, %s, line %d\n", idn_result_tostring(r), lineno)); return (r); } r = idn_normalizer_add(ctx->normalizer, argv[0]); if (r == idn_invalid_name) { ERROR(("libidnkit: unknown normalization scheme \"%-.30s\", " "line %d\n", argv[0], lineno)); return (r); } else if (r != idn_success) { return (r); } /* * Set prohibit checker. */ r = idn_checker_create(&ctx->prohibit_checker); if (r != idn_success) { ERROR(("libidnkit: cannot create prohibit checker, %s, " "line %d\n", idn_result_tostring(r), lineno)); return (r); } sprintf(scheme_name, "%s%s", IDN_CHECKER_PROHIBIT_PREFIX, argv[0]); r = idn_checker_add(ctx->prohibit_checker, scheme_name); if (r == idn_invalid_name) { ERROR(("libidnkit: unknown prohibit scheme \"%-.30s\", " "line %d\n", argv[0], lineno)); return (r); } else if (r != idn_success) { return (r); } /* * Set unassigned checker. */ r = idn_checker_create(&ctx->unassigned_checker); if (r != idn_success) { ERROR(("libidnkit: cannot create unassigned checker, %s, " "line %d\n", idn_result_tostring(r), lineno)); return (r); } sprintf(scheme_name, "%s%s", IDN_CHECKER_UNASSIGNED_PREFIX, argv[0]); r = idn_checker_add(ctx->unassigned_checker, scheme_name); if (r == idn_invalid_name) { ERROR(("libidnkit: unknown unassigned scheme \"%-.30s\", " "line %d\n", argv[0], lineno)); return (r); } else if (r != idn_success) { return (r); } /* * Set bidi checker. */ r = idn_checker_create(&ctx->bidi_checker); if (r != idn_success) { ERROR(("libidnkit: cannot create bidi checker, %s, line %d\n", idn_result_tostring(r), lineno)); return (r); } sprintf(scheme_name, "%s%s", IDN_CHECKER_BIDI_PREFIX, argv[0]); r = idn_checker_add(ctx->bidi_checker, scheme_name); if (r == idn_invalid_name) { ERROR(("libidnkit: unknown bidi scheme \"%-.30s\", " "line %d\n", argv[0], lineno)); return (r); } else if (r != idn_success) { return (r); } return (idn_success); }
idn_result_t selective_encode(idn_resconf_t conf, idn_action_t actions, char *from, char *to, int tolen) { for (;;) { int len; char *region_start, *region_end; idn_result_t r; char save; /* * Find the region that needs conversion. */ r = idn_selectiveencode_findregion(from, ®ion_start, ®ion_end); if (r == idn_notfound) { /* * Not found. Just copy the whole thing. */ if (tolen <= strlen(from)) return (idn_buffer_overflow); (void)strcpy(to, from); return (idn_success); } else if (r != idn_success) { /* This should not happen.. */ errormsg("internal error at line %d: %s\n", line_number, idn_result_tostring(r)); return (r); } /* * We have found a region to convert. * First, copy the prefix part verbatim. */ len = region_start - from; if (tolen < len) { errormsg("internal buffer overflow at line %d\n", line_number); return (idn_buffer_overflow); } (void)memcpy(to, from, len); to += len; tolen -= len; /* * Terminate the region with NUL. */ save = *region_end; *region_end = '\0'; /* * Encode the region. */ r = idn_res_encodename(conf, actions, region_start, to, tolen); /* * Restore character. */ *region_end = save; if (r != idn_success) return (r); len = strlen(to); to += len; tolen -= len; from = region_end; } }
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); }
int main(int ac, char **av) { idn_result_t r; int exit_code = IDNCHECK_EXITCODE_SUCCESS; idncheck_option_t option; idn_action_t actions; idn_resconf_t resconf = NULL; #ifdef HAVE_SETLOCALE setlocale(LC_ALL, ""); #endif /* * Parse command line options. */ idncheck_option_init(&option); if (!parse_command_line(ac, av, &option)) { errormsg("try 'idncheck -help' for more information.\n"); exit_code = IDNCHECK_EXITCODE_FAILURE; goto ret; } quiet_mode = option.quiet; /* * Initialize idnkit library. */ r = idn_resconf_initialize(); if (r != idn_success) { errormsg("error initializing library\n"); exit_code = IDNCHECK_EXITCODE_FAILURE; goto ret; } /* * Create a resource context. */ if (!create_resconf(&resconf, option.no_conf, option.conf_file, option.in_code, option.localcheck_file)) { exit_code = IDNCHECK_EXITCODE_FAILURE; goto ret; } /* * Determine main actions. */ if (option.protocol == idncheck_registration) actions = IDN_CHECK_REGIST & ~option.skip_actions; else actions = IDN_CHECK_LOOKUP & ~option.skip_actions; if (option.localcheck_file != NULL && !(option.skip_actions & ~IDN_LOCALCHECK)) { actions |= IDN_LOCALCHECK; } /* * Test mode. */ if (option.test) { print_test_status(resconf); goto ret; } /* * Encode two names and compare them. */ r = idn_res_checkname(resconf, actions, option.name); if (r == idn_success) { errormsg("passed.\n"); } else if (r == idn_prohcheck_error || r == idn_unascheck_error || r == idn_nfccheck_error || r == idn_prefcheck_error || r == idn_hyphcheck_error || r == idn_combcheck_error || r == idn_ctxjcheck_error || r == idn_ctxocheck_error || r == idn_bidicheck_error || r == idn_localcheck_error || r == idn_lencheck_error || r == idn_rtcheck_error || r == idn_tr46check_error) { errormsg("%s\n", idn_result_tostring(r)); exit_code = IDNCHECK_EXITCODE_CHECKERROR; } else if (r != idn_success) { errormsg("%s\n", idn_result_tostring(r)); exit_code = IDNCHECK_EXITCODE_FAILURE; } ret: if (resconf != NULL) idn_resconf_destroy(resconf); return (exit_code); }