Convert all Windows file sources to new framework.

Not tested, not yet included in build.
diff --git a/developer-xcode/libzip.xcodeproj/project.pbxproj b/developer-xcode/libzip.xcodeproj/project.pbxproj
index 2fd9fe7..8ef4e86 100644
--- a/developer-xcode/libzip.xcodeproj/project.pbxproj
+++ b/developer-xcode/libzip.xcodeproj/project.pbxproj
@@ -635,6 +635,9 @@
 		4B93995F24640B1700AEBDA4 /* zip_source_file_win32.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = zip_source_file_win32.h; sourceTree = "<group>"; };
 		4B93996024640B1700AEBDA4 /* zip_source_file_win32.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = zip_source_file_win32.c; sourceTree = "<group>"; };
 		4B93996124641D5700AEBDA4 /* zip_source_file_win32_ansi.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = zip_source_file_win32_ansi.c; sourceTree = "<group>"; };
+		4B93996224643F5700AEBDA4 /* zip_source_file_win32_utf8.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = zip_source_file_win32_utf8.c; sourceTree = "<group>"; };
+		4B9399632464401300AEBDA4 /* zip_source_file_win32_utf16.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip_source_file_win32_utf16.c; sourceTree = "<group>"; };
+		4B93996424644E7E00AEBDA4 /* zip_source_file_win32_write.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = zip_source_file_win32_write.c; sourceTree = "<group>"; };
 		4B97204D188EBE85002FAFAD /* zip_file_get_external_attributes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip_file_get_external_attributes.c; sourceTree = "<group>"; };
 		4B97204E188EBE85002FAFAD /* zip_file_set_external_attributes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip_file_set_external_attributes.c; sourceTree = "<group>"; };
 		4BACD57715BC2AEF00920691 /* add_from_filep.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = add_from_filep.c; path = ../regress/add_from_filep.c; sourceTree = "<group>"; };
@@ -1496,6 +1499,9 @@
 				4B93995824631B3E00AEBDA4 /* zip_source_file_stdio.h */,
 				4B93996024640B1700AEBDA4 /* zip_source_file_win32.c */,
 				4B93996124641D5700AEBDA4 /* zip_source_file_win32_ansi.c */,
+				4B93996424644E7E00AEBDA4 /* zip_source_file_win32_write.c */,
+				4B9399632464401300AEBDA4 /* zip_source_file_win32_utf16.c */,
+				4B93996224643F5700AEBDA4 /* zip_source_file_win32_utf8.c */,
 				4B93995F24640B1700AEBDA4 /* zip_source_file_win32.h */,
 				4B93995924631B3E00AEBDA4 /* zip_source_file.h */,
 				4BDC722F15B1B25E00236D3C /* zip_source_free.c */,
diff --git a/lib/zip_source_file_win32.c b/lib/zip_source_file_win32.c
index 8e55dd7..dbb21da 100644
--- a/lib/zip_source_file_win32.c
+++ b/lib/zip_source_file_win32.c
@@ -33,7 +33,7 @@
 
 #include "zip_source_file_win32.h"
 
-zip_source_file_operations_t ops_win32_read = {
+static zip_source_file_operations_t ops_win32_read = {
     _zip_win32_op_close,
     NULL,
     NULL,
@@ -67,13 +67,13 @@
         return NULL;
     }
 
-    return zip_source_file_common_new(NULL, h, start, len, NULL, ops_win32_read, &za->error);
+    return zip_source_file_common_new(NULL, h, start, len, NULL, ops_win32_read, NULL, error);
 }
 
 
 void
 zip_win32_op_close(zip_source_file_context_t *ctx) {
-    CloseHandle(ctx->h);
+    CloseHandle((HANDLE)ctx->f);
 }
 
 
@@ -129,7 +129,7 @@
 zip_int64_t
 _zip_win32_op_write(zip_source_file_context_t *ctx, const void *data, zip_uint64_t len) {
     DWORD ret;
-    if (!WriteFile(ctx->hout, data, (DWORD)len, &ret, NULL) || ret != len) {
+    if (!WriteFile((HANDLE)ctx->fout, data, (DWORD)len, &ret, NULL) || ret != len) {
         zip_error_set(&ctx->error, ZIP_ER_WRITE, _zip_win32_error_to_errno(GetLastError()));
         return -1;
     }
@@ -143,7 +143,7 @@
     LARGE_INTEGER zero;
     LARGE_INTEGER new_offset;
     
-    if (!SetFilePointerEx(ctx->h, zero, &new_offset, FILE_CURRENT)) {
+    if (!SetFilePointerEx((HANDLE)ctx->f, zero, &new_offset, FILE_CURRENT)) {
         zip_error_set(&ctx->error, ZIP_ER_SEEK, _zip_win32_error_to_errno(GetLastError()));
         return -1;
     }
@@ -175,6 +175,64 @@
     }
 }
 
+zip_int64_t
+_zip_win32_create_temp_output(zip_source_file_context_t *ctx, char *tmpname, size_t tmpname_size, _zip_win32_open_t open, _zip_win32_mktmepname_t mktempname) {
+    /* Windows has GetTempFileName(), but it closes the file after
+     creation, leaving it open to a horrible race condition. So
+     we reinvent the wheel.
+     */
+     
+    int i;
+    HANDLE th = INVALID_HANDLE_VALUE;
+    void *temp = NULL;
+    PSECURITY_DESCRIPTOR psd = NULL;
+    PSECURITY_ATTRIBUTES psa = NULL;
+    SECURITY_ATTRIBUTES sa;
+    SECURITY_INFORMATION si;
+    DWORD success;
+    PACL dacl = NULL;
+
+    /*
+     Read the DACL from the original file, so we can copy it to the temp file.
+     If there is no original file, or if we can't read the DACL, we'll use the
+     default security descriptor.
+     */
+     
+    if ((HANDLE)ctx->f != INVALID_HANDLE_VALUE && GetFileType((HANDLE)ctx->f) == FILE_TYPE_DISK) {
+        si = DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION;
+        success = GetSecurityInfo(ctx->h, SE_FILE_OBJECT, si, NULL, NULL, &dacl, NULL, &psd);
+        if (success == ERROR_SUCCESS) {
+            sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+            sa.bInheritHandle = FALSE;
+            sa.lpSecurityDescriptor = psd;
+            psa = &sa;
+        }
+    }
+
+    #ifndef MS_UWP
+        value = GetTickCount();
+    #else
+        value = (zip_uint32_t)GetTickCount64();
+    #endif
+
+    for (i = 0; i < 1024 && th == INVALID_HANDLE_VALUE; i++) {
+        mktempname(tmpname, tmpname_size, value + i);
+        th = open(ctx, tmpname, true, psa);
+
+        if (th == INVALID_HANDLE_VALUE && GetLastError() != ERROR_FILE_EXISTS)
+            break;
+    }
+
+    LocalFree(psd);
+
+    if (th == INVALID_HANDLE_VALUE) {
+        zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, _zip_win32_error_to_errno(GetLastError()));
+        return INVALID_HANDLE_VALUE;
+    }
+
+    return th;
+}
+
 bool
 _zip_stat_win32(zip_source_file_context_t *ctx, zip_source_file_stat_t *st, HANDLE h) {
     FILETIME mtimeft;
diff --git a/lib/zip_source_file_win32.h b/lib/zip_source_file_win32.h
index 96b76db..63aa48e 100644
--- a/lib/zip_source_file_win32.h
+++ b/lib/zip_source_file_win32.h
@@ -34,6 +34,28 @@
   IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
+/* 0x0501 => Windows XP; needs to be at least this value because of GetFileSizeEx */
+#if !defined(MS_UWP) && !defined(_WIN32_WINNT)
+#define _WIN32_WINNT 0x0501
+#endif
+
+#include <windows.h>
+
+struct zip_source_file_win32_write_operations {
+    char *(*allocate_tempname)(const char *name, size_t extra_chars),
+    HANDLE (*create_file)(const char *name, DWORD access, DWORD share_mode, PSECURITY_ATTRIBUTES security_attributes, DWORD creation_disposition, DWORD file_attributes, HANDLE template_file),
+    bool (*delete_file)(const char *name),
+    DWORD (*get_file_attributes)(const char *name),
+    void (*make_tempname)(char *buf, size_t len, const char *name, int i),
+    bool (*move_file)(const char *from, const char *to),
+    bool (*set_file_attributes)(const char *name, DWORD attributes),
+    char *(*strdup)(const char *string)
+};
+
+typedef struct zip_source_file_win32_write_operations zip_source_file_win32_write_operations_t;
+
+zip_source_file_operations_t zip_source_file_win32_write_operations;
+
 zip_int64_t _zip_win32_op_read(zip_source_file_context_t *ctx, void *buf, zip_uint64_t len);
 bool _zip_win32_op_seek(zip_source_file_context_t *ctx, void *f, zip_int64_t offset, int whence);
 zip_int64_t _zip_win32_op_tell(zip_source_file_context_t *ctx, void *f);
diff --git a/lib/zip_source_file_win32_ansi.c b/lib/zip_source_file_win32_ansi.c
index 4017428..7dcf15c 100644
--- a/lib/zip_source_file_win32_ansi.c
+++ b/lib/zip_source_file_win32_ansi.c
@@ -1,5 +1,5 @@
 /*
-  zip_source_file_win32_ansi.c -- read/write Windows ANSI file source implementation
+  zip_source_file_win32_ansi.c -- Windows file source write operations for ANSI interface
   Copyright (C) 1999-2020 Dieter Baron and Thomas Klausner
 
   This file is part of libzip, a library to manipulate ZIP archives.
@@ -33,138 +33,47 @@
 
 #include "zip_source_file_win32.h"
 
-static zip_int64_t _zip_win32_ansi_op_commit_write(zip_source_file_context_t *ctx);
-static zip_int64_t _zip_win32_ansi_op_create_temp_output(zip_source_file_context_t *ctx);
-static zip_int64_t _zip_win32_ansi_op_commit_write(zip_source_file_context_t *ctx);
-static bool _zip_win32_ansi_op_open(zip_source_file_context_t *ctx);
-static zip_int64_t _zip_win32_ansi_op_remove(zip_source_file_context_t *ctx);
-static void _zip_win32_ansi_op_rollback_write(zip_source_file_context_t *ctx);
-static bool _zip_win32_ansi_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st);
+static char *ansi_allocate_tempname(const char *name, size_t extra_chars);
+static void ansi_make_tempname(char *buf, size_t len, const char *name, int i);
 
-static HANDLE win32_ansi_open(zip_source_file_context_t *ctx);
+zip_source_file_win32_write_operations_t ops_ansi {
+    ansi_allocate_tempname,
+    CreateFileA,
+    DeleteFileA,
+    GetFileAttributesA,
+    ansi_make_tempname,
+    MoveFileA,
+    SetFileAttributesA,
+    strdup
+};
 
-zip_source_file_operations_t ops_win32_read = {
-    _zip_win32_op_close,
-    _zip_win32_ansi_op_commit_write,
-    _zip_win32_ansi_op_create_temp_output,
-    NULL,
-    _zip_win32_ansi_op_open,
-    _zip_win32_op_read,
-    _zip_win32_ansi_op_remove,
-    _zip_win32_ansi_op_rollback_write,
-    _zip_win32_op_seek,
-    _zip_win32_ansi_op_stat,
-    strdup,
-    _zip_win32_op_tell,
-    _zip_win32_op_write
-}
+ZIP_EXTERN zip_source_t *
+zip_source_win32a(zip_t *za, const char *fname, zip_uint64_t start, zip_int64_t len) {
+    if (za == NULL)
+    return NULL;
 
-static zip_int64_t
-_zip_win32_ansi_op_commit_write(zip_source_file_context_t *ctx) {
-    if (!CloseHandle((HANDLE)ctx->fout)) {
-        zip_error_set(&ctx->error, ZIP_ER_WRITE, _zip_win32_error_to_errno(GetLastError()));
-        return -1
-    }
-    
-    DWORD attributes = GetFileAttributesA(ctx->tmpname);
-    if (attributes == INVALID_FILE_ATTRIBUTES) {
-        zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError()));
-        return -1;
-    }
-
-    if (attributes & FILE_ATTRIBUTE_TEMPORARY) {
-        if (!SetFileAttributesA(ctx->tmpname, attributes & ~FILE_ATTRIBUTE_TEMPORARY)) {
-            zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError()));
-            return -1;
-        }
-    }
-
-    if (!MoveFileExA(ctx->tmpname, ctx->fname, MOVEFILE_REPLACE_EXISTING)) {
-        zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError()));
-        return -1;
-    }
-
-    return 0;
-}
-
-static zip_int64_t
-_zip_win32_ansi_op_create_temp_output(zip_source_file_context_t *ctx) {
-    size_t len;
-    void *temp;
-    HANDLE h;
-
-    len = strlen(ctx->fname) + 10;
-    if ((temp = malloc(len)) == NULL) {
-        zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
-        return false;
-    }
-    if (sprintf((char *)*temp, "%s.%08x", (const char *)ctx->fname, value) != len - 1) {
-        return -1;
-    }
-    
-    h = CreateFileA((const char *)*temp, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, sa, CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_TEMPORARY, NULL);
-    if (h == INVALID_HANDLE_VALUE) {
-        free(temp);
-        return -1;
-    }
-    
-    ctx->tmpname = temp;
-    ctx->fout = h;
-    
-    return 0;
+    return zip_source_win32a_create(fname, start, len, &za->error);
 }
 
 
-
-static bool
-_zip_win32_ansi_op_open(zip_source_file_context_t *ctx) {
-    HANDLE h = win32_ansi_open(ctx);
-    
-    if (h == INVALID_HANDLE_VALUE) {
-        return false;
+ZIP_EXTERN zip_source_t *
+zip_source_win32a_create(const char *fname, zip_uint64_t start, zip_int64_t length, zip_error_t *error) {
+    if (fname == NULL || length < -1) {
+    zip_error_set(error, ZIP_ER_INVAL, 0);
+    return NULL;
     }
-    
-    ctx->f = h;
-    return true;
+
+    return zip_source_file_common_new(fname, NULL, start, length, NULL, &zip_source_file_win32_write_operations, &ops_ansi, error);
 }
 
 
-static zip_int64_t
-_zip_win32_ansi_op_remove(zip_source_file_context_t *ctx) {
-    DeleteFileA((const char *)fname);
-    /* TODO: propagate errors */
-    return 0;
+static char *
+ansi_allocate_tempname(const char *name, size_t extra_chars) {
+    return (char *)malloc(strlen(name) + extra_chars);
 }
 
 
 static void
-_zip_win32_ansi_op_rollback_write(zip_source_file_context_t *ctx) {
-    if (ctx->fout) {
-        CloseHandle((HANDLE)ctx->fout);
-    }
-    DeleteFileA(ctx->tmpname);
-}
-
-
-static bool
-_zip_win32_ansi_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st) {
-    HANDLE h = win32_ansi_open(ctx);
-    
-    if (h == INVALID_HANDLE_VALUE) {
-        return false;
-    }
-
-    return _zip_stat_win32(ctx, st, h);
-}
-
-
-static HANDLE
-win32_ansi_open(zip_source_file_context_t *ctx) {
-    HANDLE h = CreateFileA(ctx->fname, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-    
-    if (h == INVALID_HANDLE_VALUE) {
-        zip_error_set(&ctx->error, ZIP_ER_OPEN, _zip_win32_error_to_errno(GetLastError()));
-    }
-
-    return h;
+ansi_make_tempname(char *buf, size_t len, const char *name, int i) {
+    snprintf(buf, len, "%s.%d", name, i);
 }
diff --git a/lib/zip_source_file_win32_utf16.c b/lib/zip_source_file_win32_utf16.c
new file mode 100644
index 0000000..34aa923
--- /dev/null
+++ b/lib/zip_source_file_win32_utf16.c
@@ -0,0 +1,123 @@
+/*
+  zip_source_file_win32_utf16.c -- Windows file source write operations for UTF-16 interface
+  Copyright (C) 1999-2020 Dieter Baron and Thomas Klausner
+
+  This file is part of libzip, a library to manipulate ZIP archives.
+  The authors can be contacted at <libzip@nih.at>
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  1. Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in
+  the documentation and/or other materials provided with the
+  distribution.
+  3. The names of the authors may not be used to endorse or promote
+  products derived from this software without specific prior
+  written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "zip_source_file_win32.h"
+
+static char *utf16_allocate_tempname(const char *name, size_t extra_chars);
+static HANDLE utf16_create_file(const char *name, DWORD access, DWORD share_mode, PSECURITY_ATTRIBUTES security_attributes, DWORD creation_disposition, DWORD file_attributes, HANDLE template_file);
+static bool utf16_delete_file(const char *name);
+static DWORD utf16_get_file_attributes(const char *name);
+static void utf16_make_tempname(char *buf, size_t len, const char *name, int i);
+static bool utf16_move_file(const char *from, const char *to);
+static bool utf16_set_file_attributes(const char *name, DWORD attributes);
+static char *utf16_strdup(const char *string);
+
+zip_source_file_win32_write_operations_t ops_utf16 {
+    utf16_allocate_tempname,
+    utf16_create_file,
+    utf16_delete_file,
+    utf16_get_file_attributes,
+    utf16_make_tempname,
+    utf16_move_file,
+    utf16_set_file_attributes,
+    utf16_strdup
+};
+
+ZIP_EXTERN zip_source_t *
+zip_source_win32w(zip_t *za, const char *fname, zip_uint64_t start, zip_int64_t len) {
+    if (za == NULL)
+    return NULL;
+
+    return zip_source_win32w_create(fname, start, len, &za->error);
+}
+
+
+ZIP_EXTERN zip_source_t *
+zip_source_win32w_create(const char *fname, zip_uint64_t start, zip_int64_t length, zip_error_t *error) {
+    if (fname == NULL || length < -1) {
+    zip_error_set(error, ZIP_ER_INVAL, 0);
+    return NULL;
+    }
+
+    return zip_source_file_common_new(fname, NULL, start, length, NULL, &zip_source_file_win32_write_operations, &ops_utf16, error);
+}
+
+
+static char *
+utf16_allocate_tempname(const char *name, size_t extra_chars) {
+    return (char *)malloc((wcslen(name) + extra_chars) * sizeof(wchar_t));
+}
+
+
+HANDLE utf16_create_file(const char *name, DWORD access, DWORD share_mode, PSECURITY_ATTRIBUTES security_attributes, DWORD creation_disposition, DWORD file_attributes, HANDLE template_file) {
+#ifdef MS_UWP
+    CREATEFILE2_EXTENDED_PARAMETERS extParams = {0};
+    extParams.dwFileAttributes = file_attributes;
+        extParams.dwFileFlags = FILE_FLAG_RANDOM_ACCESS;
+        extParams.dwSecurityQosFlags = SECURITY_ANONYMOUS;
+        extParams.dwSize = sizeof(extParams);
+        extParams.hTemplateFile = NULL;
+        extParams.lpSecurityAttributes = security_attributes;
+
+        return CreateFile2((const wchar_t *)name, access, share_mode, creation_disposition, &extParams);
+    #else
+        return CreateFileW((const wchar_t *)name, access, share_mode, security_attributes, creation_disposition, file_attributes, NULL);
+    #endif
+}
+
+
+bool utf16_delete_file(const char *name) {
+    return DeleteFileW((const wchar_t *)name);
+}
+
+
+DWORD utf16_get_file_attributes(const char *name) {
+    return GetFileAttributesW((const wchar_t *)name)
+}
+
+
+static void
+utf16_make_tempname(char *buf, size_t len, const char *name, int i) {
+    _snwprintf((wchar_t *)*buf, len, L"%s.%08x", (const wchar_t *)name, i);
+}
+
+static bool
+utf16_set_file_attributes(const char *name, DWORD attributes) {
+    return SetFileAttributesW((const wchar_t *)name, attributes);
+}
+
+
+static char *
+utf16_strdup(const char *string) {
+    return (char *)_wcsdup((const wchar_t *)string);
+}
diff --git a/lib/zip_source_file_win32_utf8.c b/lib/zip_source_file_win32_utf8.c
new file mode 100644
index 0000000..eaeacdc
--- /dev/null
+++ b/lib/zip_source_file_win32_utf8.c
@@ -0,0 +1,73 @@
+/*
+  zip_source_file_win32_ansi.c -- read/write Windows UTF-8 file source implementation
+  Copyright (C) 1999-2020 Dieter Baron and Thomas Klausner
+
+  This file is part of libzip, a library to manipulate ZIP archives.
+  The authors can be contacted at <libzip@nih.at>
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  1. Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in
+  the documentation and/or other materials provided with the
+  distribution.
+  3. The names of the authors may not be used to endorse or promote
+  products derived from this software without specific prior
+  written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "zip_source_file_win32.h"
+
+ZIP_EXTERN zip_source_t *
+zip_source_file(zip_t *za, const char *fname, zip_uint64_t start, zip_int64_t len) {
+    if (za == NULL) {
+        return NULL;
+    }
+    
+    return zip_source_file_create(fname, start, len, &za->error);
+}
+
+
+ZIP_EXTERN zip_source_t *
+zip_source_file_create(const char *fname, zip_uint64_t start, zip_int64_t length, zip_error_t *error) {
+    int size;
+    wchar_t *wfname;
+    zip_source_t *source;
+
+    if (fname == NULL || length < -1) {
+        zip_error_set(error, ZIP_ER_INVAL, 0);
+        return NULL;
+    }
+
+    /* Convert fname from UTF-8 to Windows-friendly UTF-16. */
+    size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, fname, -1, NULL, 0);
+    if (size == 0) {
+        zip_error_set(error, ZIP_ER_INVAL, 0);
+        return NULL;
+    }
+    if ((wfname = (wchar_t *)malloc(sizeof(wchar_t) * size)) == NULL) {
+        zip_error_set(error, ZIP_ER_MEMORY, 0);
+        return NULL;
+    }
+    MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, fname, -1, wfname, size);
+
+    source = zip_source_win32w_create(wfname, start, length, error);
+    
+    free(wfname);
+    return source;
+}
diff --git a/lib/zip_source_file_win32_write.c b/lib/zip_source_file_win32_write.c
new file mode 100644
index 0000000..640860f
--- /dev/null
+++ b/lib/zip_source_file_win32_write.c
@@ -0,0 +1,225 @@
+/*
+  zip_source_file_win32_write.c -- read/write Windows file source implementation
+  Copyright (C) 1999-2020 Dieter Baron and Thomas Klausner
+
+  This file is part of libzip, a library to manipulate ZIP archives.
+  The authors can be contacted at <libzip@nih.at>
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  1. Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in
+  the documentation and/or other materials provided with the
+  distribution.
+  3. The names of the authors may not be used to endorse or promote
+  products derived from this software without specific prior
+  written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "zip_source_file_win32.h"
+
+static zip_int64_t _zip_win32_write_op_commit_write(zip_source_file_context_t *ctx);
+static zip_int64_t _zip_win32_write_op_create_temp_output(zip_source_file_context_t *ctx);
+static zip_int64_t _zip_win32_write_op_commit_write(zip_source_file_context_t *ctx);
+static bool _zip_win32_write_op_open(zip_source_file_context_t *ctx);
+static zip_int64_t _zip_win32_write_op_remove(zip_source_file_context_t *ctx);
+static void _zip_win32_write_op_rollback_write(zip_source_file_context_t *ctx);
+static bool _zip_win32_write_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st);
+
+static HANDLE win32_write_open(zip_source_file_context_t *ctx);
+
+/* clang-format off */
+zip_source_file_operations_t zip_source_file_win32_write_operations = {
+    _zip_win32_op_close,
+    _zip_win32_write_op_commit_write,
+    _zip_win32_write_op_create_temp_output,
+    NULL,
+    _zip_win32_write_op_open,
+    _zip_win32_op_read,
+    _zip_win32_write_op_remove,
+    _zip_win32_write_op_rollback_write,
+    _zip_win32_op_seek,
+    _zip_win32_write_op_stat,
+    strdup,
+    _zip_win32_op_tell,
+    _zip_win32_op_write
+};
+/* clang-format on */
+
+static zip_int64_t
+_zip_win32_write_op_commit_write(zip_source_file_context_t *ctx) {
+    zip_source_file_win32_write_operations_t *write_ops = (zip_source_file_win32_write_operations_t *)ctx->ops_userdata;
+    
+    if (!CloseHandle((HANDLE)ctx->fout)) {
+        zip_error_set(&ctx->error, ZIP_ER_WRITE, _zip_win32_error_to_errno(GetLastError()));
+        return -1
+    }
+    
+    DWORD attributes = write_ops->get_file_attributes(ctx->tmpname);
+    if (attributes == INVALID_FILE_ATTRIBUTES) {
+        zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError()));
+        return -1;
+    }
+
+    if (attributes & FILE_ATTRIBUTE_TEMPORARY) {
+        if (!write_ops->set_file_attributes(ctx->tmpname, attributes & ~FILE_ATTRIBUTE_TEMPORARY)) {
+            zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError()));
+            return -1;
+        }
+    }
+
+    if (!write_ops->move_file(ctx->tmpname, ctx->fname, MOVEFILE_REPLACE_EXISTING)) {
+        zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError()));
+        return -1;
+    }
+
+    return 0;
+}
+
+static zip_int64_t
+_zip_win32_write_op_create_temp_output(zip_source_file_context_t *ctx) {
+    zip_source_file_win32_write_operations_t *write_ops = (zip_source_file_win32_write_operations_t *)ctx->ops_userdata;
+
+    int i;
+    HANDLE th = INVALID_HANDLE_VALUE;
+    void *temp = NULL;
+    PSECURITY_DESCRIPTOR psd = NULL;
+    PSECURITY_ATTRIBUTES psa = NULL;
+    SECURITY_ATTRIBUTES sa;
+    SECURITY_INFORMATION si;
+    DWORD success;
+    PACL dacl = NULL;
+    char *tempname = NULL;
+    size_t tempname_size = 0;
+
+     if ((HANDLE)ctx->f != INVALID_HANDLE_VALUE && GetFileType((HANDLE)ctx->f) == FILE_TYPE_DISK) {
+         si = DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION;
+         success = GetSecurityInfo(ctx->h, SE_FILE_OBJECT, si, NULL, NULL, &dacl, NULL, &psd);
+         if (success == ERROR_SUCCESS) {
+             sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+             sa.bInheritHandle = FALSE;
+             sa.lpSecurityDescriptor = psd;
+             psa = &sa;
+         }
+     }
+
+ #ifndef MS_UWP
+    value = GetTickCount();
+#else
+    value = (zip_uint32_t)GetTickCount64();
+#endif
+    
+    if ((tempname = write_ops->allocate_tempname(ctx->fname, 10, &tempname_size)) == NULL) {
+        zip_error_set(&ctx->error, ZIP_ER_NOMEM, 0);
+        return -1;
+    }
+        
+    for (i = 0; i < 1024 && th == INVALID_HANDLE_VALUE; i++) {
+        write_ops->make_tempname(tempname, tempname_size, ctx->fname, value + i);
+        
+        th = win32_write_open(ctx, tempname, true, psa);
+        if (th == INVALID_HANDLE_VALUE && GetLastError() != ERROR_FILE_EXISTS)
+            break;
+    }
+    
+    if (th == INVALID_HANDLE_VALUE) {
+        free(tempname);
+        LocalFree(psd);
+        zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, _zip_win32_error_to_errno(GetLastError()));
+        return -1;
+    }
+    
+    LocalFree(psd);
+    ctx->fout = th;
+    ctx->tmpname = tempname;
+    
+    return 0;
+}
+
+
+static bool
+_zip_win32_write_op_open(zip_source_file_context_t *ctx) {
+    HANDLE h = win32_write_open(ctx, ctx->fname, false, NULL);
+    
+    if (h == INVALID_HANDLE_VALUE) {
+        return false;
+    }
+    
+    ctx->f = h;
+    return true;
+}
+
+
+static zip_int64_t
+_zip_win32_write_op_remove(zip_source_file_context_t *ctx) {
+    zip_source_file_win32_write_operations_t *write_ops = (zip_source_file_win32_write_operations_t *)ctx->ops_userdata;
+
+    if (!write_ops->delete_file(ctx->fname)) {
+        zip_error_set(&ctx->error, ZIP_ER_REMOVE, _zip_win32_error_to_errno(GetLastError()));
+        return -1;
+    }
+
+    return 0;
+}
+
+
+static void
+_zip_win32_write_op_rollback_write(zip_source_file_context_t *ctx) {
+    zip_source_file_win32_write_operations_t *write_ops = (zip_source_file_win32_write_operations_t *)ctx->ops_userdata;
+
+    if (ctx->fout) {
+        CloseHandle((HANDLE)ctx->fout);
+    }
+    write_ops->delete_file(ctx->tmpname);
+}
+
+
+static bool
+_zip_win32_write_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st) {
+    HANDLE h = win32_write_open(ctx, ctx->fname, false, NULL);
+    
+    if (h == INVALID_HANDLE_VALUE) {
+        return false;
+    }
+
+    return _zip_stat_win32(ctx, st, h);
+}
+
+
+static HANDLE
+win32_write_open(zip_source_file_context_t *ctx, const char *name, bool temporary, PSECURITY_ATTRIBUTES security_attributes) {
+    DWORD access = GENERIC_READ;
+    DWORD share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+    DWORD creation_disposition = OPEN_EXISTING;
+    DWORD file_attributes = FILE_ATTRIBUTE_NORMAL;
+    
+    if (temporary) {
+        access |= GENERIC_WRITE;
+        share_mode = FILE_SHARE_READ;
+        creation_disposition = CREATE_NEW;
+        file_attributes |= FILE_ATTRIBUTE_TEMPORARY;
+    }
+
+    HANDLE h = write_ops->create_file(name, access, share_mode, security_attributes, creation_disposition, file_attributes);
+    
+    if (h == INVALID_HANDLE_VALUE) {
+        zip_error_set(&ctx->error, ZIP_ER_OPEN, _zip_win32_error_to_errno(GetLastError()));
+    }
+
+    return h;
+}
diff --git a/lib/zip_source_win32utf8.c b/lib/zip_source_win32utf8.c
index 3d2ce39..6b33560 100644
--- a/lib/zip_source_win32utf8.c
+++ b/lib/zip_source_win32utf8.c
@@ -40,9 +40,10 @@
 
 ZIP_EXTERN zip_source_t *
 zip_source_file(zip_t *za, const char *fname, zip_uint64_t start, zip_int64_t len) {
-    if (za == NULL)
-	return NULL;
-
+    if (za == NULL) {
+        return NULL;
+    }
+    
     return zip_source_file_create(fname, start, len, &za->error);
 }
 
@@ -54,24 +55,24 @@
     zip_source_t *source;
 
     if (fname == NULL || length < -1) {
-	zip_error_set(error, ZIP_ER_INVAL, 0);
-	return NULL;
+        zip_error_set(error, ZIP_ER_INVAL, 0);
+        return NULL;
     }
 
     /* Convert fname from UTF-8 to Windows-friendly UTF-16. */
     size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, fname, -1, NULL, 0);
     if (size == 0) {
-	zip_error_set(error, ZIP_ER_INVAL, 0);
-	return NULL;
+        zip_error_set(error, ZIP_ER_INVAL, 0);
+        return NULL;
     }
     if ((wfname = (wchar_t *)malloc(sizeof(wchar_t) * size)) == NULL) {
-	zip_error_set(error, ZIP_ER_MEMORY, 0);
-	return NULL;
+        zip_error_set(error, ZIP_ER_MEMORY, 0);
+        return NULL;
     }
     MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, fname, -1, wfname, size);
 
     source = zip_source_win32w_create(wfname, start, length, error);
-
+    
     free(wfname);
     return source;
 }