Improve tstr <=> UTF-16LE conversions
authorEric Biggers <ebiggers3@gmail.com>
Tue, 13 May 2014 05:25:50 +0000 (00:25 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Tue, 13 May 2014 05:26:42 +0000 (00:26 -0500)
Consolidated conditional code into encoding.h.
A few related cleanups.

include/wimlib/dentry.h
include/wimlib/encoding.h
src/dentry.c
src/encoding.c
src/extract.c
src/inode.c
src/iterate_dir.c
src/textfile.c
src/update_image.c
src/wildcard.c

index edd9920..bdbd5f7 100644 (file)
@@ -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,
index 20cb8d8..00f1a38 100644 (file)
@@ -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 <string.h>
+
 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 */
index 3e462a6..123ae90 100644 (file)
@@ -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.  */
index e588eab..927cb5d 100644 (file)
@@ -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;
 }
-
index bc769ee..a4029ec 100644 (file)
@@ -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)
index f6e14e9..992a424 100644 (file)
@@ -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;
index 977a6e6..db43f50 100644 (file)
@@ -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);
 }
 
index 332386d..e59a5c6 100644 (file)
@@ -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;
index ceb7601..df0ab99 100644 (file)
@@ -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;
 }
 
index 2619f47..234ee91 100644 (file)
@@ -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;
 }