Char encoding updates and misc. fixes
authorEric Biggers <ebiggers3@gmail.com>
Sat, 23 Mar 2013 21:04:41 +0000 (16:04 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Sat, 23 Mar 2013 21:04:41 +0000 (16:04 -0500)
36 files changed:
Makefile.am
configure.ac
programs/imagex-win32.c
programs/imagex-win32.h
programs/imagex.c
programs/wgetopt.c [new file with mode: 0644]
programs/wgetopt.h [new file with mode: 0644]
src/add_image.c
src/dentry.c
src/dentry.h
src/encoding.c
src/export_image.c
src/extract_image.c
src/hardlink.c
src/header.c
src/integrity.c
src/lookup_table.c
src/lookup_table.h
src/metadata_resource.c
src/mount_image.c
src/ntfs-apply.c
src/ntfs-capture.c
src/resource.c
src/security.c
src/sha1.c
src/split.c
src/symlink.c
src/util.c
src/util.h
src/verify.c
src/wim.c
src/wimlib.h
src/win32.c
src/write.c
src/xml.c
wimlib_tchar.h [new file with mode: 0644]

index 8592d07..3ac56d4 100644 (file)
@@ -1,9 +1,8 @@
 ACLOCAL_AMFLAGS = -I m4
 
-AM_CPPFLAGS    = -I$(top_srcdir)/src $(WINDOWS_CPPFLAGS)
-
-AM_CFLAGS      = -std=gnu99 -D_LARGEFILE_SOURCE \
-                  -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
+AM_CPPFLAGS    = -I$(top_srcdir)/src $(WINDOWS_CPPFLAGS) \
+                 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
+AM_CFLAGS      = -std=gnu99
 
 lib_LTLIBRARIES = libwim.la
 
@@ -52,6 +51,7 @@ libwim_la_SOURCES =           \
        src/verify.c            \
        src/wim.c               \
        src/wimlib.h            \
+       wimlib_tchar.h          \
        src/wimlib_internal.h   \
        src/write.c             \
        src/xml.c               \
@@ -95,11 +95,16 @@ libwim_la_CFLAGS =          \
 
 
 bin_PROGRAMS    = imagex
-imagex_SOURCES   = programs/imagex.c
+imagex_SOURCES   = programs/imagex.c wimlib_tchar.h
 imagex_LDADD    = $(top_builddir)/libwim.la
+imagex_CFLAGS    = $(AM_CFLAGS) $(WINDOWS_CFLAGS)
 
 if WINDOWS_NATIVE_BUILD
-imagex_SOURCES += programs/imagex-win32.c programs/imagex-win32.h
+imagex_SOURCES += programs/imagex-win32.c      \
+                 programs/imagex-win32.h       \
+                 programs/wgetopt.c            \
+                 programs/wgetopt.h
+
 libwim_la_SOURCES += src/win32.c
 endif
 
index 7113639..fe07a3c 100644 (file)
@@ -179,6 +179,7 @@ WITH_NTFS_3G_DEFAULT="yes"
 WITH_FUSE_DEFAULT="yes"
 WINDOWS_NATIVE_BUILD="no"
 VISIBILITY_CFLAGS="-fvisibility=hidden"
+WINDOWS_CFLAGS=""
 WINDOWS_CPPFLAGS=""
 WINDOWS_LDFLAGS=""
 WINDOWS_LDADD=""
@@ -190,12 +191,15 @@ case "$host" in
                WITH_FUSE_DEFAULT="no"
                WINDOWS_NATIVE_BUILD="yes"
                VISIBILITY_CFLAGS=""
+               WINDOWS_CFLAGS="-municode"
                WINDOWS_CPPFLAGS="-D_POSIX"
                WINDOWS_LDFLAGS="-no-undefined"
                WINDOWS_LDADD="-lshlwapi"
                ;;
        *-*-cygwin*)
                # Cygwin (WARNING: not well supported)
+               AC_MSG_WARN([wimlib has not been tested with Cygwin!  Please do
+                            a Windows-native build with MinGW-w64 instead])
                WITH_NTFS_3G_DEFAULT="no"
                WITH_FUSE_DEFAULT="no"
                VISIBILITY_CFLAGS=""
@@ -209,6 +213,7 @@ AC_SUBST([VISIBILITY_CFLAGS], [$VISIBILITY_CFLAGS])
 AC_SUBST([WINDOWS_LDFLAGS], [$WINDOWS_LDFLAGS])
 AC_SUBST([WINDOWS_LDADD], [$WINDOWS_LDADD])
 AC_SUBST([WINDOWS_CPPFLAGS], [$WINDOWS_CPPFLAGS])
+AC_SUBST([WINDOWS_CFLAGS], [$WINDOWS_CFLAGS])
 AM_CONDITIONAL([WINDOWS_NATIVE_BUILD], [test "x$WINDOWS_NATIVE_BUILD" = "xyes"])
 
 AC_MSG_CHECKING([whether to include support for ntfs-3g])
index 1664850..18581ed 100644 (file)
 #include <stdio.h>
 
 /* Replacement for glob() in Windows native builds. */
-int glob(const char *pattern, int flags,
-        int (*errfunc)(const char *epath, int eerrno),
-        glob_t *pglob)
+int
+win32_wglob(const wchar_t *pattern, int flags,
+           int (*errfunc)(const wchar_t *epath, int eerrno),
+           glob_t *pglob)
 {
-       WIN32_FIND_DATA dat;
+       WIN32_FIND_DATAW dat;
        DWORD err;
        HANDLE hFind;
        int ret;
        size_t nspaces;
 
-       const char *backslash, *forward_slash, *end_slash;
+       const wchar_t *backslash, *end_slash;
        size_t prefix_len;
 
-       backslash = strrchr(pattern, '\\');
-       end_slash = strrchr(pattern, '/');
+       backslash = wcsrchr(pattern, L'\\');
+       end_slash = wcsrchr(pattern, L'/');
 
        if (backslash > end_slash)
                end_slash = backslash;
@@ -46,7 +47,7 @@ int glob(const char *pattern, int flags,
        assert((flags & GLOB_ERR) == GLOB_ERR);
        assert((flags & ~(GLOB_NOSORT | GLOB_ERR)) == 0);
 
-       hFind = FindFirstFileA(pattern, &dat);
+       hFind = FindFirstFileW(pattern, &dat);
        if (hFind == INVALID_HANDLE_VALUE) {
                err = GetLastError();
                if (err == ERROR_FILE_NOT_FOUND) {
@@ -63,10 +64,10 @@ int glob(const char *pattern, int flags,
        pglob->gl_pathv = NULL;
        nspaces = 0;
        do {
-               char *path;
+               wchar_t *path;
                if (pglob->gl_pathc == nspaces) {
                        size_t new_nspaces;
-                       char **pathv;
+                       wchar_t **pathv;
 
                        new_nspaces = nspaces * 2 + 1;  
                        pathv = realloc(pglob->gl_pathv,
@@ -76,17 +77,17 @@ int glob(const char *pattern, int flags,
                        pglob->gl_pathv = pathv;
                        nspaces = new_nspaces;
                }
-               size_t filename_len = strlen(dat.cFileName);
+               size_t filename_len = wcslen(dat.cFileName);
                size_t len_needed = prefix_len + filename_len;
 
-               path = malloc(len_needed + 1);
+               path = malloc(len_needed + sizeof(wchar_t));
                if (!path)
                        goto oom;
 
-               memcpy(path, pattern, prefix_len);
-               memcpy(path + prefix_len, dat.cFileName, filename_len + 1);
+               wmemcpy(path, pattern, prefix_len);
+               wmemcpy(path + prefix_len, dat.cFileName, filename_len + 1);
                pglob->gl_pathv[pglob->gl_pathc++] = path;
-       } while (FindNextFileA(hFind, &dat));
+       } while (FindNextFileW(hFind, &dat));
        err = GetLastError();
        CloseHandle(hFind);
        if (err == ERROR_NO_MORE_FILES) {
@@ -108,7 +109,8 @@ fail_globfree:
        return ret;
 }
 
-void globfree(glob_t *pglob)
+void
+globfree(glob_t *pglob)
 {
        size_t i;
        for (i = 0; i < pglob->gl_pathc; i++)
@@ -142,13 +144,13 @@ win32_modify_privilege(const char *privilege, bool enable)
        CloseHandle(hToken);
 out:
        if (!ret) {
-               fprintf(stderr, "WARNING: Failed to %s privilege %s\n",
-                       enable ? "enable" : "disable", privilege);
-               fprintf(stderr,
-                       "WARNING: The program will continue, "
-                       "but if permission issues are\n"
-                       "encountered, you may need to run "
-                       "this program as the administrator\n");
+               fwprintf(stderr, L"WARNING: Failed to %ls privilege %s\n",
+                       enable ? L"enable" : L"disable", privilege);
+               fwprintf(stderr,
+                       L"WARNING: The program will continue, "
+                       L"but if permission issues are\n"
+                       L"encountered, you may need to run "
+                       L"this program as the administrator\n");
        }
        return ret;
 }
@@ -191,3 +193,69 @@ win32_release_restore_privileges()
 {
        win32_modify_restore_privileges(false);
 }
+
+wchar_t *
+win32_mbs_to_wcs(const char *mbs, size_t mbs_nbytes, size_t *num_wchars_ret)
+{
+       if (mbs_nbytes > INT_MAX) {
+               fwprintf(stderr, L"ERROR: too much data (%zu bytes)!\n",
+                        mbs_nbytes);
+               return NULL;
+       }
+       if (mbs_nbytes == 0) {
+               *num_wchars_ret = 0;
+               return (wchar_t*)mbs;
+       }
+       int len = MultiByteToWideChar(CP_ACP,
+                                     MB_ERR_INVALID_CHARS,
+                                     mbs,
+                                     mbs_nbytes,
+                                     NULL,
+                                     0);
+       if (len <= 0)
+               goto out_invalid;
+       wchar_t *wcs = malloc(len * sizeof(wchar_t));
+       if (!wcs) {
+               fwprintf(stderr, L"ERROR: out of memory!\n");
+               return NULL;
+       }
+       int len2 = MultiByteToWideChar(CP_ACP,
+                                      MB_ERR_INVALID_CHARS,
+                                      mbs,
+                                      mbs_nbytes,
+                                      wcs,
+                                      len);
+       if (len2 != len) {
+               free(wcs);
+               goto out_invalid;
+       }
+       *num_wchars_ret = len;
+       return wcs;
+out_invalid:
+       fwprintf(stderr,
+L"ERROR: Invalid multi-byte string in the text file you provided as input!\n"
+L"       Maybe try converting your text file to UTF-16LE?\n"
+       );
+       return NULL;
+}
+
+static inline bool
+is_path_separator(wchar_t c)
+{
+       return c == L'/' || c == L'\\';
+}
+
+wchar_t *
+win32_wbasename(wchar_t *path)
+{
+       wchar_t *p = wcschr(path, L'\0');
+
+       p--;
+       while (p >= path && is_path_separator(*p))
+               *p-- = '\0';
+       while (p >= path && !is_path_separator(*p))
+               p--;
+       p++;
+       return p;
+}
+
index 1de8e98..9e18eab 100644 (file)
@@ -3,17 +3,19 @@
 
 #include <stddef.h>
 #include <stdbool.h>
+#include <wchar.h>
 
 typedef struct {
-       size_t gl_pathc;
-       char **gl_pathv;
-       size_t gl_offs;
+       size_t    gl_pathc;
+       wchar_t **gl_pathv;
+       size_t    gl_offs;
 } glob_t;
 
 /* WARNING: this is a reduced functionality replacement */
-extern int glob(const char *pattern, int flags,
-               int (*errfunc)(const char *epath, int eerrno),
-               glob_t *pglob);
+extern int
+win32_wglob(const wchar_t *pattern, int flags,
+           int (*errfunc)(const wchar_t *epath, int eerrno),
+           glob_t *pglob);
 
 extern void globfree(glob_t *pglob);
 
@@ -37,4 +39,22 @@ win32_acquire_restore_privileges();
 extern void
 win32_release_restore_privileges();
 
+extern wchar_t *
+win32_mbs_to_wcs(const char *mbs, size_t mbs_nbytes, size_t *num_wchars_ret);
+
+extern wchar_t *
+win32_wbasename(wchar_t *path);
+
+#include "wgetopt.h"
+
+#define optarg                 woptarg
+#define optind                 woptind
+#define opterr                 wopterr
+#define optopt                 woptopt
+#define option                 woption
+
+#define getopt_long_only       wgetopt_long_only
+#define getopt_long            wgetopt_long
+#define getopt                 wgetopt
+
 #endif
index 0d271e4..a2e9e5e 100644 (file)
  */
 
 #include "config.h"
-
+#include "wimlib_tchar.h"
 #include "wimlib.h"
 
 #include <ctype.h>
 #include <errno.h>
-#include <getopt.h>
 
 #include <inttypes.h>
 #include <libgen.h>
 
 #ifdef __WIN32__
 #  include "imagex-win32.h"
-#else
+#  define tbasename    win32_wbasename
+#  define tglob                win32_wglob
+#else /* __WIN32__ */
 #  include <glob.h>
-#endif
+#  include <getopt.h>
+#  include <langinfo.h>
+#  define tbasename    basename
+#  define tglob                glob
+#endif /* !__WIN32 */
+
 
 #define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0]))
 
-#define for_opt(c, opts) while ((c = getopt_long_only(argc, (char**)argv, "", \
+#define for_opt(c, opts) while ((c = getopt_long_only(argc, (tchar**)argv, T(""), \
                                opts, NULL)) != -1)
 
 enum imagex_op_type {
@@ -75,192 +81,222 @@ static void usage(int cmd_type);
 static void usage_all();
 
 
-static const char *usage_strings[] = {
+static const tchar *usage_strings[] = {
 [APPEND] =
+T(
 IMAGEX_PROGNAME" append (DIRECTORY | NTFS_VOLUME) WIMFILE [IMAGE_NAME]\n"
 "                     [DESCRIPTION] [--boot] [--check] [--flags EDITION_ID]\n"
 "                     [--verbose] [--dereference] [--config=FILE]\n"
 "                     [--threads=NUM_THREADS] [--rebuild] [--unix-data]\n"
-"                     [--source-list] [--noacls]\n",
+"                     [--source-list] [--noacls]\n"
+),
 [APPLY] =
+T(
 IMAGEX_PROGNAME" apply WIMFILE [IMAGE_NUM | IMAGE_NAME | all]\n"
 "                    (DIRECTORY | NTFS_VOLUME) [--check] [--hardlink]\n"
 "                    [--symlink] [--verbose] [--ref=\"GLOB\"] [--unix-data]\n"
-"                    [--noacls]\n",
+"                    [--noacls]\n"
+),
 [CAPTURE] =
+T(
 IMAGEX_PROGNAME" capture (DIRECTORY | NTFS_VOLUME) WIMFILE [IMAGE_NAME]\n"
 "                      [DESCRIPTION] [--boot] [--check] [--compress=TYPE]\n"
 "                      [--flags EDITION_ID] [--verbose] [--dereference]\n"
 "                      [--config=FILE] [--threads=NUM_THREADS] [--unix-data]\n"
-"                      [--source-list] [--noacls]\n",
+"                      [--source-list] [--noacls]\n"
+),
 [DELETE] =
-IMAGEX_PROGNAME" delete WIMFILE (IMAGE_NUM | IMAGE_NAME | all) [--check] [--soft]\n",
+T(
+IMAGEX_PROGNAME" delete WIMFILE (IMAGE_NUM | IMAGE_NAME | all) [--check] [--soft]\n"
+),
 [DIR] =
-IMAGEX_PROGNAME" dir WIMFILE (IMAGE_NUM | IMAGE_NAME | all)\n",
+T(
+IMAGEX_PROGNAME" dir WIMFILE (IMAGE_NUM | IMAGE_NAME | all)\n"
+),
 [EXPORT] =
+T(
 IMAGEX_PROGNAME" export SRC_WIMFILE (SRC_IMAGE_NUM | SRC_IMAGE_NAME | all ) \n"
 "              DEST_WIMFILE [DEST_IMAGE_NAME] [DEST_IMAGE_DESCRIPTION]\n"
 "              [--boot] [--check] [--compress=TYPE] [--ref=\"GLOB\"]\n"
-"              [--threads=NUM_THREADS] [--rebuild]\n",
+"              [--threads=NUM_THREADS] [--rebuild]\n"
+),
 [INFO] =
+T(
 IMAGEX_PROGNAME" info WIMFILE [IMAGE_NUM | IMAGE_NAME] [NEW_NAME]\n"
 "                   [NEW_DESC] [--boot] [--check] [--header] [--lookup-table]\n"
-"                   [--xml] [--extract-xml FILE] [--metadata]\n",
+"                   [--xml] [--extract-xml FILE] [--metadata]\n"
+),
 [JOIN] =
-IMAGEX_PROGNAME" join [--check] WIMFILE SPLIT_WIM...\n",
+T(
+IMAGEX_PROGNAME" join [--check] WIMFILE SPLIT_WIM...\n"
+),
 [MOUNT] =
+T(
 IMAGEX_PROGNAME" mount WIMFILE (IMAGE_NUM | IMAGE_NAME) DIRECTORY\n"
 "                    [--check] [--debug] [--streams-interface=INTERFACE]\n"
-"                    [--ref=\"GLOB\"] [--unix-data] [--allow-other]\n",
+"                    [--ref=\"GLOB\"] [--unix-data] [--allow-other]\n"
+),
 [MOUNTRW] =
+T(
 IMAGEX_PROGNAME" mountrw WIMFILE [IMAGE_NUM | IMAGE_NAME] DIRECTORY\n"
 "                      [--check] [--debug] [--streams-interface=INTERFACE]\n"
-"                      [--staging-dir=DIR] [--unix-data] [--allow-other]\n",
+"                      [--staging-dir=DIR] [--unix-data] [--allow-other]\n"
+),
 [OPTIMIZE] =
-IMAGEX_PROGNAME" optimize WIMFILE [--check] [--recompress] [--compress=TYPE]\n",
+T(
+IMAGEX_PROGNAME" optimize WIMFILE [--check] [--recompress]\n"
+),
 [SPLIT] =
-IMAGEX_PROGNAME" split WIMFILE SPLIT_WIMFILE PART_SIZE_MB [--check]\n",
+T(
+IMAGEX_PROGNAME" split WIMFILE SPLIT_WIMFILE PART_SIZE_MB [--check]\n"
+),
 [UNMOUNT] =
-IMAGEX_PROGNAME" unmount DIRECTORY [--commit] [--check] [--rebuild]\n",
+T(
+IMAGEX_PROGNAME" unmount DIRECTORY [--commit] [--check] [--rebuild]\n"
+),
 };
 
 static const struct option apply_options[] = {
-       {"check",     no_argument,       NULL, 'c'},
-       {"hardlink",  no_argument,       NULL, 'h'},
-       {"symlink",   no_argument,       NULL, 's'},
-       {"verbose",   no_argument,       NULL, 'v'},
-       {"ref",       required_argument, NULL, 'r'},
-       {"unix-data", no_argument,       NULL, 'U'},
-       {"noacls",    no_argument,       NULL, 'N'},
+       {T("check"),     no_argument,       NULL, 'c'},
+       {T("hardlink"),  no_argument,       NULL, 'h'},
+       {T("symlink"),   no_argument,       NULL, 's'},
+       {T("verbose"),   no_argument,       NULL, 'v'},
+       {T("ref"),       required_argument, NULL, 'r'},
+       {T("unix-data"), no_argument,       NULL, 'U'},
+       {T("noacls"),    no_argument,       NULL, 'N'},
        {NULL, 0, NULL, 0},
 };
 static const struct option capture_or_append_options[] = {
-       {"boot",        no_argument,       NULL, 'b'},
-       {"check",       no_argument,       NULL, 'c'},
-       {"compress",    required_argument, NULL, 'x'},
-       {"config",      required_argument, NULL, 'C'},
-       {"dereference", no_argument,       NULL, 'L'},
-       {"flags",       required_argument, NULL, 'f'},
-       {"verbose",     no_argument,       NULL, 'v'},
-       {"threads",     required_argument, NULL, 't'},
-       {"rebuild",     no_argument,       NULL, 'R'},
-       {"unix-data",   no_argument,       NULL, 'U'},
-       {"source-list", no_argument,       NULL, 'S'},
-       {"noacls",      no_argument,       NULL, 'N'},
+       {T("boot"),     no_argument,       NULL, 'b'},
+       {T("check"),    no_argument,       NULL, 'c'},
+       {T("compress"), required_argument, NULL, 'x'},
+       {T("config"),   required_argument, NULL, 'C'},
+       {T("dereference"), no_argument,    NULL, 'L'},
+       {T("flags"),    required_argument, NULL, 'f'},
+       {T("verbose"),  no_argument,       NULL, 'v'},
+       {T("threads"),     required_argument, NULL, 't'},
+       {T("rebuild"),     no_argument,       NULL, 'R'},
+       {T("unix-data"),   no_argument,       NULL, 'U'},
+       {T("source-list"), no_argument,       NULL, 'S'},
+       {T("noacls"),      no_argument,       NULL, 'N'},
        {NULL, 0, NULL, 0},
 };
 static const struct option delete_options[] = {
-       {"check", no_argument, NULL, 'c'},
-       {"soft",  no_argument, NULL, 's'},
+       {T("check"), no_argument, NULL, 'c'},
+       {T("soft"),  no_argument, NULL, 's'},
        {NULL, 0, NULL, 0},
 };
 
 static const struct option export_options[] = {
-       {"boot",       no_argument,       NULL, 'b'},
-       {"check",      no_argument,       NULL, 'c'},
-       {"compress",   required_argument, NULL, 'x'},
-       {"ref",        required_argument, NULL, 'r'},
-       {"threads",    required_argument, NULL, 't'},
-       {"rebuild",    no_argument,       NULL, 'R'},
+       {T("boot"),       no_argument,    NULL, 'b'},
+       {T("check"),      no_argument,    NULL, 'c'},
+       {T("compress"),   required_argument, NULL, 'x'},
+       {T("ref"),        required_argument, NULL, 'r'},
+       {T("threads"),    required_argument, NULL, 't'},
+       {T("rebuild"),    no_argument,       NULL, 'R'},
        {NULL, 0, NULL, 0},
 };
 
 static const struct option info_options[] = {
-       {"boot",         no_argument, NULL, 'b'},
-       {"check",        no_argument, NULL, 'c'},
-       {"extract-xml",  required_argument, NULL, 'X'},
-       {"header",       no_argument, NULL, 'h'},
-       {"lookup-table", no_argument, NULL, 'l'},
-       {"metadata",     no_argument, NULL, 'm'},
-       {"xml",          no_argument, NULL, 'x'},
+       {T("boot"),         no_argument, NULL, 'b'},
+       {T("check"),        no_argument, NULL, 'c'},
+       {T("extract-xml"),  required_argument, NULL, 'X'},
+       {T("header"),       no_argument, NULL, 'h'},
+       {T("lookup-table"), no_argument, NULL, 'l'},
+       {T("metadata"),     no_argument, NULL, 'm'},
+       {T("xml"),          no_argument, NULL, 'x'},
        {NULL, 0, NULL, 0},
 };
 
 static const struct option join_options[] = {
-       {"check", no_argument, NULL, 'c'},
+       {T("check"), no_argument, NULL, 'c'},
        {NULL, 0, NULL, 0},
 };
 
 static const struct option mount_options[] = {
-       {"check",             no_argument,       NULL, 'c'},
-       {"debug",             no_argument,       NULL, 'd'},
-       {"streams-interface", required_argument, NULL, 's'},
-       {"ref",               required_argument, NULL, 'r'},
-       {"staging-dir",       required_argument, NULL, 'D'},
-       {"unix-data",         no_argument,       NULL, 'U'},
-       {"allow-other",       no_argument,       NULL, 'A'},
+       {T("check"),          no_argument,       NULL, 'c'},
+       {T("debug"),          no_argument,       NULL, 'd'},
+       {T("streams-interface"), required_argument, NULL, 's'},
+       {T("ref"),               required_argument, NULL, 'r'},
+       {T("staging-dir"),       required_argument, NULL, 'D'},
+       {T("unix-data"),         no_argument,       NULL, 'U'},
+       {T("allow-other"),       no_argument,       NULL, 'A'},
        {NULL, 0, NULL, 0},
 };
 
 static const struct option optimize_options[] = {
-       {"check",      no_argument, NULL, 'c'},
-       {"recompress", no_argument, NULL, 'r'},
+       {T("check"),      no_argument, NULL, 'c'},
+       {T("recompress"), no_argument, NULL, 'r'},
        {NULL, 0, NULL, 0},
 };
 
 static const struct option split_options[] = {
-       {"check", no_argument, NULL, 'c'},
+       {T("check"), no_argument, NULL, 'c'},
        {NULL, 0, NULL, 0},
 };
 
 static const struct option unmount_options[] = {
-       {"commit",  no_argument, NULL, 'c'},
-       {"check",   no_argument, NULL, 'C'},
-       {"rebuild", no_argument, NULL, 'R'},
+       {T("commit"),  no_argument, NULL, 'c'},
+       {T("check"),   no_argument, NULL, 'C'},
+       {T("rebuild"), no_argument, NULL, 'R'},
        {NULL, 0, NULL, 0},
 };
 
 
 
 /* Print formatted error message to stderr. */
-static void imagex_error(const char *format, ...)
+static void
+imagex_error(const tchar *format, ...)
 {
        va_list va;
        va_start(va, format);
-       fputs("ERROR: ", stderr);
-       vfprintf(stderr, format, va);
-       putc('\n', stderr);
+       tfputs(T("ERROR: "), stderr);
+       tvfprintf(stderr, format, va);
+       tputc(T('\n'), stderr);
        va_end(va);
 }
 
 /* Print formatted error message to stderr. */
-static void imagex_error_with_errno(const char *format, ...)
+static void
+imagex_error_with_errno(const tchar *format, ...)
 {
        int errno_save = errno;
        va_list va;
        va_start(va, format);
-       fputs("ERROR: ", stderr);
-       vfprintf(stderr, format, va);
-       fprintf(stderr, ": %s\n", strerror(errno_save));
+       tfputs(T("ERROR: "), stderr);
+       tvfprintf(stderr, format, va);
+       tfprintf(stderr, T(": %"TS"\n"), tstrerror(errno_save));
        va_end(va);
 }
 
-static int verify_image_exists(int image, const char *image_name,
-                              const char *wim_name)
+static int
+verify_image_exists(int image, const tchar *image_name, const tchar *wim_name)
 {
        if (image == WIMLIB_NO_IMAGE) {
-               imagex_error("\"%s\" is not a valid image in `%s'!\n"
+               imagex_error(T("\"%"TS"\" is not a valid image in \"%"TS"\"!\n"
                             "       Please specify a 1-based image index or "
                             "image name.\n"
                             "       You may use `"IMAGEX_PROGNAME" info' to list the images "
-                            "contained in a WIM.",
+                            "contained in a WIM."),
                             image_name, wim_name);
                return -1;
        }
        return 0;
 }
 
-static int verify_image_is_single(int image)
+static int
+verify_image_is_single(int image)
 {
        if (image == WIMLIB_ALL_IMAGES) {
-               imagex_error("Cannot specify all images for this action!");
+               imagex_error(T("Cannot specify all images for this action!"));
                return -1;
        }
        return 0;
 }
 
-static int verify_image_exists_and_is_single(int image, const char *image_name,
-                                            const char *wim_name)
+static int
+verify_image_exists_and_is_single(int image, const tchar *image_name,
+                                 const tchar *wim_name)
 {
        int ret;
        ret = verify_image_exists(image, image_name, wim_name);
@@ -270,33 +306,36 @@ static int verify_image_exists_and_is_single(int image, const char *image_name,
 }
 
 /* Parse the argument to --compress */
-static int get_compression_type(const char *optarg)
+static int
+get_compression_type(const tchar *optarg)
 {
-       if (strcasecmp(optarg, "maximum") == 0 || strcasecmp(optarg, "lzx") == 0)
+       if (tstrcasecmp(optarg, T("maximum")) == 0 || tstrcasecmp(optarg, T("lzx")) == 0)
                return WIMLIB_COMPRESSION_TYPE_LZX;
-       else if (strcasecmp(optarg, "fast") == 0 || strcasecmp(optarg, "xpress") == 0)
+       else if (tstrcasecmp(optarg, T("fast")) == 0 || tstrcasecmp(optarg, T("xpress")) == 0)
                return WIMLIB_COMPRESSION_TYPE_XPRESS;
-       else if (strcasecmp(optarg, "none") == 0)
+       else if (tstrcasecmp(optarg, T("none")) == 0)
                return WIMLIB_COMPRESSION_TYPE_NONE;
        else {
-               imagex_error("Invalid compression type `%s'! Must be "
-                            "\"maximum\", \"fast\", or \"none\".", optarg);
+               imagex_error(T("Invalid compression type \"%"TS"\"! Must be "
+                            "\"maximum\", \"fast\", or \"none\"."), optarg);
                return WIMLIB_COMPRESSION_TYPE_INVALID;
        }
 }
 
 /* Returns the size of a file given its name, or -1 if the file does not exist
  * or its size cannot be determined.  */
-static off_t file_get_size(const char *filename)
+static off_t
+file_get_size(const tchar *filename)
 {
        struct stat st;
-       if (stat(filename, &st) == 0)
+       if (tstat(filename, &st) == 0)
                return st.st_size;
        else
                return (off_t)-1;
 }
 
-static const char *default_capture_config =
+static const tchar *default_capture_config =
+T(
 "[ExclusionList]\n"
 "\\$ntfs.log\n"
 "\\hiberfil.sys\n"
@@ -309,46 +348,8 @@ static const char *default_capture_config =
 "*.mp3\n"
 "*.zip\n"
 "*.cab\n"
-"\\WINDOWS\\inf\\*.pnf\n";
-
-/* Read standard input until EOF and return the full contents in a malloc()ed
- * buffer and the number of bytes of data in @len_ret.  Returns NULL on read
- * error. */
-static char *stdin_get_contents(size_t *len_ret)
-{
-       /* stdin can, of course, be a pipe or other non-seekable file, so the
-        * total length of the data cannot be pre-determined */
-       char *buf = NULL;
-       size_t newlen = 1024;
-       size_t pos = 0;
-       size_t inc = 1024;
-       for (;;) {
-               char *p = realloc(buf, newlen);
-               size_t bytes_read, bytes_to_read;
-               if (!p) {
-                       imagex_error("out of memory while reading stdin");
-                       break;
-               }
-               buf = p;
-               bytes_to_read = newlen - pos;
-               bytes_read = fread(&buf[pos], 1, bytes_to_read, stdin);
-               pos += bytes_read;
-               if (bytes_read != bytes_to_read) {
-                       if (feof(stdin)) {
-                               *len_ret = pos;
-                               return buf;
-                       } else {
-                               imagex_error_with_errno("error reading stdin");
-                               break;
-                       }
-               }
-               newlen += inc;
-               inc *= 3;
-               inc /= 2;
-       }
-       free(buf);
-       return NULL;
-}
+"\\WINDOWS\\inf\\*.pnf\n"
+);
 
 enum {
        PARSE_FILENAME_SUCCESS = 0,
@@ -379,31 +380,32 @@ enum {
  *          closing quote; or PARSE_FILENAME_NONE if the line ended before the
  *          beginning of a filename was found.
  */
-static int parse_filename(char **line_p, size_t *len_p, char **fn_ret)
+static int
+parse_filename(tchar **line_p, size_t *len_p, tchar **fn_ret)
 {
        size_t len = *len_p;
-       char *line = *line_p;
-       char *fn;
-       char quote_char;
+       tchar *line = *line_p;
+       tchar *fn;
+       tchar quote_char;
 
        /* Skip leading whitespace */
        for (;;) {
                if (len == 0)
                        return PARSE_FILENAME_NONE;
-               if (!isspace(*line) && *line != '\0')
+               if (!istspace(*line) && *line != T('\0'))
                        break;
                line++;
                len--;
        }
        quote_char = *line;
-       if (quote_char == '"' || quote_char == '\'') {
+       if (quote_char == T('"') || quote_char == T('\'')) {
                /* Quoted filename */
                line++;
                len--;
                fn = line;
-               line = memchr(line, quote_char, len);
+               line = tmemchr(line, quote_char, len);
                if (!line) {
-                       imagex_error("Missing closing quote: %s", fn - 1);
+                       imagex_error(T("Missing closing quote: %"TS), fn - 1);
                        return PARSE_FILENAME_FAILURE;
                }
        } else {
@@ -412,9 +414,9 @@ static int parse_filename(char **line_p, size_t *len_p, char **fn_ret)
                fn = line;
                do {
                        line++;
-               } while (!isspace(*line) && *line != '\0');
+               } while (!istspace(*line) && *line != T('\0'));
        }
-       *line = '\0';
+       *line = T('\0');
        len -= line - fn;
        *len_p = len;
        *line_p = line;
@@ -437,7 +439,7 @@ static int parse_filename(char **line_p, size_t *len_p, char **fn_ret)
  *
  * Returns true if the line was valid; false otherwise.  */
 static bool
-parse_source_list_line(char *line, size_t len,
+parse_source_list_line(tchar *line, size_t len,
                       struct wimlib_capture_source *source)
 {
        /* SOURCE [DEST] */
@@ -453,12 +455,13 @@ parse_source_list_line(char *line, size_t len,
 
 /* Returns %true if the given line of length @len > 0 is a comment or empty line
  * in the source list file format. */
-static bool is_comment_line(const char *line, size_t len)
+static bool
+is_comment_line(const tchar *line, size_t len)
 {
        for (;;) {
-               if (*line == '#')
+               if (*line == T('#'))
                        return true;
-               if (!isspace(*line) && *line != '\0')
+               if (!istspace(*line) && *line != T('\0'))
                        return false;
                ++line;
                --len;
@@ -485,31 +488,45 @@ static bool is_comment_line(const char *line, size_t len)
  * the wimlib_add_image_multisource() function to specify how a WIM image is to
  * be created.  */
 static struct wimlib_capture_source *
-parse_source_list(char *source_list_contents, size_t source_list_nbytes,
+parse_source_list(tchar **source_list_contents_p, size_t source_list_nchars,
                  size_t *nsources_ret)
 {
        size_t nlines;
-       char *p;
+       tchar *p;
        struct wimlib_capture_source *sources;
        size_t i, j;
+       tchar *source_list_contents = *source_list_contents_p;
 
        nlines = 0;
-       for (i = 0; i < source_list_nbytes; i++)
-               if (source_list_contents[i] == '\n')
+       for (i = 0; i < source_list_nchars; i++)
+               if (source_list_contents[i] == T('\n'))
                        nlines++;
-       sources = calloc(nlines, sizeof(*sources));
-       if (!sources) {
-               imagex_error("out of memory");
-               return NULL;
+
+       /* Handle last line not terminated by a newline */
+       if (source_list_nchars != 0 &&
+           source_list_contents[source_list_nchars - 1] != T('\n'))
+       {
+               source_list_contents = realloc(source_list_contents,
+                                              (source_list_nchars + 1) * sizeof(tchar));
+               if (!source_list_contents)
+                       goto oom;
+               source_list_contents[source_list_nchars] = T('\n');
+               *source_list_contents_p = source_list_contents;
+               source_list_nchars++;
+               nlines++;
        }
+
+       sources = calloc(nlines, sizeof(*sources));
+       if (!sources)
+               goto oom;
        p = source_list_contents;
        j = 0;
        for (i = 0; i < nlines; i++) {
                /* XXX: Could use rawmemchr() here instead, but it may not be
                 * available on all platforms. */
-               char *endp = memchr(p, '\n', source_list_nbytes);
+               tchar *endp = tmemchr(p, T('\n'), source_list_nchars);
                size_t len = endp - p + 1;
-               *endp = '\0';
+               *endp = T('\0');
                if (!is_comment_line(p, len)) {
                        if (!parse_source_list_line(p, len, &sources[j++])) {
                                free(sources);
@@ -521,37 +538,41 @@ parse_source_list(char *source_list_contents, size_t source_list_nbytes,
        }
        *nsources_ret = j;
        return sources;
+oom:
+       imagex_error(T("out of memory"));
+       return NULL;
 }
 
 /* Reads the contents of a file into memory. */
-static char *file_get_contents(const char *filename, size_t *len_ret)
+static char *
+file_get_contents(const tchar *filename, size_t *len_ret)
 {
        struct stat stbuf;
-       char *buf = NULL;
+       void *buf = NULL;
        size_t len;
        FILE *fp;
 
-       if (stat(filename, &stbuf) != 0) {
-               imagex_error_with_errno("Failed to stat the file `%s'", filename);
+       if (tstat(filename, &stbuf) != 0) {
+               imagex_error_with_errno(T("Failed to stat the file \"%"TS"\""), filename);
                goto out;
        }
        len = stbuf.st_size;
 
-       fp = fopen(filename, "rb");
+       fp = tfopen(filename, T("rb"));
        if (!fp) {
-               imagex_error_with_errno("Failed to open the file `%s'", filename);
+               imagex_error_with_errno(T("Failed to open the file \"%"TS"\""), filename);
                goto out;
        }
 
        buf = malloc(len);
        if (!buf) {
-               imagex_error("Failed to allocate buffer of %zu bytes to hold "
-                            "contents of file `%s'", len, filename);
+               imagex_error(T("Failed to allocate buffer of %zu bytes to hold "
+                              "contents of file \"%"TS"\""), len, filename);
                goto out_fclose;
        }
        if (fread(buf, 1, len, fp) != len) {
-               imagex_error_with_errno("Failed to read %lu bytes from the "
-                                       "file `%s'", len, filename);
+               imagex_error_with_errno(T("Failed to read %zu bytes from the "
+                                         "file \"%"TS"\""), len, filename);
                goto out_free_buf;
        }
        *len_ret = len;
@@ -565,14 +586,119 @@ out:
        return buf;
 }
 
+/* Read standard input until EOF and return the full contents in a malloc()ed
+ * buffer and the number of bytes of data in @len_ret.  Returns NULL on read
+ * error. */
+static char *
+stdin_get_contents(size_t *len_ret)
+{
+       /* stdin can, of course, be a pipe or other non-seekable file, so the
+        * total length of the data cannot be pre-determined */
+       char *buf = NULL;
+       size_t newlen = 1024;
+       size_t pos = 0;
+       size_t inc = 1024;
+       for (;;) {
+               char *p = realloc(buf, newlen);
+               size_t bytes_read, bytes_to_read;
+               if (!p) {
+                       imagex_error(T("out of memory while reading stdin"));
+                       break;
+               }
+               buf = p;
+               bytes_to_read = newlen - pos;
+               bytes_read = fread(&buf[pos], 1, bytes_to_read, stdin);
+               pos += bytes_read;
+               if (bytes_read != bytes_to_read) {
+                       if (feof(stdin)) {
+                               *len_ret = pos;
+                               return buf;
+                       } else {
+                               imagex_error_with_errno(T("error reading stdin"));
+                               break;
+                       }
+               }
+               newlen += inc;
+               inc *= 3;
+               inc /= 2;
+       }
+       free(buf);
+       return NULL;
+}
+
+
+static tchar *
+translate_text_to_tstr(char **text_p, size_t num_bytes,
+                      size_t *num_tchars_ret)
+{
+#ifndef __WIN32__
+       /* On non-Windows, assume an ASCII-compatible encoding, such as UTF-8.
+        * */
+       *num_tchars_ret = num_bytes;
+       return *text_p;
+#else /* !__WIN32__ */
+       /* On Windows, translate the text to UTF-16LE */
+       const char *text_bytestr = *text_p;
+       wchar_t *text_wstr;
+       size_t num_wchars;
+
+       if (num_bytes >= 2 &&
+           ((text_bytestr[0] == 0xff && text_bytestr[1] == 0xfe) ||
+            (text_bytestr[0] <= 0x7f && text_bytestr[1] == 0x00)))
+       {
+               /* File begins with 0xfeff, the BOM for UTF-16LE, or it begins
+                * with something that looks like an ASCII character encoded as
+                * a UTF-16LE code unit.  Assume the file is encoded as
+                * UTF-16LE.  This is not a 100% reliable check. */
+               num_wchars = num_bytes / 2;
+               text_wstr = (wchar_t*)text_bytestr;
+       } else {
+               /* File does not look like UTF-16LE.  Assume it is encoded in
+                * the current Windows code page.  I think these are always
+                * ASCII-compatible, so any so-called "plain-text" (ASCII) files
+                * should work as expected. */
+               text_wstr = win32_mbs_to_wcs(text_bytestr,
+                                            num_bytes,
+                                            &num_wchars);
+       }
+       *num_tchars_ret = num_wchars;
+       return text_wstr;
+#endif /* __WIN32__ */
+}
+
+static tchar *
+file_get_text_contents(const tchar *filename, size_t *num_tchars_ret)
+{
+       char *contents;
+       size_t num_bytes;
+
+       contents = file_get_contents(filename, &num_bytes);
+       if (!contents)
+               return NULL;
+       return translate_text_to_tstr(&contents, num_bytes, num_tchars_ret);
+}
+
+static tchar *
+stdin_get_text_contents(size_t *num_tchars_ret)
+{
+       char *contents;
+       size_t num_bytes;
+
+       contents = stdin_get_contents(&num_bytes);
+       if (!contents)
+               return NULL;
+       return translate_text_to_tstr(&contents, num_bytes, num_tchars_ret);
+}
+
 /* Return 0 if a path names a file to which the current user has write access;
  * -1 otherwise (and print an error message). */
-static int file_writable(const char *path)
+static int
+file_writable(const tchar *path)
 {
        int ret;
-       ret = access(path, W_OK);
+       ret = taccess(path, W_OK);
        if (ret != 0)
-               imagex_error_with_errno("Can't modify `%s'", path);
+               imagex_error_with_errno(T("Can't modify \"%"TS"\""), path);
        return ret;
 }
 
@@ -581,22 +707,24 @@ static int file_writable(const char *path)
 
 /* Given an enumerated value for WIM compression type, return a descriptive
  * string. */
-static const char *get_data_type(int ctype)
+static const tchar *
+get_data_type(int ctype)
 {
        switch (ctype) {
        case WIMLIB_COMPRESSION_TYPE_NONE:
-               return "uncompressed";
+               return T("uncompressed");
        case WIMLIB_COMPRESSION_TYPE_LZX:
-               return "LZX-compressed";
+               return T("LZX-compressed");
        case WIMLIB_COMPRESSION_TYPE_XPRESS:
-               return "XPRESS-compressed";
+               return T("XPRESS-compressed");
        }
        return NULL;
 }
 
 /* Progress callback function passed to various wimlib functions. */
-static int imagex_progress_func(enum wimlib_progress_msg msg,
-                               const union wimlib_progress_info *info)
+static int
+imagex_progress_func(enum wimlib_progress_msg msg,
+                    const union wimlib_progress_info *info)
 {
        unsigned percent_done;
        switch (msg) {
@@ -604,69 +732,70 @@ static int imagex_progress_func(enum wimlib_progress_msg msg,
                percent_done = TO_PERCENT(info->write_streams.completed_bytes,
                                          info->write_streams.total_bytes);
                if (info->write_streams.completed_streams == 0) {
-                       const char *data_type;
+                       const tchar *data_type;
 
                        data_type = get_data_type(info->write_streams.compression_type);
-                       printf("Writing %s data using %u thread%s\n",
-                              data_type, info->write_streams.num_threads,
-                              (info->write_streams.num_threads == 1) ? "" : "s");
+                       tprintf(T("Writing %"TS" data using %u thread%"TS"\n"),
+                               data_type, info->write_streams.num_threads,
+                               (info->write_streams.num_threads == 1) ? T("") : T("s"));
                }
-               printf("\r%"PRIu64" MiB of %"PRIu64" MiB (uncompressed) "
-                      "written (%u%% done)",
-                      info->write_streams.completed_bytes >> 20,
-                      info->write_streams.total_bytes >> 20,
-                      percent_done);
+               tprintf(T("\r%"PRIu64" MiB of %"PRIu64" MiB (uncompressed) "
+                       "written (%u%% done)"),
+                       info->write_streams.completed_bytes >> 20,
+                       info->write_streams.total_bytes >> 20,
+                       percent_done);
                if (info->write_streams.completed_bytes >= info->write_streams.total_bytes)
-                       putchar('\n');
+                       tputchar(T('\n'));
                break;
        case WIMLIB_PROGRESS_MSG_SCAN_BEGIN:
-               printf("Scanning `%s'", info->scan.source);
+               tprintf(T("Scanning \"%"TS"\""), info->scan.source);
                if (*info->scan.wim_target_path) {
-                       printf(" (loading as WIM path: `/%s')...\n",
+                       tprintf(T(" (loading as WIM path: \"/%"TS"\")...\n"),
                               info->scan.wim_target_path);
                } else {
-                       printf(" (loading as root of WIM image)...\n");
+                       tprintf(T(" (loading as root of WIM image)...\n"));
                }
                break;
        case WIMLIB_PROGRESS_MSG_SCAN_DENTRY:
                if (info->scan.excluded)
-                       printf("Excluding `%s' from capture\n", info->scan.cur_path);
+                       tprintf(T("Excluding \"%"TS"\" from capture\n"), info->scan.cur_path);
                else
-                       printf("Scanning `%s'\n", info->scan.cur_path);
+                       tprintf(T("Scanning \"%"TS"\"\n"), info->scan.cur_path);
                break;
        /*case WIMLIB_PROGRESS_MSG_SCAN_END:*/
                /*break;*/
        case WIMLIB_PROGRESS_MSG_VERIFY_INTEGRITY:
                percent_done = TO_PERCENT(info->integrity.completed_bytes,
                                          info->integrity.total_bytes);
-               printf("\rVerifying integrity of `%s': %"PRIu64" MiB "
-                      "of %"PRIu64" MiB (%u%%) done",
-                      info->integrity.filename,
-                      info->integrity.completed_bytes >> 20,
-                      info->integrity.total_bytes >> 20,
-                      percent_done);
+               tprintf(T("\rVerifying integrity of \"%"TS"\": %"PRIu64" MiB "
+                       "of %"PRIu64" MiB (%u%%) done"),
+                       info->integrity.filename,
+                       info->integrity.completed_bytes >> 20,
+                       info->integrity.total_bytes >> 20,
+                       percent_done);
                if (info->integrity.completed_bytes == info->integrity.total_bytes)
-                       putchar('\n');
+                       tputchar(T('\n'));
                break;
        case WIMLIB_PROGRESS_MSG_CALC_INTEGRITY:
                percent_done = TO_PERCENT(info->integrity.completed_bytes,
                                          info->integrity.total_bytes);
-               printf("\rCalculating integrity table for WIM: %"PRIu64" MiB "
-                      "of %"PRIu64" MiB (%u%%) done",
-                      info->integrity.completed_bytes >> 20,
-                      info->integrity.total_bytes >> 20,
-                      percent_done);
+               tprintf(T("\rCalculating integrity table for WIM: %"PRIu64" MiB "
+                         "of %"PRIu64" MiB (%u%%) done"),
+                       info->integrity.completed_bytes >> 20,
+                       info->integrity.total_bytes >> 20,
+                       percent_done);
                if (info->integrity.completed_bytes == info->integrity.total_bytes)
-                       putchar('\n');
+                       tputchar(T('\n'));
                break;
        case WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_BEGIN:
-               printf("Applying image %d (%s) from `%s' to %s `%s'\n",
-                      info->extract.image,
-                      info->extract.image_name,
-                      info->extract.wimfile_name,
-                      ((info->extract.extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) ?
-                               "NTFS volume" : "directory"),
-                      info->extract.target);
+               tprintf(T("Applying image %d (%"TS") from \"%"TS"\" "
+                         "to %"TS" \"%"TS"\"\n"),
+                       info->extract.image,
+                       info->extract.image_name,
+                       info->extract.wimfile_name,
+                       ((info->extract.extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) ?
+                        T("NTFS volume") : T("directory")),
+                       info->extract.target);
                break;
        /*case WIMLIB_PROGRESS_MSG_EXTRACT_DIR_STRUCTURE_BEGIN:*/
                /*printf("Applying directory structure to %s\n",*/
@@ -675,24 +804,24 @@ static int imagex_progress_func(enum wimlib_progress_msg msg,
        case WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS:
                percent_done = TO_PERCENT(info->extract.completed_bytes,
                                          info->extract.total_bytes);
-               printf("\rExtracting files: "
-                      "%"PRIu64" MiB of %"PRIu64" MiB (%u%%) done",
-                      info->extract.completed_bytes >> 20,
-                      info->extract.total_bytes >> 20,
-                      percent_done);
+               tprintf(T("\rExtracting files: "
+                         "%"PRIu64" MiB of %"PRIu64" MiB (%u%%) done"),
+                       info->extract.completed_bytes >> 20,
+                       info->extract.total_bytes >> 20,
+                       percent_done);
                if (info->extract.completed_bytes >= info->extract.total_bytes)
                        putchar('\n');
                break;
        case WIMLIB_PROGRESS_MSG_EXTRACT_DENTRY:
-               puts(info->extract.cur_path);
+               tprintf(T("%"TS"\n"), info->extract.cur_path);
                break;
        case WIMLIB_PROGRESS_MSG_APPLY_TIMESTAMPS:
-               printf("Setting timestamps on all extracted files...\n");
+               tprintf(T("Setting timestamps on all extracted files...\n"));
                break;
        case WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_END:
                if (info->extract.extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) {
-                       printf("Unmounting NTFS volume `%s'...\n",
-                              info->extract.target);
+                       tprintf(T("Unmounting NTFS volume \"%"TS"\"...\n"),
+                               info->extract.target);
                }
                break;
        case WIMLIB_PROGRESS_MSG_JOIN_STREAMS:
@@ -710,16 +839,17 @@ static int imagex_progress_func(enum wimlib_progress_msg msg,
        case WIMLIB_PROGRESS_MSG_SPLIT_BEGIN_PART:
                percent_done = TO_PERCENT(info->split.completed_bytes,
                                          info->split.total_bytes);
-               printf("Writing `%s': %"PRIu64" MiB of %"PRIu64" MiB (%u%%) written\n",
-                      info->split.part_name,
-                      info->split.completed_bytes >> 20,
-                      info->split.total_bytes >> 20,
-                      percent_done);
+               tprintf(T("Writing \"%"TS"\": %"PRIu64" MiB of "
+                         "%"PRIu64" MiB (%u%%) written\n"),
+                       info->split.part_name,
+                       info->split.completed_bytes >> 20,
+                       info->split.total_bytes >> 20,
+                       percent_done);
                break;
        case WIMLIB_PROGRESS_MSG_SPLIT_END_PART:
                if (info->split.completed_bytes == info->split.total_bytes) {
-                       printf("Finished writing %u split WIM parts\n",
-                              info->split.cur_part_number);
+                       tprintf(T("Finished writing %u split WIM parts\n"),
+                               info->split.cur_part_number);
                }
                break;
        default:
@@ -733,11 +863,12 @@ static int imagex_progress_func(enum wimlib_progress_msg msg,
  *
  * @first_part specifies the first part of the split WIM and it may be either
  * included or omitted from the glob. */
-static int open_swms_from_glob(const char *swm_glob,
-                              const char *first_part,
-                              int open_flags,
-                              WIMStruct ***additional_swms_ret,
-                              unsigned *num_additional_swms_ret)
+static int
+open_swms_from_glob(const tchar *swm_glob,
+                   const tchar *first_part,
+                   int open_flags,
+                   WIMStruct ***additional_swms_ret,
+                   unsigned *num_additional_swms_ret)
 {
        unsigned num_additional_swms = 0;
        WIMStruct **additional_swms = NULL;
@@ -745,14 +876,14 @@ static int open_swms_from_glob(const char *swm_glob,
        int ret;
 
        /* Warning: glob() is replaced in Windows native builds */
-       ret = glob(swm_glob, GLOB_ERR | GLOB_NOSORT, NULL, &globbuf);
+       ret = tglob(swm_glob, GLOB_ERR | GLOB_NOSORT, NULL, &globbuf);
        if (ret != 0) {
                if (ret == GLOB_NOMATCH) {
-                       imagex_error("Found no files for glob \"%s\"",
+                       imagex_error(T("Found no files for glob \"%"TS"\""),
                                     swm_glob);
                } else {
-                       imagex_error_with_errno("Failed to process glob "
-                                               "\"%s\"", swm_glob);
+                       imagex_error_with_errno(T("Failed to process glob \"%"TS"\""),
+                                               swm_glob);
                }
                ret = -1;
                goto out;
@@ -760,13 +891,13 @@ static int open_swms_from_glob(const char *swm_glob,
        num_additional_swms = globbuf.gl_pathc;
        additional_swms = calloc(num_additional_swms, sizeof(additional_swms[0]));
        if (!additional_swms) {
-               imagex_error("Out of memory");
+               imagex_error(T("Out of memory"));
                ret = -1;
                goto out_globfree;
        }
        unsigned offset = 0;
        for (unsigned i = 0; i < num_additional_swms; i++) {
-               if (strcmp(globbuf.gl_pathv[i], first_part) == 0) {
+               if (tstrcmp(globbuf.gl_pathv[i], first_part) == 0) {
                        offset++;
                        continue;
                }
@@ -792,12 +923,13 @@ out:
 }
 
 
-static unsigned parse_num_threads(const char *optarg)
+static unsigned
+parse_num_threads(const tchar *optarg)
 {
-       char *tmp;
-       unsigned nthreads = strtoul(optarg, &tmp, 10);
+       tchar *tmp;
+       unsigned nthreads = tstrtoul(optarg, &tmp, 10);
        if (nthreads == UINT_MAX || *tmp || tmp == optarg) {
-               imagex_error("Number of threads must be a non-negative integer!");
+               imagex_error(T("Number of threads must be a non-negative integer!"));
                return UINT_MAX;
        } else {
                return nthreads;
@@ -807,7 +939,8 @@ static unsigned parse_num_threads(const char *optarg)
 
 /* Apply one image, or all images, from a WIM file into a directory, OR apply
  * one image from a WIM file to a NTFS volume. */
-static int imagex_apply(int argc, char **argv)
+static int
+imagex_apply(int argc, tchar **argv)
 {
        int c;
        int open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK;
@@ -815,12 +948,12 @@ static int imagex_apply(int argc, char **argv)
        int num_images;
        WIMStruct *w;
        int ret;
-       const char *wimfile;
-       const char *target;
-       const char *image_num_or_name;
+       const tchar *wimfile;
+       const tchar *target;
+       const tchar *image_num_or_name;
        int extract_flags = WIMLIB_EXTRACT_FLAG_SEQUENTIAL;
 
-       const char *swm_glob = NULL;
+       const tchar *swm_glob = NULL;
        WIMStruct **additional_swms = NULL;
        unsigned num_additional_swms = 0;
 
@@ -861,7 +994,7 @@ static int imagex_apply(int argc, char **argv)
 
        wimfile = argv[0];
        if (argc == 2) {
-               image_num_or_name = "1";
+               image_num_or_name = T("1");
                target = argv[1];
        } else {
                image_num_or_name = argv[1];
@@ -879,8 +1012,8 @@ static int imagex_apply(int argc, char **argv)
 
        num_images = wimlib_get_num_images(w);
        if (argc == 2 && num_images != 1) {
-               imagex_error("`%s' contains %d images; Please select one "
-                            "(or all)", wimfile, num_images);
+               imagex_error(T("\"%"TS"\" contains %d images; Please select one "
+                              "(or all)"), wimfile, num_images);
                usage(APPLY);
                ret = -1;
                goto out;
@@ -896,13 +1029,14 @@ static int imagex_apply(int argc, char **argv)
 
        struct stat stbuf;
 
-       ret = stat(target, &stbuf);
+       ret = tstat(target, &stbuf);
        if (ret == 0) {
                if (S_ISBLK(stbuf.st_mode) || S_ISREG(stbuf.st_mode))
                        extract_flags |= WIMLIB_EXTRACT_FLAG_NTFS;
        } else {
                if (errno != ENOENT) {
-                       imagex_error_with_errno("Failed to stat `%s'", target);
+                       imagex_error_with_errno(T("Failed to stat \"%"TS"\""),
+                                               target);
                        ret = -1;
                        goto out;
                }
@@ -915,7 +1049,7 @@ static int imagex_apply(int argc, char **argv)
                                   additional_swms, num_additional_swms,
                                   imagex_progress_func);
        if (ret == 0)
-               printf("Done applying WIM image.\n");
+               tprintf(T("Done applying WIM image.\n"));
 #ifdef __WIN32__
        win32_release_restore_privileges();
 #endif
@@ -933,34 +1067,35 @@ out:
  * directory trees.  'wimlib-imagex capture': create a new WIM file containing
  * the desired image.  'wimlib-imagex append': add a new image to an existing
  * WIM file. */
-static int imagex_capture_or_append(int argc, char **argv)
+static int
+imagex_capture_or_append(int argc, tchar **argv)
 {
        int c;
        int open_flags = 0;
        int add_image_flags = 0;
        int write_flags = 0;
        int compression_type = WIMLIB_COMPRESSION_TYPE_XPRESS;
-       const char *wimfile;
-       const char *name;
-       const char *desc;
-       const char *flags_element = NULL;
+       const tchar *wimfile;
+       const tchar *name;
+       const tchar *desc;
+       const tchar *flags_element = NULL;
        WIMStruct *w = NULL;
        int ret;
        int cur_image;
-       int cmd = strcmp(argv[0], "append") ? CAPTURE : APPEND;
+       int cmd = tstrcmp(argv[0], T("append")) ? CAPTURE : APPEND;
        unsigned num_threads = 0;
 
-       char *source;
+       tchar *source;
        size_t source_name_len;
-       char *source_copy;
+       tchar *source_copy;
 
-       const char *config_file = NULL;
-       char *config_str = NULL;
+       const tchar *config_file = NULL;
+       tchar *config_str = NULL;
        size_t config_len;
 
        bool source_list = false;
-       size_t source_list_nbytes;
-       char *source_list_contents = NULL;
+       size_t source_list_nchars;
+       tchar *source_list_contents = NULL;
        bool capture_sources_malloced = false;
        struct wimlib_capture_source *capture_sources;
        size_t num_sources;
@@ -1030,26 +1165,26 @@ static int imagex_capture_or_append(int argc, char **argv)
                /* Set default name to SOURCE argument, omitting any directory
                 * prefixes and trailing slashes.  This requires making a copy
                 * of @source. */
-               source_name_len = strlen(source);
-               source_copy = alloca(source_name_len + 1);
-               name = basename(strcpy(source_copy, source));
+               source_name_len = tstrlen(source);
+               source_copy = alloca((source_name_len + 1) * sizeof(tchar));
+               name = tbasename(tstrcpy(source_copy, source));
        }
        /* Image description defaults to NULL if not given. */
        desc = (argc >= 4) ? argv[3] : NULL;
 
        if (source_list) {
                /* Set up capture sources in source list mode */
-               if (source[0] == '-' && source[1] == '\0') {
-                       source_list_contents = stdin_get_contents(&source_list_nbytes);
+               if (source[0] == T('-') && source[1] == T('\0')) {
+                       source_list_contents = stdin_get_text_contents(&source_list_nchars);
                } else {
-                       source_list_contents = file_get_contents(source,
-                                                                &source_list_nbytes);
+                       source_list_contents = file_get_text_contents(source,
+                                                                     &source_list_nchars);
                }
                if (!source_list_contents)
                        return -1;
 
-               capture_sources = parse_source_list(source_list_contents,
-                                                   source_list_nbytes,
+               capture_sources = parse_source_list(&source_list_contents,
+                                                   source_list_nchars,
                                                    &num_sources);
                if (!capture_sources) {
                        ret = -1;
@@ -1067,7 +1202,7 @@ static int imagex_capture_or_append(int argc, char **argv)
        }
 
        if (config_file) {
-               config_str = file_get_contents(config_file, &config_len);
+               config_str = file_get_text_contents(config_file, &config_len);
                if (!config_str) {
                        ret = -1;
                        goto out;
@@ -1084,16 +1219,17 @@ static int imagex_capture_or_append(int argc, char **argv)
 
        if (!source_list) {
                struct stat stbuf;
-               ret = stat(source, &stbuf);
+               ret = tstat(source, &stbuf);
                if (ret == 0) {
                        if (S_ISBLK(stbuf.st_mode) || S_ISREG(stbuf.st_mode)) {
-                               printf("Capturing WIM image from NTFS filesystem on `%s'\n",
-                                      source);
+                               tprintf(T("Capturing WIM image from NTFS "
+                                         "filesystem on \"%"TS"\"\n"), source);
                                add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_NTFS;
                        }
                } else {
                        if (errno != ENOENT) {
-                               imagex_error_with_errno("Failed to stat `%s'", source);
+                               imagex_error_with_errno(T("Failed to stat "
+                                                         "\"%"TS"\""), source);
                                ret = -1;
                                goto out;
                        }
@@ -1108,7 +1244,7 @@ static int imagex_capture_or_append(int argc, char **argv)
                                           (config_str ? config_str :
                                                default_capture_config),
                                           (config_str ? config_len :
-                                               strlen(default_capture_config)),
+                                               tstrlen(default_capture_config)),
                                           add_image_flags,
                                           imagex_progress_func);
        if (ret != 0)
@@ -1134,7 +1270,8 @@ static int imagex_capture_or_append(int argc, char **argv)
        if (ret == WIMLIB_ERR_REOPEN)
                ret = 0;
        if (ret != 0)
-               imagex_error("Failed to write the WIM file `%s'", wimfile);
+               imagex_error(T("Failed to write the WIM file \"%"TS"\""),
+                            wimfile);
 out_release_privs:
 #ifdef __WIN32__
        win32_release_capture_privileges();
@@ -1149,13 +1286,14 @@ out:
 }
 
 /* Remove image(s) from a WIM. */
-static int imagex_delete(int argc, char **argv)
+static int
+imagex_delete(int argc, tchar **argv)
 {
        int c;
        int open_flags = 0;
        int write_flags = 0;
-       const char *wimfile;
-       const char *image_num_or_name;
+       const tchar *wimfile;
+       const tchar *image_num_or_name;
        WIMStruct *w;
        int image;
        int ret;
@@ -1179,9 +1317,9 @@ static int imagex_delete(int argc, char **argv)
 
        if (argc != 2) {
                if (argc < 1)
-                       imagex_error("Must specify a WIM file");
+                       imagex_error(T("Must specify a WIM file"));
                if (argc < 2)
-                       imagex_error("Must specify an image");
+                       imagex_error(T("Must specify an image"));
                usage(DELETE);
                return -1;
        }
@@ -1205,7 +1343,7 @@ static int imagex_delete(int argc, char **argv)
 
        ret = wimlib_delete_image(w, image);
        if (ret != 0) {
-               imagex_error("Failed to delete image from `%s'", wimfile);
+               imagex_error(T("Failed to delete image from \"%"TS"\""), wimfile);
                goto out;
        }
 
@@ -1213,8 +1351,8 @@ static int imagex_delete(int argc, char **argv)
        if (ret == WIMLIB_ERR_REOPEN)
                ret = 0;
        if (ret != 0) {
-               imagex_error("Failed to write the file `%s' with image "
-                            "deleted", wimfile);
+               imagex_error(T("Failed to write the file \"%"TS"\" with image "
+                              "deleted"), wimfile);
        }
 out:
        wimlib_free(w);
@@ -1222,21 +1360,22 @@ out:
 }
 
 /* Print the files contained in an image(s) in a WIM file. */
-static int imagex_dir(int argc, char **argv)
+static int
+imagex_dir(int argc, tchar **argv)
 {
-       const char *wimfile;
+       const tchar *wimfile;
        WIMStruct *w;
        int image;
        int ret;
        int num_images;
 
        if (argc < 2) {
-               imagex_error("Must specify a WIM file");
+               imagex_error(T("Must specify a WIM file"));
                usage(DIR);
                return -1;
        }
        if (argc > 3) {
-               imagex_error("Too many arguments");
+               imagex_error(T("Too many arguments"));
                usage(DIR);
                return -1;
        }
@@ -1257,8 +1396,8 @@ static int imagex_dir(int argc, char **argv)
                 * choose that one; otherwise, print an error. */
                num_images = wimlib_get_num_images(w);
                if (num_images != 1) {
-                       imagex_error("The file `%s' contains %d images; Please "
-                                    "select one.", wimfile, num_images);
+                       imagex_error(T("The file \"%"TS"\" contains %d images; Please "
+                                      "select one."), wimfile, num_images);
                        usage(DIR);
                        ret = -1;
                        goto out;
@@ -1274,7 +1413,8 @@ out:
 
 /* Exports one, or all, images from a WIM file to a new WIM file or an existing
  * WIM file. */
-static int imagex_export(int argc, char **argv)
+static int
+imagex_export(int argc, tchar **argv)
 {
        int c;
        int open_flags = 0;
@@ -1282,18 +1422,18 @@ static int imagex_export(int argc, char **argv)
        int write_flags = 0;
        int compression_type = WIMLIB_COMPRESSION_TYPE_NONE;
        bool compression_type_specified = false;
-       const char *src_wimfile;
-       const char *src_image_num_or_name;
-       const char *dest_wimfile;
-       const char *dest_name;
-       const char *dest_desc;
+       const tchar *src_wimfile;
+       const tchar *src_image_num_or_name;
+       const tchar *dest_wimfile;
+       const tchar *dest_name;
+       const tchar *dest_desc;
        WIMStruct *src_w = NULL;
        WIMStruct *dest_w = NULL;
        int ret;
        int image;
        struct stat stbuf;
        bool wim_is_new;
-       const char *swm_glob = NULL;
+       const tchar *swm_glob = NULL;
        WIMStruct **additional_swms = NULL;
        unsigned num_additional_swms = 0;
        unsigned num_threads = 0;
@@ -1349,14 +1489,14 @@ static int imagex_export(int argc, char **argv)
        /* Determine if the destination is an existing file or not.
         * If so, we try to append the exported image(s) to it; otherwise, we
         * create a new WIM containing the exported image(s). */
-       if (stat(dest_wimfile, &stbuf) == 0) {
+       if (tstat(dest_wimfile, &stbuf) == 0) {
                int dest_ctype;
 
                wim_is_new = false;
                /* Destination file exists. */
 
                if (!S_ISREG(stbuf.st_mode)) {
-                       imagex_error("`%s' is not a regular file",
+                       imagex_error(T("\"%"TS"\" is not a regular file"),
                                     dest_wimfile);
                        ret = -1;
                        goto out;
@@ -1374,9 +1514,9 @@ static int imagex_export(int argc, char **argv)
                if (compression_type_specified
                    && compression_type != dest_ctype)
                {
-                       imagex_error("Cannot specify a compression type that is "
-                                    "not the same as that used in the "
-                                    "destination WIM");
+                       imagex_error(T("Cannot specify a compression type that is "
+                                      "not the same as that used in the "
+                                      "destination WIM"));
                        ret = -1;
                        goto out;
                }
@@ -1390,7 +1530,7 @@ static int imagex_export(int argc, char **argv)
                        if (ret != 0)
                                goto out;
                } else {
-                       imagex_error_with_errno("Cannot stat file `%s'",
+                       imagex_error_with_errno(T("Cannot stat file \"%"TS"\""),
                                                dest_wimfile);
                        ret = -1;
                        goto out;
@@ -1439,7 +1579,8 @@ out:
 
 /* Prints information about a WIM file; also can mark an image as bootable,
  * change the name of an image, or change the description of an image. */
-static int imagex_info(int argc, char **argv)
+static int
+imagex_info(int argc, tchar **argv)
 {
        int c;
        bool boot         = false;
@@ -1449,11 +1590,11 @@ static int imagex_info(int argc, char **argv)
        bool xml          = false;
        bool metadata     = false;
        bool short_header = true;
-       const char *xml_out_file = NULL;
-       const char *wimfile;
-       const char *image_num_or_name = "all";
-       const char *new_name = NULL;
-       const char *new_desc = NULL;
+       const tchar *xml_out_file = NULL;
+       const tchar *wimfile;
+       const tchar *image_num_or_name = T("all");
+       const tchar *new_name = NULL;
+       const tchar *new_desc = NULL;
        WIMStruct *w;
        FILE *fp;
        int image;
@@ -1525,13 +1666,14 @@ static int imagex_info(int argc, char **argv)
        part_number = wimlib_get_part_number(w, &total_parts);
 
        image = wimlib_resolve_image(w, image_num_or_name);
-       if (image == WIMLIB_NO_IMAGE && strcmp(image_num_or_name, "0") != 0) {
-               imagex_error("The image `%s' does not exist",
+       if (image == WIMLIB_NO_IMAGE && tstrcmp(image_num_or_name, T("0"))) {
+               imagex_error(T("The image \"%"TS"\" does not exist"),
                             image_num_or_name);
-               if (boot)
-                       imagex_error("If you would like to set the boot "
-                                    "index to 0, specify image \"0\" with "
-                                    "the --boot flag.");
+               if (boot) {
+                       imagex_error(T("If you would like to set the boot "
+                                      "index to 0, specify image \"0\" with "
+                                      "the --boot flag."));
+               }
                ret = WIMLIB_ERR_INVALID_IMAGE;
                goto out;
        }
@@ -1540,8 +1682,8 @@ static int imagex_info(int argc, char **argv)
 
        if (num_images == 0) {
                if (boot) {
-                       imagex_error("--boot is meaningless on a WIM with no "
-                                    "images");
+                       imagex_error(T("--boot is meaningless on a WIM with no "
+                                      "images"));
                        ret = WIMLIB_ERR_INVALID_IMAGE;
                        goto out;
                }
@@ -1549,16 +1691,16 @@ static int imagex_info(int argc, char **argv)
 
        if (image == WIMLIB_ALL_IMAGES && num_images > 1) {
                if (boot) {
-                       imagex_error("Cannot specify the --boot flag "
-                                    "without specifying a specific "
-                                    "image in a multi-image WIM");
+                       imagex_error(T("Cannot specify the --boot flag "
+                                      "without specifying a specific "
+                                      "image in a multi-image WIM"));
                        ret = WIMLIB_ERR_INVALID_IMAGE;
                        goto out;
                }
                if (new_name) {
-                       imagex_error("Cannot specify the NEW_NAME "
-                                    "without specifying a specific "
-                                    "image in a multi-image WIM");
+                       imagex_error(T("Cannot specify the NEW_NAME "
+                                      "without specifying a specific "
+                                      "image in a multi-image WIM"));
                        ret = WIMLIB_ERR_INVALID_IMAGE;
                        goto out;
                }
@@ -1571,7 +1713,7 @@ static int imagex_info(int argc, char **argv)
                /* Read-only operations */
 
                if (image == WIMLIB_NO_IMAGE) {
-                       imagex_error("`%s' is not a valid image",
+                       imagex_error(T("\"%"TS"\" is not a valid image"),
                                     image_num_or_name);
                        ret = WIMLIB_ERR_INVALID_IMAGE;
                        goto out;
@@ -1585,9 +1727,9 @@ static int imagex_info(int argc, char **argv)
 
                if (lookup_table) {
                        if (total_parts != 1) {
-                               printf("Warning: Only showing the lookup table "
-                                      "for part %d of a %d-part WIM.\n",
-                                      part_number, total_parts);
+                               tprintf(T("Warning: Only showing the lookup table "
+                                         "for part %d of a %d-part WIM.\n"),
+                                       part_number, total_parts);
                        }
                        wimlib_print_lookup_table(w);
                }
@@ -1599,18 +1741,19 @@ static int imagex_info(int argc, char **argv)
                }
 
                if (xml_out_file) {
-                       fp = fopen(xml_out_file, "wb");
+                       fp = tfopen(xml_out_file, T("wb"));
                        if (!fp) {
-                               imagex_error_with_errno("Failed to open the "
-                                                       "file `%s' for "
-                                                       "writing ",
+                               imagex_error_with_errno(T("Failed to open the "
+                                                         "file \"%"TS"\" for "
+                                                         "writing "),
                                                        xml_out_file);
                                ret = -1;
                                goto out;
                        }
                        ret = wimlib_extract_xml_data(w, fp);
                        if (fclose(fp) != 0) {
-                               imagex_error("Failed to close the file `%s'",
+                               imagex_error(T("Failed to close the file "
+                                              "\"%"TS"\""),
                                             xml_out_file);
                                ret = -1;
                        }
@@ -1631,7 +1774,7 @@ static int imagex_info(int argc, char **argv)
 
                /* Modification operations */
                if (total_parts != 1) {
-                       imagex_error("Modifying a split WIM is not supported.");
+                       imagex_error(T("Modifying a split WIM is not supported."));
                        ret = -1;
                        goto out;
                }
@@ -1639,47 +1782,47 @@ static int imagex_info(int argc, char **argv)
                        image = 1;
 
                if (image == WIMLIB_NO_IMAGE && new_name) {
-                       imagex_error("Cannot specify new_name (`%s') when "
-                                    "using image 0", new_name);
+                       imagex_error(T("Cannot specify new_name (\"%"TS"\") "
+                                      "when using image 0"), new_name);
                        ret = -1;
                        goto out;
                }
 
                if (boot) {
                        if (image == wimlib_get_boot_idx(w)) {
-                               printf("Image %d is already marked as "
-                                      "bootable.\n", image);
+                               tprintf(T("Image %d is already marked as "
+                                         "bootable.\n"), image);
                                boot = false;
                        } else {
-                               printf("Marking image %d as bootable.\n",
-                                      image);
+                               tprintf(T("Marking image %d as bootable.\n"),
+                                       image);
                                wimlib_set_boot_idx(w, image);
                        }
                }
                if (new_name) {
-                       if (strcmp(wimlib_get_image_name(w, image),
-                                               new_name) == 0) {
-                               printf("Image %d is already named \"%s\".\n",
-                                      image, new_name);
+                       if (!tstrcmp(wimlib_get_image_name(w, image), new_name))
+                       {
+                               tprintf(T("Image %d is already named \"%"TS"\".\n"),
+                                       image, new_name);
                                new_name = NULL;
                        } else {
-                               printf("Changing the name of image %d to "
-                                      "\"%s\".\n", image, new_name);
+                               tprintf(T("Changing the name of image %d to "
+                                         "\"%"TS"\".\n"), image, new_name);
                                ret = wimlib_set_image_name(w, image, new_name);
                                if (ret != 0)
                                        goto out;
                        }
                }
                if (new_desc) {
-                       const char *old_desc;
+                       const tchar *old_desc;
                        old_desc = wimlib_get_image_description(w, image);
-                       if (old_desc && strcmp(old_desc, new_desc) == 0) {
-                               printf("The description of image %d is already "
-                                      "\"%s\".\n", image, new_desc);
+                       if (old_desc && !tstrcmp(old_desc, new_desc)) {
+                               tprintf(T("The description of image %d is already "
+                                         "\"%"TS"\".\n"), image, new_desc);
                                new_desc = NULL;
                        } else {
-                               printf("Changing the description of image %d "
-                                      "to \"%s\".\n", image, new_desc);
+                               tprintf(T("Changing the description of image %d "
+                                         "to \"%"TS"\".\n"), image, new_desc);
                                ret = wimlib_set_image_descripton(w, image,
                                                                  new_desc);
                                if (ret != 0)
@@ -1708,8 +1851,8 @@ static int imagex_info(int argc, char **argv)
                        if (ret == WIMLIB_ERR_REOPEN)
                                ret = 0;
                } else {
-                       printf("The file `%s' was not modified because nothing "
-                              "needed to be done.\n", wimfile);
+                       tprintf(T("The file \"%"TS"\" was not modified because nothing "
+                                 "needed to be done.\n"), wimfile);
                        ret = 0;
                }
        }
@@ -1719,12 +1862,13 @@ out:
 }
 
 /* Join split WIMs into one part WIM */
-static int imagex_join(int argc, char **argv)
+static int
+imagex_join(int argc, tchar **argv)
 {
        int c;
        int swm_open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK;
        int wim_write_flags = 0;
-       const char *output_path;
+       const tchar *output_path;
 
        for_opt(c, join_options) {
                switch (c) {
@@ -1740,13 +1884,16 @@ static int imagex_join(int argc, char **argv)
        argv += optind;
 
        if (argc < 2) {
-               imagex_error("Must specify one or more split WIM (.swm) parts "
-                            "to join");
+               imagex_error(T("Must specify one or more split WIM (.swm) "
+                              "parts to join"));
                goto err;
        }
        output_path = argv[0];
-       return wimlib_join((const char **)++argv, --argc, output_path,
-                          swm_open_flags, wim_write_flags,
+       return wimlib_join((const tchar * const *)++argv,
+                          --argc,
+                          output_path,
+                          swm_open_flags,
+                          wim_write_flags,
                           imagex_progress_func);
 err:
        usage(JOIN);
@@ -1754,23 +1901,24 @@ err:
 }
 
 /* Mounts an image using a FUSE mount. */
-static int imagex_mount_rw_or_ro(int argc, char **argv)
+static int
+imagex_mount_rw_or_ro(int argc, tchar **argv)
 {
        int c;
        int mount_flags = 0;
        int open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK;
-       const char *wimfile;
-       const char *dir;
+       const tchar *wimfile;
+       const tchar *dir;
        WIMStruct *w;
        int image;
        int num_images;
        int ret;
-       const char *swm_glob = NULL;
+       const tchar *swm_glob = NULL;
        WIMStruct **additional_swms = NULL;
        unsigned num_additional_swms = 0;
-       const char *staging_dir = NULL;
+       const tchar *staging_dir = NULL;
 
-       if (strcmp(argv[0], "mountrw") == 0)
+       if (tstrcmp(argv[0], T("mountrw")) == 0)
                mount_flags |= WIMLIB_MOUNT_FLAG_READWRITE;
 
        for_opt(c, mount_options) {
@@ -1785,14 +1933,15 @@ static int imagex_mount_rw_or_ro(int argc, char **argv)
                        mount_flags |= WIMLIB_MOUNT_FLAG_DEBUG;
                        break;
                case 's':
-                       if (strcasecmp(optarg, "none") == 0)
+                       if (tstrcasecmp(optarg, T("none")) == 0)
                                mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE;
-                       else if (strcasecmp(optarg, "xattr") == 0)
+                       else if (tstrcasecmp(optarg, T("xattr")) == 0)
                                mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR;
-                       else if (strcasecmp(optarg, "windows") == 0)
+                       else if (tstrcasecmp(optarg, T("windows")) == 0)
                                mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS;
                        else {
-                               imagex_error("Unknown stream interface \"%s\"", optarg);
+                               imagex_error(T("Unknown stream interface \"%"TS"\""),
+                                            optarg);
                                goto mount_usage;
                        }
                        break;
@@ -1833,8 +1982,8 @@ static int imagex_mount_rw_or_ro(int argc, char **argv)
                image = 1;
                num_images = wimlib_get_num_images(w);
                if (num_images != 1) {
-                       imagex_error("The file `%s' contains %d images; Please "
-                                    "select one.", wimfile, num_images);
+                       imagex_error(T("The file \"%"TS"\" contains %d images; Please "
+                                      "select one."), wimfile, num_images);
                        usage((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)
                                        ? MOUNTRW : MOUNT);
                        ret = -1;
@@ -1858,7 +2007,8 @@ static int imagex_mount_rw_or_ro(int argc, char **argv)
        ret = wimlib_mount_image(w, image, dir, mount_flags, additional_swms,
                                 num_additional_swms, staging_dir);
        if (ret != 0) {
-               imagex_error("Failed to mount image %d from `%s' on `%s'",
+               imagex_error(T("Failed to mount image %d from \"%"TS"\" "
+                              "on \"%"TS"\""),
                             image, wimfile, dir);
 
        }
@@ -1877,14 +2027,15 @@ mount_usage:
 }
 
 /* Rebuild a WIM file */
-static int imagex_optimize(int argc, char **argv)
+static int
+imagex_optimize(int argc, tchar **argv)
 {
        int c;
        int open_flags = 0;
        int write_flags = WIMLIB_WRITE_FLAG_REBUILD;
        int ret;
        WIMStruct *w;
-       const char *wimfile;
+       const tchar *wimfile;
        off_t old_size;
        off_t new_size;
 
@@ -1918,28 +2069,28 @@ static int imagex_optimize(int argc, char **argv)
                return ret;
 
        old_size = file_get_size(argv[0]);
-       printf("`%s' original size: ", wimfile);
+       tprintf(T("\"%"TS"\" original size: "), wimfile);
        if (old_size == -1)
-               puts("Unknown");
+               tfputs(T("Unknown\n"), stdout);
        else
-               printf("%"PRIu64" KiB\n", old_size >> 10);
+               tprintf(T("%"PRIu64" KiB\n"), old_size >> 10);
 
        ret = wimlib_overwrite(w, write_flags, 0, imagex_progress_func);
 
        if (ret == 0) {
                new_size = file_get_size(argv[0]);
-               printf("`%s' optimized size: ", wimfile);
+               tprintf(T("\"%"TS"\" optimized size: "), wimfile);
                if (new_size == -1)
-                       puts("Unknown");
+                       tfputs(T("Unknown\n"), stdout);
                else
-                       printf("%"PRIu64" KiB\n", new_size >> 10);
+                       tprintf(T("%"PRIu64" KiB\n"), new_size >> 10);
 
-               fputs("Space saved: ", stdout);
+               tfputs(T("Space saved: "), stdout);
                if (new_size != -1 && old_size != -1) {
-                       printf("%lld KiB\n",
+                       tprintf(T("%lld KiB\n"),
                               ((long long)old_size - (long long)new_size) >> 10);
                } else {
-                       puts("Unknown");
+                       tfputs(T("Unknown\n"), stdout);
                }
        }
 
@@ -1948,13 +2099,14 @@ static int imagex_optimize(int argc, char **argv)
 }
 
 /* Split a WIM into a spanned set */
-static int imagex_split(int argc, char **argv)
+static int
+imagex_split(int argc, tchar **argv)
 {
        int c;
        int open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK;
        int write_flags = 0;
        unsigned long part_size;
-       char *tmp;
+       tchar *tmp;
        int ret;
        WIMStruct *w;
 
@@ -1976,10 +2128,11 @@ static int imagex_split(int argc, char **argv)
                usage(SPLIT);
                return -1;
        }
-       part_size = strtod(argv[2], &tmp) * (1 << 20);
+       part_size = tstrtod(argv[2], &tmp) * (1 << 20);
        if (tmp == argv[2] || *tmp) {
-               imagex_error("Invalid part size \"%s\"", argv[2]);
-               imagex_error("The part size must be an integer or floating-point number of megabytes.");
+               imagex_error(T("Invalid part size \"%"TS"\""), argv[2]);
+               imagex_error(T("The part size must be an integer or "
+                              "floating-point number of megabytes."));
                return -1;
        }
        ret = wimlib_open_wim(argv[0], open_flags, &w, imagex_progress_func);
@@ -1991,7 +2144,8 @@ static int imagex_split(int argc, char **argv)
 }
 
 /* Unmounts a mounted WIM image. */
-static int imagex_unmount(int argc, char **argv)
+static int
+imagex_unmount(int argc, tchar **argv)
 {
        int c;
        int unmount_flags = 0;
@@ -2023,13 +2177,13 @@ static int imagex_unmount(int argc, char **argv)
        ret = wimlib_unmount_image(argv[0], unmount_flags,
                                   imagex_progress_func);
        if (ret != 0)
-               imagex_error("Failed to unmount `%s'", argv[0]);
+               imagex_error(T("Failed to unmount \"%"TS"\""), argv[0]);
        return ret;
 }
 
 struct imagex_command {
-       const char *name;
-       int (*func)(int , char **);
+       const tchar *name;
+       int (*func)(int , tchar **);
        int cmd;
 };
 
@@ -2038,39 +2192,43 @@ struct imagex_command {
                p != &imagex_commands[ARRAY_LEN(imagex_commands)]; p++)
 
 static const struct imagex_command imagex_commands[] = {
-       {"append",  imagex_capture_or_append, APPEND},
-       {"apply",   imagex_apply,             APPLY},
-       {"capture", imagex_capture_or_append, CAPTURE},
-       {"delete",  imagex_delete,            DELETE},
-       {"dir",     imagex_dir,               DIR},
-       {"export",  imagex_export,            EXPORT},
-       {"info",    imagex_info,              INFO},
-       {"join",    imagex_join,              JOIN},
-       {"mount",   imagex_mount_rw_or_ro,    MOUNT},
-       {"mountrw", imagex_mount_rw_or_ro,    MOUNTRW},
-       {"optimize",imagex_optimize,          OPTIMIZE},
-       {"split",   imagex_split,             SPLIT},
-       {"unmount", imagex_unmount,           UNMOUNT},
+       {T("append"),  imagex_capture_or_append, APPEND},
+       {T("apply"),   imagex_apply,             APPLY},
+       {T("capture"), imagex_capture_or_append, CAPTURE},
+       {T("delete"),  imagex_delete,            DELETE},
+       {T("dir"),     imagex_dir,               DIR},
+       {T("export"),  imagex_export,            EXPORT},
+       {T("info"),    imagex_info,              INFO},
+       {T("join"),    imagex_join,              JOIN},
+       {T("mount"),   imagex_mount_rw_or_ro,    MOUNT},
+       {T("mountrw"), imagex_mount_rw_or_ro,    MOUNTRW},
+       {T("optimize"),imagex_optimize,          OPTIMIZE},
+       {T("split"),   imagex_split,             SPLIT},
+       {T("unmount"), imagex_unmount,           UNMOUNT},
 };
 
-static void version()
+static void
+version()
 {
-       static const char *s =
-       IMAGEX_PROGNAME " (" PACKAGE ") " PACKAGE_VERSION "\n"
-       "Copyright (C) 2012, 2013 Eric Biggers\n"
-       "License GPLv3+; GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n"
-       "This is free software: you are free to change and redistribute it.\n"
-       "There is NO WARRANTY, to the extent permitted by law.\n"
-       "\n"
-       "Report bugs to "PACKAGE_BUGREPORT".\n";
-       fputs(s, stdout);
+       static const tchar *s =
+       T(
+IMAGEX_PROGNAME " (" PACKAGE ") " PACKAGE_VERSION "\n"
+"Copyright (C) 2012, 2013 Eric Biggers\n"
+"License GPLv3+; GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n"
+"This is free software: you are free to change and redistribute it.\n"
+"There is NO WARRANTY, to the extent permitted by law.\n"
+"\n"
+"Report bugs to "PACKAGE_BUGREPORT".\n"
+       );
+       tfputs(s, stdout);
 }
 
 
-static void help_or_version(int argc, char **argv)
+static void
+help_or_version(int argc, tchar **argv)
 {
        int i;
-       const char *p;
+       const tchar *p;
        const struct imagex_command *cmd;
 
        for (i = 1; i < argc; i++) {
@@ -2081,9 +2239,9 @@ static void help_or_version(int argc, char **argv)
                        continue;
                if (*p == '-')
                        p++;
-               if (strcmp(p, "help") == 0) {
+               if (!tstrcmp(p, T("help"))) {
                        for_imagex_command(cmd) {
-                               if (strcmp(cmd->name, argv[1]) == 0) {
+                               if (!tstrcmp(cmd->name, argv[1])) {
                                        usage(cmd->cmd);
                                        exit(0);
                                }
@@ -2091,7 +2249,7 @@ static void help_or_version(int argc, char **argv)
                        usage_all();
                        exit(0);
                }
-               if (strcmp(p, "version") == 0) {
+               if (!tstrcmp(p, T("version"))) {
                        version();
                        exit(0);
                }
@@ -2099,43 +2257,70 @@ static void help_or_version(int argc, char **argv)
 }
 
 
-static void usage(int cmd_type)
+static void
+usage(int cmd_type)
 {
        const struct imagex_command *cmd;
-       printf("Usage: %s", usage_strings[cmd_type]);
+       tprintf(T("Usage:\n%"TS), usage_strings[cmd_type]);
        for_imagex_command(cmd) {
-               if (cmd->cmd == cmd_type)
-                       printf("\nTry `man "IMAGEX_PROGNAME"-%s' for more details.\n",
-                              cmd->name);
+               if (cmd->cmd == cmd_type) {
+                       tprintf(T("\nTry `man "IMAGEX_PROGNAME"-%"TS"' "
+                                 "for more details.\n"), cmd->name);
+               }
        }
 }
 
-static void usage_all()
+static void
+usage_all()
 {
-       puts("IMAGEX: Usage:");
+       tfputs(T("Usage:\n"), stdout);
        for (int i = 0; i < ARRAY_LEN(usage_strings); i++)
-               printf("    %s", usage_strings[i]);
-       static const char *extra =
+               tprintf(T("    %"TS), usage_strings[i]);
+       static const tchar *extra =
+       T(
 "    "IMAGEX_PROGNAME" --help\n"
 "    "IMAGEX_PROGNAME" --version\n"
 "\n"
 "    The compression TYPE may be \"maximum\", \"fast\", or \"none\".\n"
 "\n"
 "    Try `man "IMAGEX_PROGNAME"' for more information.\n"
-       ;
-       fputs(extra, stdout);
+       );
+       tfputs(extra, stdout);
 }
 
-/* Entry point for wimlib's ImageX implementation */
-int main(int argc, char **argv)
+/* Entry point for wimlib's ImageX implementation.  On UNIX the command
+ * arguments will just be 'char' strings (ideally UTF-8 encoded, but could be
+ * something else), while an Windows the command arguments will be UTF-16LE
+ * encoded 'wchar_t' strings. */
+int
+#ifdef __WIN32__
+wmain(int argc, wchar_t **argv, wchar_t **envp)
+#else
+main(int argc, char **argv)
+#endif
 {
        const struct imagex_command *cmd;
        int ret;
 
+#ifndef __WIN32__
        setlocale(LC_ALL, "");
+       {
+               char *codeset = nl_langinfo(CODESET);
+               if (!strstr(codeset, "UTF-8") &&
+                   !strstr(codeset, "UTF8") &&
+                   !strstr(codeset, "utf-8") &&
+                   !strstr(codeset, "utf8"))
+               {
+                       fputs(
+"WARNING: Running "IMAGEX_PROGNAME" in a UTF-8 locale is recommended!\n"
+"         (Maybe try: `export LANG=en_US.UTF-8'?\n", stderr);
+
+               }
+       }
+#endif /* !__WIN32__ */
 
        if (argc < 2) {
-               imagex_error("No command specified");
+               imagex_error(T("No command specified"));
                usage_all();
                return 1;
        }
@@ -2156,13 +2341,13 @@ int main(int argc, char **argv)
 
        /* Search for the function to handle the ImageX subcommand. */
        for_imagex_command(cmd) {
-               if (strcmp(cmd->name, *argv) == 0) {
+               if (!tstrcmp(cmd->name, *argv)) {
                        ret = cmd->func(argc, argv);
                        goto out_check_write_error;
                }
        }
 
-       imagex_error("Unrecognized command: `%s'", argv[0]);
+       imagex_error(T("Unrecognized command: `%"TS"'"), argv[0]);
        usage_all();
        return 1;
 out_check_write_error:
@@ -2172,7 +2357,7 @@ out_check_write_error:
         * there was a write error. */
        if (cmd == &imagex_commands[INFO] || cmd == &imagex_commands[DIR]) {
                if (ferror(stdout) || fclose(stdout)) {
-                       imagex_error_with_errno("output error");
+                       imagex_error_with_errno(T("output error"));
                        if (ret == 0)
                                ret = -1;
                }
@@ -2183,11 +2368,11 @@ out:
         * indicates a wimlib error code from which an error message can be
         * printed. */
        if (ret > 0) {
-               imagex_error("Exiting with error code %d:\n"
-                            "       %s.", ret,
+               imagex_error(T("Exiting with error code %d:\n"
+                              "       %"TS"."), ret,
                             wimlib_get_error_string(ret));
                if (ret == WIMLIB_ERR_NTFS_3G && errno != 0)
-                       imagex_error_with_errno("errno");
+                       imagex_error_with_errno(T("errno"));
        }
 
        /* Make the library free any resources it's holding (not strictly
diff --git a/programs/wgetopt.c b/programs/wgetopt.c
new file mode 100644 (file)
index 0000000..5c9b74e
--- /dev/null
@@ -0,0 +1,750 @@
+/* 
+ * wgetopt.c:  Wide-character versions of getopt, getopt_long, and
+ * getopt_long_only.
+ *
+ * This has been modified from the original, which is
+ * Copyright (C) 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+ * 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+ * 2010 Free Software Foundation, Inc.
+ *
+ * This file is part of wimlib, a library for working with WIM files.
+ *
+ * wimlib is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with wimlib; if not, see http://www.gnu.org/licenses/.
+ */
+
+#include "wgetopt.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+wchar_t *woptarg = NULL;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `woptind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* 1003.2 says this must be 1 before any call.  */
+int woptind = 1;
+
+/* Formerly, initialization of getopt depended on woptind==0, which
+   causes problems with re-calling getopt as programs generally don't
+   know that. */
+
+int __getopt_initialized = 0;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static wchar_t *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int wopterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int woptopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return -1 with `woptind' != ARGC.  */
+
+static enum
+{
+  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable.  */
+static char *posixly_correct;
+
+
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,woptind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+static void
+exchange (wchar_t **argv)
+{
+  int bottom = first_nonopt;
+  int middle = last_nonopt;
+  int top = woptind;
+  wchar_t *tem;
+
+  /* Exchange the shorter segment with the far end of the longer segment.
+     That puts the shorter segment into the right place.
+     It leaves the longer segment in the right place overall,
+     but it consists of two parts that need to be swapped next.  */
+
+  while (top > middle && middle > bottom)
+    {
+      if (top - middle > middle - bottom)
+       {
+         /* Bottom segment is the short one.  */
+         int len = middle - bottom;
+         register int i;
+
+         /* Swap it with the top part of the top segment.  */
+         for (i = 0; i < len; i++)
+           {
+             tem = argv[bottom + i];
+             argv[bottom + i] = argv[top - (middle - bottom) + i];
+             argv[top - (middle - bottom) + i] = tem;
+           }
+         /* Exclude the moved bottom segment from further swapping.  */
+         top -= len;
+       }
+      else
+       {
+         /* Top segment is the short one.  */
+         int len = top - middle;
+         register int i;
+
+         /* Swap it with the bottom part of the bottom segment.  */
+         for (i = 0; i < len; i++)
+           {
+             tem = argv[bottom + i];
+             argv[bottom + i] = argv[middle + i];
+             argv[middle + i] = tem;
+           }
+         /* Exclude the moved top segment from further swapping.  */
+         bottom += len;
+       }
+    }
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (woptind - last_nonopt);
+  last_nonopt = woptind;
+}
+
+/* Initialize the internal data when the first call is made.  */
+
+static const wchar_t *
+_getopt_initialize (int argc, wchar_t *const *argv, const wchar_t *optstring)
+{
+  /* Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  first_nonopt = last_nonopt = woptind;
+
+  nextchar = NULL;
+
+  posixly_correct = getenv ("POSIXLY_CORRECT");
+
+  /* Determine how to handle the ordering of options and nonoptions.  */
+
+  if (optstring[0] == L'-')
+    {
+      ordering = RETURN_IN_ORDER;
+      ++optstring;
+    }
+  else if (optstring[0] == L'+')
+    {
+      ordering = REQUIRE_ORDER;
+      ++optstring;
+    }
+  else if (posixly_correct != NULL)
+    ordering = REQUIRE_ORDER;
+  else
+    ordering = PERMUTE;
+
+  return optstring;
+}
+\f
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `woptind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns -1.
+   Then `woptind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `wopterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `woptarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `woptarg', otherwise `woptarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct woption' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+_wgetopt_internal (int argc, wchar_t *const *argv, const wchar_t *optstring,
+                  const struct woption *longopts, int *longind, int long_only)
+{
+  woptarg = NULL;
+
+  if (woptind == 0 || !__getopt_initialized)
+    {
+      if (woptind == 0)
+       woptind = 1;    /* Don't scan ARGV[0], the program name.  */
+      optstring = _getopt_initialize (argc, argv, optstring);
+      __getopt_initialized = 1;
+    }
+
+  /* Test whether ARGV[woptind] points to a non-option argument.
+     Either it does not have option syntax, or there is an environment flag
+     from the shell indicating it is not an option.  The later information
+     is only used when the used in the GNU libc.  */
+# define NONOPTION_P (argv[woptind][0] != L'-' || argv[woptind][1] == L'\0')
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      /* Advance to the next ARGV-element.  */
+
+      /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+        moved back by the user (who may also have changed the arguments).  */
+      if (last_nonopt > woptind)
+       last_nonopt = woptind;
+      if (first_nonopt > woptind)
+       first_nonopt = woptind;
+
+      if (ordering == PERMUTE)
+       {
+         /* If we have just processed some options following some non-options,
+            exchange them so that the options come first.  */
+
+         if (first_nonopt != last_nonopt && last_nonopt != woptind)
+           exchange ((wchar_t **) argv);
+         else if (last_nonopt != woptind)
+           first_nonopt = woptind;
+
+         /* Skip any additional non-options
+            and extend the range of non-options previously skipped.  */
+
+         while (woptind < argc && NONOPTION_P)
+           woptind++;
+         last_nonopt = woptind;
+       }
+
+      /* The special ARGV-element `--' means premature end of options.
+        Skip it like a null option,
+        then exchange with previous non-options as if it were an option,
+        then skip everything else like a non-option.  */
+
+      if (woptind != argc && !wcscmp (argv[woptind], L"--"))
+       {
+         woptind++;
+
+         if (first_nonopt != last_nonopt && last_nonopt != woptind)
+           exchange ((wchar_t **) argv);
+         else if (first_nonopt == last_nonopt)
+           first_nonopt = woptind;
+         last_nonopt = argc;
+
+         woptind = argc;
+       }
+
+      /* If we have done all the ARGV-elements, stop the scan
+        and back over any non-options that we skipped and permuted.  */
+
+      if (woptind == argc)
+       {
+         /* Set the next-arg-index to point at the non-options
+            that we previously skipped, so the caller will digest them.  */
+         if (first_nonopt != last_nonopt)
+           woptind = first_nonopt;
+         return -1;
+       }
+
+      /* If we have come to a non-option and did not permute it,
+        either stop the scan or describe it to the caller and pass it by.  */
+
+      if (NONOPTION_P)
+       {
+         if (ordering == REQUIRE_ORDER)
+           return -1;
+         woptarg = argv[woptind++];
+         return 1;
+       }
+
+      /* We have found another option-ARGV-element.
+        Skip the initial punctuation.  */
+
+      nextchar = (argv[woptind] + 1
+                 + (longopts != NULL && argv[woptind][1] == L'-'));
+    }
+
+  /* Decode the current option-ARGV-element.  */
+
+  /* Check whether the ARGV-element is a long option.
+
+     If long_only and the ARGV-element has the form "-f", where f is
+     a valid short option, don't consider it an abbreviated form of
+     a long option that starts with f.  Otherwise there would be no
+     way to give the -f short option.
+
+     On the other hand, if there's a long option "fubar" and
+     the ARGV-element is "-fu", do consider that an abbreviation of
+     the long option, just like "--fu", and not "-f" with arg "u".
+
+     This distinction seems to be the most useful approach.  */
+
+  if (longopts != NULL
+      && (argv[woptind][1] == L'-'
+         || (long_only && (argv[woptind][2] || !wcschr (optstring, argv[woptind][1])))))
+    {
+      wchar_t *nameend;
+      const struct woption *p;
+      const struct woption *pfound = NULL;
+      int exact = 0;
+      int ambig = 0;
+      int indfound = -1;
+      int option_index;
+
+      for (nameend = nextchar; *nameend && *nameend != L'='; nameend++)
+       /* Do nothing.  */ ;
+
+      /* Test all long options for either exact match
+        or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name; p++, option_index++)
+       if (!wcsncmp (p->name, nextchar, nameend - nextchar))
+         {
+           if ((unsigned int) (nameend - nextchar)
+               == (unsigned int) wcslen (p->name))
+             {
+               /* Exact match found.  */
+               pfound = p;
+               indfound = option_index;
+               exact = 1;
+               break;
+             }
+           else if (pfound == NULL)
+             {
+               /* First nonexact match found.  */
+               pfound = p;
+               indfound = option_index;
+             }
+           else
+             /* Second or later nonexact match found.  */
+             ambig = 1;
+         }
+
+      if (ambig && !exact)
+       {
+         if (wopterr)
+           fwprintf (stderr, L"%ls: option `%ls' is ambiguous\n",
+                     argv[0], argv[woptind]);
+         nextchar += wcslen (nextchar);
+         woptind++;
+         woptopt = 0;
+         return L'?';
+       }
+
+      if (pfound != NULL)
+       {
+         option_index = indfound;
+         woptind++;
+         if (*nameend)
+           {
+             /* Don't test has_arg with >, because some C compilers don't
+                allow it to be used on enums.  */
+             if (pfound->has_arg)
+               woptarg = nameend + 1;
+             else
+               {
+                 if (wopterr) {
+                  if (argv[woptind - 1][1] == L'-')
+                   /* --option */
+                   fwprintf (stderr,
+                    L"%ls: option `--%ls' doesn't allow an argument\n",
+                    argv[0], pfound->name);
+                  else
+                   /* +option or -option */
+                   fwprintf (stderr,
+                    L"%ls: option `%lc%ls' doesn't allow an argument\n",
+                    argv[0], argv[woptind - 1][0], pfound->name);
+                 }
+
+                 nextchar += wcslen (nextchar);
+
+                 woptopt = pfound->val;
+                 return L'?';
+               }
+           }
+         else if (pfound->has_arg == 1)
+           {
+             if (woptind < argc)
+               woptarg = argv[woptind++];
+             else
+               {
+                 if (wopterr)
+                   fwprintf (stderr,
+                          L"%ls: option `%ls' requires an argument\n",
+                          argv[0], argv[woptind - 1]);
+                 nextchar += wcslen (nextchar);
+                 woptopt = pfound->val;
+                 return optstring[0] == L':' ? L':' : L'?';
+               }
+           }
+         nextchar += wcslen (nextchar);
+         if (longind != NULL)
+           *longind = option_index;
+         if (pfound->flag)
+           {
+             *(pfound->flag) = pfound->val;
+             return 0;
+           }
+         return pfound->val;
+       }
+
+      /* Can't find it as a long option.  If this is not getopt_long_only,
+        or the option starts with '--' or is not a valid short
+        option, then it's an error.
+        Otherwise interpret it as a short option.  */
+      if (!long_only || argv[woptind][1] == L'-'
+         || wcschr (optstring, *nextchar) == NULL)
+       {
+         if (wopterr)
+           {
+             if (argv[woptind][1] == '-')
+               /* --option */
+               fwprintf (stderr, L"%ls: unrecognized option `--%ls'\n",
+                        argv[0], nextchar);
+             else
+               /* +option or -option */
+               fwprintf (stderr, L"%ls: unrecognized option `%lc%ls'\n",
+                        argv[0], argv[woptind][0], nextchar);
+           }
+         nextchar = (wchar_t *) L"";
+         woptind++;
+         woptopt = 0;
+         return L'?';
+       }
+    }
+
+  /* Look at and handle the next short option-character.  */
+
+  {
+    wchar_t c = *nextchar++;
+    wchar_t *temp = wcschr (optstring, c);
+
+    /* Increment `woptind' when we start to process its last character.  */
+    if (*nextchar == L'\0')
+      ++woptind;
+
+    if (temp == NULL || c == L':')
+      {
+       if (wopterr)
+         {
+           if (posixly_correct)
+             /* 1003.2 specifies the format of this message.  */
+             fwprintf (stderr, L"%ls: illegal option -- %lc\n",
+                      argv[0], c);
+           else
+             fwprintf (stderr, L"%ls: invalid option -- %lc\n",
+                      argv[0], c);
+         }
+       woptopt = c;
+       return L'?';
+      }
+    /* Convenience. Treat POSIX -W foo same as long option --foo */
+    if (temp[0] == L'W' && temp[1] == L';')
+      {
+       wchar_t *nameend;
+       const struct woption *p;
+       const struct woption *pfound = NULL;
+       int exact = 0;
+       int ambig = 0;
+       int indfound = 0;
+       int option_index;
+
+       /* This is an option that requires an argument.  */
+       if (*nextchar != L'\0')
+         {
+           woptarg = nextchar;
+           /* If we end this ARGV-element by taking the rest as an arg,
+              we must advance to the next element now.  */
+           woptind++;
+         }
+       else if (woptind == argc)
+         {
+           if (wopterr)
+             {
+               /* 1003.2 specifies the format of this message.  */
+               fwprintf (stderr, L"%ls: option requires an argument -- %lc\n",
+                        argv[0], c);
+             }
+           woptopt = c;
+           if (optstring[0] == L':')
+             c = L':';
+           else
+             c = L'?';
+           return c;
+         }
+       else
+         /* We already incremented `woptind' once;
+            increment it again when taking next ARGV-elt as argument.  */
+         woptarg = argv[woptind++];
+
+       /* woptarg is now the argument, see if it's in the
+          table of longopts.  */
+
+       for (nextchar = nameend = woptarg; *nameend && *nameend != L'='; nameend++)
+         /* Do nothing.  */ ;
+
+       /* Test all long options for either exact match
+          or abbreviated matches.  */
+       for (p = longopts, option_index = 0; p->name; p++, option_index++)
+         if (!wcsncmp (p->name, nextchar, nameend - nextchar))
+           {
+             if ((unsigned int) (nameend - nextchar) == wcslen (p->name))
+               {
+                 /* Exact match found.  */
+                 pfound = p;
+                 indfound = option_index;
+                 exact = 1;
+                 break;
+               }
+             else if (pfound == NULL)
+               {
+                 /* First nonexact match found.  */
+                 pfound = p;
+                 indfound = option_index;
+               }
+             else
+               /* Second or later nonexact match found.  */
+               ambig = 1;
+           }
+       if (ambig && !exact)
+         {
+           if (wopterr)
+             fwprintf (stderr, L"%ls: option `-W %ls' is ambiguous\n",
+                      argv[0], argv[woptind]);
+           nextchar += wcslen (nextchar);
+           woptind++;
+           return L'?';
+         }
+       if (pfound != NULL)
+         {
+           option_index = indfound;
+           if (*nameend)
+             {
+               /* Don't test has_arg with >, because some C compilers don't
+                  allow it to be used on enums.  */
+               if (pfound->has_arg)
+                 woptarg = nameend + 1;
+               else
+                 {
+                   if (wopterr)
+                     fwprintf (stderr, L"\
+%ls: option `-W %ls' doesn't allow an argument\n",
+                              argv[0], pfound->name);
+
+                   nextchar += wcslen (nextchar);
+                   return L'?';
+                 }
+             }
+           else if (pfound->has_arg == 1)
+             {
+               if (woptind < argc)
+                 woptarg = argv[woptind++];
+               else
+                 {
+                   if (wopterr)
+                     fwprintf (stderr,
+                              L"%ls: option `%ls' requires an argument\n",
+                              argv[0], argv[woptind - 1]);
+                   nextchar += wcslen (nextchar);
+                   return optstring[0] == L':' ? L':' : L'?';
+                 }
+             }
+           nextchar += wcslen (nextchar);
+           if (longind != NULL)
+             *longind = option_index;
+           if (pfound->flag)
+             {
+               *(pfound->flag) = pfound->val;
+               return 0;
+             }
+           return pfound->val;
+         }
+         nextchar = NULL;
+         return L'W';  /* Let the application handle it.   */
+      }
+    if (temp[1] == L':')
+      {
+       if (temp[2] == L':')
+         {
+           /* This is an option that accepts an argument optionally.  */
+           if (*nextchar != L'\0')
+             {
+               woptarg = nextchar;
+               woptind++;
+             }
+           else
+             woptarg = NULL;
+           nextchar = NULL;
+         }
+       else
+         {
+           /* This is an option that requires an argument.  */
+           if (*nextchar != L'\0')
+             {
+               woptarg = nextchar;
+               /* If we end this ARGV-element by taking the rest as an arg,
+                  we must advance to the next element now.  */
+               woptind++;
+             }
+           else if (woptind == argc)
+             {
+               if (wopterr)
+                 {
+                   /* 1003.2 specifies the format of this message.  */
+                   fwprintf (stderr,
+                            L"%ls: option requires an argument -- %lc\n",
+                            argv[0], c);
+                 }
+               woptopt = c;
+               if (optstring[0] == L':')
+                 c = L':';
+               else
+                 c = L'?';
+             }
+           else
+             /* We already incremented `woptind' once;
+                increment it again when taking next ARGV-elt as argument.  */
+             woptarg = argv[woptind++];
+           nextchar = NULL;
+         }
+      }
+    return c;
+  }
+}
+
+int
+wgetopt (int argc, wchar_t *const *argv, const wchar_t *optstring)
+{
+  return _wgetopt_internal (argc, argv, optstring,
+                           (const struct woption *) 0,
+                           (int *) 0,
+                           0);
+}
+
+int
+wgetopt_long (int argc, wchar_t * const *argv, const wchar_t *options,
+             const struct woption *long_options, int *opt_index)
+{
+  return _wgetopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+   If an option that starts with '-' (not '--') doesn't match a long option,
+   but does match a short option, it is parsed as a short option
+   instead.  */
+int
+wgetopt_long_only (int argc, wchar_t * const *argv, const wchar_t *options,
+                  const struct woption *long_options, int *opt_index)
+{
+  return _wgetopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
diff --git a/programs/wgetopt.h b/programs/wgetopt.h
new file mode 100644 (file)
index 0000000..9b2f3a3
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef _WGETOPT_H
+#define _WGETOPT_H
+
+#include <wchar.h>
+
+extern wchar_t *woptarg;
+extern int woptind, wopterr, woptopt;
+
+struct woption {
+       const wchar_t *name;
+       int            has_arg;
+       int           *flag;
+       int            val;
+};
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+extern int
+wgetopt (int argc, wchar_t *const *argv, const wchar_t *optstring);
+
+extern int
+wgetopt_long(int argc, wchar_t * const *argv, const wchar_t *options,
+            const struct woption *long_options, int *opt_index);
+
+extern int
+wgetopt_long_only(int argc, wchar_t *const *argv, const wchar_t *options,
+                 const struct woption *long_options, int *opt_index);
+
+#endif
index f435c3f..5f7a183 100644 (file)
 #include <ctype.h>
 #include <errno.h>
 #include <stdlib.h>
-
-#if TCHAR_IS_UTF16LE
-#  include <wchar.h>
-#else
-#  include <string.h>
-#endif
+#include <string.h>
 
 #include <unistd.h>
 
@@ -144,7 +139,7 @@ static int
 unix_build_dentry_tree(struct wim_dentry **root_ret,
                       const char *root_disk_path,
                       struct wim_lookup_table *lookup_table,
-                      struct sd_set *sd,
+                      struct sd_set *sd_set,
                       const struct capture_config *config,
                       int add_image_flags,
                       wimlib_progress_func_t progress_func,
@@ -526,19 +521,20 @@ init_capture_config(struct capture_config *config,
                        if (*pp == T('\\'))
                                *pp = T('/');
 
-               /* Remove drive letter 
-                * XXX maybe keep drive letter on Windows */
+               /* Remove drive letter (UNIX only) */
+       #ifndef __WIN32__
                if (eol - p > 2 && istalpha(*p) && *(p + 1) == T(':'))
                        p += 2;
+       #endif
 
                ret = 0;
-               if (tstrcmp(p, T("[ExclusionList]")) == 0)
+               if (!tstrcmp(p, T("[ExclusionList]")))
                        type = EXCLUSION_LIST;
-               else if (tstrcmp(p, T("[ExclusionException]")) == 0)
+               else if (!tstrcmp(p, T("[ExclusionException]")))
                        type = EXCLUSION_EXCEPTION;
-               else if (tstrcmp(p, T("[CompressionExclusionList]")) == 0)
+               else if (!tstrcmp(p, T("[CompressionExclusionList]")))
                        type = COMPRESSION_EXCLUSION_LIST;
-               else if (tstrcmp(p, T("[AlignmentList]")) == 0)
+               else if (!tstrcmp(p, T("[AlignmentList]")))
                        type = ALIGNMENT_LIST;
                else if (p[0] == T('[') && tstrrchr(p, T(']'))) {
                        ERROR("Unknown capture configuration section \"%"TS"\"", p);
@@ -640,9 +636,11 @@ exclude_path(const tchar *path, const struct capture_config *config,
        const tchar *basename = path_basename(path);
        if (exclude_prefix) {
                wimlib_assert(tstrlen(path) >= config->prefix_num_tchars);
-               if (tmemcmp(config->prefix, path, config->prefix_num_tchars) == 0
-                    && path[config->prefix_num_tchars] == T('/'))
+               if (!tmemcmp(config->prefix, path, config->prefix_num_tchars) &&
+                   path[config->prefix_num_tchars] == T('/'))
+               {
                        path += config->prefix_num_tchars;
+               }
        }
        return match_pattern(path, basename, &config->exclusion_list) &&
                !match_pattern(path, basename, &config->exclusion_exception);
@@ -666,22 +664,12 @@ canonicalize_target_path(tchar *target_path)
                        break;
        }
 
-       p = target_path + tstrlen(target_path) - 1;
+       p = tstrchr(target_path, T('\0')) - 1;
        while (*p == T('/'))
                *p-- = T('\0');
        return target_path;
 }
 
-static void
-zap_backslashes(tchar *s)
-{
-       while (*s) {
-               if (*s == T('\\'))
-                       *s = T('/');
-               s++;
-       }
-}
-
 /* Strip leading and trailing slashes from the target paths */
 static void
 canonicalize_targets(struct wimlib_capture_source *sources, size_t num_sources)
@@ -733,7 +721,7 @@ check_sorted_sources(struct wimlib_capture_source *sources, size_t num_sources,
                              "(the NTFS volume) in NTFS mode!");
                        return WIMLIB_ERR_INVALID_PARAM;
                }
-               if (sources[0].wim_target_path[0] != '\0') {
+               if (sources[0].wim_target_path[0] != T('\0')) {
                        ERROR("In NTFS capture mode the target path inside "
                              "the image must be the root directory!");
                        return WIMLIB_ERR_INVALID_PARAM;
@@ -880,7 +868,7 @@ attach_branch(struct wim_dentry **root_p, struct wim_dentry *branch,
         * */
        parent = *root_p;
        while ((slash = tstrchr(target_path, T('/')))) {
-               *slash = '\0';
+               *slash = T('\0');
                dentry = get_dentry_child_with_name(parent, target_path);
                if (!dentry) {
                        ret = new_filler_directory(target_path, &dentry);
@@ -1112,7 +1100,7 @@ out_destroy_imd:
        destroy_image_metadata(&w->image_metadata[w->hdr.image_count - 1],
                               w->lookup_table);
        w->hdr.image_count--;
-       goto out;
+       goto out_destroy_sd_set;
 out_free_branch:
        free_dentry_tree(branch, w->lookup_table);
 out_free_dentry_tree:
index 503dbba..677db1d 100644 (file)
 #include "wimlib_internal.h"
 #include <errno.h>
 
-#ifdef TCHAR_IS_UTF16LE
-#  include <wchar.h>
-#endif
-
 /* Calculates the unaligned length, in bytes, of an on-disk WIM dentry that has
  * a file name and short name that take the specified numbers of bytes.  This
  * excludes any alternate data stream entries that may follow the dentry. */
@@ -91,20 +87,20 @@ get_utf16le_name(const tchar *name, utf16lechar **name_utf16le_ret,
        size_t name_utf16le_nbytes;
        int ret;
 #if TCHAR_IS_UTF16LE
-       name_utf16le_nbytes = tstrlen(name) * 2;
-       name_utf16le = MALLOC(name_utf16le_nbytes + 2);
+       name_utf16le_nbytes = tstrlen(name) * sizeof(utf16lechar);
+       name_utf16le = MALLOC(name_utf16le_nbytes + sizeof(utf16lechar));
        if (!name_utf16le)
                return WIMLIB_ERR_NOMEM;
-       memcpy(name_utf16le, name, name_utf16le_nbytes + 2);
+       memcpy(name_utf16le, name, name_utf16le_nbytes + sizeof(utf16lechar));
        ret = 0;
 #else
 
-       ret = tstr_to_utf16le(name, strlen(name), &name_utf16le,
+       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 \"%s\" is too long!", name);
+                       ERROR("Multibyte string \"%"TS"\" is too long!", name);
                        ret = WIMLIB_ERR_INVALID_UTF8_STRING;
                }
        }
@@ -278,7 +274,7 @@ for_dentry_in_tree_depth(struct wim_dentry *root,
 }
 
 /* Calculate the full path of @dentry.  The full path of its parent must have
- * already been calculated. */
+ * already been calculated, or it must be the root dentry. */
 int
 calculate_dentry_full_path(struct wim_dentry *dentry, void *ignore)
 {
@@ -289,18 +285,15 @@ calculate_dentry_full_path(struct wim_dentry *dentry, void *ignore)
                      dentry->parent->full_path != NULL);
 
        if (dentry_is_root(dentry)) {
-               full_path = TMALLOC(2);
+               full_path = TSTRDUP(T("/"));
                if (!full_path)
                        return WIMLIB_ERR_NOMEM;
-               full_path[0] = T('/');
-               full_path[1] = T('\0');
                full_path_nbytes = 1 * sizeof(tchar);
        } else {
+               const struct wim_dentry *parent;
                tchar *parent_full_path;
                u32 parent_full_path_nbytes;
-               const struct wim_dentry *parent;
                size_t filename_nbytes;
-               int ret;
 
                parent = dentry->parent;
                if (dentry_is_root(parent)) {
@@ -310,31 +303,37 @@ calculate_dentry_full_path(struct wim_dentry *dentry, void *ignore)
                        parent_full_path = parent->full_path;
                        parent_full_path_nbytes = parent->full_path_nbytes;
                }
+
+               /* 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
-               ret = utf16le_to_mbs_nbytes(dentry->file_name,
-                                           dentry->file_name_nbytes,
-                                           &filename_nbytes);
-               if (ret)
-                       return ret;
+               {
+                       int ret = utf16le_to_tstr_nbytes(dentry->file_name,
+                                                        dentry->file_name_nbytes,
+                                                        &filename_nbytes);
+                       if (ret)
+                               return ret;
+               }
        #endif
 
                full_path_nbytes = parent_full_path_nbytes + sizeof(tchar) +
-                                  dentry->file_name_nbytes;
+                                  filename_nbytes;
                full_path = MALLOC(full_path_nbytes + sizeof(tchar));
                if (!full_path)
                        return WIMLIB_ERR_NOMEM;
                memcpy(full_path, parent_full_path, parent_full_path_nbytes);
-               full_path[parent_full_path_nbytes] = T('/');
+               full_path[parent_full_path_nbytes / sizeof(tchar)] = T('/');
        #if TCHAR_IS_UTF16LE
-               memcpy(&full_path[parent_full_path_nbytes + 1],
+               memcpy(&full_path[parent_full_path_nbytes / sizeof(tchar) + 1],
                       dentry->file_name,
-                      dentry->file_name_nbytes + sizeof(tchar));
+                      filename_nbytes + sizeof(tchar));
        #else
-               utf16le_to_mbs_buf(dentry->file_name,
-                                  dentry->file_name_nbytes,
-                                  &full_path[parent_full_path_nbytes + 1]);
+               utf16le_to_tstr_buf(dentry->file_name,
+                                   dentry->file_name_nbytes,
+                                   &full_path[parent_full_path_nbytes /
+                                              sizeof(tchar) + 1]);
        #endif
        }
        FREE(dentry->full_path);
@@ -448,7 +447,7 @@ get_dentry_child_with_name(const struct wim_dentry *dentry, const tchar *name)
        int ret;
        struct wim_dentry *child;
 
-       ret = tstr_to_utf16le(name, strlen(name),
+       ret = tstr_to_utf16le(name, tstrlen(name) * sizeof(tchar),
                              &utf16le_name, &utf16le_name_nbytes);
        if (ret) {
                child = NULL;
@@ -469,12 +468,11 @@ get_dentry_utf16le(WIMStruct *w, const utf16lechar *path,
        struct wim_dentry *cur_dentry, *parent_dentry;
        const utf16lechar *p, *pp;
 
-       parent_dentry = wim_root_dentry(w);
+       cur_dentry = parent_dentry = wim_root_dentry(w);
        p = path;
        while (1) {
                while (*p == cpu_to_le16('/'))
                        p++;
-               cur_dentry = parent_dentry;
                if (*p == '\0')
                        break;
                pp = p;
@@ -516,7 +514,7 @@ get_dentry(WIMStruct *w, const tchar *path)
                return NULL;
        dentry = get_dentry_utf16le(w, path_utf16le, path_utf16le_nbytes);
        FREE(path_utf16le);
-       return cur_dentry;
+       return dentry;
 #endif
 }
 
@@ -531,6 +529,21 @@ wim_pathname_to_inode(WIMStruct *w, const tchar *path)
                return NULL;
 }
 
+/* Takes in a path of length @len in @buf, and transforms it into a string for
+ * the path of its parent directory. */
+static void
+to_parent_name(tchar *buf, size_t len)
+{
+       ssize_t i = (ssize_t)len - 1;
+       while (i >= 0 && buf[i] == T('/'))
+               i--;
+       while (i >= 0 && buf[i] != T('/'))
+               i--;
+       while (i >= 0 && buf[i] == T('/'))
+               i--;
+       buf[i + 1] = T('\0');
+}
+
 /* Returns the dentry that corresponds to the parent directory of @path, or NULL
  * if the dentry is not found. */
 struct wim_dentry *
@@ -549,7 +562,7 @@ int
 print_dentry_full_path(struct wim_dentry *dentry, void *ignore)
 {
        if (dentry->full_path)
-               printf("%"TS"\n", dentry->full_path);
+               tprintf(T("%"TS"\n"), dentry->full_path);
        return 0;
 }
 
@@ -616,7 +629,7 @@ print_dentry(struct wim_dentry *dentry, void *lookup_table)
        if (dentry_has_short_name(dentry))
                wimlib_printf(T("Short Name \"%"WS"\"\n"), dentry->short_name);
        if (dentry->full_path)
-               tprintf(T("Full Path = \"%"WS"\"\n"), dentry->full_path);
+               tprintf(T("Full Path = \"%"TS"\"\n"), dentry->full_path);
 
        lte = inode_stream_lte(dentry->d_inode, 0, lookup_table);
        if (lte) {
@@ -690,7 +703,8 @@ new_inode()
 }
 
 /* Creates an unlinked directory entry. */
-int new_dentry(const tchar *name, struct wim_dentry **dentry_ret)
+int
+new_dentry(const tchar *name, struct wim_dentry **dentry_ret)
 {
        struct wim_dentry *dentry;
        int ret;
@@ -938,7 +952,6 @@ inode_get_ads_entry(struct wim_inode *inode, const tchar *stream_name,
        if (inode->i_num_ads == 0) {
                return NULL;
        } else {
-               int ret;
                size_t stream_name_utf16le_nbytes;
                u16 i;
                struct wim_ads_entry *result;
@@ -951,11 +964,15 @@ inode_get_ads_entry(struct wim_inode *inode, const tchar *stream_name,
        #else
                utf16lechar *stream_name_utf16le;
 
-               ret = tstr_to_utf16le(stream_name, tstrlen(stream_name) * sizeof(tchar),
-                                     &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;
@@ -1509,9 +1526,9 @@ read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
                 *      u64 reserved1; (always 0)
                 *      u64 reserved2; (always 0)
                 * };*/
-               /*DEBUG("Dentry for file or directory `%s' has %"PRIu64" extra "*/
-                     /*"bytes of data",*/
-                     /*file_name_utf8, dentry->length - calculated_size);*/
+               /*DEBUG("Dentry for file or directory `%"WS"' has %"PRIu64" "*/
+                     /*"extra bytes of data", file_name,*/
+                     /*dentry->length - calculated_size);*/
        }
 
        /* Read the short filename if present.  Note: if there is no short
index 6a3affc..e8d8328 100644 (file)
@@ -142,9 +142,10 @@ struct wim_dentry {
        u16 file_name_nbytes;
 
        /* Length of full path name encoded using "tchars", in bytes, not
-        * including the terminating null terminator. */
+        * including the terminating null character. */
        u32 full_path_nbytes;
 
+       /* Has this dentry been extracted yet? */
        u8 is_extracted : 1;
 
        /* Only used during NTFS capture */
index 256103a..f5b978a 100644 (file)
@@ -1,7 +1,5 @@
 /*
- * encoding.c:  Convert "multibyte" strings (the locale-default encoding---
- * generally, UTF-8 or something like ISO-8859-1) to UTF-16LE strings, and vice
- * versa.  Also, convert UTF-8 strings to multibyte strings.
+ * encoding.c
  */
 
 /*
@@ -117,11 +115,12 @@ static bool error_message_being_printed = false;
                                         earlyreturn,                   \
                                         worst_case_len_expr,           \
                                         err_return,                    \
-                                        err_msg)                       \
+                                        err_msg,                       \
+                                        modifier)                      \
 static ICONV_LIST(iconv_##varname1##_to_##varname2,                    \
                  longname1, longname2);                                \
                                                                        \
-int                                                                    \
+modifier int                                                           \
 varname1##_to_##varname2##_nbytes(const chartype1 *in, size_t in_nbytes,\
                                  size_t *out_nbytes_ret)               \
 {                                                                      \
@@ -154,7 +153,7 @@ varname1##_to_##varname2##_nbytes(const chartype1 *in, size_t in_nbytes,\
        return ret;                                                     \
 }                                                                      \
                                                                        \
-int                                                                    \
+modifier int                                                           \
 varname1##_to_##varname2##_buf(const chartype1 *in, size_t in_nbytes,  \
                               chartype2 *out)                          \
 {                                                                      \
@@ -186,7 +185,7 @@ varname1##_to_##varname2##_buf(const chartype1 *in, size_t in_nbytes,       \
        return ret;                                                     \
 }                                                                      \
                                                                        \
-int                                                                    \
+modifier int                                                           \
 varname1##_to_##varname2(const chartype1 *in, size_t in_nbytes,                \
                         chartype2 **out_ret,                           \
                         size_t *out_nbytes_ret)                        \
@@ -228,62 +227,63 @@ varname1##_to_##varname2(const chartype1 *in, size_t in_nbytes,           \
        return ret;                                                     \
 }
 
-#if 0
-DEFINE_CHAR_CONVERSION_FUNCTIONS(utf16le, "UTF-16LE", utf16lechar,
-                                mbs, "", mbchar,
-                                false,
-                                in_nbytes / 2 * MB_CUR_MAX,
-                                WIMLIB_ERR_UNICODE_STRING_NOT_REPRESENTABLE,
-                                ERROR("Failed to convert UTF-16LE string "
-                                      "to multibyte string!");
-                                ERROR("This may be because the UTF-16LE data "
-                                      "could not be represented in your "
-                                      "locale's character encoding."))
-#endif
-
 #if !TCHAR_IS_UTF16LE
 DEFINE_CHAR_CONVERSION_FUNCTIONS(tstr, "", tchar,
                                 utf16le, "UTF-16LE", utf16lechar,
                                 false,
-                                in_nbytes * 2,
+                                in_nbytes * 4,
                                 WIMLIB_ERR_INVALID_MULTIBYTE_STRING,
                                 ERROR_WITH_ERRNO("Failed to convert multibyte "
                                                  "string \"%"TS"\" to UTF-16LE string!", in);
                                 ERROR("If the data you provided was UTF-8, please make sure "
-                                      "the character encoding of your current locale is UTF-8."))
+                                      "the character encoding of your current locale is UTF-8."),
+                                )
+
+DEFINE_CHAR_CONVERSION_FUNCTIONS(utf16le, "UTF-16LE", utf16lechar,
+                                tstr, "", tchar,
+                                false,
+                                in_nbytes * 2,
+                                WIMLIB_ERR_UNICODE_STRING_NOT_REPRESENTABLE,
+                                ERROR("Failed to convert UTF-16LE string to "
+                                      "multibyte string!");
+                                ERROR("This may be because the UTF-16LE string "
+                                      "could not be represented in your "
+                                      "locale's character encoding."),
+                                )
 #endif
 
 /* tchar to UTF-8 and back */
 #if TCHAR_IS_UTF16LE
 DEFINE_CHAR_CONVERSION_FUNCTIONS(tstr, "UTF16-LE", tchar,
-                                utf8, "UTF-8", utf8char,
+                                utf8, "UTF-8", char,
                                 false,
                                 in_nbytes * 2,
-                                WIMLIB_ERR_INVALID_MULTIBYTE_STRING,
+                                WIMLIB_ERR_INVALID_UTF16_STRING,
                                 ERROR_WITH_ERRNO("Failed to convert UTF-16LE "
-                                                 "string \"%"TS"\" to UTF-8 string!", in);
-                               )
+                                                 "string \"%"TS"\" to UTF-8 string!", in),
+                                static)
 
-DEFINE_CHAR_CONVERSION_FUNCTIONS(utf8, "UTF-8", utf8char,
+DEFINE_CHAR_CONVERSION_FUNCTIONS(utf8, "UTF-8", char,
                                 tstr, "UTF16-LE", tchar,
                                 false,
                                 in_nbytes * 2,
-                                WIMLIB_ERR_INVALID_MULTIBYTE_STRING,
+                                WIMLIB_ERR_INVALID_UTF8_STRING,
                                 ERROR_WITH_ERRNO("Failed to convert UTF-8 string "
-                                                 "to UTF-16LE string!");
-                               )
+                                                 "to UTF-16LE string!"),
+                                static)
 #else
 DEFINE_CHAR_CONVERSION_FUNCTIONS(tstr, "", tchar,
-                                utf8, "UTF-8", utf8char,
+                                utf8, "UTF-8", char,
                                 wimlib_mbs_is_utf8,
                                 in_nbytes * 4,
                                 WIMLIB_ERR_INVALID_MULTIBYTE_STRING,
                                 ERROR_WITH_ERRNO("Failed to convert multibyte "
                                                  "string \"%"TS"\" to UTF-8 string!", in);
                                 ERROR("If the data you provided was UTF-8, please make sure "
-                                      "the character encoding of your current locale is UTF-8.");)
+                                      "the character encoding of your current locale is UTF-8."),
+                                static)
 
-DEFINE_CHAR_CONVERSION_FUNCTIONS(utf8, "UTF-8", utf8char,
+DEFINE_CHAR_CONVERSION_FUNCTIONS(utf8, "UTF-8", char,
                                 tstr, "", tchar,
                                 wimlib_mbs_is_utf8,
                                 in_nbytes * 4,
@@ -292,18 +292,19 @@ DEFINE_CHAR_CONVERSION_FUNCTIONS(utf8, "UTF-8", utf8char,
                                       "multibyte string!");
                                 ERROR("This may be because the UTF-8 data "
                                       "could not be represented in your "
-                                      "locale's character encoding.");)
+                                      "locale's character encoding."),
+                                static)
 #endif
 
 int
-tstr_to_utf8_simple(const tchar *tstr, utf8char **out)
+tstr_to_utf8_simple(const tchar *tstr, char **out)
 {
        size_t out_nbytes;
        return tstr_to_utf8(tstr, tstrlen(tstr), out, &out_nbytes);
 }
 
 int
-utf8_to_tstr_simple(const utf8char *utf8str, tchar **out)
+utf8_to_tstr_simple(const char *utf8str, tchar **out)
 {
        size_t out_nbytes;
        return utf8_to_tstr(utf8str, strlen(utf8str), out, &out_nbytes);
@@ -326,21 +327,10 @@ iconv_cleanup(struct iconv_list_head *head)
 void
 iconv_global_cleanup()
 {
-       /*iconv_cleanup(&iconv_utf16le_to_mbs);*/
+       iconv_cleanup(&iconv_utf8_to_tstr);
+       iconv_cleanup(&iconv_tstr_to_utf8);
 #if !TCHAR_IS_UTF16LE
-       iconv_cleanup(&iconv_mbs_to_utf16le);
+       iconv_cleanup(&iconv_utf16le_to_tstr);
+       iconv_cleanup(&iconv_tstr_to_utf16le);
 #endif
-       /*iconv_cleanup(&iconv_utf8_to_mbs);*/
 }
-
-#if 0
-bool
-utf8_str_contains_nonascii_chars(const utf8char *utf8_str)
-{
-       do {
-               if ((unsigned char)*utf8_str > 127)
-                       return true;
-       } while (*++utf8_str);
-       return false;
-}
-#endif
index dfd9f05..b62f67c 100644 (file)
 #include "lookup_table.h"
 #include "xml.h"
 
-static int inode_allocate_needed_ltes(struct wim_inode *inode,
-                                     struct wim_lookup_table *src_lookup_table,
-                                     struct wim_lookup_table *dest_lookup_table,
-                                     struct list_head *lte_list_head)
+static int
+inode_allocate_needed_ltes(struct wim_inode *inode,
+                          struct wim_lookup_table *src_lookup_table,
+                          struct wim_lookup_table *dest_lookup_table,
+                          struct list_head *lte_list_head)
 {
        struct wim_lookup_table_entry *src_lte, *dest_lte;
        unsigned i;
@@ -53,10 +54,11 @@ static int inode_allocate_needed_ltes(struct wim_inode *inode,
        return 0;
 }
 
-static void inode_move_ltes_to_table(struct wim_inode *inode,
-                                    struct wim_lookup_table *src_lookup_table,
-                                    struct wim_lookup_table *dest_lookup_table,
-                                    struct list_head *lte_list_head)
+static void
+inode_move_ltes_to_table(struct wim_inode *inode,
+                        struct wim_lookup_table *src_lookup_table,
+                        struct wim_lookup_table *dest_lookup_table,
+                        struct list_head *lte_list_head)
 {
        struct wim_lookup_table_entry *src_lte, *dest_lte;
        unsigned i;
@@ -92,15 +94,16 @@ static void inode_move_ltes_to_table(struct wim_inode *inode,
 /*
  * Copies an image, or all the images, from a WIM file, into another WIM file.
  */
-WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
-                                 int src_image,
-                                 WIMStruct *dest_wim,
-                                 const tchar *dest_name,
-                                 const tchar *dest_description,
-                                 int export_flags,
-                                 WIMStruct **additional_swms,
-                                 unsigned num_additional_swms,
-                                 wimlib_progress_func_t progress_func)
+WIMLIBAPI int
+wimlib_export_image(WIMStruct *src_wim,
+                   int src_image,
+                   WIMStruct *dest_wim,
+                   const tchar *dest_name,
+                   const tchar *dest_description,
+                   int export_flags,
+                   WIMStruct **additional_swms,
+                   unsigned num_additional_swms,
+                   wimlib_progress_func_t progress_func)
 {
        int ret;
        struct wim_security_data *sd;
@@ -208,10 +211,9 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
        /* Pre-allocate the new lookup table entries that will be needed.  This
         * way, it's not possible to run out of memory part-way through
         * modifying the lookup table of the destination WIM. */
-       INIT_LIST_HEAD(&lte_list_head);
        for_lookup_table_entry(src_wim->lookup_table, lte_zero_out_refcnt, NULL);
        src_imd = wim_get_current_image_metadata(src_wim);
-
+       INIT_LIST_HEAD(&lte_list_head);
        hlist_for_each_entry(inode, cur_node, &src_imd->inode_list, i_hlist) {
                ret = inode_allocate_needed_ltes(inode,
                                                 src_wim->lookup_table,
@@ -256,7 +258,7 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
        goto out;
 
 out_xml_delete_image:
-       xml_delete_image(&dest_wim->wim_info, dest_wim->hdr.image_count);
+       xml_delete_image(&dest_wim->wim_info, dest_wim->hdr.image_count + 1);
 out_free_ltes:
        {
                struct wim_lookup_table_entry *lte, *tmp;
index 17b1280..0f9252a 100644 (file)
 #  include <alloca.h>
 #endif
 
-#if TCHAR_IS_UTF16LE
-#  include <wchar.h>
-#endif
-
 #ifndef __WIN32__
+
+/* Returns the number of components of @path.  */
+static unsigned
+get_num_path_components(const char *path)
+{
+       unsigned num_components = 0;
+       while (*path) {
+               while (*path == '/')
+                       path++;
+               if (*path)
+                       num_components++;
+               while (*path && *path != '/')
+                       path++;
+       }
+       return num_components;
+}
+
+static const char *
+path_next_part(const char *path)
+{
+       while (*path && *path != '/')
+               path++;
+       while (*path && *path == '/')
+               path++;
+       return path;
+}
+
 static int
 extract_regular_file_linked(struct wim_dentry *dentry,
                            const char *output_path,
@@ -110,8 +133,10 @@ extract_regular_file_linked(struct wim_dentry *dentry,
                p2 = lte->extracted_file;
                while (*p2 == '/')
                        p2++;
-               while (num_output_dir_path_components--)
-                       p2 = path_next_part(p2, NULL);
+               while (num_output_dir_path_components > 0) {
+                       p2 = path_next_part(p2);
+                       num_output_dir_path_components--;
+               }
                strcpy(p, p2);
                if (symlink(buf, output_path) != 0) {
                        ERROR_WITH_ERRNO("Failed to symlink `%s' to `%s'",
@@ -123,7 +148,7 @@ extract_regular_file_linked(struct wim_dentry *dentry,
 }
 
 static int
-symlink_apply_unix_data(const mbchar *link,
+symlink_apply_unix_data(const char *link,
                        const struct wimlib_unix_data *unix_data)
 {
        if (lchown(link, unix_data->uid, unix_data->gid)) {
@@ -887,19 +912,22 @@ out:
        return ret;
 }
 
+static const tchar *filename_forbidden_chars = 
+T(
+#ifdef __WIN32__
+"<>:\"/\\|?*"
+#else
+"/"
+#endif
+);
 
+/* This function checks if it is okay to use a WIM image's name as a directory
+ * name.  */
 static bool
 image_name_ok_as_dir(const tchar *image_name)
 {
-       if (image_name == NULL)
-               return false;
-       if (image_name[0] == T('\0'))
-               return false;
-       if (tstrchr(image_name, T('/')))
-               return false;
-       if (tstrchr(image_name, T('\\')))
-               return false;
-       return true;
+       return image_name && *image_name &&
+               !tstrpbrk(image_name, filename_forbidden_chars);
 }
 
 /* Extracts all images from the WIM to the directory @target, with the images
@@ -921,16 +949,15 @@ extract_all_images(WIMStruct *w,
        if (ret)
                return ret;
 
-       wmemcpy(buf, target, output_path_len);
+       tmemcpy(buf, target, output_path_len);
        buf[output_path_len] = T('/');
        for (image = 1; image <= w->hdr.image_count; image++) {
                image_name = wimlib_get_image_name(w, image);
                if (image_name_ok_as_dir(image_name)) {
                        tstrcpy(buf + output_path_len + 1, image_name);
                } else {
-                       /* Image name is empty, or may not be representable in
-                        * the current locale, or contains path separators.  Use
-                        * the image number instead. */
+                       /* Image name is empty, or contains forbidden
+                        * characters. */
                        tsprintf(buf + output_path_len + 1, T("%d"), image);
                }
                ret = extract_single_image(w, image, buf, extract_flags,
index 479b126..f8fed90 100644 (file)
@@ -156,7 +156,7 @@ print_inode_dentries(const struct wim_inode *inode)
 {
        struct wim_dentry *dentry;
        inode_for_each_dentry(dentry, inode)
-               printf("`%s'\n", dentry->full_path);
+               tprintf(T("`%"TS"'\n"), dentry->full_path);
 }
 #endif
 
@@ -382,17 +382,18 @@ next_dentry_2:
         if (num_true_inodes != 1) {
                inode = container_of(true_inodes.first, struct wim_inode, i_hlist);
 
-               printf("Split nominal inode 0x%"PRIx64" into %zu "
-                      "inodes:\n",
-                      inode->i_ino, num_true_inodes);
-               puts("------------------------------------------------------------------------------");
+               tprintf(T("Split nominal inode 0x%"PRIx64" into %zu "
+                         "inodes:\n"), inode->i_ino, num_true_inodes);
+               tputs(T("----------------------------------------------------"
+                       "--------------------------"));
                size_t i = 1;
                hlist_for_each_entry(inode, cur, &true_inodes, i_hlist) {
-                       printf("[Split inode %zu]\n", i++);
+                       tprintf(T("[Split inode %zu]\n"), i++);
                        print_inode_dentries(inode);
-                       putchar('\n');
+                       tputchar(T('\n'));
                }
-               puts("------------------------------------------------------------------------------");
+               tputs(T("----------------------------------------------------"
+                       "--------------------------"));
         }
        #endif
 
index 8dcfcde..dd274ca 100644 (file)
@@ -259,53 +259,53 @@ wimlib_print_header(const WIMStruct *w)
 {
        const struct wim_header *hdr = &w->hdr;
 
-       printf("Magic Characters            = MSWIM\\000\\000\\000\n");
-       printf("Header Size                 = %u\n", WIM_HEADER_DISK_SIZE);
-       printf("Version                     = 0x%x\n", WIM_VERSION);
+       tprintf(T("Magic Characters            = MSWIM\\000\\000\\000\n"));
+       tprintf(T("Header Size                 = %u\n"), WIM_HEADER_DISK_SIZE);
+       tprintf(T("Version                     = 0x%x\n"), WIM_VERSION);
 
-       printf("Flags                       = 0x%x\n", hdr->flags);
+       tprintf(T("Flags                       = 0x%x\n"), hdr->flags);
        for (size_t i = 0; i < ARRAY_LEN(hdr_flags); i++)
                if (hdr_flags[i].flag & hdr->flags)
-                       printf("    WIM_HDR_FLAG_%s is set\n", hdr_flags[i].name);
+                       tprintf(T("    WIM_HDR_FLAG_%s is set\n"), hdr_flags[i].name);
 
-       printf("Chunk Size                  = %u\n", WIM_CHUNK_SIZE);
-       fputs ("GUID                        = ", stdout);
+       tprintf(T("Chunk Size                  = %u\n"), WIM_CHUNK_SIZE);
+       tfputs (T("GUID                        = "), stdout);
        print_byte_field(hdr->guid, WIM_GID_LEN);
-       putchar('\n');
-       printf("Part Number                 = %hu\n", w->hdr.part_number);
-       printf("Total Parts                 = %hu\n", w->hdr.total_parts);
-       printf("Image Count                 = %u\n", hdr->image_count);
-       printf("Lookup Table Size           = %"PRIu64"\n",
+       tputchar(T('\n'));
+       tprintf(T("Part Number                 = %hu\n"), w->hdr.part_number);
+       tprintf(T("Total Parts                 = %hu\n"), w->hdr.total_parts);
+       tprintf(T("Image Count                 = %u\n"), hdr->image_count);
+       tprintf(T("Lookup Table Size           = %"PRIu64"\n"),
                                (u64)hdr->lookup_table_res_entry.size);
-       printf("Lookup Table Flags          = 0x%hhx\n",
+       tprintf(T("Lookup Table Flags          = 0x%hhx\n"),
                                (u8)hdr->lookup_table_res_entry.flags);
-       printf("Lookup Table Offset         = %"PRIu64"\n",
+       tprintf(T("Lookup Table Offset         = %"PRIu64"\n"),
                                hdr->lookup_table_res_entry.offset);
-       printf("Lookup Table Original_size  = %"PRIu64"\n",
+       tprintf(T("Lookup Table Original_size  = %"PRIu64"\n"),
                                hdr->lookup_table_res_entry.original_size);
-       printf("XML Data Size               = %"PRIu64"\n",
+       tprintf(T("XML Data Size               = %"PRIu64"\n"),
                                (u64)hdr->xml_res_entry.size);
-       printf("XML Data Flags              = 0x%hhx\n",
+       tprintf(T("XML Data Flags              = 0x%hhx\n"),
                                (u8)hdr->xml_res_entry.flags);
-       printf("XML Data Offset             = %"PRIu64"\n",
+       tprintf(T("XML Data Offset             = %"PRIu64"\n"),
                                hdr->xml_res_entry.offset);
-       printf("XML Data Original Size      = %"PRIu64"\n",
+       tprintf(T("XML Data Original Size      = %"PRIu64"\n"),
                                hdr->xml_res_entry.original_size);
-       printf("Boot Metadata Size          = %"PRIu64"\n",
+       tprintf(T("Boot Metadata Size          = %"PRIu64"\n"),
                                (u64)hdr->boot_metadata_res_entry.size);
-       printf("Boot Metadata Flags         = 0x%hhx\n",
+       tprintf(T("Boot Metadata Flags         = 0x%hhx\n"),
                                (u8)hdr->boot_metadata_res_entry.flags);
-       printf("Boot Metadata Offset        = %"PRIu64"\n",
+       tprintf(T("Boot Metadata Offset        = %"PRIu64"\n"),
                                hdr->boot_metadata_res_entry.offset);
-       printf("Boot Metadata Original Size = %"PRIu64"\n",
+       tprintf(T("Boot Metadata Original Size = %"PRIu64"\n"),
                                hdr->boot_metadata_res_entry.original_size);
-       printf("Boot Index                  = %u\n", hdr->boot_idx);
-       printf("Integrity Size              = %"PRIu64"\n",
+       tprintf(T("Boot Index                  = %u\n"), hdr->boot_idx);
+       tprintf(T("Integrity Size              = %"PRIu64"\n"),
                                (u64)hdr->integrity.size);
-       printf("Integrity Flags             = 0x%hhx\n",
+       tprintf(T("Integrity Flags             = 0x%hhx\n"),
                                (u8)hdr->integrity.flags);
-       printf("Integrity Offset            = %"PRIu64"\n",
+       tprintf(T("Integrity Offset            = %"PRIu64"\n"),
                                hdr->integrity.offset);
-       printf("Integrity Original_size     = %"PRIu64"\n",
+       tprintf(T("Integrity Original_size     = %"PRIu64"\n"),
                                hdr->integrity.original_size);
 }
index 6711921..bbabaea 100644 (file)
@@ -45,8 +45,9 @@ struct integrity_table {
        u8  sha1sums[0][20];
 };
 
-static int calculate_chunk_sha1(FILE *fp, size_t this_chunk_size,
-                               off_t offset, u8 sha1_md[])
+static int
+calculate_chunk_sha1(FILE *fp, size_t this_chunk_size,
+                    off_t offset, u8 sha1_md[])
 {
        int ret;
        u8 buf[BUFFER_SIZE];
@@ -109,10 +110,11 @@ static int calculate_chunk_sha1(FILE *fp, size_t this_chunk_size,
  *                                 data.
  *     * WIMLIB_ERR_READ:   Could not read the integrity data from the WIM file.
  */
-static int read_integrity_table(const struct resource_entry *res_entry,
-                               FILE *fp,
-                               u64 num_checked_bytes,
-                               struct integrity_table **table_ret)
+static int
+read_integrity_table(const struct resource_entry *res_entry,
+                    FILE *fp,
+                    u64 num_checked_bytes,
+                    struct integrity_table **table_ret)
 {
        struct integrity_table *table = NULL;
        int ret = 0;
@@ -229,12 +231,13 @@ out:
  *
  * Returns 0 on success; nonzero on failure.
  */
-static int calculate_integrity_table(FILE *fp,
-                                    off_t new_check_end,
-                                    const struct integrity_table *old_table,
-                                    off_t old_check_end,
-                                    wimlib_progress_func_t progress_func,
-                                    struct integrity_table **integrity_table_ret)
+static int
+calculate_integrity_table(FILE *fp,
+                         off_t new_check_end,
+                         const struct integrity_table *old_table,
+                         off_t old_check_end,
+                         wimlib_progress_func_t progress_func,
+                         struct integrity_table **integrity_table_ret)
 {
        int ret = 0;
        size_t chunk_size = INTEGRITY_CHUNK_SIZE;
@@ -360,11 +363,12 @@ static int calculate_integrity_table(FILE *fp,
  *        * WIMLIB_ERR_READ:   Could not read a chunk of data that needed
  *                             to be checked.
  */
-int write_integrity_table(FILE *fp,
-                         struct resource_entry *integrity_res_entry,
-                         off_t new_lookup_table_end,
-                         off_t old_lookup_table_end,
-                         wimlib_progress_func_t progress_func)
+int
+write_integrity_table(FILE *fp,
+                     struct resource_entry *integrity_res_entry,
+                     off_t new_lookup_table_end,
+                     off_t old_lookup_table_end,
+                     wimlib_progress_func_t progress_func)
 {
        struct integrity_table *old_table;
        struct integrity_table *new_table;
@@ -454,10 +458,11 @@ out_free_old_table:
  *     were no inconsistencies.
  *     -1 (WIM_INTEGRITY_NOT_OK) if the WIM failed the integrity check.
  */
-static int verify_integrity(FILE *fp, const tchar *filename,
-                           const struct integrity_table *table,
-                           u64 bytes_to_check,
-                           wimlib_progress_func_t progress_func)
+static int
+verify_integrity(FILE *fp, const tchar *filename,
+                const struct integrity_table *table,
+                u64 bytes_to_check,
+                wimlib_progress_func_t progress_func)
 {
        int ret;
        u64 offset = WIM_HEADER_DISK_SIZE;
@@ -523,7 +528,8 @@ static int verify_integrity(FILE *fp, const tchar *filename,
  *     -2 (WIM_INTEGRITY_NONEXISTENT) if the WIM contains no integrity
  *     information.
  */
-int check_wim_integrity(WIMStruct *w, wimlib_progress_func_t progress_func)
+int
+check_wim_integrity(WIMStruct *w, wimlib_progress_func_t progress_func)
 {
        int ret;
        u64 bytes_to_check;
index d1e5061..bfa0c85 100644 (file)
@@ -33,7 +33,8 @@
 #include <unistd.h>
 #endif
 
-struct wim_lookup_table *new_lookup_table(size_t capacity)
+struct wim_lookup_table *
+new_lookup_table(size_t capacity)
 {
        struct wim_lookup_table *table;
        struct hlist_head *array;
@@ -84,7 +85,9 @@ clone_lookup_table_entry(const struct wim_lookup_table_entry *old)
        memcpy(new, old, sizeof(*old));
        new->extracted_file = NULL;
        switch (new->resource_location) {
+#ifdef __WIN32__
        case RESOURCE_WIN32:
+#endif
        case RESOURCE_IN_STAGING_FILE:
        case RESOURCE_IN_FILE_ON_DISK:
                BUILD_BUG_ON((void*)&old->file_on_disk !=
@@ -132,7 +135,8 @@ out_free:
        return NULL;
 }
 
-void free_lookup_table_entry(struct wim_lookup_table_entry *lte)
+void
+free_lookup_table_entry(struct wim_lookup_table_entry *lte)
 {
        if (lte) {
                switch (lte->resource_location) {
@@ -164,15 +168,16 @@ void free_lookup_table_entry(struct wim_lookup_table_entry *lte)
        }
 }
 
-static int do_free_lookup_table_entry(struct wim_lookup_table_entry *entry,
-                                     void *ignore)
+static int
+do_free_lookup_table_entry(struct wim_lookup_table_entry *entry, void *ignore)
 {
        free_lookup_table_entry(entry);
        return 0;
 }
 
 
-void free_lookup_table(struct wim_lookup_table *table)
+void
+free_lookup_table(struct wim_lookup_table *table)
 {
        DEBUG2("Freeing lookup table");
        if (table) {
@@ -192,8 +197,9 @@ void free_lookup_table(struct wim_lookup_table *table)
  * @table:     A pointer to the lookup table.
  * @lte:       A pointer to the entry to insert.
  */
-void lookup_table_insert(struct wim_lookup_table *table,
-                        struct wim_lookup_table_entry *lte)
+void
+lookup_table_insert(struct wim_lookup_table *table,
+                   struct wim_lookup_table_entry *lte)
 {
        size_t i = lte->hash_short % table->capacity;
        hlist_add_head(&lte->hash_list, &table->array[i]);
@@ -202,7 +208,8 @@ void lookup_table_insert(struct wim_lookup_table *table,
        table->num_entries++;
 }
 
-static void finalize_lte(struct wim_lookup_table_entry *lte)
+static void
+finalize_lte(struct wim_lookup_table_entry *lte)
 {
        #ifdef WITH_FUSE
        if (lte->resource_location == RESOURCE_IN_STAGING_FILE) {
@@ -217,8 +224,9 @@ static void finalize_lte(struct wim_lookup_table_entry *lte)
  * reference count reaches 0, it is unlinked from the lookup table.  If,
  * furthermore, the entry has no opened file descriptors associated with it, the
  * entry is freed.  */
-void lte_decrement_refcnt(struct wim_lookup_table_entry *lte,
-                         struct wim_lookup_table *table)
+void
+lte_decrement_refcnt(struct wim_lookup_table_entry *lte,
+                    struct wim_lookup_table *table)
 {
        wimlib_assert(lte != NULL);
        wimlib_assert(lte->refcnt != 0);
@@ -232,7 +240,8 @@ void lte_decrement_refcnt(struct wim_lookup_table_entry *lte,
 }
 
 #ifdef WITH_FUSE
-void lte_decrement_num_opened_fds(struct wim_lookup_table_entry *lte)
+void
+lte_decrement_num_opened_fds(struct wim_lookup_table_entry *lte)
 {
        if (lte->num_opened_fds != 0)
                if (--lte->num_opened_fds == 0 && lte->refcnt == 0)
@@ -242,9 +251,10 @@ void lte_decrement_num_opened_fds(struct wim_lookup_table_entry *lte)
 
 /* Calls a function on all the entries in the WIM lookup table.  Stop early and
  * return nonzero if any call to the function returns nonzero. */
-int for_lookup_table_entry(struct wim_lookup_table *table,
-                          int (*visitor)(struct wim_lookup_table_entry *, void *),
-                          void *arg)
+int
+for_lookup_table_entry(struct wim_lookup_table *table,
+                      int (*visitor)(struct wim_lookup_table_entry *, void *),
+                      void *arg)
 {
        struct wim_lookup_table_entry *lte;
        struct hlist_node *pos, *tmp;
@@ -266,7 +276,8 @@ int for_lookup_table_entry(struct wim_lookup_table *table,
 /*
  * Reads the lookup table from a WIM file.
  */
-int read_lookup_table(WIMStruct *w)
+int
+read_lookup_table(WIMStruct *w)
 {
        u64 num_entries;
        u8 buf[WIM_LOOKUP_TABLE_ENTRY_DISK_SIZE];
@@ -400,7 +411,8 @@ out:
 /*
  * Writes a lookup table entry to the output file.
  */
-int write_lookup_table_entry(struct wim_lookup_table_entry *lte, void *__out)
+int
+write_lookup_table_entry(struct wim_lookup_table_entry *lte, void *__out)
 {
        FILE *out;
        u8 buf[WIM_LOOKUP_TABLE_ENTRY_DISK_SIZE];
@@ -431,8 +443,9 @@ int write_lookup_table_entry(struct wim_lookup_table_entry *lte, void *__out)
 }
 
 /* Writes the lookup table to the output file. */
-int write_lookup_table(struct wim_lookup_table *table, FILE *out,
-                      struct resource_entry *out_res_entry)
+int
+write_lookup_table(struct wim_lookup_table *table, FILE *out,
+                  struct resource_entry *out_res_entry)
 {
        off_t start_offset, end_offset;
        int ret;
@@ -458,19 +471,22 @@ int write_lookup_table(struct wim_lookup_table *table, FILE *out,
 }
 
 
-int lte_zero_real_refcnt(struct wim_lookup_table_entry *lte, void *ignore)
+int
+lte_zero_real_refcnt(struct wim_lookup_table_entry *lte, void *ignore)
 {
        lte->real_refcnt = 0;
        return 0;
 }
 
-int lte_zero_out_refcnt(struct wim_lookup_table_entry *lte, void *ignore)
+int
+lte_zero_out_refcnt(struct wim_lookup_table_entry *lte, void *ignore)
 {
        lte->out_refcnt = 0;
        return 0;
 }
 
-int lte_free_extracted_file(struct wim_lookup_table_entry *lte, void *ignore)
+int
+lte_free_extracted_file(struct wim_lookup_table_entry *lte, void *ignore)
 {
        if (lte->extracted_file != NULL) {
                FREE(lte->extracted_file);
@@ -479,8 +495,8 @@ int lte_free_extracted_file(struct wim_lookup_table_entry *lte, void *ignore)
        return 0;
 }
 
-void print_lookup_table_entry(const struct wim_lookup_table_entry *lte,
-                             FILE *out)
+void
+print_lookup_table_entry(const struct wim_lookup_table_entry *lte, FILE *out)
 {
        if (!lte) {
                tputc(T('\n'), out);
@@ -520,6 +536,9 @@ void print_lookup_table_entry(const struct wim_lookup_table_entry *lte,
                                 lte->wim->filename);
                }
                break;
+#ifdef __WIN32__
+       case RESOURCE_WIN32:
+#endif
        case RESOURCE_IN_FILE_ON_DISK:
                tfprintf(out, T("File on Disk      = `%"TS"'\n"),
                         lte->file_on_disk);
@@ -534,8 +553,8 @@ void print_lookup_table_entry(const struct wim_lookup_table_entry *lte,
        tputc(T('\n'), out);
 }
 
-static int do_print_lookup_table_entry(struct wim_lookup_table_entry *lte,
-                                      void *fp)
+static int
+do_print_lookup_table_entry(struct wim_lookup_table_entry *lte, void *fp)
 {
        print_lookup_table_entry(lte, (FILE*)fp);
        return 0;
@@ -544,7 +563,8 @@ static int do_print_lookup_table_entry(struct wim_lookup_table_entry *lte,
 /*
  * Prints the lookup table of a WIM file.
  */
-WIMLIBAPI void wimlib_print_lookup_table(WIMStruct *w)
+WIMLIBAPI void
+wimlib_print_lookup_table(WIMStruct *w)
 {
        for_lookup_table_entry(w->lookup_table,
                               do_print_lookup_table_entry,
@@ -650,7 +670,8 @@ out:
  * This function always succeeds; unresolved lookup table entries are given a
  * NULL pointer.
  */
-void inode_resolve_ltes(struct wim_inode *inode, struct wim_lookup_table *table)
+void
+inode_resolve_ltes(struct wim_inode *inode, struct wim_lookup_table *table)
 {
 
        if (!inode->i_resolved) {
@@ -669,7 +690,8 @@ void inode_resolve_ltes(struct wim_inode *inode, struct wim_lookup_table *table)
        }
 }
 
-void inode_unresolve_ltes(struct wim_inode *inode)
+void
+inode_unresolve_ltes(struct wim_inode *inode)
 {
        if (inode->i_resolved) {
                if (inode->i_lte)
@@ -693,7 +715,7 @@ void inode_unresolve_ltes(struct wim_inode *inode)
  * stream_idx = 0 means the default un-named file stream, and stream_idx >= 1
  * corresponds to an alternate data stream.
  *
- * This works for both resolved and un-resolved dentries.
+ * This works for both resolved and un-resolved inodes.
  */
 struct wim_lookup_table_entry *
 inode_stream_lte(const struct wim_inode *inode, unsigned stream_idx,
@@ -732,14 +754,15 @@ inode_unnamed_lte(const struct wim_inode *inode,
                return inode_unnamed_lte_unresolved(inode, table);
 }
 
-static int lte_add_stream_size(struct wim_lookup_table_entry *lte,
-                              void *total_bytes_p)
+static int
+lte_add_stream_size(struct wim_lookup_table_entry *lte, void *total_bytes_p)
 {
        *(u64*)total_bytes_p += lte->resource_entry.size;
        return 0;
 }
 
-u64 lookup_table_total_stream_size(struct wim_lookup_table *table)
+u64
+lookup_table_total_stream_size(struct wim_lookup_table *table)
 {
        u64 total_size = 0;
        for_lookup_table_entry(table, lte_add_stream_size, &total_size);
index 1759df4..78de61a 100644 (file)
@@ -163,7 +163,7 @@ struct wim_lookup_table_entry {
                WIMStruct *wim;
                tchar *file_on_disk;
                tchar *staging_file_name;
-               u8 *attached_buffer;
+               void *attached_buffer;
        #ifdef WITH_NTFS_3G
                struct ntfs_location *ntfs_loc;
        #endif
index 13a6a96..d54641d 100644 (file)
@@ -42,7 +42,8 @@
  *
  * @return:    Zero on success, nonzero on failure.
  */
-int read_metadata_resource(WIMStruct *w, struct wim_image_metadata *imd)
+int
+read_metadata_resource(WIMStruct *w, struct wim_image_metadata *imd)
 {
        u8 *buf;
        u32 dentry_offset;
@@ -185,7 +186,8 @@ out_free_buf:
        return ret;
 }
 
-static void recalculate_security_data_length(struct wim_security_data *sd)
+static void
+recalculate_security_data_length(struct wim_security_data *sd)
 {
        u32 total_length = sizeof(u64) * sd->num_entries + 2 * sizeof(u32);
        for (u32 i = 0; i < sd->num_entries; i++)
@@ -196,10 +198,11 @@ static void recalculate_security_data_length(struct wim_security_data *sd)
 /* Like write_wim_resource(), but the resource is specified by a buffer of
  * uncompressed data rather a lookup table entry; also writes the SHA1 hash of
  * the buffer to @hash.  */
-static int write_wim_resource_from_buffer(const u8 *buf, u64 buf_size,
-                                         FILE *out_fp, int out_ctype,
-                                         struct resource_entry *out_res_entry,
-                                         u8 hash[SHA1_HASH_SIZE])
+static int
+write_wim_resource_from_buffer(const u8 *buf, u64 buf_size,
+                              FILE *out_fp, int out_ctype,
+                              struct resource_entry *out_res_entry,
+                              u8 hash[SHA1_HASH_SIZE])
 {
        /* Set up a temporary lookup table entry to provide to
         * write_wim_resource(). */
@@ -210,7 +213,7 @@ static int write_wim_resource_from_buffer(const u8 *buf, u64 buf_size,
        lte.resource_entry.size          = buf_size;
        lte.resource_entry.offset        = 0;
        lte.resource_location            = RESOURCE_IN_ATTACHED_BUFFER;
-       lte.attached_buffer              = (u8*)buf;
+       lte.attached_buffer              = buf;
 
        zero_out_hash(lte.hash);
        ret = write_wim_resource(&lte, out_fp, out_ctype, out_res_entry, 0);
@@ -221,7 +224,8 @@ static int write_wim_resource_from_buffer(const u8 *buf, u64 buf_size,
 }
 
 /* Write the metadata resource for the current WIM image. */
-int write_metadata_resource(WIMStruct *w)
+int
+write_metadata_resource(WIMStruct *w)
 {
        u8 *buf;
        u8 *p;
index 04ecbfe..024c82b 100644 (file)
@@ -1805,10 +1805,10 @@ wimfs_listxattr(const char *path, char *list, size_t size)
                size_t stream_name_mbs_nbytes;
                int ret;
 
-               ret = utf16le_to_mbs(inode->i_ads_entries[i].stream_name,
-                                    inode->i_ads_entries[i].stream_name_nbytes,
-                                    &stream_name_mbs,
-                                    &stream_name_mbs_nbytes);
+               ret = utf16le_to_tstr(inode->i_ads_entries[i].stream_name,
+                                     inode->i_ads_entries[i].stream_name_nbytes,
+                                     &stream_name_mbs,
+                                     &stream_name_mbs_nbytes);
                if (ret)
                        return -errno;
 
@@ -2014,10 +2014,10 @@ dentry_fuse_fill(struct wim_dentry *dentry, void *arg)
        size_t file_name_mbs_nbytes;
        int ret;
 
-       ret = utf16le_to_mbs(dentry->file_name,
-                            dentry->file_name_nbytes,
-                            &file_name_mbs,
-                            &file_name_mbs_nbytes);
+       ret = utf16le_to_tstr(dentry->file_name,
+                             dentry->file_name_nbytes,
+                             &file_name_mbs,
+                             &file_name_mbs_nbytes);
        if (ret)
                return -errno;
 
index 4d2292b..245e0b5 100644 (file)
@@ -176,10 +176,10 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct wim_dentry *dent
 static ntfs_inode *
 dentry_open_parent_ni(const struct wim_dentry *dentry, ntfs_volume *vol)
 {
-       mbchar *p;
-       const mbchar *dir_name;
+       char *p;
+       const char *dir_name;
        ntfs_inode *dir_ni;
-       mbchar orig;
+       char orig;
 
        p = dentry->full_path + dentry->full_path_nbytes;
        do {
@@ -455,12 +455,12 @@ do_apply_dentry_ntfs(struct wim_dentry *dentry, ntfs_inode *dir_ni,
 
        /* Set DOS (short) name if given */
        if (dentry_has_short_name(dentry)) {
-               mbchar *short_name_mbs;
+               char *short_name_mbs;
                size_t short_name_mbs_nbytes;
-               ret = utf16le_to_mbs(dentry->short_name,
-                                    dentry->short_name_nbytes,
-                                    &short_name_mbs,
-                                    &short_name_mbs_nbytes);
+               ret = utf16le_to_tstr(dentry->short_name,
+                                     dentry->short_name_nbytes,
+                                     &short_name_mbs,
+                                     &short_name_mbs_nbytes);
                if (ret != 0)
                        goto out_close_dir_ni;
 
@@ -571,7 +571,7 @@ apply_dentry_ntfs(struct wim_dentry *dentry, void *arg)
         * file.  So, this implies that the correct ordering of function calls
         * to extract a NTFS file are:
         *
-               if (file has a DOS name) {
+        *      if (file has a DOS name) {
         *              - Call ntfs_create() to create long name associated with
         *              the DOS name (this initially creates a POSIX name)
         *              - Call ntfs_set_ntfs_dos_name() to associate a DOS name
index 31c8e56..dfc153f 100644 (file)
@@ -441,8 +441,8 @@ wim_ntfs_capture_filldir(void *dirent, const ntfschar *name,
                if (ret != 0 || name_type == FILE_NAME_DOS)
                        goto out;
        }
-       ret = utf16le_to_mbs(name, name_nbytes,
-                            &mbs_name, &mbs_name_nbytes);
+       ret = utf16le_to_tstr(name, name_nbytes,
+                             &mbs_name, &mbs_name_nbytes);
        if (ret)
                goto out;
 
index 1ab9124..d3380ca 100644 (file)
@@ -80,7 +80,7 @@ read_compressed_resource(FILE *fp, u64 resource_compressed_size,
               resource_compressed_size,
               resource_uncompressed_size,
               resource_offset);
-       DEBUG2("resource_ctype = %s, len = %"PRIu64", offset = %"PRIu64"",
+       DEBUG2("resource_ctype = %"TS", len = %"PRIu64", offset = %"PRIu64"",
               wimlib_get_compression_type_string(resource_ctype), len, offset);
        /* Trivial case */
        if (len == 0)
index 88e6c84..7efc542 100644 (file)
 #include "buffer_io.h"
 #include "security.h"
 
-
-#define        SECURITY_DESCRIPTOR_REVISION    1
-#define        SECURITY_DESCRIPTOR_REVISION1   1
-
-/* inherit AceFlags */
-#define        OBJECT_INHERIT_ACE              0x01
-#define        CONTAINER_INHERIT_ACE           0x02
-#define        NO_PROPAGATE_INHERIT_ACE        0x04
-#define        INHERIT_ONLY_ACE                0x08
-#define        INHERITED_ACE                   0x10
-#define        VALID_INHERIT_FLAGS             0x1F
-
-#define SE_OWNER_DEFAULTED             0x00000001
-#define SE_GROUP_DEFAULTED             0x00000002
-#define SE_DACL_PRESENT                        0x00000004
-#define SE_DACL_DEFAULTED              0x00000008
-#define SE_SACL_PRESENT                        0x00000010
-#define SE_SACL_DEFAULTED              0x00000020
-#define SE_DACL_AUTO_INHERIT_REQ       0x00000100
-#define SE_SACL_AUTO_INHERIT_REQ       0x00000200
-#define SE_DACL_AUTO_INHERITED         0x00000400
-#define SE_SACL_AUTO_INHERITED         0x00000800
-#define SE_DACL_PROTECTED              0x00001000
-#define SE_SACL_PROTECTED              0x00002000
-#define SE_RM_CONTROL_VALID            0x00004000
-#define SE_SELF_RELATIVE               0x00008000
-
-/* Flags in access control entries */
-#define DELETE                     0x00010000
-#define READ_CONTROL               0x00020000
-#define WRITE_DAC                  0x00040000
-#define WRITE_OWNER                0x00080000
-#define SYNCHRONIZE                0x00100000
-#define STANDARD_RIGHTS_REQUIRED   0x000f0000
-
-#define STANDARD_RIGHTS_READ       READ_CONTROL
-#define STANDARD_RIGHTS_WRITE      READ_CONTROL
-#define STANDARD_RIGHTS_EXECUTE    READ_CONTROL
-
-#define STANDARD_RIGHTS_ALL        0x001f0000
-
-#define SPECIFIC_RIGHTS_ALL        0x0000ffff
-
-#define GENERIC_READ               0x80000000
-#define GENERIC_WRITE              0x40000000
-#define GENERIC_EXECUTE            0x20000000
-#define GENERIC_ALL                0x10000000
-
-#define MAXIMUM_ALLOWED            0x02000000
-#define ACCESS_SYSTEM_SECURITY     0x01000000
-
-#define EVENT_QUERY_STATE          0x0001
-#define EVENT_MODIFY_STATE         0x0002
-#define EVENT_ALL_ACCESS           (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3)
-
-#define SEMAPHORE_MODIFY_STATE     0x0002
-#define SEMAPHORE_ALL_ACCESS       (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3)
-
-#define MUTEX_MODIFY_STATE         0x0001
-#define MUTEX_ALL_ACCESS           (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x1)
-
-#define JOB_OBJECT_ASSIGN_PROCESS           0x0001
-#define JOB_OBJECT_SET_ATTRIBUTES           0x0002
-#define JOB_OBJECT_QUERY                    0x0004
-#define JOB_OBJECT_TERMINATE                0x0008
-#define JOB_OBJECT_SET_SECURITY_ATTRIBUTES  0x0010
-#define JOB_OBJECT_ALL_ACCESS               (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x1f)
-
-#define TIMER_QUERY_STATE          0x0001
-#define TIMER_MODIFY_STATE         0x0002
-#define TIMER_ALL_ACCESS           (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3)
-
-#define PROCESS_TERMINATE          0x0001
-#define PROCESS_CREATE_THREAD      0x0002
-#define PROCESS_VM_OPERATION       0x0008
-#define PROCESS_VM_READ            0x0010
-#define PROCESS_VM_WRITE           0x0020
-#define PROCESS_DUP_HANDLE         0x0040
-#define PROCESS_CREATE_PROCESS     0x0080
-#define PROCESS_SET_QUOTA          0x0100
-#define PROCESS_SET_INFORMATION    0x0200
-#define PROCESS_QUERY_INFORMATION  0x0400
-#define PROCESS_SUSPEND_RESUME     0x0800
-#define PROCESS_QUERY_LIMITED_INFORMATION 0x1000
-#define PROCESS_ALL_ACCESS         (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0xfff)
-
-#define THREAD_TERMINATE           0x0001
-#define THREAD_SUSPEND_RESUME      0x0002
-#define THREAD_GET_CONTEXT         0x0008
-#define THREAD_SET_CONTEXT         0x0010
-#define THREAD_SET_INFORMATION     0x0020
-#define THREAD_QUERY_INFORMATION   0x0040
-#define THREAD_SET_THREAD_TOKEN    0x0080
-#define THREAD_IMPERSONATE         0x0100
-#define THREAD_DIRECT_IMPERSONATION 0x0200
-#define THREAD_ALL_ACCESS          (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3ff)
-
-#define THREAD_BASE_PRIORITY_LOWRT  15
-#define THREAD_BASE_PRIORITY_MAX    2
-#define THREAD_BASE_PRIORITY_MIN   -2
-#define THREAD_BASE_PRIORITY_IDLE  -15
-
-/* predefined authority values for SID's (security identifiers) */
-enum sid_authority_value {
-       SECURITY_NULL_SID_AUTHORITY    = 0,
-       SECURITY_WORLD_SID_AUTHORITY   = 1,
-       SECURITY_LOCAL_SID_AUTHORITY   = 2,
-       SECURITY_CREATOR_SID_AUTHORITY = 3,
-       SECURITY_NON_UNIQUE_AUTHORITY  = 4,
-       SECURITY_NT_AUTHORITY          = 5,
-};
-
-/* local administrators group */
-#define SECURITY_BUILTIN_DOMAIN_RID 32
-#define DOMAIN_ALIAS_RID_ADMINS     544
-
-/* See ACEHeader. */
-enum ace_type {
-       ACCESS_ALLOWED_ACE_TYPE = 0,
-       ACCESS_DENIED_ACE_TYPE  = 1,
-       SYSTEM_AUDIT_ACE_TYPE   = 2,
-};
-
 /* At the start of each type of access control entry.  */
 typedef struct {
        /* enum ace_type, specifies what type of ACE this is.  */
@@ -463,74 +340,76 @@ write_security_data(const struct wim_security_data *sd, u8 *p)
 }
 
 static void
-print_acl(const u8 *p, const char *type)
+print_acl(const void *p, const tchar *type)
 {
-       const ACL *acl = (const ACL*)p;
+       const ACL *acl = p;
        u8 revision = acl->revision;
        u16 acl_size = le16_to_cpu(acl->acl_size);
        u16 ace_count = le16_to_cpu(acl->ace_count);
-       printf("    [%s ACL]\n", type);
-       printf("    Revision = %u\n", revision);
-       printf("    ACL Size = %u\n", acl_size);
-       printf("    ACE Count = %u\n", ace_count);
+       tprintf(T("    [%"TS" ACL]\n"), type);
+       tprintf(T("    Revision = %u\n"), revision);
+       tprintf(T("    ACL Size = %u\n"), acl_size);
+       tprintf(T("    ACE Count = %u\n"), ace_count);
 
        p += sizeof(ACL);
        for (u16 i = 0; i < ace_count; i++) {
-               const ACEHeader *hdr = (const ACEHeader*)p;
-               printf("        [ACE]\n");
-               printf("        ACE type  = %d\n", hdr->type);
-               printf("        ACE flags = 0x%x\n", hdr->flags);
-               printf("        ACE size  = %u\n", hdr->size);
+               const ACEHeader *hdr = p;
+               tprintf(T("        [ACE]\n"));
+               tprintf(T("        ACE type  = %d\n"), hdr->type);
+               tprintf(T("        ACE flags = 0x%x\n"), hdr->flags);
+               tprintf(T("        ACE size  = %u\n"), hdr->size);
                const AccessAllowedACE *aaa = (const AccessAllowedACE*)hdr;
-               printf("        ACE mask = %x\n", le32_to_cpu(aaa->mask));
-               printf("        SID start = %u\n", le32_to_cpu(aaa->sid_start));
+               tprintf(T("        ACE mask = %x\n"), le32_to_cpu(aaa->mask));
+               tprintf(T("        SID start = %u\n"), le32_to_cpu(aaa->sid_start));
                p += hdr->size;
        }
-       putchar('\n');
+       tputchar(T('\n'));
 }
 
 static void
-print_sid(const u8 *p, const char *type)
+print_sid(const void *p, const tchar *type)
 {
-       const SID *sid = (const SID*)p;
-       printf("    [%s SID]\n", type);
-       printf("    Revision = %u\n", sid->revision);
-       printf("    Subauthority count = %u\n", sid->sub_authority_count);
-       printf("    Identifier authority = ");
+       const SID *sid = p;
+       tprintf(T("    [%"TS" SID]\n"), type);
+       tprintf(T("    Revision = %u\n"), sid->revision);
+       tprintf(T("    Subauthority count = %u\n"), sid->sub_authority_count);
+       tprintf(T("    Identifier authority = "));
        print_byte_field(sid->identifier_authority,
                         sizeof(sid->identifier_authority));
-       putchar('\n');
-       for (u8 i = 0; i < sid->sub_authority_count; i++)
-               printf("    Subauthority %u = %u\n",
-                      i, le32_to_cpu(sid->sub_authority[i]));
-       putchar('\n');
+       tputchar(T('\n'));
+       for (u8 i = 0; i < sid->sub_authority_count; i++) {
+               tprintf(T("    Subauthority %u = %u\n"),
+                       i, le32_to_cpu(sid->sub_authority[i]));
+       }
+       tputchar(T('\n'));
 }
 
 static void
-print_security_descriptor(const u8 *p, u64 size)
+print_security_descriptor(const void *p, u64 size)
 {
-       const SecurityDescriptor *sd = (const SecurityDescriptor*)p;
+       const SecurityDescriptor *sd = p;
+
        u8 revision      = sd->revision;
        u16 control      = le16_to_cpu(sd->security_descriptor_control);
        u32 owner_offset = le32_to_cpu(sd->owner_offset);
        u32 group_offset = le32_to_cpu(sd->group_offset);
        u32 sacl_offset  = le32_to_cpu(sd->sacl_offset);
        u32 dacl_offset  = le32_to_cpu(sd->dacl_offset);
-       printf("Revision = %u\n", revision);
-       printf("Security Descriptor Control = %#x\n", control);
-       printf("Owner offset = %u\n", owner_offset);
-       printf("Group offset = %u\n", group_offset);
-       printf("System ACL offset = %u\n", sacl_offset);
-       printf("Discretionary ACL offset = %u\n", dacl_offset);
+       tprintf(T("Revision = %u\n"), revision);
+       tprintf(T("Security Descriptor Control = %#x\n"), control);
+       tprintf(T("Owner offset = %u\n"), owner_offset);
+       tprintf(T("Group offset = %u\n"), group_offset);
+       tprintf(T("System ACL offset = %u\n"), sacl_offset);
+       tprintf(T("Discretionary ACL offset = %u\n"), dacl_offset);
 
        if (sd->owner_offset != 0)
-               print_sid(p + owner_offset, "Owner");
+               print_sid(p + owner_offset, T("Owner"));
        if (sd->group_offset != 0)
-               print_sid(p + group_offset, "Group");
+               print_sid(p + group_offset, T("Group"));
        if (sd->sacl_offset != 0)
-               print_acl(p + sacl_offset, "System");
+               print_acl(p + sacl_offset, T("System"));
        if (sd->dacl_offset != 0)
-               print_acl(p + dacl_offset, "Discretionary");
+               print_acl(p + dacl_offset, T("Discretionary"));
 }
 
 /*
@@ -541,17 +420,17 @@ print_security_data(const struct wim_security_data *sd)
 {
        wimlib_assert(sd != NULL);
 
-       puts("[SECURITY DATA]");
-       printf("Length            = %"PRIu32" bytes\n", sd->total_length);
-       printf("Number of Entries = %"PRIu32"\n", sd->num_entries);
+       tputs(T("[SECURITY DATA]"));
+       tprintf(T("Length            = %"PRIu32" bytes\n"), sd->total_length);
+       tprintf(T("Number of Entries = %"PRIu32"\n"), sd->num_entries);
 
        for (u32 i = 0; i < sd->num_entries; i++) {
-               printf("[SecurityDescriptor %"PRIu32", length = %"PRIu64"]\n",
-                      i, sd->sizes[i]);
+               tprintf(T("[SecurityDescriptor %"PRIu32", length = %"PRIu64"]\n"),
+                       i, sd->sizes[i]);
                print_security_descriptor(sd->descriptors[i], sd->sizes[i]);
-               putchar('\n');
+               tputchar(T('\n'));
        }
-       putchar('\n');
+       tputchar(T('\n'));
 }
 
 void
index b787942..6fb18c4 100644 (file)
@@ -66,7 +66,8 @@ sha1_update(SHA_CTX *context, const void *data, size_t len)
 {
        sha1_update_intel((int*)&context->state, data, len / 64);
        size_t j = (context->count[0] >> 3) & 63;
-       if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
+       if ((context->count[0] += len << 3) < (len << 3))
+               context->count[1]++;
        context->count[1] += (len >> 29);
 }
 #include <stdlib.h>
index 385dc2a..71b32ce 100644 (file)
 #include "xml.h"
 #include "buffer_io.h"
 
-#if TCHAR_IS_UTF16LE
-#  include <wchar.h>
-#endif
-
 struct split_args {
        WIMStruct *w;
        tchar *swm_base_name;
index 1e0109f..70301b3 100644 (file)
@@ -48,7 +48,7 @@ static ssize_t
 get_symlink_name(const void *resource, size_t resource_len, char *buf,
                 size_t buf_len, u32 reparse_tag)
 {
-       const u8 *p = resource;
+       const void *p = resource;
        u16 substitute_name_offset;
        u16 substitute_name_len;
        u16 print_name_offset;
@@ -82,17 +82,12 @@ get_symlink_name(const void *resource, size_t resource_len, char *buf,
        if (header_size + substitute_name_offset + substitute_name_len > resource_len)
                return -EIO;
 
-       ret = utf16le_to_mbs((const utf16lechar*)(p + substitute_name_offset),
-                           substitute_name_len,
-                           &link_target, &link_target_len);
+       ret = utf16le_to_tstr((const utf16lechar*)(p + substitute_name_offset),
+                             substitute_name_len,
+                             &link_target, &link_target_len);
        if (ret)
                return -errno;
 
-       wimlib_assert(ret == 0);
-
-       if (!link_target)
-               return -EIO;
-
        if (link_target_len + 1 > buf_len) {
                ret = -ENAMETOOLONG;
                goto out;
@@ -150,7 +145,7 @@ make_symlink_reparse_data_buf(const char *symlink_target,
        size_t len = 12 + name_utf16le_nbytes * 2;
        void *buf = MALLOC(len);
        if (buf) {
-               u8 *p = buf;
+               void *p = buf;
                p = put_u16(p, name_utf16le_nbytes); /* Substitute name offset */
                p = put_u16(p, name_utf16le_nbytes); /* Substitute name length */
                p = put_u16(p, 0); /* Print name offset */
@@ -269,4 +264,4 @@ out_free_symlink_buf:
        return ret;
 }
 
-#endif /* !defined(__WIN32__) && !defined(WITH_FUSE) */
+#endif /* !defined(__WIN32__) */
index 1e26a6f..07d5fc6 100644 (file)
@@ -43,7 +43,7 @@
 
 #include <unistd.h> /* for getpid() */
 
-size_t
+static size_t
 utf16le_strlen(const utf16lechar *s)
 {
        const utf16lechar *p = s;
@@ -52,48 +52,41 @@ utf16le_strlen(const utf16lechar *s)
        return (p - s) * sizeof(utf16lechar);
 }
 
-/* Handle %W for UTF16-LE printing and %U for UTF-8 printing.
+#ifdef __WIN32__
+#  define wimlib_vfprintf vfwprintf
+#else
+/* Handle %W for UTF16-LE printing.
  *
  * TODO: this is not yet done properly--- it's assumed that if the format string
- * contains %W and/or %U, then it contains no other format specifiers.
+ * contains %W, then it contains no other format specifiers.
  */
 static int
 wimlib_vfprintf(FILE *fp, const tchar *format, va_list va)
 {
        const tchar *p;
+       int n;
 
        for (p = format; *p; p++)
-               if (*p == '%' && (*(p + 1) == T('W') || *(p + 1) == T('U')))
+               if (*p == T('%') && *(p + 1) == T('W'))
                        goto special;
        return tvfprintf(fp, format, va);
 special:
-       /* XXX */
-       wimlib_assert(0);
-#if 0
-       ;
-       int n = 0;
+       n = 0;
        for (p = format; *p; p++) {
-               if (*p == T('%') && (*(p + 1) == T('W') || *(p + 1) == T('U'))) {
+               if (*p == T('%') && (*(p + 1) == T('W'))) {
                        int ret;
-                       tchar *mbs;
-                       size_t mbs_nbytes;
-
-                       if (*(p + 1) == T('W')) {
-                               utf16lechar *ucs = va_arg(va, utf16lechar*);
-                               size_t ucs_nbytes = utf16le_strlen(ucs);
-                               ret = utf16le_to_mbs(ucs, ucs_nbytes,
-                                                    &mbs, &mbs_nbytes);
-                       } else {
-                               utf8char *ucs = va_arg(va, utf8char*);
-                               size_t ucs_nbytes = strlen(ucs);
-                               ret = utf8_to_mbs(ucs, ucs_nbytes,
-                                                 &mbs, &mbs_nbytes);
-                       }
+                       tchar *tstr;
+                       size_t tstr_nbytes;
+                       utf16lechar *ucs = va_arg(va, utf16lechar*);
+                       size_t ucs_nbytes = utf16le_strlen(ucs);
+
+                       ret = utf16le_to_tstr(ucs, ucs_nbytes,
+                                             &tstr, &tstr_nbytes);
                        if (ret) {
                                ret = tfprintf(fp, T("??????"));
                        } else {
-                               ret = tfprintf(fp, T("%s"), mbs);
-                               FREE(mbs);
+                               ret = tfprintf(fp, T("%"TS), tstr);
+                               FREE(tstr);
                        }
                        if (ret < 0)
                                return -1;
@@ -101,13 +94,12 @@ special:
                                n += ret;
                        p++;
                } else {
-                       if (putc(*p, fp) == EOF)
+                       if (tputc(*p, fp) == EOF)
                                return -1;
                        n++;
                }
        }
        return n;
-#endif
 }
 
 int
@@ -133,6 +125,7 @@ wimlib_fprintf(FILE *fp, const tchar *format, ...)
        va_end(va);
        return ret;
 }
+#endif
 
 #if defined(ENABLE_ERROR_MESSAGES) || defined(ENABLE_DEBUG)
 static void
@@ -486,21 +479,6 @@ randomize_byte_array(u8 *p, size_t n)
                *p++ = rand();
 }
 
-/* Takes in a path of length @len in @buf, and transforms it into a string for
- * the path of its parent directory. */
-void
-to_parent_name(tchar *buf, size_t len)
-{
-       ssize_t i = (ssize_t)len - 1;
-       while (i >= 0 && buf[i] == T('/'))
-               i--;
-       while (i >= 0 && buf[i] != T('/'))
-               i--;
-       while (i >= 0 && buf[i] == T('/'))
-               i--;
-       buf[i + 1] = T('\0');
-}
-
 const tchar *
 path_basename_with_len(const tchar *path, size_t len)
 {
@@ -544,69 +522,6 @@ path_stream_name(const tchar *path)
                return stream_name + 1;
 }
 
-/*
- * Splits a file path into the part before the first '/', or the entire name if
- * there is no '/', and the part after the first sequence of '/' characters.
- *
- * @path:              The file path to split.
- * @first_part_len_ret: A pointer to a `size_t' into which the length of the
- *                             first part of the path will be returned.
- * @return:            A pointer to the next part of the path, after the first
- *                             sequence of '/', or a pointer to the terminating
- *                             null byte in the case of a path without any '/'.
- */
-const tchar *
-path_next_part(const tchar *path, size_t *first_part_len_ret)
-{
-       size_t i;
-       const tchar *next_part;
-
-       i = 0;
-       while (path[i] != T('/') && path[i] != T('\0'))
-               i++;
-       if (first_part_len_ret)
-               *first_part_len_ret = i;
-       next_part = &path[i];
-       while (*next_part == T('/'))
-               next_part++;
-       return next_part;
-}
-
-/* Returns the number of components of @path.  */
-int
-get_num_path_components(const char *path)
-{
-       int num_components = 0;
-       while (*path) {
-               while (*path == '/')
-                       path++;
-               if (*path)
-                       num_components++;
-               while (*path && *path != '/')
-                       path++;
-       }
-       return num_components;
-}
-
-
-/*
- * Prints a string.  Printable characters are printed as-is, while unprintable
- * characters are printed as their octal escape codes.
- */
-void
-print_string(const void *string, size_t len)
-{
-       const u8 *p = string;
-
-       while (len--) {
-               if (isprint(*p))
-                       putchar(*p);
-               else
-                       printf("\\%03hho", *p);
-               p++;
-       }
-}
-
 u64
 get_wim_timestamp()
 {
@@ -623,3 +538,15 @@ wim_timestamp_to_str(u64 timestamp, tchar *buf, size_t len)
        gmtime_r(&t, &tm);
        tstrftime(buf, len, T("%a %b %d %H:%M:%S %Y UTC"), &tm);
 }
+
+void
+zap_backslashes(tchar *s)
+{
+       if (s) {
+               while (*s != T('\0')) {
+                       if (*s == T('\\'))
+                               *s = T('/');
+                       s++;
+               }
+       }
+}
index 07e12fe..4b75eda 100644 (file)
@@ -1,12 +1,14 @@
 #ifndef _WIMLIB_UTIL_H
 #define _WIMLIB_UTIL_H
 
+#include "config.h"
+#include "wimlib_tchar.h"
+
 #include <stdio.h>
 #include <stdbool.h>
 #include <stddef.h>
 #include <inttypes.h>
 #include <sys/types.h>
-#include "config.h"
 
 #ifdef __GNUC__
 #      if defined(__CYGWIN__) || defined(__WIN32__)
@@ -16,9 +18,8 @@
 #      endif
 #      define ALWAYS_INLINE inline __attribute__((always_inline))
 #      define PACKED __attribute__((packed))
-//#    define FORMAT(type, format_str, args_start) \
-                       //__attribute__((format(type, format_str, args_start)))
-#      define FORMAT(type, format_str, args_start)
+#      define FORMAT(type, format_str, args_start) \
+                       /*__attribute__((format(type, format_str, args_start))) */
 #      if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)
 #              define COLD     __attribute__((cold))
 #      else
@@ -54,101 +55,8 @@ typedef uint64_t u64;
 /* A pointer to 'utf16lechar' indicates a UTF-16LE encoded string */
 typedef u16 utf16lechar;
 
-typedef u8 utf8char;
-
-#ifdef __WIN32__
-/* For Windows builds, the "tchar" type will be 2 bytes and will be equivalent
- * to "wchar_t" and "utf16lechar".  All indicate one code unit of a UTF16-LE
- * string. */
-typedef wchar_t tchar;
-#  define TCHAR_IS_UTF16LE 1
-#  define T(text) L##text /* Make a string literal into a wide string */
-#  define TS "ls" /* Format a string of "tchar" */
-#  define WS "ls" /* Format a UTF-16LE string (same as above) */
-
-/* For Windows builds, the following definitions replace the "tchar" functions
- * with the "wide-character" functions. */
-#  define tmemchr  wmemchr
-#  define tmemcpy  wmemcpy
-#  define tstrcpy  wcscpy
-#  define tprintf  wprintf
-#  define tsprintf swprintf
-#  define tfprintf fwprintf
-#  define tvfprintf vfwprintf
-#  define istalpha iswalpha
-#  define tstrcmp  wcscmp
-#  define tstrchr  wcschr
-#  define tstrrchr wcsrchr
-#  define tstrlen  wcslen
-#  define tmemcmp  wmemcmp
-#  define tstrftime wcsftime
-#  define tputchar putwchar
-#  define tputc    putwc
-#  define tputs    _putws
-#  define tfputs   fputws
-#  define tfopen   _wfopen
-#  define tstat    _wstati64
-#  define tstrtol  wcstol
-#  define tunlink  _wunlink
-/* The following "tchar" functions do not have exact wide-character equivalents
- * on Windows so require parameter rearrangement or redirection to a replacement
- * function defined ourselves. */
-#  define TSTRDUP  WSTRDUP
-#  define tmkdir(path, mode) _wmkdir(path)
-#  define tstrerror_r(errnum, buf, bufsize) _wcserror_s(buf, bufsize, errnum)
-#  define trename  win32_rename_replacement
-#  define ttruncate win32_truncate_replacement
-#else
-/* For non-Windows builds, the "tchar" type will be one byte and will specify a
- * string in the locale-dependent multibyte encoding.  However, only UTF-8 is
- * well supported in this library. */
-typedef char tchar;
-#  define TCHAR_IS_UTF16LE 0
-#  define T(text) text /* In this case, strings of "tchar" are simply strings of
-                         char */
-#  define TS "s"       /* Similarly, a string of "tchar" is printed just as a
-                         normal string. */
-#  define WS "W"       /* UTF-16LE strings must be printed using a special
-                         extension implemented by wimlib itself.  Note that
-                         "ls" will not work here because a string of wide
-                         characters on non-Windows systems is typically not
-                         UTF-16LE. */
-/* For non-Windows builds, replace the "tchar" functions with the regular old
- * string functions. */
-#  define tmemchr  memchr
-#  define tmemcpy  memcpy
-#  define tstrcpy  strcpy
-#  define tprintf  printf
-#  define tsprintf sprintf
-#  define tfprintf fprintf
-#  define tvfprintf vfprintf
-#  define istalpha isalpha
-#  define tstrcmp  strcmp
-#  define tstrchr  strchr
-#  define tstrrchr strrchr
-#  define tstrlen  strlen
-#  define tmemcmp  memcmp
-#  define tstrftime strftime
-#  define tputchar putchar
-#  define tputc    putc
-#  define tputs    puts
-#  define tfputs   fputs
-#  define tfopen   fopen
-#  define tstat    stat
-#  define tunlink  unlink
-#  define tstrtol  strtol
-#  define tmkdir   mkdir
-#  define TSTRDUP  STRDUP
-#  define tstrerror_r strerror_r
-#  define trename  rename
-#  define ttruncate truncate
-#endif
-
 #define TMALLOC(n) MALLOC((n) * sizeof(tchar))
 
-extern size_t
-utf16le_strlen(const utf16lechar *s);
-
 /* encoding.c */
 extern void
 iconv_global_cleanup();
@@ -159,27 +67,29 @@ extern bool wimlib_mbs_is_utf8;
                                          chartype1, chartype2)         \
                                                                        \
 extern int                                                             \
+varname1##_to_##varname2(const chartype1 *in, size_t in_nbytes,                \
+                        chartype2 **out_ret,                           \
+                        size_t *out_nbytes_ret);                       \
+                                                                       \
+extern int                                                             \
 varname1##_to_##varname2##_nbytes(const chartype1 *in, size_t in_nbytes,\
                                  size_t *out_nbytes_ret);              \
                                                                        \
 extern int                                                             \
 varname1##_to_##varname2##_buf(const chartype1 *in, size_t in_nbytes,  \
-                              chartype2 *out);                         \
-                                                                       \
-extern int                                                             \
-varname1##_to_##varname2(const chartype1 *in, size_t in_nbytes,                \
-                        chartype2 **out_ret,                           \
-                        size_t *out_nbytes_ret);                       \
+                              chartype2 *out);
+
 
 #if !TCHAR_IS_UTF16LE
 DECLARE_CHAR_CONVERSION_FUNCTIONS(utf16le, tstr, utf16lechar, tchar);
+DECLARE_CHAR_CONVERSION_FUNCTIONS(tstr, utf16le, tchar, utf16lechar);
 #endif
 
 extern int
-utf8_to_tstr_simple(const utf8char *utf8str, tchar **out);
+utf8_to_tstr_simple(const char *utf8str, tchar **out);
 
 extern int
-tstr_to_utf8_simple(const tchar *tstr, utf8char **out);
+tstr_to_utf8_simple(const tchar *tstr, char **out);
 
 #ifndef min
 #define min(a, b) ({ typeof(a) __a = (a); typeof(b) __b = (b); \
@@ -222,7 +132,7 @@ tstr_to_utf8_simple(const tchar *tstr, utf8char **out);
 #define BUFFER_SIZE 4096
 
 static inline void FORMAT(printf, 1, 2)
-dummy_printf(const char *format, ...)
+dummy_tprintf(const tchar *format, ...)
 {
 }
 
@@ -243,10 +153,10 @@ wimlib_warning_with_errno(const tchar *format, ...) FORMAT(printf, 1, 2) COLD;
 #  define WARNING(format, ...)                 wimlib_warning(T(format), ## __VA_ARGS__)
 #  define WARNING_WITH_ERRNO(format, ...)      wimlib_warning(T(format), ## __VA_ARGS__)
 #else /* ENABLE_ERROR_MESSAGES */
-#  define ERROR(format, ...)                   dummy_printf(format, ## __VA_ARGS__)
-#  define ERROR_WITH_ERRNO(format, ...)                dummy_printf(format, ## __VA_ARGS__)
-#  define WARNING(format, ...)                 dummy_printf(format, ## __VA_ARGS__)
-#  define WARNING_WITH_ERRNO(format, ...)      dummy_printf(format, ## __VA_ARGS__)
+#  define ERROR(format, ...)                   dummy_tprintf(T(format), ## __VA_ARGS__)
+#  define ERROR_WITH_ERRNO(format, ...)                dummy_tprintf(T(format), ## __VA_ARGS__)
+#  define WARNING(format, ...)                 dummy_tprintf(T(format), ## __VA_ARGS__)
+#  define WARNING_WITH_ERRNO(format, ...)      dummy_tprintf(T(format), ## __VA_ARGS__)
 #endif /* !ENABLE_ERROR_MESSAGES */
 
 #if defined(ENABLE_MORE_DEBUG) && !defined(ENABLE_DEBUG)
@@ -265,13 +175,13 @@ wimlib_debug(const tchar *file, int line, const char *func,
                wimlib_debug(T(__FILE__), __LINE__, __func__, T(format), ## __VA_ARGS__);
 
 #else
-#  define DEBUG(format, ...) dummy_printf(format, ## __VA_ARGS__)
+#  define DEBUG(format, ...) dummy_tprintf(T(format), ## __VA_ARGS__)
 #endif /* !ENABLE_DEBUG */
 
 #ifdef ENABLE_MORE_DEBUG
 #  define DEBUG2(format, ...) DEBUG(format, ## __VA_ARGS__)
 #else
-#  define DEBUG2(format, ...) dummy_printf(format, ## __VA_ARGS__)
+#  define DEBUG2(format, ...) dummy_tprintf(T(format), ## __VA_ARGS__)
 #endif /* !ENABLE_MORE_DEBUG */
 
 #ifdef ENABLE_ASSERTIONS
@@ -323,9 +233,6 @@ randomize_byte_array(u8 *p, size_t n);
 extern void
 randomize_char_array_with_alnum(tchar p[], size_t n);
 
-extern const tchar *
-path_next_part(const tchar *path, size_t *first_part_len_ret);
-
 const tchar *
 path_basename_with_len(const tchar *path, size_t len);
 
@@ -335,15 +242,6 @@ path_basename(const tchar *path);
 extern const tchar *
 path_stream_name(const tchar *path);
 
-extern void
-to_parent_name(tchar *buf, size_t len);
-
-extern void
-print_string(const void *string, size_t len);
-
-extern int
-get_num_path_components(const char *path);
-
 static inline void
 print_byte_field(const u8 field[], size_t len)
 {
@@ -367,14 +265,18 @@ bsr32(u32 n)
 #endif
 }
 
+#ifdef __WIN32__
+#  define wimlib_fprintf fwprintf
+#  define wimlib_printf         wprintf
+#else /* __WIN32__ */
 extern int
-wimlib_fprintf(FILE *fp, const tchar *format, ...)
-       //FORMAT(printf, 2, 3)
-       ;
+wimlib_fprintf(FILE *fp, const tchar *format, ...) FORMAT(printf, 2, 3);
 
 extern int
-wimlib_printf(const tchar *format, ...)
-       //FORMAT(printf, 1, 2)
-       ;
+wimlib_printf(const tchar *format, ...) FORMAT(printf, 1, 2);
+#endif /* !__WIN32__ */
+
+extern void
+zap_backslashes(tchar *s);
 
 #endif /* _WIMLIB_UTIL_H */
index 62e9547..efaca0d 100644 (file)
@@ -30,7 +30,8 @@
 #include "dentry.h"
 #include "lookup_table.h"
 
-static int verify_inode(struct wim_inode *inode, const WIMStruct *w)
+static int
+verify_inode(struct wim_inode *inode, const WIMStruct *w)
 {
        const struct wim_lookup_table *table = w->lookup_table;
        const struct wim_security_data *sd = wim_const_security_data(w);
@@ -42,13 +43,13 @@ static int verify_inode(struct wim_inode *inode, const WIMStruct *w)
         * descriptor".  Anything else has to be a valid index into the WIM
         * image's security descriptors table. */
        if (inode->i_security_id < -1) {
-               ERROR("Dentry `%s' has an invalid security ID (%d)",
-                       first_dentry->full_path, inode->i_security_id);
+               ERROR("Dentry `%"TS"' has an invalid security ID (%d)",
+                     first_dentry->full_path, inode->i_security_id);
                goto out;
        }
 
        if (inode->i_security_id >= sd->num_entries) {
-               ERROR("Dentry `%s' has an invalid security ID (%d) "
+               ERROR("Dentry `%"TS"' has an invalid security ID (%d) "
                      "(there are only %u entries in the security table)",
                      first_dentry->full_path, inode->i_security_id,
                      sd->num_entries);
@@ -68,49 +69,12 @@ static int verify_inode(struct wim_inode *inode, const WIMStruct *w)
                        lte = __lookup_resource(table, hash);
                        if (!lte && !is_zero_hash(hash)) {
                                ERROR("Could not find lookup table entry for stream "
-                                     "%u of dentry `%s'", i, first_dentry->full_path);
+                                     "%u of dentry `%"TS"'",
+                                     i, first_dentry->full_path);
                                goto out;
                        }
                        if (lte)
                                lte->real_refcnt += inode->i_nlink;
-
-                       /* The following is now done when required by
-                        * wim_run_full_verifications(). */
-
-               #if 0
-                       if (lte && !w->full_verification_in_progress &&
-                           lte->real_refcnt > lte->refcnt)
-                       {
-                       #ifdef ENABLE_ERROR_MESSAGES
-                               WARNING("The following lookup table entry "
-                                       "has a reference count of %u, but",
-                                       lte->refcnt);
-                               WARNING("We found %u references to it",
-                                       lte->real_refcnt);
-                               WARNING("(One dentry referencing it is at `%s')",
-                                        first_dentry->full_path_utf8);
-
-                               print_lookup_table_entry(lte);
-                       #endif
-                               /* Guess what!  install.wim for Windows 8
-                                * contains many streams referenced by more
-                                * dentries than the refcnt stated in the lookup
-                                * table entry.  So we will need to handle this
-                                * case and not just make it be an error...  I'm
-                                * just setting the reference count to the
-                                * number of references we found.
-                                * (Unfortunately, even after doing this, the
-                                * reference count could be too low if it's also
-                                * referenced in other WIM images) */
-
-                       #if 1
-                               lte->refcnt = lte->real_refcnt;
-                               WARNING("Fixing reference count");
-                       #else
-                               goto out;
-                       #endif
-                       }
-               #endif
                }
        }
 
@@ -123,7 +87,7 @@ static int verify_inode(struct wim_inode *inode, const WIMStruct *w)
                        num_unnamed_streams++;
        }
        if (num_unnamed_streams > 1) {
-               ERROR("Dentry `%s' has multiple (%u) un-named streams",
+               ERROR("Dentry `%"TS"' has multiple (%u) un-named streams",
                      first_dentry->full_path, num_unnamed_streams);
                goto out;
        }
@@ -136,7 +100,7 @@ static int verify_inode(struct wim_inode *inode, const WIMStruct *w)
                if (dentry_has_short_name(dentry)) {
                        if (dentry_with_dos_name) {
                                ERROR("Hard-linked file has a DOS name at "
-                                     "both `%s' and `%s'",
+                                     "both `%"TS"' and `%"TS"'",
                                      dentry_with_dos_name->full_path,
                                      dentry->full_path);
                                goto out;
@@ -147,7 +111,7 @@ static int verify_inode(struct wim_inode *inode, const WIMStruct *w)
 
        /* Directories with multiple links have not been tested. XXX */
        if (inode->i_nlink > 1 && inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY) {
-               ERROR("Hard-linked directory `%s' is unsupported",
+               ERROR("Hard-linked directory `%"TS"' is unsupported",
                      first_dentry->full_path);
                goto out;
        }
@@ -159,14 +123,17 @@ out:
 }
 
 /* Run some miscellaneous verifications on a WIM dentry */
-int verify_dentry(struct wim_dentry *dentry, void *wim)
+int
+verify_dentry(struct wim_dentry *dentry, void *wim)
 {
        int ret;
+       WIMStruct *w = wim;
 
        /* Verify the associated inode, but only one time no matter how many
-        * dentries it has. */
-       if (!dentry->d_inode->i_verified) {
-               ret = verify_inode(dentry->d_inode, wim);
+        * dentries it has (unless we are doing a full verification of the WIM,
+        * in which case we need to force the inode to be verified again.) */
+       if (!dentry->d_inode->i_verified || w->full_verification_in_progress) {
+               ret = verify_inode(dentry->d_inode, w);
                if (ret != 0)
                        return ret;
        }
@@ -185,7 +152,7 @@ int verify_dentry(struct wim_dentry *dentry, void *wim)
                }
        } else {
                if (!dentry_has_long_name(dentry)) {
-                       ERROR("Dentry `%s' has no long name!",
+                       ERROR("Dentry `%"TS"' has no long name!",
                              dentry->full_path);
                        return WIMLIB_ERR_INVALID_DENTRY;
                }
@@ -195,20 +162,22 @@ int verify_dentry(struct wim_dentry *dentry, void *wim)
        /* Check timestamps */
        if (inode->i_last_access_time < inode->i_creation_time ||
            inode->i_last_write_time < inode->i_creation_time) {
-               WARNING("Dentry `%s' was created after it was last accessed or "
-                     "written to", dentry->full_path_utf8);
+               WARNING("Dentry `%"TS"' was created after it was last accessed or "
+                       "written to", dentry->full_path);
        }
 #endif
 
        return 0;
 }
 
-static int image_run_full_verifications(WIMStruct *w)
+static int
+image_run_full_verifications(WIMStruct *w)
 {
        return for_dentry_in_tree(wim_root_dentry(w), verify_dentry, w);
 }
 
-static int lte_fix_refcnt(struct wim_lookup_table_entry *lte, void *ctr)
+static int
+lte_fix_refcnt(struct wim_lookup_table_entry *lte, void *ctr)
 {
        if (lte->refcnt != lte->real_refcnt) {
        #ifdef ENABLE_ERROR_MESSAGES
@@ -232,7 +201,8 @@ static int lte_fix_refcnt(struct wim_lookup_table_entry *lte, void *ctr)
  * problem by looking at ALL the images to re-calculate the reference count of
  * EVERY lookup table entry.  This only absolutely has to be done before an image
  * is deleted or before an image is mounted read-write. */
-int wim_run_full_verifications(WIMStruct *w)
+int
+wim_run_full_verifications(WIMStruct *w)
 {
        int ret;
 
@@ -276,31 +246,32 @@ int wim_run_full_verifications(WIMStruct *w)
  * @return:
  *     0 on success; WIMLIB_ERR_SPLIT_INVALID if the set is not valid.
  */
-int verify_swm_set(WIMStruct *w, WIMStruct **additional_swms,
-                  unsigned num_additional_swms)
+int
+verify_swm_set(WIMStruct *w, WIMStruct **additional_swms,
+              unsigned num_additional_swms)
 {
        unsigned total_parts = w->hdr.total_parts;
        int ctype;
        const u8 *guid;
 
        if (total_parts != num_additional_swms + 1) {
-               ERROR("`%s' says there are %u parts in the spanned set, "
-                     "but %s%u part%s provided",
+               ERROR("`%"TS"' says there are %u parts in the spanned set, "
+                     "but %"TS"%u part%"TS" provided",
                      w->filename, total_parts,
-                     (num_additional_swms + 1 < total_parts) ? "only " : "",
+                     (num_additional_swms + 1 < total_parts) ? T("only ") : T(""),
                      num_additional_swms + 1,
-                     (num_additional_swms) ? "s were" : " was");
+                     (num_additional_swms) ? T("s were") : T(" was"));
                return WIMLIB_ERR_SPLIT_INVALID;
        }
        if (w->hdr.part_number != 1) {
-               ERROR("WIM `%s' is not the first part of the split WIM.",
-                     w->filename);
+               ERROR("WIM `%"TS"' is not the first part of the split WIM.",
+                     T(w->filename));
                return WIMLIB_ERR_SPLIT_INVALID;
        }
        for (unsigned i = 0; i < num_additional_swms; i++) {
                if (additional_swms[i]->hdr.total_parts != total_parts) {
-                       ERROR("WIM `%s' says there are %u parts in the spanned set, "
-                             "but %u parts were provided",
+                       ERROR("WIM `%"TS"' says there are %u parts in the "
+                             "spanned set, but %u parts were provided",
                              additional_swms[i]->filename,
                              additional_swms[i]->hdr.total_parts,
                              total_parts);
@@ -335,24 +306,24 @@ int verify_swm_set(WIMStruct *w, WIMStruct **additional_swms,
                                return WIMLIB_ERR_SPLIT_INVALID;
                        }
                        if (swm->hdr.part_number == 1) {
-                               ERROR("WIMs `%s' and `%s' both are marked as the "
-                                     "first WIM in the spanned set",
+                               ERROR("WIMs `%"TS"' and `%"TS"' both are marked "
+                                     "as the first WIM in the spanned set",
                                      w->filename, swm->filename);
                                return WIMLIB_ERR_SPLIT_INVALID;
                        }
                        if (swm->hdr.part_number == 0 ||
                            swm->hdr.part_number > total_parts)
                        {
-                               ERROR("WIM `%s' says it is part %u in the spanned set, "
-                                     "but the part number must be in the range "
-                                     "[1, %u]",
+                               ERROR("WIM `%"TS"' says it is part %u in the "
+                                     "spanned set, but the part number must "
+                                     "be in the range [1, %u]",
                                      swm->filename, swm->hdr.part_number, total_parts);
                                return WIMLIB_ERR_SPLIT_INVALID;
                        }
                        if (parts_to_swms[swm->hdr.part_number - 2])
                        {
-                               ERROR("`%s' and `%s' are both marked as part %u of %u "
-                                     "in the spanned set",
+                               ERROR("`%"TS"' and `%"TS"' are both marked as "
+                                     "part %u of %u in the spanned set",
                                      parts_to_swms[swm->hdr.part_number - 2]->filename,
                                      swm->filename,
                                      swm->hdr.part_number,
@@ -365,4 +336,3 @@ int verify_swm_set(WIMStruct *w, WIMStruct **additional_swms,
        }
        return 0;
 }
-
index bba8487..f2794fe 100644 (file)
--- a/src/wim.c
+++ b/src/wim.c
@@ -184,7 +184,7 @@ wimlib_create_new_wim(int ctype, WIMStruct **w_ret)
        struct wim_lookup_table *table;
        int ret;
 
-       DEBUG("Creating new WIM with %s compression.",
+       DEBUG("Creating new WIM with %"TS" compression.",
              wimlib_get_compression_type_string(ctype));
 
        /* Allocate the WIMStruct. */
@@ -304,8 +304,8 @@ wimlib_resolve_image(WIMStruct *w, const tchar *image_name_or_num)
        if (!image_name_or_num || !*image_name_or_num)
                return WIMLIB_NO_IMAGE;
 
-       if (tstrcmp(image_name_or_num, T("all")) == 0
-           || tstrcmp(image_name_or_num, T("*")) == 0)
+       if (!tstrcasecmp(image_name_or_num, T("all"))
+           || !tstrcasecmp(image_name_or_num, T("*")))
                return WIMLIB_ALL_IMAGES;
        image = tstrtol(image_name_or_num, &p, 10);
        if (p != image_name_or_num && *p == T('\0') && image > 0) {
@@ -675,13 +675,13 @@ test_locale_ctype_utf8()
 {
        char *ctype = nl_langinfo(CODESET);
 
-       return (strstr(ctype, "UTF-8") == 0 ||
-               strstr(ctype, "UTF8") == 0 ||
-               strstr(ctype, "utf8") == 0 ||
-               strstr(ctype, "utf-8") == 0);
+       return (!strstr(ctype, "UTF-8") ||
+               !strstr(ctype, "UTF8") ||
+               !strstr(ctype, "utf8") ||
+               !strstr(ctype, "utf-8"));
 }
 
-/* Get global memory allocations out of the way.  Not strictly necessary in
+/* Get global memory allocations out of the way
  * single-threaded programs like 'imagex'. */
 WIMLIBAPI int
 wimlib_global_init()
index d1b22cd..403d387 100644 (file)
@@ -1500,12 +1500,17 @@ 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.  Also, since wimlib
- * 1.3.0, you must call this function if the character encoding of the current
- * locale is not UTF-8.  Otherwise, calling this function this function is not
- * required.
+ * threads, then you must call this function serially first.
  *
- * This function always returns 0.
+ * Since wimlib 1.3.0, you must call this function if the character encoding of
+ * the current locale is not UTF-8.
+ *
+ * Since wimlib 1.3.2, you must call this function if using the Windows-native
+ * build of the library so that certain functions can be dynamically loaded from
+ * system DLLs.
+ *
+ * This function currently always returns 0, but it may return other error codes
+ * in future releases.
  */
 extern int
 wimlib_global_init();
index 2b26e1c..dfa92ff 100644 (file)
@@ -31,7 +31,7 @@
 #include <windows.h>
 #include <ntdef.h>
 #include <wchar.h>
-#include <shlwapi.h> /* shlwapi.h for PathMatchSpecA() */
+#include <shlwapi.h> /* shlwapi.h for PathMatchSpecW() */
 #ifdef ERROR /* windows.h defines this */
 #  undef ERROR
 #endif
@@ -70,7 +70,7 @@ win32_global_init()
 
        if (hKernel32 == NULL) {
                DEBUG("Loading Kernel32.dll");
-               hKernel32 = LoadLibraryA("Kernel32.dll");
+               hKernel32 = LoadLibraryW(L"Kernel32.dll");
                if (hKernel32 == NULL) {
                        err = GetLastError();
                        WARNING("Can't load Kernel32.dll");
@@ -329,7 +329,7 @@ win32_recurse_directory(struct wim_dentry *root,
        } while (FindNextFileW(hFind, &dat));
        err = GetLastError();
        if (err != ERROR_NO_MORE_FILES) {
-               ERROR("Failed to read directory \"%s\"", dir_path);
+               ERROR("Failed to read directory \"%ls\"", dir_path);
                win32_error(err);
                if (ret == 0)
                        ret = WIMLIB_ERR_READ;
@@ -818,7 +818,7 @@ win32_build_dentry_tree(struct wim_dentry **root_ret,
        size_t path_nchars;
        wchar_t *path;
        int ret;
-       
+
        path_nchars = wcslen(root_disk_path);
        if (path_nchars > 32767)
                return WIMLIB_ERR_INVALID_PARAM;
@@ -831,6 +831,8 @@ win32_build_dentry_tree(struct wim_dentry **root_ret,
        if (!path)
                return WIMLIB_ERR_NOMEM;
 
+       wmemcpy(path, root_disk_path, path_nchars + 1);
+
        ret = win32_build_dentry_tree_recursive(root_ret,
                                                path,
                                                path_nchars,
@@ -1189,7 +1191,6 @@ win32_do_apply_dentry_timestamps(const wchar_t *path,
 {
        DWORD err;
        HANDLE h;
-       int ret;
        const struct wim_inode *inode = dentry->d_inode;
 
        DEBUG("Opening \"%ls\" to set timestamps", path);
index 1c57405..633196b 100644 (file)
 #  define INVALID_HANDLE_VALUE ((HANDLE)(-1))
 #endif
 
-#if TCHAR_IS_UTF16LE
-#  include <wchar.h>
-#endif
-
 static int
 fflush_and_ftruncate(FILE *fp, off_t size)
 {
@@ -550,8 +546,8 @@ write_wim_resource(struct wim_lookup_table_entry *lte,
                } else if (!hashes_equal(md, lte->hash)) {
                        ERROR("WIM resource has incorrect hash!");
                        if (lte->resource_location == RESOURCE_IN_FILE_ON_DISK) {
-                               ERROR("We were reading it from `%s'; maybe it changed "
-                                     "while we were reading it.",
+                               ERROR("We were reading it from `%"TS"'; maybe "
+                                     "it changed while we were reading it.",
                                      lte->file_on_disk);
                        }
                        ret = WIMLIB_ERR_INVALID_RESOURCE_HASH;
@@ -1692,11 +1688,11 @@ lock_wim(WIMStruct *w, FILE *fp)
 
 static int
 open_wim_writable(WIMStruct *w, const tchar *path,
-                 bool trunc, bool readable)
+                 bool trunc, bool also_readable)
 {
        const tchar *mode;
        if (trunc)
-               if (readable)
+               if (also_readable)
                        mode = T("w+b");
                else
                        mode = T("wb");
index c4382d4..4b1d708 100644 (file)
--- a/src/xml.c
+++ b/src/xml.c
@@ -82,7 +82,7 @@ struct image_info {
 };
 
 struct xml_string_spec {
-       const utf8char *name;
+       const char *name;
        size_t offset;
 };
 
@@ -126,7 +126,7 @@ get_arch(int arch)
                return T("x86_64");
        /* XXX Are there other arch values? */
        default:
-               return NULL;
+               return T("unknown");
        }
 }
 
@@ -149,34 +149,36 @@ node_is_text(xmlNode *node)
 }
 
 static inline bool
-node_name_is(xmlNode *node, const utf8char *name)
+node_name_is(xmlNode *node, const char *name)
 {
        /* For now, both upper case and lower case element names are accepted. */
        return strcasecmp((const char *)node->name, name) == 0;
 }
 
-/* Finds the text node that is a child of an element node and returns its
- * content converted to a 64-bit unsigned integer.  Returns 0 if no text node is
- * found. */
 static u64
-node_get_u64(const xmlNode *u64_node)
+node_get_number(const xmlNode *u64_node, int base)
 {
        xmlNode *child;
        for_node_child(u64_node, child)
                if (node_is_text(child))
-                       return strtoull((const char *)child->content, NULL, 10);
+                       return strtoull(child->content, NULL, base);
        return 0;
 }
 
+/* Finds the text node that is a child of an element node and returns its
+ * content converted to a 64-bit unsigned integer.  Returns 0 if no text node is
+ * found. */
+static u64
+node_get_u64(const xmlNode *u64_node)
+{
+       return node_get_number(u64_node, 10);
+}
+
 /* Like node_get_u64(), but expects a number in base 16. */
 static u64
 node_get_hex_u64(const xmlNode *u64_node)
 {
-       xmlNode *child;
-       for_node_child(u64_node, child)
-               if (node_is_text(child))
-                       return strtoull(child->content, NULL, 16);
-       return 0;
+       return node_get_number(u64_node, 16);
 }
 
 static int
@@ -529,7 +531,7 @@ print_windows_info(const struct windows_info *windows_info)
        const struct windows_version *windows_version;
 
        tprintf(T("Architecture:           %"TS"\n"),
-               get_arch(windows_info->arch) ?: T("unknown"));
+               get_arch(windows_info->arch));
 
        if (windows_info->product_name) {
                tprintf(T("Product Name:           %"TS"\n"),
@@ -597,7 +599,7 @@ xml_write_string(xmlTextWriter *writer, const char *name,
                 const tchar *tstr)
 {
        if (tstr) {
-               utf8char *utf8_str;
+               char *utf8_str;
                int rc = tstr_to_utf8_simple(tstr, &utf8_str);
                if (rc)
                        return rc;
@@ -745,7 +747,7 @@ xml_write_windows_info(xmlTextWriter *writer,
 
 /* Writes a time element to the XML document being constructed in memory. */
 static int
-xml_write_time(xmlTextWriter *writer, const utf8char *element_name, u64 time)
+xml_write_time(xmlTextWriter *writer, const char *element_name, u64 time)
 {
        int rc;
        rc = xmlTextWriterStartElement(writer, element_name);
@@ -813,7 +815,7 @@ xml_write_image_info(xmlTextWriter *writer, const struct image_info *image_info)
 
        if (image_info->windows_info_exists) {
                rc = xml_write_windows_info(writer, &image_info->windows_info);
-               if (rc < 0)
+               if (rc)
                        return rc;
        }
 
@@ -856,6 +858,8 @@ clone_windows_info(const struct windows_info *old, struct windows_info *new)
 
        ret = dup_strings_from_specs(old, new, windows_info_xml_string_specs,
                                     ARRAY_LEN(windows_info_xml_string_specs));
+       if (ret)
+               return ret;
 
        if (old->languages) {
                new->languages = CALLOC(old->num_languages, sizeof(new->languages[0]));
@@ -982,9 +986,9 @@ xml_delete_image(struct wim_info **wim_info_p, int image)
 {
        struct wim_info *wim_info;
 
-       DEBUG("Deleting image %d from the XML data.", image);
-
        wim_info = *wim_info_p;
+       wimlib_assert(image >= 1 && image <= wim_info->num_images);
+       DEBUG("Deleting image %d from the XML data.", image);
 
        destroy_image_info(&wim_info->images[image - 1]);
 
@@ -1117,8 +1121,8 @@ xml_update_image_info(WIMStruct *w, int image)
        image_info->dir_count       = 0;
        image_info->total_bytes     = 0;
        image_info->hard_link_bytes = 0;
-
        image_info->lookup_table = w->lookup_table;
+
        for_dentry_in_tree(w->image_metadata[image - 1].root_dentry,
                           calculate_dentry_statistics,
                           image_info);
@@ -1295,8 +1299,7 @@ read_xml_data(FILE *fp, const struct resource_entry *res_entry,
        }
 
        if (!node_is_element(root) || !node_name_is(root, "WIM")) {
-               ERROR("Expected <WIM> for the root XML element (found <%s>)",
-                     root->name);
+               ERROR("Expected <WIM> for the root XML element");
                ret = WIMLIB_ERR_XML;
                goto out_free_doc;
        }
@@ -1482,7 +1485,7 @@ wimlib_image_name_in_use(const WIMStruct *w, const tchar *name)
        if (!name || !*name)
                return false;
        for (int i = 1; i <= w->hdr.image_count; i++)
-               if (tstrcmp(w->wim_info->images[i - 1].name, name) == 0)
+               if (!tstrcmp(w->wim_info->images[i - 1].name, name))
                        return true;
        return false;
 }
diff --git a/wimlib_tchar.h b/wimlib_tchar.h
new file mode 100644 (file)
index 0000000..75f8e81
--- /dev/null
@@ -0,0 +1,111 @@
+#ifndef _WIMLIB_TCHAR_H
+#define _WIMLIB_TCHAR_H
+
+/* Functions to act on "tchar" strings, which have a platform-dependent encoding
+ * and character size. */
+
+#ifdef __WIN32__
+#include <wchar.h>
+/* For Windows builds, the "tchar" type will be 2 bytes and will be equivalent
+ * to "wchar_t" and "utf16lechar".  All indicate one code unit of a UTF16-LE
+ * string. */
+typedef wchar_t tchar;
+#  define TCHAR_IS_UTF16LE 1
+#  define _T(text) L##text
+#  define T(text) _T(text) /* Make a string literal into a wide string */
+#  define TS "ls" /* Format a string of "tchar" */
+#  define WS "ls" /* Format a UTF-16LE string (same as above) */
+
+/* For Windows builds, the following definitions replace the "tchar" functions
+ * with the "wide-character" functions. */
+#  define tmemchr      wmemchr
+#  define tmemcpy      wmemcpy
+#  define tstrcpy      wcscpy
+#  define tprintf      wprintf
+#  define tsprintf     swprintf
+#  define tfprintf     fwprintf
+#  define tvfprintf    vfwprintf
+#  define istalpha     iswalpha
+#  define istspace     iswspace
+#  define tstrcmp      wcscmp
+#  define tstrchr      wcschr
+#  define tstrpbrk     wcspbrk
+#  define tstrrchr     wcsrchr
+#  define tstrlen      wcslen
+#  define tmemcmp      wmemcmp
+#  define tstrcasecmp   _wcsicmp
+#  define tstrftime    wcsftime
+#  define tputchar     putwchar
+#  define tputc                putwc
+#  define tputs                _putws
+#  define tfputs       fputws
+#  define tfopen       _wfopen
+#  define tstat                _wstati64
+#  define tstrtol      wcstol
+#  define tstrtod      wcstod
+#  define tstrtoul     wcstoul
+#  define tunlink      _wunlink
+#  define tstrerror    _wcserror
+#  define taccess      _waccess
+/* The following "tchar" functions do not have exact wide-character equivalents
+ * on Windows so require parameter rearrangement or redirection to a replacement
+ * function defined ourselves. */
+#  define TSTRDUP      WSTRDUP
+#  define tmkdir(path, mode) _wmkdir(path)
+#  define tstrerror_r(errnum, buf, bufsize) _wcserror_s(buf, bufsize, errnum)
+#  define trename      win32_rename_replacement
+#  define ttruncate    win32_truncate_replacement
+#else /* __WIN32__ */
+/* For non-Windows builds, the "tchar" type will be one byte and will specify a
+ * string in the locale-dependent multibyte encoding.  However, only UTF-8 is
+ * well supported in this library. */
+typedef char tchar;
+#  define TCHAR_IS_UTF16LE 0
+#  define T(text) text /* In this case, strings of "tchar" are simply strings of
+                         char */
+#  define TS "s"       /* Similarly, a string of "tchar" is printed just as a
+                         normal string. */
+#  define WS "W"       /* UTF-16LE strings must be printed using a special
+                         extension implemented by wimlib itself.  Note that
+                         "ls" will not work here because a string of wide
+                         characters on non-Windows systems is typically not
+                         UTF-16LE. */
+/* For non-Windows builds, replace the "tchar" functions with the regular old
+ * string functions. */
+#  define tmemchr      memchr
+#  define tmemcpy      memcpy
+#  define tstrcpy      strcpy
+#  define tprintf      printf
+#  define tsprintf     sprintf
+#  define tfprintf     fprintf
+#  define tvfprintf    vfprintf
+#  define istalpha     isalpha
+#  define istspace     isspace
+#  define tstrcmp      strcmp
+#  define tstrchr      strchr
+#  define tstrpbrk     strpbrk
+#  define tstrrchr     strrchr
+#  define tstrlen      strlen
+#  define tmemcmp      memcmp
+#  define tstrcasecmp   strcasecmp
+#  define tstrftime    strftime
+#  define tputchar     putchar
+#  define tputc                putc
+#  define tputs                puts
+#  define tfputs       fputs
+#  define tfopen       fopen
+#  define tstat                stat
+#  define tunlink      unlink
+#  define tstrerror    strerror
+#  define tstrtol      strtol
+#  define tstrtod      strtod
+#  define tstrtoul     strtoul
+#  define tmkdir       mkdir
+#  define TSTRDUP      STRDUP
+#  define tstrerror_r  strerror_r
+#  define trename      rename
+#  define ttruncate    truncate
+#  define taccess      access
+#endif /* !__WIN32__ */
+
+#endif /* _WIMLIB_TCHAR_H */