X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fencoding.c;h=ff90a23b8ca74bdda4ff2fc763eb66142ce1d818;hb=b9a937bf6a343e90d75c964d452fca9986361ff8;hp=8c5bd2af6acf4ef9e2d9b2a678084d217d92c883;hpb=dec3bbfa2c3e9fc8e4b1adbaa0323337a75aaadb;p=wimlib diff --git a/src/encoding.c b/src/encoding.c index 8c5bd2af..ff90a23b 100644 --- a/src/encoding.c +++ b/src/encoding.c @@ -39,6 +39,10 @@ #include #include +#ifdef HAVE_ALLOCA_H +# include +#endif + bool wimlib_mbs_is_utf8 = !TCHAR_IS_UTF16LE; /* List of iconv_t conversion descriptors for a specific character conversion. @@ -64,8 +68,6 @@ struct iconv_node { struct iconv_list_head name = { \ .from_encoding = from, \ .to_encoding = to, \ - .list = LIST_HEAD_INIT(name.list), \ - .mutex = PTHREAD_MUTEX_INITIALIZER, \ } static iconv_t * @@ -115,11 +117,6 @@ put_iconv(iconv_t *cd) errno = errno_save; } -/* Prevent printing an error message if a character conversion error occurs - * while printing an error message. (This variable is not per-thread but it - * doesn't matter too much since it's just the error messages.) */ -static bool error_message_being_printed = false; - #define DEFINE_CHAR_CONVERSION_FUNCTIONS(varname1, longname1, chartype1,\ varname2, longname2, chartype2,\ earlyreturn_on_utf8_locale, \ @@ -139,28 +136,39 @@ varname1##_to_##varname2##_nbytes(const chartype1 *in, size_t in_nbytes,\ if (cd == NULL) \ return WIMLIB_ERR_ICONV_NOT_AVAILABLE; \ \ + chartype2 *buf; \ + size_t bufsize; \ + bool buf_onheap; \ + bufsize = (worst_case_len_expr) * sizeof(chartype2); \ /* Worst case length */ \ - chartype2 buf[worst_case_len_expr]; \ + if (bufsize <= STACK_MAX) { \ + buf = alloca(bufsize); \ + buf_onheap = false; \ + } else { \ + buf = MALLOC(bufsize); \ + if (!buf) \ + return WIMLIB_ERR_NOMEM; \ + buf_onheap = true; \ + } \ + \ char *inbuf = (char*)in; \ size_t inbytesleft = in_nbytes; \ char *outbuf = (char*)buf; \ - size_t outbytesleft = sizeof(buf); \ + size_t outbytesleft = bufsize; \ size_t len; \ int ret; \ \ len = iconv(*cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); \ if (len == (size_t)-1) { \ - if (!error_message_being_printed) { \ - error_message_being_printed = true; \ - err_msg; \ - error_message_being_printed = false; \ - } \ + err_msg; \ ret = err_return; \ } else { \ - *out_nbytes_ret = sizeof(buf) - outbytesleft; \ + *out_nbytes_ret = bufsize - outbytesleft; \ ret = 0; \ } \ put_iconv(cd); \ + if (buf_onheap) \ + FREE(buf); \ return ret; \ } \ \ @@ -182,11 +190,7 @@ varname1##_to_##varname2##_buf(const chartype1 *in, size_t in_nbytes, \ \ len = iconv(*cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); \ if (len == (size_t)-1) { \ - if (!error_message_being_printed) { \ - error_message_being_printed = true; \ - err_msg; \ - error_message_being_printed = false; \ - } \ + err_msg; \ ret = err_return; \ } else { \ out[(LARGE_NUMBER-outbytesleft)/sizeof(chartype2)] = 0; \ @@ -357,6 +361,13 @@ utf8_to_tstr_simple(const char *utf8str, tchar **out) return utf8_to_tstr(utf8str, strlen(utf8str), out, &out_nbytes); } +static void +iconv_init(struct iconv_list_head *head) +{ + pthread_mutex_init(&head->mutex, NULL); + INIT_LIST_HEAD(&head->list); +} + static void iconv_cleanup(struct iconv_list_head *head) { @@ -371,6 +382,19 @@ iconv_cleanup(struct iconv_list_head *head) } } +void +iconv_global_init(void) +{ + iconv_init(&iconv_utf8_to_tstr); + iconv_init(&iconv_tstr_to_utf8); +#if !TCHAR_IS_UTF16LE + iconv_init(&iconv_utf16le_to_tstr); + iconv_init(&iconv_tstr_to_utf16le); + iconv_init(&iconv_utf16le_to_utf8); + iconv_init(&iconv_utf8_to_utf16le); +#endif +} + void iconv_global_cleanup(void) { @@ -539,40 +563,14 @@ cmp_utf16le_strings(const utf16lechar *s1, size_t n1, return (n1 < n2) ? -1 : 1; } -/* Duplicates a string of system-dependent encoding into a UTF-16LE string and - * returns the string and its length, in bytes, in the pointer arguments. Frees - * any existing string at the return location before overwriting it. */ -int -get_utf16le_string(const tchar *name, utf16lechar **name_utf16le_ret, - u16 *name_utf16le_nbytes_ret) +/* Duplicate a UTF16-LE string which may not be null-terminated. */ +utf16lechar * +utf16le_dupz(const utf16lechar *ustr, size_t usize) { - utf16lechar *name_utf16le; - size_t name_utf16le_nbytes; - int ret; -#if TCHAR_IS_UTF16LE - name_utf16le_nbytes = tstrlen(name) * sizeof(utf16lechar); - name_utf16le = MALLOC(name_utf16le_nbytes + sizeof(utf16lechar)); - if (name_utf16le == NULL) - return WIMLIB_ERR_NOMEM; - memcpy(name_utf16le, name, name_utf16le_nbytes + sizeof(utf16lechar)); - ret = 0; -#else - - ret = tstr_to_utf16le(name, tstrlen(name), &name_utf16le, - &name_utf16le_nbytes); - if (ret == 0) { - if (name_utf16le_nbytes > 0xffff) { - FREE(name_utf16le); - ERROR("Multibyte string \"%"TS"\" is too long!", name); - ret = WIMLIB_ERR_INVALID_UTF8_STRING; - } + utf16lechar *dup = MALLOC(usize + sizeof(utf16lechar)); + if (dup) { + memcpy(dup, ustr, usize); + dup[usize / sizeof(utf16lechar)] = 0; } -#endif - if (ret == 0) { - FREE(*name_utf16le_ret); - *name_utf16le_ret = name_utf16le; - *name_utf16le_nbytes_ret = name_utf16le_nbytes; - } - return ret; + return dup; } -