From ced16a28e197645a40fa04a54793d117a04526d7 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 13 May 2014 00:25:50 -0500 Subject: [PATCH] Improve tstr <=> UTF-16LE conversions Consolidated conditional code into encoding.h. A few related cleanups. --- include/wimlib/dentry.h | 3 +- include/wimlib/encoding.h | 94 ++++++++++++++++- src/dentry.c | 206 ++++++++++++++------------------------ src/encoding.c | 42 ++------ src/extract.c | 35 +++---- src/inode.c | 114 +++++++++------------ src/iterate_dir.c | 55 ++++------ src/textfile.c | 13 --- src/update_image.c | 86 +++++----------- src/wildcard.c | 18 ++-- 10 files changed, 291 insertions(+), 375 deletions(-) diff --git a/include/wimlib/dentry.h b/include/wimlib/dentry.h index edd99209..bdbd5f75 100644 --- a/include/wimlib/dentry.h +++ b/include/wimlib/dentry.h @@ -198,7 +198,8 @@ extern int dentry_set_name(struct wim_dentry *dentry, const tchar *new_name); extern int -dentry_set_name_utf16le(struct wim_dentry *dentry, const utf16lechar *new_name); +dentry_set_name_utf16le(struct wim_dentry *dentry, const utf16lechar *new_name, + size_t new_name_nbytes); extern struct wim_dentry * get_dentry(struct WIMStruct *wim, const tchar *path, diff --git a/include/wimlib/encoding.h b/include/wimlib/encoding.h index 20cb8d83..00f1a388 100644 --- a/include/wimlib/encoding.h +++ b/include/wimlib/encoding.h @@ -1,8 +1,12 @@ #ifndef _WIMLIB_ENCODING_H #define _WIMLIB_ENCODING_H +#include "wimlib/error.h" +#include "wimlib/util.h" #include "wimlib/types.h" +#include + extern void iconv_global_cleanup(void); @@ -27,10 +31,28 @@ extern int \ varname1##_to_##varname2##_buf(const chartype1 *in, size_t in_nbytes, \ chartype2 *out); +extern utf16lechar * +utf16le_dupz(const utf16lechar *ustr, size_t usize); #if !TCHAR_IS_UTF16LE DECLARE_CHAR_CONVERSION_FUNCTIONS(utf16le, tstr, utf16lechar, tchar); DECLARE_CHAR_CONVERSION_FUNCTIONS(tstr, utf16le, tchar, utf16lechar); +#else + +static inline int +tstr_to_utf16le(const tchar *tstr, size_t tsize, + utf16lechar **ustr_ret, size_t *usize_ret) +{ + utf16lechar *ustr = utf16le_dupz(tstr, tsize); + if (!ustr) + return WIMLIB_ERR_NOMEM; + *ustr_ret = ustr; + *usize_ret = tsize; + return 0; +} + +#define utf16le_to_tstr tstr_to_utf16le + #endif DECLARE_CHAR_CONVERSION_FUNCTIONS(utf8, tstr, char, tchar); @@ -47,9 +69,75 @@ cmp_utf16le_strings(const utf16lechar *s1, size_t n1, const utf16lechar *s2, size_t n2, bool ignore_case); -extern int -get_utf16le_string(const tchar *name, utf16lechar **name_utf16le_ret, - u16 *name_utf16le_nbytes_ret); +/* Convert a string in the platform-dependent encoding to UTF-16LE, but if both + * encodings are UTF-16LE, simply re-use the string. Release with + * tstr_put_utf16le() when done. */ +static inline int +tstr_get_utf16le_and_len(const tchar *tstr, + const utf16lechar **ustr_ret, size_t *usize_ret) +{ + size_t tsize = tstrlen(tstr) * sizeof(tchar); +#if TCHAR_IS_UTF16LE + /* No conversion or copy needed */ + *ustr_ret = tstr; + *usize_ret = tsize; + return 0; +#else + return tstr_to_utf16le(tstr, tsize, (utf16lechar **)ustr_ret, usize_ret); +#endif +} + +/* Convert a string in the platform-dependent encoding to UTF-16LE, but if both + * encodings are UTF-16LE, simply re-use the string. Release with + * tstr_put_utf16le() when done. */ +static inline int +tstr_get_utf16le(const tchar *tstr, const utf16lechar **ustr_ret) +{ +#if TCHAR_IS_UTF16LE + /* No conversion or copy needed */ + *ustr_ret = tstr; + return 0; +#else + size_t tsize = tstrlen(tstr) * sizeof(tchar); + size_t dummy; + return tstr_to_utf16le(tstr, tsize, (utf16lechar **)ustr_ret, &dummy); +#endif +} +/* Release a string acquired with tstr_get_utf16le() or + * tstr_get_utf16le_and_len(). */ +static inline void +tstr_put_utf16le(const utf16lechar *ustr) +{ +#if !TCHAR_IS_UTF16LE + FREE((void *)ustr); +#endif +} + +/* Convert a UTF16-LE string to the platform-dependent encoding, but if both + * encodings are UTF-16LE, simply re-use the string. Release with + * utf16le_put_tstr() when done. */ +static inline int +utf16le_get_tstr(const utf16lechar *ustr, size_t usize, + const tchar **tstr_ret, size_t *tsize_ret) +{ +#if TCHAR_IS_UTF16LE + /* No conversion or copy needed */ + *tstr_ret = ustr; + *tsize_ret = usize; + return 0; +#else + return utf16le_to_tstr(ustr, usize, (tchar **)tstr_ret, tsize_ret); +#endif +} + +/* Release a string acquired with utf16le_get_tstr(). */ +static inline void +utf16le_put_tstr(const tchar *tstr) +{ +#if !TCHAR_IS_UTF16LE + FREE((void *)tstr); +#endif +} #endif /* _WIMLIB_ENCODING_H */ diff --git a/src/dentry.c b/src/dentry.c index 3e462a6e..123ae908 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -214,60 +214,59 @@ dentry_correct_length_aligned(const struct wim_dentry *dentry) return (len + 7) & ~7; } -static int -dentry_clear_short_name(struct wim_dentry *dentry) +static void +do_dentry_set_name(struct wim_dentry *dentry, utf16lechar *file_name, + size_t file_name_nbytes) { + FREE(dentry->file_name); + dentry->file_name = file_name; + dentry->file_name_nbytes = file_name_nbytes; + if (dentry_has_short_name(dentry)) { FREE(dentry->short_name); dentry->short_name = NULL; dentry->short_name_nbytes = 0; } - return 0; } -/* Sets the name of a WIM dentry from a multibyte string. +/* Sets the name of a WIM dentry from a UTF-16LE string. * Only use this on dentries not inserted into the tree. Use rename_wim_path() * to do a real rename. */ int -dentry_set_name(struct wim_dentry *dentry, const tchar *new_name) +dentry_set_name_utf16le(struct wim_dentry *dentry, const utf16lechar *name, + size_t name_nbytes) { - int ret; - - ret = get_utf16le_string(new_name, &dentry->file_name, - &dentry->file_name_nbytes); - if (ret) - return ret; + utf16lechar *dup = NULL; - return dentry_clear_short_name(dentry); + if (name_nbytes) { + dup = utf16le_dupz(name, name_nbytes); + if (!dup) + return WIMLIB_ERR_NOMEM; + } + do_dentry_set_name(dentry, dup, name_nbytes); + return 0; } -/* Sets the name of a WIM dentry from a UTF-16LE string. + +/* Sets the name of a WIM dentry from a multibyte string. * Only use this on dentries not inserted into the tree. Use rename_wim_path() * to do a real rename. */ int -dentry_set_name_utf16le(struct wim_dentry *dentry, const utf16lechar *new_name) +dentry_set_name(struct wim_dentry *dentry, const tchar *name) { - utf16lechar *name = NULL; - size_t name_nbytes = 0; - - if (new_name && *new_name) { - const utf16lechar *tmp; - - tmp = new_name; - do { - name_nbytes += sizeof(utf16lechar); - } while (*++tmp); + utf16lechar *name_utf16le = NULL; + size_t name_utf16le_nbytes = 0; + int ret; - name = memdup(new_name, name_nbytes + sizeof(utf16lechar)); - if (!name) - return WIMLIB_ERR_NOMEM; + if (name && *name) { + ret = tstr_to_utf16le(name, tstrlen(name) * sizeof(tchar), + &name_utf16le, &name_utf16le_nbytes); + if (ret) + return ret; } - FREE(dentry->file_name); - dentry->file_name = name; - dentry->file_name_nbytes = name_nbytes; - - return dentry_clear_short_name(dentry); + do_dentry_set_name(dentry, name_utf16le, name_utf16le_nbytes); + return 0; } /* Returns the total length of a WIM alternate data stream entry on-disk, @@ -400,74 +399,36 @@ for_dentry_in_tree_depth(struct wim_dentry *root, int calculate_dentry_full_path(struct wim_dentry *dentry) { - tchar *full_path; - u32 full_path_nbytes; - int ret; + size_t ulen; + size_t dummy; + const struct wim_dentry *d; if (dentry->_full_path) return 0; - if (dentry_is_root(dentry)) { - static const tchar _root_path[] = {WIM_PATH_SEPARATOR, T('\0')}; - full_path = TSTRDUP(_root_path); - if (full_path == NULL) - return WIMLIB_ERR_NOMEM; - full_path_nbytes = 1 * sizeof(tchar); - } else { - struct wim_dentry *parent; - tchar *parent_full_path; - u32 parent_full_path_nbytes; - size_t filename_nbytes; - - parent = dentry->parent; - if (dentry_is_root(parent)) { - parent_full_path = T(""); - parent_full_path_nbytes = 0; - } else { - if (parent->_full_path == NULL) { - ret = calculate_dentry_full_path(parent); - if (ret) - return ret; - } - parent_full_path = parent->_full_path; - parent_full_path_nbytes = parent->full_path_nbytes; - } + ulen = 0; + d = dentry; + do { + ulen += d->file_name_nbytes / sizeof(utf16lechar); + ulen++; + d = d->parent; /* assumes d == d->parent for root */ + } while (!dentry_is_root(d)); - /* Append this dentry's name as a tchar string to the full path - * of the parent followed by the path separator */ - #if TCHAR_IS_UTF16LE - filename_nbytes = dentry->file_name_nbytes; - #else - { - int ret = utf16le_to_tstr_nbytes(dentry->file_name, - dentry->file_name_nbytes, - &filename_nbytes); - if (ret) - return ret; - } - #endif + utf16lechar ubuf[ulen]; + utf16lechar *p = &ubuf[ulen]; - full_path_nbytes = parent_full_path_nbytes + sizeof(tchar) + - filename_nbytes; - full_path = MALLOC(full_path_nbytes + sizeof(tchar)); - if (full_path == NULL) - return WIMLIB_ERR_NOMEM; - memcpy(full_path, parent_full_path, parent_full_path_nbytes); - full_path[parent_full_path_nbytes / sizeof(tchar)] = WIM_PATH_SEPARATOR; - #if TCHAR_IS_UTF16LE - memcpy(&full_path[parent_full_path_nbytes / sizeof(tchar) + 1], - dentry->file_name, - filename_nbytes + sizeof(tchar)); - #else - utf16le_to_tstr_buf(dentry->file_name, - dentry->file_name_nbytes, - &full_path[parent_full_path_nbytes / - sizeof(tchar) + 1]); - #endif - } - dentry->_full_path = full_path; - dentry->full_path_nbytes= full_path_nbytes; - return 0; + d = dentry; + do { + p -= d->file_name_nbytes / sizeof(utf16lechar); + memcpy(p, d->file_name, d->file_name_nbytes); + *--p = cpu_to_le16(WIM_PATH_SEPARATOR); + d = d->parent; /* assumes d == d->parent for root */ + } while (!dentry_is_root(d)); + + wimlib_assert(p == ubuf); + + return utf16le_to_tstr(ubuf, ulen * sizeof(utf16lechar), + &dentry->_full_path, &dummy); } tchar * @@ -598,8 +559,8 @@ dir_lookup_ci(const struct wim_inode *dir, const struct wim_dentry *dummy) } /* Given a UTF-16LE filename and a directory, look up the dentry for the file. - * Return it if found, otherwise NULL. This is case-sensitive on UNIX and - * case-insensitive on Windows. */ + * Return it if found, otherwise NULL. This has configurable case sensitivity, + * and @name need not be null-terminated. */ struct wim_dentry * get_dentry_child_with_utf16le_name(const struct wim_dentry *dentry, const utf16lechar *name, @@ -660,29 +621,22 @@ struct wim_dentry * get_dentry_child_with_name(const struct wim_dentry *dentry, const tchar *name, CASE_SENSITIVITY_TYPE case_type) { -#if TCHAR_IS_UTF16LE - return get_dentry_child_with_utf16le_name(dentry, name, - tstrlen(name) * sizeof(tchar), - case_type); -#else - utf16lechar *utf16le_name; - size_t utf16le_name_nbytes; int ret; + const utf16lechar *name_utf16le; + size_t name_utf16le_nbytes; struct wim_dentry *child; - ret = tstr_to_utf16le(name, tstrlen(name) * sizeof(tchar), - &utf16le_name, &utf16le_name_nbytes); - if (ret) { - child = NULL; - } else { - child = get_dentry_child_with_utf16le_name(dentry, - utf16le_name, - utf16le_name_nbytes, - case_type); - FREE(utf16le_name); - } + ret = tstr_get_utf16le_and_len(name, &name_utf16le, + &name_utf16le_nbytes); + if (ret) + return NULL; + + child = get_dentry_child_with_utf16le_name(dentry, + name_utf16le, + name_utf16le_nbytes, + case_type); + tstr_put_utf16le(name_utf16le); return child; -#endif } static struct wim_dentry * @@ -789,22 +743,16 @@ get_dentry_utf16le(WIMStruct *wim, const utf16lechar *path, struct wim_dentry * get_dentry(WIMStruct *wim, const tchar *path, CASE_SENSITIVITY_TYPE case_type) { -#if TCHAR_IS_UTF16LE - return get_dentry_utf16le(wim, path, case_type); -#else - utf16lechar *path_utf16le; - size_t path_utf16le_nbytes; int ret; + const utf16lechar *path_utf16le; struct wim_dentry *dentry; - ret = tstr_to_utf16le(path, tstrlen(path) * sizeof(tchar), - &path_utf16le, &path_utf16le_nbytes); + ret = tstr_get_utf16le(path, &path_utf16le); if (ret) return NULL; dentry = get_dentry_utf16le(wim, path_utf16le, case_type); - FREE(path_utf16le); + tstr_put_utf16le(path_utf16le); return dentry; -#endif } /* Takes in a path of length @len in @buf, and transforms it into a string for @@ -1318,29 +1266,27 @@ read_dentry(const u8 * restrict buf, size_t buf_len, /* Read the filename if present. Note: if the filename is empty, there * is no null terminator following it. */ if (file_name_nbytes) { - dentry->file_name = MALLOC(file_name_nbytes + 2); + dentry->file_name = utf16le_dupz((const utf16lechar *)p, + file_name_nbytes); if (dentry->file_name == NULL) { ret = WIMLIB_ERR_NOMEM; goto err_free_dentry; } dentry->file_name_nbytes = file_name_nbytes; - memcpy(dentry->file_name, p, file_name_nbytes); p += file_name_nbytes + 2; - dentry->file_name[file_name_nbytes / 2] = cpu_to_le16(0); } /* Read the short filename if present. Note: if there is no short * filename, there is no null terminator following it. */ if (short_name_nbytes) { - dentry->short_name = MALLOC(short_name_nbytes + 2); + dentry->short_name = utf16le_dupz((const utf16lechar *)p, + short_name_nbytes); if (dentry->short_name == NULL) { ret = WIMLIB_ERR_NOMEM; goto err_free_dentry; } dentry->short_name_nbytes = short_name_nbytes; - memcpy(dentry->short_name, p, short_name_nbytes); p += short_name_nbytes + 2; - dentry->short_name[short_name_nbytes / 2] = cpu_to_le16(0); } /* Align the dentry length. */ diff --git a/src/encoding.c b/src/encoding.c index e588eabf..927cb5da 100644 --- a/src/encoding.c +++ b/src/encoding.c @@ -558,40 +558,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; - } - } -#endif - if (ret == 0) { - FREE(*name_utf16le_ret); - *name_utf16le_ret = name_utf16le; - *name_utf16le_nbytes_ret = name_utf16le_nbytes; + utf16lechar *dup = MALLOC(usize + sizeof(utf16lechar)); + if (dup) { + memcpy(dup, ustr, usize); + dup[usize / sizeof(utf16lechar)] = 0; } - return ret; + return dup; } - diff --git a/src/extract.c b/src/extract.c index bc769eec..a4029ec2 100644 --- a/src/extract.c +++ b/src/extract.c @@ -1858,16 +1858,12 @@ dentry_calculate_extraction_name(struct wim_dentry *dentry, } if (file_name_valid(dentry->file_name, dentry->file_name_nbytes / 2, false)) { -#if TCHAR_IS_UTF16LE - dentry->extraction_name = dentry->file_name; - dentry->extraction_name_nchars = dentry->file_name_nbytes / 2; - return 0; -#else - return utf16le_to_tstr(dentry->file_name, + ret = utf16le_get_tstr(dentry->file_name, dentry->file_name_nbytes, - &dentry->extraction_name, + (const tchar **)&dentry->extraction_name, &dentry->extraction_name_nchars); -#endif + dentry->extraction_name_nchars /= sizeof(tchar); + return ret; } else { if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_REPLACE_INVALID_FILENAMES) { @@ -1891,18 +1887,17 @@ out_replace: memcpy(utf16_name_copy, dentry->file_name, dentry->file_name_nbytes); file_name_valid(utf16_name_copy, dentry->file_name_nbytes / 2, true); - tchar *tchar_name; + const tchar *tchar_name; size_t tchar_nchars; - #if TCHAR_IS_UTF16LE - tchar_name = utf16_name_copy; - tchar_nchars = dentry->file_name_nbytes / 2; - #else - ret = utf16le_to_tstr(utf16_name_copy, - dentry->file_name_nbytes, - &tchar_name, &tchar_nchars); + + ret = utf16le_get_tstr(utf16_name_copy, + dentry->file_name_nbytes, + &tchar_name, &tchar_nchars); if (ret) return ret; - #endif + + tchar_nchars /= sizeof(tchar); + size_t fixed_name_num_chars = tchar_nchars; tchar fixed_name[tchar_nchars + 50]; @@ -1910,9 +1905,9 @@ out_replace: fixed_name_num_chars += tsprintf(fixed_name + tchar_nchars, T(" (invalid filename #%lu)"), ++ctx->invalid_sequence); - #if !TCHAR_IS_UTF16LE - FREE(tchar_name); - #endif + + utf16le_put_tstr(tchar_name); + dentry->extraction_name = memdup(fixed_name, 2 * fixed_name_num_chars + 2); if (!dentry->extraction_name) diff --git a/src/inode.c b/src/inode.c index f6e14e97..992a4243 100644 --- a/src/inode.c +++ b/src/inode.c @@ -141,6 +141,8 @@ struct wim_ads_entry * inode_get_ads_entry(struct wim_inode *inode, const tchar *stream_name, u16 *idx_ret) { + int ret; + const utf16lechar *stream_name_utf16le; size_t stream_name_utf16le_nbytes; u16 i; struct wim_ads_entry *result; @@ -151,24 +153,11 @@ inode_get_ads_entry(struct wim_inode *inode, const tchar *stream_name, if (stream_name[0] == T('\0')) return NULL; -#if TCHAR_IS_UTF16LE - const utf16lechar *stream_name_utf16le; - - stream_name_utf16le = stream_name; - stream_name_utf16le_nbytes = tstrlen(stream_name) * sizeof(tchar); -#else - utf16lechar *stream_name_utf16le; + ret = tstr_get_utf16le_and_len(stream_name, &stream_name_utf16le, + &stream_name_utf16le_nbytes); + if (ret) + return NULL; - { - int ret = tstr_to_utf16le(stream_name, - tstrlen(stream_name) * - sizeof(tchar), - &stream_name_utf16le, - &stream_name_utf16le_nbytes); - if (ret) - return NULL; - } -#endif i = 0; result = NULL; do { @@ -183,46 +172,20 @@ inode_get_ads_entry(struct wim_inode *inode, const tchar *stream_name, break; } } while (++i != inode->i_num_ads); -#if !TCHAR_IS_UTF16LE - FREE(stream_name_utf16le); -#endif - return result; -} -static int -init_ads_entry(struct wim_ads_entry *ads_entry, const void *name, - size_t name_nbytes, bool is_utf16le) -{ - int ret = 0; - memset(ads_entry, 0, sizeof(*ads_entry)); + tstr_put_utf16le(stream_name_utf16le); - if (is_utf16le) { - utf16lechar *p = MALLOC(name_nbytes + sizeof(utf16lechar)); - if (p == NULL) - return WIMLIB_ERR_NOMEM; - memcpy(p, name, name_nbytes); - p[name_nbytes / 2] = cpu_to_le16(0); - ads_entry->stream_name = p; - ads_entry->stream_name_nbytes = name_nbytes; - } else { - if (name && *(const tchar*)name != T('\0')) { - ret = get_utf16le_string(name, &ads_entry->stream_name, - &ads_entry->stream_name_nbytes); - } - } - return ret; + return result; } static struct wim_ads_entry * -do_inode_add_ads(struct wim_inode *inode, const void *stream_name, - size_t stream_name_nbytes, bool is_utf16le) +do_inode_add_ads(struct wim_inode *inode, + utf16lechar *stream_name, size_t stream_name_nbytes) { u16 num_ads; struct wim_ads_entry *ads_entries; struct wim_ads_entry *new_entry; - wimlib_assert(stream_name_nbytes != 0); - if (inode->i_num_ads >= 0xfffe) { ERROR("Too many alternate data streams in one inode!"); return NULL; @@ -237,8 +200,10 @@ do_inode_add_ads(struct wim_inode *inode, const void *stream_name, inode->i_ads_entries = ads_entries; new_entry = &inode->i_ads_entries[num_ads - 1]; - if (init_ads_entry(new_entry, stream_name, stream_name_nbytes, is_utf16le)) - return NULL; + + memset(new_entry, 0, sizeof(struct wim_ads_entry)); + new_entry->stream_name = stream_name; + new_entry->stream_name_nbytes = stream_name_nbytes; new_entry->stream_id = inode->i_next_stream_id++; inode->i_num_ads = num_ads; return new_entry; @@ -246,26 +211,49 @@ do_inode_add_ads(struct wim_inode *inode, const void *stream_name, struct wim_ads_entry * inode_add_ads_utf16le(struct wim_inode *inode, - const utf16lechar *stream_name, - size_t stream_name_nbytes) + const utf16lechar *stream_name, size_t stream_name_nbytes) { - DEBUG("Add alternate data stream \"%"WS"\"", stream_name); - return do_inode_add_ads(inode, stream_name, stream_name_nbytes, true); + utf16lechar *dup = NULL; + struct wim_ads_entry *result; + + if (stream_name_nbytes) { + dup = utf16le_dupz(stream_name, stream_name_nbytes); + if (!dup) + return NULL; + } + + result = do_inode_add_ads(inode, dup, stream_name_nbytes); + if (!result) + FREE(dup); + return result; } /* * Add an alternate stream entry to a WIM inode. On success, returns a pointer * to the new entry; on failure, returns NULL. - * - * @stream_name must be a nonempty string. */ struct wim_ads_entry * inode_add_ads(struct wim_inode *inode, const tchar *stream_name) { - DEBUG("Add alternate data stream \"%"TS"\"", stream_name); - return do_inode_add_ads(inode, stream_name, - tstrlen(stream_name) * sizeof(tchar), - TCHAR_IS_UTF16LE); + utf16lechar *stream_name_utf16le = NULL; + size_t stream_name_utf16le_nbytes = 0; + int ret; + struct wim_ads_entry *result; + + if (stream_name && *stream_name) { + ret = tstr_to_utf16le(stream_name, + tstrlen(stream_name) * sizeof(tchar), + &stream_name_utf16le, + &stream_name_utf16le_nbytes); + if (ret) + return NULL; + } + + result = do_inode_add_ads(inode, stream_name_utf16le, + stream_name_utf16le_nbytes); + if (!result) + FREE(stream_name_utf16le); + return result; } int @@ -736,14 +724,10 @@ read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode, cur_entry->stream_name_nbytes > length) goto out_invalid; - cur_entry->stream_name = MALLOC(cur_entry->stream_name_nbytes + 2); + cur_entry->stream_name = utf16le_dupz(disk_entry->stream_name, + cur_entry->stream_name_nbytes); if (cur_entry->stream_name == NULL) goto out_of_memory; - - memcpy(cur_entry->stream_name, - disk_entry->stream_name, - cur_entry->stream_name_nbytes); - cur_entry->stream_name[cur_entry->stream_name_nbytes / 2] = cpu_to_le16(0); } else { /* Mark inode as having weird stream entries. */ inode->i_canonical_streams = 0; diff --git a/src/iterate_dir.c b/src/iterate_dir.c index 977a6e60..db43f502 100644 --- a/src/iterate_dir.c +++ b/src/iterate_dir.c @@ -51,27 +51,16 @@ init_wimlib_dentry(struct wimlib_dir_entry *wdentry, struct wim_lookup_table_entry *lte; const u8 *hash; -#if TCHAR_IS_UTF16LE - wdentry->filename = dentry->file_name; - wdentry->dos_name = dentry->short_name; -#else - if (dentry_has_long_name(dentry)) { - ret = utf16le_to_tstr(dentry->file_name, - dentry->file_name_nbytes, - (tchar**)&wdentry->filename, - &dummy); - if (ret) - return ret; - } - if (dentry_has_short_name(dentry)) { - ret = utf16le_to_tstr(dentry->short_name, - dentry->short_name_nbytes, - (tchar**)&wdentry->dos_name, - &dummy); - if (ret) - return ret; - } -#endif + ret = utf16le_get_tstr(dentry->file_name, dentry->file_name_nbytes, + &wdentry->filename, &dummy); + if (ret) + return ret; + + ret = utf16le_get_tstr(dentry->short_name, dentry->short_name_nbytes, + &wdentry->dos_name, &dummy); + if (ret) + return ret; + ret = calculate_dentry_full_path(dentry); if (ret) return ret; @@ -119,20 +108,16 @@ init_wimlib_dentry(struct wimlib_dir_entry *wdentry, wdentry->streams[ wdentry->num_named_streams].resource.is_missing = 1; } - #if TCHAR_IS_UTF16LE - wdentry->streams[wdentry->num_named_streams].stream_name = - inode->i_ads_entries[i].stream_name; - #else + size_t dummy; - ret = utf16le_to_tstr(inode->i_ads_entries[i].stream_name, - inode->i_ads_entries[i].stream_name_nbytes, - (tchar**)&wdentry->streams[ - wdentry->num_named_streams].stream_name, - &dummy); + ret = utf16le_get_tstr(inode->i_ads_entries[i].stream_name, + inode->i_ads_entries[i].stream_name_nbytes, + &wdentry->streams[ + wdentry->num_named_streams].stream_name, + &dummy); if (ret) return ret; - #endif } return 0; } @@ -140,12 +125,10 @@ init_wimlib_dentry(struct wimlib_dir_entry *wdentry, static void free_wimlib_dentry(struct wimlib_dir_entry *wdentry) { -#if !TCHAR_IS_UTF16LE - FREE((tchar*)wdentry->filename); - FREE((tchar*)wdentry->dos_name); + utf16le_put_tstr(wdentry->filename); + utf16le_put_tstr(wdentry->dos_name); for (unsigned i = 1; i <= wdentry->num_named_streams; i++) - FREE((tchar*)wdentry->streams[i].stream_name); -#endif + utf16le_put_tstr(wdentry->streams[i].stream_name); FREE(wdentry); } diff --git a/src/textfile.c b/src/textfile.c index 332386dc..e59a5c6c 100644 --- a/src/textfile.c +++ b/src/textfile.c @@ -131,22 +131,9 @@ translate_text_buffer(const u8 *buf_raw, size_t bufsize_raw, bufsize_raw - offset_raw, &buf_tstr, &bufsize_tstr); } else { - #if TCHAR_IS_UTF16LE - bufsize_tstr = bufsize_raw - offset_raw; - buf_tstr = MALLOC(bufsize_tstr + 2); - if (buf_tstr) { - memcpy(buf_tstr, buf_raw + offset_raw, bufsize_tstr); - ((u8*)buf_tstr)[bufsize_tstr + 0] = 0; - ((u8*)buf_tstr)[bufsize_tstr + 1] = 0; - ret = 0; - } else { - ret = WIMLIB_ERR_NOMEM; - } - #else ret = utf16le_to_tstr((const utf16lechar *)(buf_raw + offset_raw), bufsize_raw - offset_raw, &buf_tstr, &bufsize_tstr); - #endif } if (ret) return ret; diff --git a/src/update_image.c b/src/update_image.c index ceb76010..df0ab990 100644 --- a/src/update_image.c +++ b/src/update_image.c @@ -386,12 +386,14 @@ journaled_change_name(struct update_command_journal *j, struct wim_dentry *dentry, const tchar *new_name_tstr) { int ret; - utf16lechar *new_name = NULL; - u16 new_name_nbytes = 0; + utf16lechar *new_name; + size_t new_name_nbytes; struct update_primitive prim; /* Set the long name. */ - ret = get_utf16le_string(new_name_tstr, &new_name, &new_name_nbytes); + ret = tstr_to_utf16le(new_name_tstr, + tstrlen(new_name_tstr) * sizeof(tchar), + &new_name, &new_name_nbytes); if (ret) return ret; @@ -453,36 +455,6 @@ rollback_update(struct update_command_journal *j) free_update_command_journal(j); } -/* - * Set the name of @branch for placing it at @target in the WIM image. This - * assumes that @target is in "canonical form", as produced by - * canonicalize_wim_path(). - * - * Note: for the root target this produces the empty name. - */ -static int -set_branch_name(struct wim_dentry *branch, const utf16lechar *target) -{ - const utf16lechar *p; - - /* Find end of string. (We can assume it contains at least one - * character, the leading slash.) */ - wimlib_assert(target[0] == cpu_to_le16(WIM_PATH_SEPARATOR)); - p = target; - do { - p++; - } while (*p); - - while (*(p - 1) != cpu_to_le16(WIM_PATH_SEPARATOR)) - p--; - - - /* We're assuming no trailing slashes. */ - wimlib_assert(*p || p == &target[1]); - - return dentry_set_name_utf16le(branch, p); -} - static int handle_conflict(struct wim_dentry *branch, struct wim_dentry *existing, struct update_command_journal *j, @@ -569,15 +541,16 @@ handle_conflict(struct wim_dentry *branch, struct wim_dentry *existing, } static int -do_attach_branch(struct wim_dentry *branch, utf16lechar *target, +do_attach_branch(struct wim_dentry *branch, const utf16lechar *target, struct update_command_journal *j, int add_flags, wimlib_progress_func_t progress_func) { struct wim_dentry *parent; struct wim_dentry *existing; - utf16lechar empty_name[1] = {0}; - utf16lechar *cur_component_name; - utf16lechar *next_component_name; + const utf16lechar empty_name[1] = {0}; + const utf16lechar *cur_component_name; + size_t cur_component_nbytes; + const utf16lechar *next_component_name; int ret; /* Attempt to create root directory before proceeding to the "real" @@ -585,6 +558,7 @@ do_attach_branch(struct wim_dentry *branch, utf16lechar *target, parent = NULL; existing = *j->root_p; cur_component_name = empty_name; + cur_component_nbytes = 0; /* Skip leading slashes */ next_component_name = target; @@ -592,7 +566,7 @@ do_attach_branch(struct wim_dentry *branch, utf16lechar *target, next_component_name++; while (*next_component_name) { /* While not the last component ... */ - utf16lechar *end; + const utf16lechar *end; if (existing) { /* Descend into existing directory */ @@ -611,7 +585,8 @@ do_attach_branch(struct wim_dentry *branch, utf16lechar *target, if (ret) return ret; ret = dentry_set_name_utf16le(filler, - cur_component_name); + cur_component_name, + cur_component_nbytes); if (ret) { free_dentry(filler); return ret; @@ -634,7 +609,6 @@ do_attach_branch(struct wim_dentry *branch, utf16lechar *target, next_component_name = end; if (*end) { /* There will still be more components after this. */ - *end = 0; do { } while (*++next_component_name == cpu_to_le16(WIM_PATH_SEPARATOR)); wimlib_assert(*next_component_name); /* No trailing slashes */ @@ -643,10 +617,11 @@ do_attach_branch(struct wim_dentry *branch, utf16lechar *target, next_component_name = end; } parent = existing; + cur_component_nbytes = (end - cur_component_name) * sizeof(utf16lechar); existing = get_dentry_child_with_utf16le_name( parent, cur_component_name, - (end - cur_component_name) * sizeof(utf16lechar), + cur_component_nbytes, WIMLIB_CASE_PLATFORM_DEFAULT); } @@ -678,30 +653,18 @@ attach_branch(struct wim_dentry *branch, const tchar *target_tstr, int add_flags, wimlib_progress_func_t progress_func) { int ret; - utf16lechar *target; + const utf16lechar *target; + ret = 0; if (unlikely(!branch)) - return 0; + goto out; -#if TCHAR_IS_UTF16LE - target = memdup(target_tstr, - (tstrlen(target_tstr) + 1) * sizeof(target_tstr[0])); - if (!target) { - ret = WIMLIB_ERR_NOMEM; + ret = tstr_get_utf16le(target_tstr, &target); + if (ret) goto out_free_branch; - } -#else - { - size_t target_nbytes; - ret = tstr_to_utf16le(target_tstr, - tstrlen(target_tstr) * sizeof(target_tstr[0]), - &target, &target_nbytes); - if (ret) - goto out_free_branch; - } -#endif - ret = set_branch_name(branch, target); + BUILD_BUG_ON(WIM_PATH_SEPARATOR != OS_PREFERRED_PATH_SEPARATOR); + ret = dentry_set_name(branch, path_basename(target_tstr)); if (ret) goto out_free_target; @@ -711,9 +674,10 @@ attach_branch(struct wim_dentry *branch, const tchar *target_tstr, /* branch was successfully committed to the journal */ branch = NULL; out_free_target: - FREE(target); + tstr_put_utf16le(target); out_free_branch: free_dentry_tree(branch, j->lookup_table); +out: return ret; } diff --git a/src/wildcard.c b/src/wildcard.c index 2619f47b..234ee91c 100644 --- a/src/wildcard.c +++ b/src/wildcard.c @@ -188,23 +188,18 @@ wildcard_status(const tchar *wildcard) static int match_dentry(struct wim_dentry *cur_dentry, struct match_dentry_ctx *ctx) { - tchar *name; + const tchar *name; size_t name_len; int ret; if (cur_dentry->file_name_nbytes == 0) return 0; -#if TCHAR_IS_UTF16LE - name = cur_dentry->file_name; - name_len = cur_dentry->file_name_nbytes; -#else - ret = utf16le_to_tstr(cur_dentry->file_name, - cur_dentry->file_name_nbytes, - &name, &name_len); + ret = utf16le_get_tstr(cur_dentry->file_name, + cur_dentry->file_name_nbytes, + &name, &name_len); if (ret) return ret; -#endif name_len /= sizeof(tchar); if (match_wildcard(name, @@ -235,9 +230,8 @@ match_dentry(struct wim_dentry *cur_dentry, struct match_dentry_ctx *ctx) ret = 0; } -#if !TCHAR_IS_UTF16LE - FREE(name); -#endif + utf16le_put_tstr(name); + return ret; } -- 2.43.0