X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fencoding.c;h=8edf228817cba16e659ca47caed8d492e1de95cf;hb=3a900017c59c26af398f9cf375719dbcda378fb8;hp=8c5bd2af6acf4ef9e2d9b2a678084d217d92c883;hpb=dec3bbfa2c3e9fc8e4b1adbaa0323337a75aaadb;p=wimlib diff --git a/src/encoding.c b/src/encoding.c index 8c5bd2af..8edf2288 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. @@ -115,11 +119,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 +138,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 +192,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; \ @@ -539,40 +545,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; } -