diff --git a/tools/fpack.c b/tools/fpack.c index 53ac512..b8dfc77 100644 --- a/tools/fpack.c +++ b/tools/fpack.c @@ -13,6 +13,7 @@ #ifdef _WIN32 #include +#include #define PROGRAM_NAME "fpack.exe" #define fpack_fseek64(f, off, whence) _fseeki64((f), (off), (whence)) #define fpack_ftell64(f) _ftelli64((f)) @@ -23,6 +24,36 @@ #define fpack_ftell64(f) ftello((f)) #endif +#ifdef _WIN32 +static wchar_t *utf8_to_wide(const char *s) +{ + int wlen = MultiByteToWideChar(CP_UTF8, 0, s, -1, NULL, 0); + wchar_t *w; + + if (wlen <= 0) + return NULL; + w = malloc((size_t)wlen * sizeof(wchar_t)); + if (!w) + return NULL; + MultiByteToWideChar(CP_UTF8, 0, s, -1, w, wlen); + return w; +} + +static char *wide_to_utf8(const wchar_t *w) +{ + int len = WideCharToMultiByte(CP_UTF8, 0, w, -1, NULL, 0, NULL, NULL); + char *s; + + if (len <= 0) + return NULL; + s = malloc((size_t)len); + if (!s) + return NULL; + WideCharToMultiByte(CP_UTF8, 0, w, -1, s, len, NULL, NULL); + return s; +} +#endif + static double now_seconds(void) { #ifdef _WIN32 @@ -151,8 +182,16 @@ static void *read_file(const char *path, size_t *out_size) FILE *fp; int64_t len; void *buf; +#ifdef _WIN32 + wchar_t *wpath = utf8_to_wide(path); + if (!wpath) + return NULL; + fp = _wfopen(wpath, L"rb"); + free(wpath); +#else fp = fopen(path, "rb"); +#endif if (!fp) return NULL; @@ -183,6 +222,102 @@ static void *read_file(const char *path, size_t *out_size) return buf; } +static int add_file(struct fpk_writer *w, const char *path, size_t base_len) +{ + const char *rel_path = path + base_len; + void *data; + size_t size; + char *norm; + + while (*rel_path == '/') + rel_path++; + + norm = dup_str(rel_path); + normalize_path(norm); + + data = read_file(path, &size); + if (!data) { + fprintf(stderr, "fpack: cannot read: %s\n", path); + free(norm); + return 0; + } + + if (fpk_writer_add(w, norm, data, size) != 0) { + fprintf(stderr, "fpack: cannot add: %s\n", norm); + free(data); + free(norm); + return 0; + } + + entry_count++; + total_bytes += size; + + if (flags & FPACK_VERBOSE) + printf(" %s (%lu bytes)\n", norm, (unsigned long)size); + + if (flags & FPACK_PROGRESS) { + printf("\rpacked %lu files (%lu bytes)", + (unsigned long)entry_count, (unsigned long)total_bytes); + fflush(stdout); + } + + free(data); + free(norm); + return 1; +} + +#ifdef _WIN32 +static int add_dir(struct fpk_writer *w, const char *dir, size_t base_len) +{ + char *pattern = join_path(dir, "*"); + wchar_t *wpattern = utf8_to_wide(pattern); + WIN32_FIND_DATAW fd; + HANDLE h; + + free(pattern); + if (!wpattern) { + fprintf(stderr, "fpack: cannot open directory: %s\n", dir); + return 0; + } + + h = FindFirstFileW(wpattern, &fd); + free(wpattern); + if (h == INVALID_HANDLE_VALUE) { + fprintf(stderr, "fpack: cannot open directory: %s\n", dir); + return 0; + } + + do { + char *name = wide_to_utf8(fd.cFileName); + char *path; + + if (!name || name[0] == '.') { + free(name); + continue; + } + + path = join_path(dir, name); + free(name); + + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + if (!add_dir(w, path, base_len)) { + free(path); + FindClose(h); + return 0; + } + } else if (!add_file(w, path, base_len)) { + free(path); + FindClose(h); + return 0; + } + + free(path); + } while (FindNextFileW(h, &fd)); + + FindClose(h); + return 1; +} +#else static int add_dir(struct fpk_writer *w, const char *dir, size_t base_len) { DIR *d; @@ -216,50 +351,11 @@ static int add_dir(struct fpk_writer *w, const char *dir, size_t base_len) return 0; } } else if (S_ISREG(st.st_mode)) { - const char *rel_path = path + base_len; - void *data; - size_t size; - char *norm; - - while (*rel_path == '/') - rel_path++; - - norm = dup_str(rel_path); - normalize_path(norm); - - data = read_file(path, &size); - if (!data) { - fprintf(stderr, "fpack: cannot read: %s\n", path); - free(norm); + if (!add_file(w, path, base_len)) { free(path); closedir(d); return 0; } - - if (fpk_writer_add(w, norm, data, size) != 0) { - fprintf(stderr, "fpack: cannot add: %s\n", norm); - free(data); - free(norm); - free(path); - closedir(d); - return 0; - } - - entry_count++; - total_bytes += size; - - if (flags & FPACK_VERBOSE) - printf(" %s (%lu bytes)\n", norm, (unsigned long)size); - - if (flags & FPACK_PROGRESS) { - printf("\rpacked %lu files (%lu bytes)", - (unsigned long)entry_count, - (unsigned long)total_bytes); - fflush(stdout); - } - - free(data); - free(norm); } free(path); @@ -268,6 +364,7 @@ static int add_dir(struct fpk_writer *w, const char *dir, size_t base_len) closedir(d); return 1; } +#endif static void usage(void) { diff --git a/tools/funpack.c b/tools/funpack.c index 08ea4bf..0ea6b75 100644 --- a/tools/funpack.c +++ b/tools/funpack.c @@ -13,7 +13,7 @@ #ifdef _WIN32 #include #include -#define MKDIR(path) _mkdir(path) +#include #define PROGRAM_NAME "funpack.exe" #else #include @@ -21,6 +21,42 @@ #define PROGRAM_NAME "funpack" #endif +#ifdef _WIN32 +static wchar_t *utf8_to_wide(const char *s) +{ + int wlen = MultiByteToWideChar(CP_UTF8, 0, s, -1, NULL, 0); + wchar_t *w; + + if (wlen <= 0) + return NULL; + w = malloc((size_t)wlen * sizeof(wchar_t)); + if (!w) + return NULL; + MultiByteToWideChar(CP_UTF8, 0, s, -1, w, wlen); + return w; +} + +static int win_mkdir(const char *path) +{ + wchar_t *wpath = utf8_to_wide(path); + int ok; + + if (!wpath) + return -1; + ok = CreateDirectoryW(wpath, NULL); + free(wpath); + if (ok) + return 0; + if (GetLastError() == ERROR_ALREADY_EXISTS) { + errno = EEXIST; + return -1; + } + errno = 0; + return -1; +} +#define MKDIR(path) win_mkdir(path) +#endif + static double now_seconds(void) { #ifdef _WIN32 @@ -168,6 +204,9 @@ static int extract_entry(const char *out_dir, const fpk_entry_t *entry, { char *full_path = join_path(out_dir, entry->path); FILE *fp; +#ifdef _WIN32 + wchar_t *wpath; +#endif if (strchr(entry->path, '/') != NULL) { char *dir_part = dup_str(full_path); @@ -182,7 +221,13 @@ static int extract_entry(const char *out_dir, const fpk_entry_t *entry, free(dir_part); } +#ifdef _WIN32 + wpath = utf8_to_wide(full_path); + fp = wpath ? _wfopen(wpath, L"wb") : NULL; + free(wpath); +#else fp = fopen(full_path, "wb"); +#endif if (!fp) { fprintf(stderr, "funpack: cannot create: %s\n", full_path); free(full_path);