blob: 9610c63db656e42ddef0b35c8824dfd996b31159 [file] [log] [blame]
/* mz_os_win32.c -- System functions for Windows
Version 2.7.5, November 13, 2018
part of the MiniZip project
Copyright (C) 2010-2018 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <direct.h>
#include <errno.h>
#include <windows.h>
#include "mz.h"
#include "mz_os.h"
#include "mz_strm_os.h"
/***************************************************************************/
#if defined(WINAPI_FAMILY_PARTITION) && (!(defined(MZ_WINRT_API)))
# if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
# define MZ_WINRT_API 1
# endif
#endif
/***************************************************************************/
typedef struct DIR_int_s {
void *find_handle;
WIN32_FIND_DATAW find_data;
struct dirent entry;
uint8_t end;
} DIR_int;
/***************************************************************************/
wchar_t *mz_os_unicode_string_create(const char *string, int32_t encoding)
{
wchar_t *string_wide = NULL;
uint32_t string_wide_size = 0;
string_wide_size = MultiByteToWideChar(encoding, 0, string, -1, NULL, 0);
if (string_wide_size == 0)
return NULL;
string_wide = (wchar_t *)MZ_ALLOC((string_wide_size + 1) * sizeof(wchar_t));
memset(string_wide, 0, sizeof(wchar_t) * (string_wide_size + 1));
MultiByteToWideChar(encoding, 0, string, -1, string_wide, string_wide_size);
return string_wide;
}
void mz_os_unicode_string_delete(wchar_t **string)
{
if (string != NULL)
{
MZ_FREE(*string);
*string = NULL;
}
}
uint8_t *mz_os_utf8_string_create(const char *string, int32_t encoding)
{
wchar_t *string_wide = NULL;
uint8_t *string_utf8 = NULL;
uint32_t string_utf8_size = 0;
string_wide = mz_os_unicode_string_create(string, encoding);
if (string_wide)
{
string_utf8_size = WideCharToMultiByte(CP_UTF8, 0, string_wide, -1, NULL, 0, NULL, NULL);
string_utf8 = (uint8_t *)MZ_ALLOC((string_utf8_size + 1) * sizeof(wchar_t));
if (string_utf8)
{
memset(string_utf8, 0, string_utf8_size + 1);
WideCharToMultiByte(CP_UTF8, 0, string_wide, -1, (char *)string_utf8, string_utf8_size, NULL, NULL);
}
mz_os_unicode_string_delete(&string_wide);
}
return string_utf8;
}
void mz_os_utf8_string_delete(uint8_t **string)
{
if (string != NULL)
{
MZ_FREE(*string);
*string = NULL;
}
}
/***************************************************************************/
int32_t mz_os_rand(uint8_t *buf, int32_t size)
{
unsigned __int64 pentium_tsc[1];
int32_t len = 0;
for (len = 0; len < (int)size; len += 1)
{
if (len % 8 == 0)
QueryPerformanceCounter((LARGE_INTEGER *)pentium_tsc);
buf[len] = ((unsigned char*)pentium_tsc)[len % 8];
}
return len;
}
int32_t mz_os_rename(const char *source_path, const char *target_path)
{
wchar_t *source_path_wide = NULL;
wchar_t *target_path_wide = NULL;
int32_t result = 0;
int32_t err = MZ_OK;
if (source_path == NULL || target_path == NULL)
return MZ_PARAM_ERROR;
source_path_wide = mz_os_unicode_string_create(source_path, MZ_ENCODING_UTF8);
if (source_path_wide == NULL)
{
err = MZ_PARAM_ERROR;
}
else
{
target_path_wide = mz_os_unicode_string_create(target_path, MZ_ENCODING_UTF8);
if (target_path_wide == NULL)
err = MZ_PARAM_ERROR;
}
if (err == MZ_OK)
{
result = MoveFileW(source_path_wide, target_path_wide);
if (result == 0)
err = MZ_EXIST_ERROR;
}
if (target_path_wide)
mz_os_unicode_string_delete(&target_path_wide);
if (source_path_wide)
mz_os_unicode_string_delete(&source_path_wide);
return err;
}
int32_t mz_os_delete(const char *path)
{
wchar_t *path_wide = NULL;
int32_t result = 0;
if (path == NULL)
return MZ_PARAM_ERROR;
path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
if (path_wide == NULL)
return MZ_PARAM_ERROR;
result = DeleteFileW(path_wide);
mz_os_unicode_string_delete(&path_wide);
if (result == 0)
return MZ_EXIST_ERROR;
return MZ_OK;
}
int32_t mz_os_file_exists(const char *path)
{
wchar_t *path_wide = NULL;
DWORD attribs = 0;
if (path == NULL)
return MZ_PARAM_ERROR;
path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
if (path_wide == NULL)
return MZ_PARAM_ERROR;
attribs = GetFileAttributesW(path_wide);
mz_os_unicode_string_delete(&path_wide);
if (attribs == 0xFFFFFFFF)
return MZ_EXIST_ERROR;
return MZ_OK;
}
int64_t mz_os_get_file_size(const char *path)
{
HANDLE handle = NULL;
LARGE_INTEGER large_size;
wchar_t *path_wide = NULL;
if (path == NULL)
return MZ_PARAM_ERROR;
path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
if (path_wide == NULL)
return MZ_PARAM_ERROR;
#ifdef MZ_WINRT_API
handle = CreateFile2W(path_wide, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
#else
handle = CreateFileW(path_wide, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
#endif
mz_os_unicode_string_delete(&path_wide);
large_size.QuadPart = 0;
if (handle != INVALID_HANDLE_VALUE)
{
GetFileSizeEx(handle, &large_size);
CloseHandle(handle);
}
return large_size.QuadPart;
}
static void mz_os_file_to_unix_time(FILETIME file_time, time_t *unix_time)
{
uint64_t quad_file_time = 0;
quad_file_time = file_time.dwLowDateTime;
quad_file_time |= ((uint64_t)file_time.dwHighDateTime << 32);
*unix_time = (time_t)((quad_file_time - 116444736000000000LL) / 10000000);
}
static void mz_os_unix_to_file_time(time_t unix_time, FILETIME *file_time)
{
uint64_t quad_file_time = 0;
quad_file_time = ((uint64_t)unix_time * 10000000) + 116444736000000000LL;
file_time->dwHighDateTime = (quad_file_time >> 32);
file_time->dwLowDateTime = (uint32_t)(quad_file_time);
}
int32_t mz_os_get_file_date(const char *path, time_t *modified_date, time_t *accessed_date, time_t *creation_date)
{
WIN32_FIND_DATAW ff32;
HANDLE handle = NULL;
wchar_t *path_wide = NULL;
int32_t err = MZ_INTERNAL_ERROR;
if (path == NULL)
return MZ_PARAM_ERROR;
path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
if (path_wide == NULL)
return MZ_PARAM_ERROR;
handle = FindFirstFileW(path_wide, &ff32);
MZ_FREE(path_wide);
if (handle != INVALID_HANDLE_VALUE)
{
if (modified_date != NULL)
mz_os_file_to_unix_time(ff32.ftLastWriteTime, modified_date);
if (accessed_date != NULL)
mz_os_file_to_unix_time(ff32.ftLastAccessTime, accessed_date);
if (creation_date != NULL)
mz_os_file_to_unix_time(ff32.ftCreationTime, creation_date);
FindClose(handle);
err = MZ_OK;
}
return err;
}
int32_t mz_os_set_file_date(const char *path, time_t modified_date, time_t accessed_date, time_t creation_date)
{
HANDLE handle = NULL;
FILETIME ftm_creation, ftm_accessed, ftm_modified;
wchar_t *path_wide = NULL;
int32_t err = MZ_OK;
if (path == NULL)
return MZ_PARAM_ERROR;
path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
if (path_wide == NULL)
return MZ_PARAM_ERROR;
#ifdef MZ_WINRT_API
handle = CreateFile2W(path_wide, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
#else
handle = CreateFileW(path_wide, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
#endif
mz_os_unicode_string_delete(&path_wide);
if (handle != INVALID_HANDLE_VALUE)
{
GetFileTime(handle, &ftm_creation, &ftm_accessed, &ftm_modified);
if (modified_date != 0)
mz_os_unix_to_file_time(modified_date, &ftm_modified);
if (accessed_date != 0)
mz_os_unix_to_file_time(accessed_date, &ftm_accessed);
if (creation_date != 0)
mz_os_unix_to_file_time(creation_date, &ftm_creation);
if (SetFileTime(handle, &ftm_creation, &ftm_accessed, &ftm_modified) == 0)
err = MZ_INTERNAL_ERROR;
CloseHandle(handle);
}
return err;
}
int32_t mz_os_get_file_attribs(const char *path, uint32_t *attributes)
{
wchar_t *path_wide = NULL;
int32_t err = MZ_OK;
if (path == NULL || attributes == NULL)
return MZ_PARAM_ERROR;
path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
if (path_wide == NULL)
return MZ_PARAM_ERROR;
*attributes = GetFileAttributesW(path_wide);
mz_os_unicode_string_delete(&path_wide);
if (*attributes == INVALID_FILE_ATTRIBUTES)
err = MZ_INTERNAL_ERROR;
return err;
}
int32_t mz_os_set_file_attribs(const char *path, uint32_t attributes)
{
wchar_t *path_wide = NULL;
int32_t err = MZ_OK;
if (path == NULL)
return MZ_PARAM_ERROR;
path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
if (path_wide == NULL)
return MZ_PARAM_ERROR;
if (SetFileAttributesW(path_wide, attributes) == 0)
err = MZ_INTERNAL_ERROR;
mz_os_unicode_string_delete(&path_wide);
return err;
}
int32_t mz_os_make_dir(const char *path)
{
wchar_t *path_wide = NULL;
int32_t err = 0;
if (path == NULL)
return MZ_PARAM_ERROR;
path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
if (path_wide == NULL)
return MZ_PARAM_ERROR;
err = _wmkdir(path_wide);
mz_os_unicode_string_delete(&path_wide);
if (err != 0 && errno != EEXIST)
return MZ_INTERNAL_ERROR;
return MZ_OK;
}
DIR *mz_os_open_dir(const char *path)
{
WIN32_FIND_DATAW find_data;
DIR_int *dir_int = NULL;
wchar_t *path_wide = NULL;
char fixed_path[320];
void *handle = NULL;
if (path == NULL)
return NULL;
fixed_path[0] = 0;
mz_path_combine(fixed_path, path, sizeof(fixed_path));
mz_path_combine(fixed_path, "*", sizeof(fixed_path));
path_wide = mz_os_unicode_string_create(fixed_path, MZ_ENCODING_UTF8);
if (path_wide == NULL)
return NULL;
handle = FindFirstFileW(path_wide, &find_data);
mz_os_unicode_string_delete(&path_wide);
if (handle == INVALID_HANDLE_VALUE)
return NULL;
dir_int = (DIR_int *)MZ_ALLOC(sizeof(DIR_int));
dir_int->find_handle = handle;
dir_int->end = 0;
memcpy(&dir_int->find_data, &find_data, sizeof(dir_int->find_data));
return (DIR *)dir_int;
}
struct dirent* mz_os_read_dir(DIR *dir)
{
DIR_int *dir_int;
if (dir == NULL)
return NULL;
dir_int = (DIR_int *)dir;
if (dir_int->end)
return NULL;
WideCharToMultiByte(CP_UTF8, 0, dir_int->find_data.cFileName, -1,
dir_int->entry.d_name, sizeof(dir_int->entry.d_name), NULL, NULL);
if (FindNextFileW(dir_int->find_handle, &dir_int->find_data) == 0)
{
if (GetLastError() != ERROR_NO_MORE_FILES)
return NULL;
dir_int->end = 1;
}
return &dir_int->entry;
}
int32_t mz_os_close_dir(DIR *dir)
{
DIR_int *dir_int;
if (dir == NULL)
return MZ_PARAM_ERROR;
dir_int = (DIR_int *)dir;
if (dir_int->find_handle != INVALID_HANDLE_VALUE)
FindClose(dir_int->find_handle);
MZ_FREE(dir_int);
return MZ_OK;
}
int32_t mz_os_is_dir(const char *path)
{
wchar_t *path_wide = NULL;
uint32_t attribs = 0;
if (path == NULL)
return MZ_PARAM_ERROR;
path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
if (path_wide == NULL)
return MZ_PARAM_ERROR;
attribs = GetFileAttributesW(path_wide);
mz_os_unicode_string_delete(&path_wide);
if (attribs != 0xFFFFFFFF)
{
if (attribs & FILE_ATTRIBUTE_DIRECTORY)
return MZ_OK;
}
return MZ_EXIST_ERROR;
}
uint64_t mz_os_ms_time(void)
{
SYSTEMTIME system_time;
FILETIME file_time;
uint64_t quad_file_time = 0;
GetSystemTime(&system_time);
SystemTimeToFileTime(&system_time, &file_time);
quad_file_time = file_time.dwLowDateTime;
quad_file_time |= ((uint64_t)file_time.dwHighDateTime << 32);
return quad_file_time / 10000 - 11644473600000LL;
}