MINIZIP: use windows specific os support on windows
[spectmorph.git] / 3rdparty / minizip / mz_os_win32.c
1 /* mz_os_win32.c -- System functions for Windows
2    Version 2.8.1, December 1, 2018
3    part of the MiniZip project
4
5    Copyright (C) 2010-2018 Nathan Moinvaziri
6      https://github.com/nmoinvaz/minizip
7
8    This program is distributed under the terms of the same license as zlib.
9    See the accompanying LICENSE file for the full text of the license.
10 */
11
12
13 #include "mz.h"
14 #include "mz_os.h"
15 #include "mz_strm_os.h"
16
17 #include <windows.h>
18
19 /***************************************************************************/
20
21 #if defined(WINAPI_FAMILY_PARTITION) && (!(defined(MZ_WINRT_API)))
22 #  if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
23 #    define MZ_WINRT_API 1
24 #  endif
25 #endif
26
27 /***************************************************************************/
28
29 typedef struct DIR_int_s {
30     void            *find_handle;
31     WIN32_FIND_DATAW find_data;
32     struct dirent    entry;
33     uint8_t          end;
34 } DIR_int;
35
36 /***************************************************************************/
37
38 wchar_t *mz_os_unicode_string_create(const char *string, int32_t encoding)
39 {
40     wchar_t *string_wide = NULL;
41     uint32_t string_wide_size = 0;
42
43     string_wide_size = MultiByteToWideChar(encoding, 0, string, -1, NULL, 0);
44     if (string_wide_size == 0)
45         return NULL;
46     string_wide = (wchar_t *)MZ_ALLOC((string_wide_size + 1) * sizeof(wchar_t));
47     if (string_wide == NULL)
48         return NULL;
49
50     memset(string_wide, 0, sizeof(wchar_t) * (string_wide_size + 1));
51     MultiByteToWideChar(encoding, 0, string, -1, string_wide, string_wide_size);
52
53     return string_wide;
54 }
55
56 void mz_os_unicode_string_delete(wchar_t **string)
57 {
58     if (string != NULL)
59     {
60         MZ_FREE(*string);
61         *string = NULL;
62     }
63 }
64
65 uint8_t *mz_os_utf8_string_create(const char *string, int32_t encoding)
66 {
67     wchar_t *string_wide = NULL;
68     uint8_t *string_utf8 = NULL;
69     uint32_t string_utf8_size = 0;
70
71     string_wide = mz_os_unicode_string_create(string, encoding);
72     if (string_wide)
73     {
74         string_utf8_size = WideCharToMultiByte(CP_UTF8, 0, string_wide, -1, NULL, 0, NULL, NULL);
75         string_utf8 = (uint8_t *)MZ_ALLOC((string_utf8_size + 1) * sizeof(wchar_t));
76
77         if (string_utf8)
78         {
79             memset(string_utf8, 0, string_utf8_size + 1);
80             WideCharToMultiByte(CP_UTF8, 0, string_wide, -1, (char *)string_utf8, string_utf8_size, NULL, NULL);
81         }
82
83         mz_os_unicode_string_delete(&string_wide);
84     }
85
86     return string_utf8;
87 }
88
89 void mz_os_utf8_string_delete(uint8_t **string)
90 {
91     if (string != NULL)
92     {
93         MZ_FREE(*string);
94         *string = NULL;
95     }
96 }
97
98 /***************************************************************************/
99
100 int32_t mz_os_rand(uint8_t *buf, int32_t size)
101 {
102     unsigned __int64 pentium_tsc[1];
103     int32_t len = 0;
104
105     for (len = 0; len < (int)size; len += 1)
106     {
107         if (len % 8 == 0)
108             QueryPerformanceCounter((LARGE_INTEGER *)pentium_tsc);
109         buf[len] = ((unsigned char*)pentium_tsc)[len % 8];
110     }
111
112     return len;
113 }
114
115 int32_t mz_os_rename(const char *source_path, const char *target_path)
116 {
117     wchar_t *source_path_wide = NULL;
118     wchar_t *target_path_wide = NULL;
119     int32_t result = 0;
120     int32_t err = MZ_OK;
121
122     if (source_path == NULL || target_path == NULL)
123         return MZ_PARAM_ERROR;
124
125     source_path_wide = mz_os_unicode_string_create(source_path, MZ_ENCODING_UTF8);
126     if (source_path_wide == NULL)
127     {
128         err = MZ_PARAM_ERROR;
129     }
130     else
131     {
132         target_path_wide = mz_os_unicode_string_create(target_path, MZ_ENCODING_UTF8);
133         if (target_path_wide == NULL)
134             err = MZ_PARAM_ERROR;
135     }
136
137     if (err == MZ_OK)
138     {
139         result = MoveFileW(source_path_wide, target_path_wide);
140         if (result == 0)
141             err = MZ_EXIST_ERROR;
142     }
143
144     if (target_path_wide)
145         mz_os_unicode_string_delete(&target_path_wide);
146     if (source_path_wide)
147         mz_os_unicode_string_delete(&source_path_wide);
148     
149     return err;
150 }
151
152 int32_t mz_os_delete(const char *path)
153 {
154     wchar_t *path_wide = NULL;
155     int32_t result = 0;
156
157     if (path == NULL)
158         return MZ_PARAM_ERROR;
159     path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
160     if (path_wide == NULL)
161         return MZ_PARAM_ERROR;
162
163     result = DeleteFileW(path_wide);
164     mz_os_unicode_string_delete(&path_wide);
165
166     if (result == 0)
167         return MZ_EXIST_ERROR;
168
169     return MZ_OK;
170 }
171
172 int32_t mz_os_file_exists(const char *path)
173 {
174     wchar_t *path_wide = NULL;
175     DWORD attribs = 0;
176
177     if (path == NULL)
178         return MZ_PARAM_ERROR;
179     path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
180     if (path_wide == NULL)
181         return MZ_PARAM_ERROR;
182
183     attribs = GetFileAttributesW(path_wide);
184     mz_os_unicode_string_delete(&path_wide);
185
186     if (attribs == 0xFFFFFFFF)
187         return MZ_EXIST_ERROR;
188
189     return MZ_OK;
190 }
191
192 int64_t mz_os_get_file_size(const char *path)
193 {
194     HANDLE handle = NULL;
195     LARGE_INTEGER large_size;
196     wchar_t *path_wide = NULL;
197
198     if (path == NULL)
199         return MZ_PARAM_ERROR;
200     path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
201     if (path_wide == NULL)
202         return MZ_PARAM_ERROR;
203 #ifdef MZ_WINRT_API
204     handle = CreateFile2W(path_wide, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
205 #else
206     handle = CreateFileW(path_wide, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
207 #endif
208     mz_os_unicode_string_delete(&path_wide);
209
210     large_size.QuadPart = 0;
211
212     if (handle != INVALID_HANDLE_VALUE)
213     {
214         GetFileSizeEx(handle, &large_size);
215         CloseHandle(handle);
216     }
217
218     return large_size.QuadPart;
219 }
220
221 static void mz_os_file_to_unix_time(FILETIME file_time, time_t *unix_time)
222 {
223     uint64_t quad_file_time = 0;
224     quad_file_time = file_time.dwLowDateTime;
225     quad_file_time |= ((uint64_t)file_time.dwHighDateTime << 32);
226     *unix_time = (time_t)((quad_file_time - 116444736000000000LL) / 10000000);
227 }
228
229 static void mz_os_unix_to_file_time(time_t unix_time, FILETIME *file_time)
230 {
231     uint64_t quad_file_time = 0;
232     quad_file_time = ((uint64_t)unix_time * 10000000) + 116444736000000000LL;
233     file_time->dwHighDateTime = (quad_file_time >> 32);
234     file_time->dwLowDateTime = (uint32_t)(quad_file_time);
235 }
236
237 int32_t mz_os_get_file_date(const char *path, time_t *modified_date, time_t *accessed_date, time_t *creation_date)
238 {
239     WIN32_FIND_DATAW ff32;
240     HANDLE handle = NULL;
241     wchar_t *path_wide = NULL;
242     int32_t err = MZ_INTERNAL_ERROR;
243
244     if (path == NULL)
245         return MZ_PARAM_ERROR;
246     path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
247     if (path_wide == NULL)
248         return MZ_PARAM_ERROR;
249
250     handle = FindFirstFileW(path_wide, &ff32);
251     MZ_FREE(path_wide);
252
253     if (handle != INVALID_HANDLE_VALUE)
254     {
255         if (modified_date != NULL)
256             mz_os_file_to_unix_time(ff32.ftLastWriteTime, modified_date);
257         if (accessed_date != NULL)
258             mz_os_file_to_unix_time(ff32.ftLastAccessTime, accessed_date);
259         if (creation_date != NULL)
260             mz_os_file_to_unix_time(ff32.ftCreationTime, creation_date);
261
262         FindClose(handle);
263         err = MZ_OK;
264     }
265
266     return err;
267 }
268
269 int32_t mz_os_set_file_date(const char *path, time_t modified_date, time_t accessed_date, time_t creation_date)
270 {
271     HANDLE handle = NULL;
272     FILETIME ftm_creation, ftm_accessed, ftm_modified;
273     wchar_t *path_wide = NULL;
274     int32_t err = MZ_OK;
275
276     if (path == NULL)
277         return MZ_PARAM_ERROR;
278     path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
279     if (path_wide == NULL)
280         return MZ_PARAM_ERROR;
281
282 #ifdef MZ_WINRT_API
283     handle = CreateFile2W(path_wide, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
284 #else
285     handle = CreateFileW(path_wide, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
286 #endif
287     mz_os_unicode_string_delete(&path_wide);
288
289     if (handle != INVALID_HANDLE_VALUE)
290     {
291         GetFileTime(handle, &ftm_creation, &ftm_accessed, &ftm_modified);
292
293         if (modified_date != 0)
294             mz_os_unix_to_file_time(modified_date, &ftm_modified);
295         if (accessed_date != 0)
296             mz_os_unix_to_file_time(accessed_date, &ftm_accessed);
297         if (creation_date != 0)
298             mz_os_unix_to_file_time(creation_date, &ftm_creation);
299
300         if (SetFileTime(handle, &ftm_creation, &ftm_accessed, &ftm_modified) == 0)
301             err = MZ_INTERNAL_ERROR;
302
303         CloseHandle(handle);
304     }
305
306     return err;
307 }
308
309 int32_t mz_os_get_file_attribs(const char *path, uint32_t *attributes)
310 {
311     wchar_t *path_wide = NULL;
312     int32_t err = MZ_OK;
313
314     if (path == NULL || attributes == NULL)
315         return MZ_PARAM_ERROR;
316     path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
317     if (path_wide == NULL)
318         return MZ_PARAM_ERROR;
319
320     *attributes = GetFileAttributesW(path_wide);
321     mz_os_unicode_string_delete(&path_wide);
322
323     if (*attributes == INVALID_FILE_ATTRIBUTES)
324         err = MZ_INTERNAL_ERROR;
325
326     return err;
327 }
328
329 int32_t mz_os_set_file_attribs(const char *path, uint32_t attributes)
330 {
331     wchar_t *path_wide = NULL;
332     int32_t err = MZ_OK;
333
334     if (path == NULL)
335         return MZ_PARAM_ERROR;
336     path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
337     if (path_wide == NULL)
338         return MZ_PARAM_ERROR;
339
340     if (SetFileAttributesW(path_wide, attributes) == 0)
341         err = MZ_INTERNAL_ERROR;
342     mz_os_unicode_string_delete(&path_wide);
343
344     return err;
345 }
346
347 int32_t mz_os_make_dir(const char *path)
348 {
349     wchar_t *path_wide = NULL;
350     int32_t err = MZ_OK;
351
352     if (path == NULL)
353         return MZ_PARAM_ERROR;
354     path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
355     if (path_wide == NULL)
356         return MZ_PARAM_ERROR;
357
358     if (CreateDirectoryW(path_wide, NULL) == 0)
359     {
360         if (GetLastError() != ERROR_ALREADY_EXISTS)
361             err = MZ_INTERNAL_ERROR;
362     }
363
364     mz_os_unicode_string_delete(&path_wide);
365
366     return err;
367 }
368
369 DIR *mz_os_open_dir(const char *path)
370 {
371     WIN32_FIND_DATAW find_data;
372     DIR_int *dir_int = NULL;
373     wchar_t *path_wide = NULL;
374     char fixed_path[320];
375     void *handle = NULL;
376
377
378     if (path == NULL)
379         return NULL;
380
381     fixed_path[0] = 0;
382     mz_path_combine(fixed_path, path, sizeof(fixed_path));
383     mz_path_combine(fixed_path, "*", sizeof(fixed_path));
384
385     path_wide = mz_os_unicode_string_create(fixed_path, MZ_ENCODING_UTF8);
386     if (path_wide == NULL)
387         return NULL;
388
389     handle = FindFirstFileW(path_wide, &find_data);
390     mz_os_unicode_string_delete(&path_wide);
391
392     if (handle == INVALID_HANDLE_VALUE)
393         return NULL;
394
395     dir_int = (DIR_int *)MZ_ALLOC(sizeof(DIR_int));
396     if (dir_int == NULL)
397         return NULL;
398     dir_int->find_handle = handle;
399     dir_int->end = 0;
400
401     memcpy(&dir_int->find_data, &find_data, sizeof(dir_int->find_data));
402
403     return (DIR *)dir_int;
404 }
405
406 struct dirent* mz_os_read_dir(DIR *dir)
407 {
408     DIR_int *dir_int;
409
410     if (dir == NULL)
411         return NULL;
412
413     dir_int = (DIR_int *)dir;
414     if (dir_int->end)
415         return NULL;
416
417     WideCharToMultiByte(CP_UTF8, 0, dir_int->find_data.cFileName, -1,
418         dir_int->entry.d_name, sizeof(dir_int->entry.d_name), NULL, NULL);
419
420     if (FindNextFileW(dir_int->find_handle, &dir_int->find_data) == 0)
421     {
422         if (GetLastError() != ERROR_NO_MORE_FILES)
423             return NULL;
424
425         dir_int->end = 1;
426     }
427
428     return &dir_int->entry;
429 }
430
431 int32_t mz_os_close_dir(DIR *dir)
432 {
433     DIR_int *dir_int;
434
435     if (dir == NULL)
436         return MZ_PARAM_ERROR;
437
438     dir_int = (DIR_int *)dir;
439     if (dir_int->find_handle != INVALID_HANDLE_VALUE)
440         FindClose(dir_int->find_handle);
441     MZ_FREE(dir_int);
442     return MZ_OK;
443 }
444
445 int32_t mz_os_is_dir(const char *path)
446 {
447     wchar_t *path_wide = NULL;
448     uint32_t attribs = 0;
449
450     if (path == NULL)
451         return MZ_PARAM_ERROR;
452     path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
453     if (path_wide == NULL)
454         return MZ_PARAM_ERROR;
455
456     attribs = GetFileAttributesW(path_wide);
457     mz_os_unicode_string_delete(&path_wide);
458
459     if (attribs != 0xFFFFFFFF)
460     {
461         if (attribs & FILE_ATTRIBUTE_DIRECTORY)
462             return MZ_OK;
463     }
464
465     return MZ_EXIST_ERROR;
466 }
467
468 uint64_t mz_os_ms_time(void)
469 {
470     SYSTEMTIME system_time;
471     FILETIME file_time;
472     uint64_t quad_file_time = 0;
473
474     GetSystemTime(&system_time);
475     SystemTimeToFileTime(&system_time, &file_time);
476
477     quad_file_time = file_time.dwLowDateTime;
478     quad_file_time |= ((uint64_t)file_time.dwHighDateTime << 32);
479
480     return quad_file_time / 10000 - 11644473600000LL;
481 }