- if (utf16_nbytes == 0) {
- *utf8_str_ret = NULL;
- *utf8_nbytes_ret = 0;
- return 0;
- }
-
- if (utf16_nbytes & 1) {
- ERROR("UTF-16LE string is invalid (odd number of bytes)!");
- return WIMLIB_ERR_INVALID_UTF16_STRING;
- }
-#ifdef WITH_NTFS_3G
- char *outs = NULL;
- int outs_len = ntfs_ucstombs((const ntfschar*)utf16_str,
- utf16_nbytes / 2, &outs, 0);
- if (outs_len >= 0) {
- *utf8_str_ret = outs;
- *utf8_nbytes_ret = outs_len;
- ret = 0;
- } else {
- if (errno == ENOMEM)
- ret = WIMLIB_ERR_NOMEM;
- else
- ret = WIMLIB_ERR_INVALID_UTF16_STRING;
- }
-#else /* !WITH_NTFS_3G */
+#define DEFINE_CHAR_CONVERSION_FUNCTIONS(varname1, longname1, chartype1,\
+ varname2, longname2, chartype2,\
+ worst_case_len_expr, \
+ err_return, \
+ err_msg) \
+static ICONV_LIST(iconv_##varname1##_to_##varname2, \
+ longname1, longname2); \
+ \
+int \
+varname1##_to_##varname2##_nbytes(const chartype1 *in, size_t in_nbytes,\
+ size_t *out_nbytes_ret) \
+{ \
+ iconv_t *cd = get_iconv(&iconv_##varname1##_to_##varname2); \
+ if (cd == NULL) \
+ return WIMLIB_ERR_ICONV_NOT_AVAILABLE; \
+ \
+ /* Worst case length */ \
+ chartype2 buf[worst_case_len_expr]; \
+ char *inbuf = (char*)in; \
+ size_t inbytesleft = in_nbytes; \
+ char *outbuf = (char*)buf; \
+ size_t outbytesleft = sizeof(buf); \
+ 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; \
+ } \
+ ret = err_return; \
+ } else { \
+ *out_nbytes_ret = sizeof(buf) - outbytesleft; \
+ ret = 0; \
+ } \
+ put_iconv(cd); \
+ return ret; \
+} \
+ \
+int \
+varname1##_to_##varname2##_buf(const chartype1 *in, size_t in_nbytes, \
+ chartype2 *out) \
+{ \
+ iconv_t *cd = get_iconv(&iconv_##varname1##_to_##varname2); \
+ if (cd == NULL) \
+ return WIMLIB_ERR_ICONV_NOT_AVAILABLE; \
+ \
+ char *inbuf = (char*)in; \
+ size_t inbytesleft = in_nbytes; \
+ char *outbuf = (char*)out; \
+ const size_t LARGE_NUMBER = 1000000000; \
+ size_t outbytesleft = LARGE_NUMBER; \
+ 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; \
+ } \
+ ret = err_return; \
+ } else { \
+ out[(LARGE_NUMBER-outbytesleft)/sizeof(chartype2)] = 0; \
+ ret = 0; \
+ } \
+ put_iconv(cd); \
+ return ret; \
+} \
+ \
+int \
+varname1##_to_##varname2(const chartype1 *in, size_t in_nbytes, \
+ chartype2 **out_ret, \
+ size_t *out_nbytes_ret) \
+{ \
+ int ret; \
+ chartype2 *out; \
+ size_t out_nbytes; \
+ \
+ ret = varname1##_to_##varname2##_nbytes(in, in_nbytes, \
+ &out_nbytes); \
+ if (ret) \
+ return ret; \
+ \
+ out = MALLOC(out_nbytes + sizeof(chartype2)); \
+ if (!out) \
+ return WIMLIB_ERR_NOMEM; \
+ \
+ ret = varname1##_to_##varname2##_buf(in, in_nbytes, out); \
+ if (ret) { \
+ int errno_save = errno; \
+ FREE(out); \
+ errno = errno_save; \
+ } else { \
+ *out_ret = out; \
+ *out_nbytes_ret = out_nbytes; \
+ } \
+ return ret; \
+}