From 7bde3fc590afbdef8f71cd7f8ccbd24172bffc63 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 3 Mar 2013 15:16:08 -0600 Subject: [PATCH 1/1] Add wimlib_global_{init,cleanup}() --- programs/imagex.c | 22 +++++++++----- src/encoding.c | 77 +++++++++++++++++++++++++++++++---------------- src/util.h | 13 ++++++++ src/wim.c | 16 ++++++++++ src/wimlib.h | 28 +++++++++++++++++ src/xml.c | 22 +++++++++----- src/xml.h | 3 ++ 7 files changed, 140 insertions(+), 41 deletions(-) diff --git a/programs/imagex.c b/programs/imagex.c index 5ab9aeba..358e2d12 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -1779,22 +1779,28 @@ int main(int argc, const char **argv) argv++; wimlib_set_print_errors(true); + ret = wimlib_global_init(); + if (ret) + goto out; for_imagex_command(cmd) { if (strcmp(cmd->name, *argv) == 0) { ret = cmd->func(argc, argv); - if (ret > 0) { - imagex_error("Exiting with error code %d:\n" - " %s.", ret, - wimlib_get_error_string(ret)); - if (ret == WIMLIB_ERR_NTFS_3G && errno != 0) - imagex_error_with_errno("errno"); - } - return ret; + goto out; } } imagex_error("Unrecognized command: `%s'", argv[0]); usage_all(); return 1; +out: + if (ret > 0) { + imagex_error("Exiting with error code %d:\n" + " %s.", ret, + wimlib_get_error_string(ret)); + if (ret == WIMLIB_ERR_NTFS_3G && errno != 0) + imagex_error_with_errno("errno"); + } + wimlib_global_cleanup(); + return ret; } diff --git a/src/encoding.c b/src/encoding.c index edb24c70..30a8889e 100644 --- a/src/encoding.c +++ b/src/encoding.c @@ -132,6 +132,47 @@ static int utf8_to_utf16_size(const char *s) } #endif /* !WITH_NTFS_3G */ +#ifndef WITH_NTFS_3G +static iconv_t cd_utf8_to_utf16 = (iconv_t)(-1); +static iconv_t cd_utf16_to_utf8 = (iconv_t)(-1); + +int iconv_global_init() +{ + if (cd_utf16_to_utf8 == (iconv_t)(-1)) { + cd_utf16_to_utf8 = iconv_open("UTF-8", "UTF-16LE"); + if (cd_utf16_to_utf8 == (iconv_t)-1) { + ERROR_WITH_ERRNO("Failed to get conversion descriptor " + "for converting UTF-16LE to UTF-8"); + if (errno == ENOMEM) + return WIMLIB_ERR_NOMEM; + else + return WIMLIB_ERR_ICONV_NOT_AVAILABLE; + } + } + + if (cd_utf8_to_utf16 == (iconv_t)(-1)) { + cd_utf8_to_utf16 = iconv_open("UTF-16LE", "UTF-8"); + if (cd_utf8_to_utf16 == (iconv_t)-1) { + ERROR_WITH_ERRNO("Failed to get conversion descriptor " + "for converting UTF-8 to UTF-16LE"); + if (errno == ENOMEM) + return WIMLIB_ERR_NOMEM; + else + return WIMLIB_ERR_ICONV_NOT_AVAILABLE; + } + } + return 0; +} + +void iconv_global_cleanup() +{ + if (cd_utf8_to_utf16 != (iconv_t)(-1)) + iconv_close(cd_utf8_to_utf16); + if (cd_utf16_to_utf8 != (iconv_t)(-1)) + iconv_close(cd_utf16_to_utf8); +} +#endif + /* Converts a string in the UTF-16LE encoding to a newly allocated string in the * UTF-8 encoding. * @@ -167,19 +208,12 @@ int utf16_to_utf8(const char *utf16_str, size_t utf16_nbytes, else ret = WIMLIB_ERR_INVALID_UTF16_STRING; } -#else /* WITH_NTFS_3G */ - static iconv_t cd_utf16_to_utf8 = (iconv_t)(-1); - if (cd_utf16_to_utf8 == (iconv_t)(-1)) { - cd_utf16_to_utf8 = iconv_open("UTF-8", "UTF-16LE"); - if (cd_utf16_to_utf8 == (iconv_t)-1) { - ERROR_WITH_ERRNO("Failed to get conversion descriptor " - "for converting UTF-16LE to UTF-8"); - if (errno == ENOMEM) - return WIMLIB_ERR_NOMEM; - else - return WIMLIB_ERR_ICONV_NOT_AVAILABLE; - } - } +#else /* !WITH_NTFS_3G */ + + ret = iconv_global_init(); + if (ret != 0) + return ret; + ret = utf16_to_utf8_size((const u16*)utf16_str, utf16_nbytes / 2); if (ret >= 0) { size_t utf8_expected_nbytes; @@ -262,20 +296,11 @@ int utf8_to_utf16(const char *utf8_str, size_t utf8_nbytes, else ret = WIMLIB_ERR_INVALID_UTF8_STRING; } -#else /* WITH_NTFS_3G */ - static iconv_t cd_utf8_to_utf16 = (iconv_t)(-1); - if (cd_utf8_to_utf16 == (iconv_t)(-1)) { - cd_utf8_to_utf16 = iconv_open("UTF-16LE", "UTF-8"); - if (cd_utf8_to_utf16 == (iconv_t)-1) { - ERROR_WITH_ERRNO("Failed to get conversion descriptor " - "for converting UTF-8 to UTF-16LE"); - if (errno == ENOMEM) - return WIMLIB_ERR_NOMEM; - else - return WIMLIB_ERR_ICONV_NOT_AVAILABLE; - } - } +#else /* !WITH_NTFS_3G */ + ret = iconv_global_init(); + if (ret != 0) + return ret; ret = utf8_to_utf16_size(utf8_str); if (ret >= 0) { size_t utf16_expected_nbytes; diff --git a/src/util.h b/src/util.h index 3db022a1..0979d98f 100644 --- a/src/util.h +++ b/src/util.h @@ -162,6 +162,19 @@ extern char *wimlib_strdup(const char *str); /* encoding.c */ + +#ifdef WITH_NTFS_3G +static inline int iconv_global_init() +{ + return 0; +} + +static inline void iconv_global_cleanup() { } +#else +extern int iconv_global_init(); +extern void iconv_global_cleanup(); +#endif + extern int utf16_to_utf8(const char *utf16_str, size_t utf16_nbytes, char **utf8_str_ret, size_t *utf8_nbytes_ret); diff --git a/src/wim.c b/src/wim.c index 23858d69..b52a28d9 100644 --- a/src/wim.c +++ b/src/wim.c @@ -634,3 +634,19 @@ WIMLIBAPI void wimlib_free(WIMStruct *w) #endif FREE(w); } + +/* Get global memory allocations out of the way. Not strictly necessary in + * single-threaded programs like 'imagex'. */ +WIMLIBAPI int wimlib_global_init() +{ + libxml_global_init(); + return iconv_global_init(); +} + +/* Free global memory allocations. Not strictly necessary if the process using + * wimlib is just about to exit (as is the case for 'imagex'). */ +WIMLIBAPI void wimlib_global_cleanup() +{ + libxml_global_cleanup(); + iconv_global_cleanup(); +} diff --git a/src/wimlib.h b/src/wimlib.h index a249b895..1de5d045 100644 --- a/src/wimlib.h +++ b/src/wimlib.h @@ -1282,6 +1282,34 @@ extern int wimlib_get_num_images(const WIMStruct *wim); */ extern int wimlib_get_part_number(const WIMStruct *wim, int *total_parts_ret); +/** + * Since wimlib 1.2.6: Initialization function for wimlib. This is not + * re-entrant. If you are calling wimlib functions concurrently in different + * threads, then you must call this function serially first. Otherwise, calling + * this function is not required. + * + * @return 0 on success; nonzero on error. + * @retval ::WIMLIB_ERR_NOMEM + * Could not allocate memory. + * @retval ::WIMLIB_ERR_ICONV_NOT_AVAILABLE + * wimlib was configured --without-libntfs-3g at compilation time, and at + * runtime the iconv() set of functions did not seem to be available, + * perhaps due to missing files in the C library installation. + * + * If this function is not called or returns nonzero, then it will not be safe + * to use wimlib in multiple threads. Furthermore, a nonzero return value here + * indicates that further calls into wimlib will probably fail when they try to + * repeat the same initializations. + */ +extern int wimlib_global_init(); + +/** + * Since wimlib 1.2.6: Cleanup function for wimlib. This is not re-entrant. + * You are not required to call this function, but it will release any global + * memory allocated by the library. + */ +extern void wimlib_global_cleanup(); + /** * Returns true if the WIM has an integrity table. * diff --git a/src/xml.c b/src/xml.c index 9b161c28..c840da93 100644 --- a/src/xml.c +++ b/src/xml.c @@ -1177,6 +1177,16 @@ void print_image_info(const struct wim_info *wim_info, int image) putchar('\n'); } +void libxml_global_init() +{ + xmlInitParser(); +} + +void libxml_global_cleanup() +{ + xmlCleanupParser(); +} + /* * Reads the XML data from a WIM file. */ @@ -1194,19 +1204,19 @@ int read_xml_data(FILE *fp, const struct resource_entry *res_entry, if (resource_is_compressed(res_entry)) { ERROR("XML data is supposed to be uncompressed"); ret = WIMLIB_ERR_XML; - goto out_cleanup_parser; + goto out; } if (res_entry->size < 2) { ERROR("XML data must be at least 2 bytes long"); ret = WIMLIB_ERR_XML; - goto out_cleanup_parser; + goto out; } xml_data = MALLOC(res_entry->size + 2); if (!xml_data) { ret = WIMLIB_ERR_NOMEM; - goto out_cleanup_parser; + goto out; } ret = read_uncompressed_resource(fp, res_entry->offset, @@ -1249,16 +1259,14 @@ int read_xml_data(FILE *fp, const struct resource_entry *res_entry, if (ret != 0) goto out_free_doc; - DEBUG("Freeing XML tree."); - *xml_data_ret = xml_data; xml_data = NULL; out_free_doc: + DEBUG("Freeing XML tree."); xmlFreeDoc(doc); out_free_xml_data: FREE(xml_data); -out_cleanup_parser: - xmlCleanupParser(); +out: return ret; } diff --git a/src/xml.h b/src/xml.h index 5eb24c9c..54993cba 100644 --- a/src/xml.h +++ b/src/xml.h @@ -36,6 +36,9 @@ extern int read_xml_data(FILE *fp, const struct resource_entry *res, extern int write_xml_data(const struct wim_info *wim_info, int image, FILE *out, u64 total_bytes, struct resource_entry *out_res_entry); +extern void libxml_global_init(); +extern void libxml_global_cleanup(); + static inline u64 wim_info_get_total_bytes(const struct wim_info *info) { return info->total_bytes; -- 2.43.0