MINIZIP: use windows specific os support on windows
authorStefan Westerfeld <stefan@space.twc.de>
Fri, 7 Dec 2018 10:59:06 +0000 (11:59 +0100)
committerStefan Westerfeld <stefan@space.twc.de>
Fri, 7 Dec 2018 10:59:06 +0000 (11:59 +0100)
3rdparty/minizip/Makefile.am
3rdparty/minizip/mz_os_win32.c [new file with mode: 0644]
3rdparty/minizip/mz_strm_os_win32.c [new file with mode: 0644]

index 0e57045..03e759d 100644 (file)
@@ -3,7 +3,11 @@ noinst_LTLIBRARIES = libminizip.la
 MINIZIP_SRC = mz_crypt.c mz_os.c mz_strm.c mz_strm_buf.c mz_strm_mem.c mz_strm_split.c mz_zip.c mz_zip_rw.c mz_strm_zlib.c
 MINIZIP_HDRS = mz.h mz_os.h mz_crypt.h mz_strm.h mz_strm_buf.h mz_strm_mem.h mz_strm_split.h mz_strm_os.h mz_zip.h mz_zip_rw.h mz_strm_zlib.h
 
-MINIZIP_SRC += mz_os_posix.c mz_strm_os_posix.c
+if COND_WINDOWS
+  MINIZIP_SRC += mz_os_win32.c mz_strm_os_win32.c
+else
+  MINIZIP_SRC += mz_os_posix.c mz_strm_os_posix.c
+endif
 
 libminizip_la_SOURCES = $(MINIZIP_SRC) $(MINIZIP_HDRS)
 libminizip_la_CFLAGS = $(AM_CFLAGS) -DHAVE_STDINT_H -DMZ_ZIP_NO_ENCRYPTION -DHAVE_ZLIB -D_POSIX_C_SOURCE=200112L
diff --git a/3rdparty/minizip/mz_os_win32.c b/3rdparty/minizip/mz_os_win32.c
new file mode 100644 (file)
index 0000000..a852730
--- /dev/null
@@ -0,0 +1,481 @@
+/* mz_os_win32.c -- System functions for Windows
+   Version 2.8.1, December 1, 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 "mz.h"
+#include "mz_os.h"
+#include "mz_strm_os.h"
+
+#include <windows.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));
+    if (string_wide == NULL)
+        return NULL;
+
+    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 = 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 (CreateDirectoryW(path_wide, NULL) == 0)
+    {
+        if (GetLastError() != ERROR_ALREADY_EXISTS)
+            err = MZ_INTERNAL_ERROR;
+    }
+
+    mz_os_unicode_string_delete(&path_wide);
+
+    return err;
+}
+
+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));
+    if (dir_int == NULL)
+        return NULL;
+    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;
+}
diff --git a/3rdparty/minizip/mz_strm_os_win32.c b/3rdparty/minizip/mz_strm_os_win32.c
new file mode 100644 (file)
index 0000000..76c22c7
--- /dev/null
@@ -0,0 +1,319 @@
+/* mz_strm_win32.c -- Stream for filesystem access for windows
+   Version 2.8.1, December 1, 2018
+   part of the MiniZip project
+
+   Copyright (C) 2010-2018 Nathan Moinvaziri
+     https://github.com/nmoinvaz/minizip
+   Copyright (C) 2009-2010 Mathias Svensson
+     Modifications for Zip64 support
+     http://result42.com
+   Copyright (C) 1998-2010 Gilles Vollant
+     https://www.winimage.com/zLibDll/minizip.html
+
+   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 "mz.h"
+#include "mz_os.h"
+#include "mz_strm.h"
+#include "mz_strm_os.h"
+
+#include <windows.h>
+
+/***************************************************************************/
+
+#ifndef INVALID_HANDLE_VALUE
+#  define INVALID_HANDLE_VALUE (0xFFFFFFFF)
+#endif
+
+#ifndef INVALID_SET_FILE_POINTER
+#  define INVALID_SET_FILE_POINTER ((DWORD)-1)
+#endif
+
+#if defined(WINAPI_FAMILY_ONE_PARTITION) && !defined(MZ_WINRT_API)
+#  if WINAPI_FAMILY_ONE_PARTITION(WINAPI_FAMILY, WINAPI_PARTITION_APP)
+#    define MZ_WINRT_API 1
+#  endif
+#endif
+
+/***************************************************************************/
+
+static mz_stream_vtbl mz_stream_os_vtbl = {
+    mz_stream_os_open,
+    mz_stream_os_is_open,
+    mz_stream_os_read,
+    mz_stream_os_write,
+    mz_stream_os_tell,
+    mz_stream_os_seek,
+    mz_stream_os_close,
+    mz_stream_os_error,
+    mz_stream_os_create,
+    mz_stream_os_delete,
+    NULL,
+    NULL
+};
+
+/***************************************************************************/
+
+typedef struct mz_stream_win32_s
+{
+    mz_stream       stream;
+    HANDLE          handle;
+    int32_t         error;
+} mz_stream_win32;
+
+/***************************************************************************/
+
+#if 0
+#  define mz_stream_os_print printf
+#else
+#  define mz_stream_os_print(fmt,...)
+#endif
+
+/***************************************************************************/
+
+int32_t mz_stream_os_open(void *stream, const char *path, int32_t mode)
+{
+    mz_stream_win32 *win32 = (mz_stream_win32 *)stream;
+    uint32_t desired_access = 0;
+    uint32_t creation_disposition = 0;
+    uint32_t share_mode = FILE_SHARE_READ;
+    uint32_t flags_attribs = FILE_ATTRIBUTE_NORMAL;
+    wchar_t *path_wide = NULL;
+
+
+    if (path == NULL)
+        return MZ_PARAM_ERROR;
+
+    /* Some use cases require write sharing as well */
+    share_mode |= FILE_SHARE_WRITE;
+
+    if ((mode & MZ_OPEN_MODE_READWRITE) == MZ_OPEN_MODE_READ)
+    {
+        desired_access = GENERIC_READ;
+        creation_disposition = OPEN_EXISTING;
+    }
+    else if (mode & MZ_OPEN_MODE_APPEND)
+    {
+        desired_access = GENERIC_WRITE | GENERIC_READ;
+        creation_disposition = OPEN_EXISTING;
+    }
+    else if (mode & MZ_OPEN_MODE_CREATE)
+    {
+        desired_access = GENERIC_WRITE | GENERIC_READ;
+        creation_disposition = CREATE_ALWAYS;
+    }
+    else
+    {
+        return MZ_PARAM_ERROR;
+    }
+
+    mz_stream_os_print("Win32 - Open - %s (mode %"PRId32")\n", path);
+
+    path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
+    if (path_wide == NULL)
+        return MZ_PARAM_ERROR;
+
+#ifdef MZ_WINRT_API
+    win32->handle = CreateFile2W(path_wide, desired_access, share_mode, 
+        creation_disposition, NULL);
+#else
+    win32->handle = CreateFileW(path_wide, desired_access, share_mode, NULL, 
+        creation_disposition, flags_attribs, NULL);
+#endif
+
+    mz_os_unicode_string_delete(&path_wide);
+
+    if (mz_stream_os_is_open(stream) != MZ_OK)
+    {
+        win32->error = GetLastError();
+        return MZ_OPEN_ERROR;
+    }
+
+    if (mode & MZ_OPEN_MODE_APPEND)
+        return mz_stream_os_seek(stream, 0, MZ_SEEK_END);
+
+    return MZ_OK;
+}
+
+int32_t mz_stream_os_is_open(void *stream)
+{
+    mz_stream_win32 *win32 = (mz_stream_win32 *)stream;
+    if (win32->handle == NULL || win32->handle == INVALID_HANDLE_VALUE)
+        return MZ_OPEN_ERROR;
+    return MZ_OK;
+}
+
+int32_t mz_stream_os_read(void *stream, void *buf, int32_t size)
+{
+    mz_stream_win32 *win32 = (mz_stream_win32 *)stream;
+    uint32_t read = 0;
+
+    if (mz_stream_os_is_open(stream) != MZ_OK)
+        return MZ_OPEN_ERROR;
+
+    if (!ReadFile(win32->handle, buf, size, (DWORD *)&read, NULL))
+    {
+        win32->error = GetLastError();
+        if (win32->error == ERROR_HANDLE_EOF)
+            win32->error = 0;
+    }
+
+    mz_stream_os_print("Win32 - Read - %"PRId32"\n", read);
+
+    return read;
+}
+
+int32_t mz_stream_os_write(void *stream, const void *buf, int32_t size)
+{
+    mz_stream_win32 *win32 = (mz_stream_win32 *)stream;
+    int32_t written = 0;
+
+    if (mz_stream_os_is_open(stream) != MZ_OK)
+        return MZ_OPEN_ERROR;
+
+    if (!WriteFile(win32->handle, buf, size, (DWORD *)&written, NULL))
+    {
+        win32->error = GetLastError();
+        if (win32->error == ERROR_HANDLE_EOF)
+            win32->error = 0;
+    }
+
+    mz_stream_os_print("Win32 - Write - %"PRId32"\n", written);
+
+    return written;
+}
+
+static int32_t mz_stream_os_seekinternal(HANDLE handle, LARGE_INTEGER large_pos, 
+    LARGE_INTEGER *new_pos, uint32_t move_method)
+{
+#ifdef MZ_WINRT_API
+    return SetFilePointerEx(handle, pos, newPos, dwMoveMethod);
+#else
+    LONG high_part = 0;
+    uint32_t pos = 0;
+
+    high_part = large_pos.HighPart;
+    pos = SetFilePointer(handle, large_pos.LowPart, &high_part, move_method);
+
+    if ((pos == INVALID_SET_FILE_POINTER) && (GetLastError() != NO_ERROR))
+        return MZ_SEEK_ERROR;
+
+    if (new_pos != NULL)
+    {
+        new_pos->LowPart = pos;
+        new_pos->HighPart = high_part;
+    }
+
+    return MZ_OK;
+#endif
+}
+
+int64_t mz_stream_os_tell(void *stream)
+{
+    mz_stream_win32 *win32 = (mz_stream_win32 *)stream;
+    LARGE_INTEGER large_pos;
+
+    if (mz_stream_os_is_open(stream) != MZ_OK)
+        return MZ_OPEN_ERROR;
+
+    large_pos.QuadPart = 0;
+
+    if (mz_stream_os_seekinternal(win32->handle, large_pos, &large_pos, FILE_CURRENT) != MZ_OK)
+        win32->error = GetLastError();
+
+    mz_stream_os_print("Win32 - Tell - %"PRId64"\n", large_pos.QuadPart);
+
+    return large_pos.QuadPart;
+}
+
+int32_t mz_stream_os_seek(void *stream, int64_t offset, int32_t origin)
+{
+    mz_stream_win32 *win32 = (mz_stream_win32 *)stream;
+    uint32_t move_method = 0xFFFFFFFF;
+    int32_t err = MZ_OK;
+    LARGE_INTEGER large_pos;
+
+
+    if (mz_stream_os_is_open(stream) != MZ_OK)
+        return MZ_OPEN_ERROR;
+
+    switch (origin)
+    {
+        case MZ_SEEK_CUR:
+            move_method = FILE_CURRENT;
+            break;
+        case MZ_SEEK_END:
+            move_method = FILE_END;
+            break;
+        case MZ_SEEK_SET:
+            move_method = FILE_BEGIN;
+            break;
+        default:
+            return MZ_SEEK_ERROR;
+    }
+
+    mz_stream_os_print("Win32 - Seek - %"PRId64" (origin %"PRId32")\n", offset, origin);
+
+    large_pos.QuadPart = offset;
+
+    err = mz_stream_os_seekinternal(win32->handle, large_pos, NULL, move_method);
+    if (err != MZ_OK)
+    {
+        win32->error = GetLastError();
+        return err;
+    }
+
+    return MZ_OK;
+}
+
+int32_t mz_stream_os_close(void *stream)
+{
+    mz_stream_win32 *win32 = (mz_stream_win32 *)stream;
+
+    if (win32->handle != NULL)
+        CloseHandle(win32->handle);
+    mz_stream_os_print("Win32 - Close\n");
+    win32->handle = NULL;
+    return MZ_OK;
+}
+
+int32_t mz_stream_os_error(void *stream)
+{
+    mz_stream_win32 *win32 = (mz_stream_win32 *)stream;
+    return win32->error;
+}
+
+void *mz_stream_os_create(void **stream)
+{
+    mz_stream_win32 *win32 = NULL;
+
+    win32 = (mz_stream_win32 *)MZ_ALLOC(sizeof(mz_stream_win32));
+    if (win32 != NULL)
+    {
+        memset(win32, 0, sizeof(mz_stream_win32));
+        win32->stream.vtbl = &mz_stream_os_vtbl;
+    }
+    if (stream != NULL)
+        *stream = win32;
+
+    return win32;
+}
+
+void mz_stream_os_delete(void **stream)
+{
+    mz_stream_win32 *win32 = NULL;
+    if (stream == NULL)
+        return;
+    win32 = (mz_stream_win32 *)*stream;
+    if (win32 != NULL)
+        MZ_FREE(win32);
+    *stream = NULL;
+}
+
+void *mz_stream_os_get_interface(void)
+{
+    return (void *)&mz_stream_os_vtbl;
+}