blob: 9d11f871c73973e3a6aecdb69e0fd8476eaeb7d7 [file] [log] [blame]
Nathan Moinvaziriaa323f52017-10-05 23:32:57 -07001/* mz_os.c -- System functions
Nathan Moinvaziridb958942021-01-23 16:18:11 -08002 part of the minizip-ng project
Nathan Moinvaziriaa323f52017-10-05 23:32:57 -07003
Nathan Moinvaziridb958942021-01-23 16:18:11 -08004 Copyright (C) 2010-2021 Nathan Moinvaziri
5 https://github.com/zlib-ng/minizip-ng
Nathan Moinvaziri21e87252017-10-23 22:17:03 -07006 Copyright (C) 1998-2010 Gilles Vollant
Viktor Szakats9dea6f22018-10-17 22:39:01 +00007 https://www.winimage.com/zLibDll/minizip.html
Nathan Moinvaziriaa323f52017-10-05 23:32:57 -07008
9 This program is distributed under the terms of the same license as zlib.
10 See the accompanying LICENSE file for the full text of the license.
11*/
12
Nathan Moinvaziri00cca9f2017-10-16 07:37:11 -070013#include "mz.h"
Nathan Moinvazirie63d2312018-11-03 19:45:41 -070014#include "mz_crypt.h"
Nathan Moinvaziriaa323f52017-10-05 23:32:57 -070015#include "mz_os.h"
Nathan Moinvaziri70d41f62017-10-23 22:12:07 -070016#include "mz_strm.h"
Nathan Moinvaziri8cb7df72018-10-25 08:39:48 -070017#include "mz_strm_os.h"
Nathan Moinvazirid83efdc2017-10-09 00:40:53 -070018
Nathan Moinvazirib16ab562018-11-20 16:56:21 -080019#include <ctype.h> /* tolower */
Nathan Moinvaziri1ee609b2018-11-19 21:34:35 -080020
Nathan Moinvaziri638f31f2018-08-27 08:17:16 -070021/***************************************************************************/
Nathan Moinvazirid83efdc2017-10-09 00:40:53 -070022
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -070023int32_t mz_path_combine(char *path, const char *join, int32_t max_path) {
Nathan Moinvaziri77008c62017-10-16 14:50:31 -070024 int32_t path_len = 0;
25
26 if (path == NULL || join == NULL || max_path == 0)
27 return MZ_PARAM_ERROR;
28
Nathan Moinvaziri09304a62018-10-08 23:44:45 -070029 path_len = (int32_t)strlen(path);
Nathan Moinvaziri77008c62017-10-16 14:50:31 -070030
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -070031 if (path_len == 0) {
Viktor Szakatsab850762018-09-06 22:12:49 +000032 strncpy(path, join, max_path - 1);
Nathan Moinvaziri09ddae62018-09-10 08:52:45 -070033 path[max_path - 1] = 0;
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -070034 } else {
Nathan Moinvaziri7d94b1f2019-05-08 23:41:47 -070035 mz_path_append_slash(path, max_path, MZ_PATH_SLASH_PLATFORM);
Peter Harris76de77b2022-02-15 16:42:45 -050036 path_len = (int32_t)strlen(path);
37 if (max_path > path_len)
38 strncat(path, join, max_path - path_len - 1);
Nathan Moinvaziri77008c62017-10-16 14:50:31 -070039 }
40
41 return MZ_OK;
42}
Nathan Moinvaziri70d41f62017-10-23 22:12:07 -070043
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -070044int32_t mz_path_append_slash(char *path, int32_t max_path, char slash) {
Nathan Moinvaziri3249eac2019-05-02 21:07:39 -070045 int32_t path_len = (int32_t)strlen(path);
Nathan Moinvaziri7d94b1f2019-05-08 23:41:47 -070046 if ((path_len + 2) >= max_path)
47 return MZ_BUF_ERROR;
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -070048 if (path[path_len - 1] != '\\' && path[path_len - 1] != '/') {
Nathan Moinvaziri7d94b1f2019-05-08 23:41:47 -070049 path[path_len] = slash;
50 path[path_len + 1] = 0;
51 }
Nathan Moinvaziri3249eac2019-05-02 21:07:39 -070052 return MZ_OK;
53}
54
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -070055int32_t mz_path_remove_slash(char *path) {
Nathan Moinvaziri3249eac2019-05-02 21:07:39 -070056 int32_t path_len = (int32_t)strlen(path);
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -070057 while (path_len > 0) {
Nathan Moinvaziria5a1d5d2019-05-05 20:13:58 -070058 if (path[path_len - 1] == '\\' || path[path_len - 1] == '/')
Nathan Moinvaziri36f61522019-05-05 08:19:14 -070059 path[path_len - 1] = 0;
60 else
61 break;
62
63 path_len -= 1;
64 }
Nathan Moinvaziri3249eac2019-05-02 21:07:39 -070065 return MZ_OK;
66}
67
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -070068int32_t mz_path_has_slash(const char *path) {
Nathan Moinvaziri3249eac2019-05-02 21:07:39 -070069 int32_t path_len = (int32_t)strlen(path);
70 if (path[path_len - 1] != '\\' && path[path_len - 1] != '/')
71 return MZ_EXIST_ERROR;
72 return MZ_OK;
73}
74
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -070075int32_t mz_path_convert_slashes(char *path, char slash) {
Nathan Moinvaziri3a941ef2019-05-08 19:24:09 -070076 int32_t i = 0;
77
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -070078 for (i = 0; i < (int32_t)strlen(path); i += 1) {
Nathan Moinvaziri3a941ef2019-05-08 19:24:09 -070079 if (path[i] == '\\' || path[i] == '/')
80 path[i] = slash;
81 }
82 return MZ_OK;
83}
84
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -070085int32_t mz_path_compare_wc(const char *path, const char *wildcard, uint8_t ignore_case) {
86 while (*path != 0) {
87 switch (*wildcard) {
Nathan Moinvaziri65a87022018-07-31 12:48:31 -070088 case '*':
89
90 if (*(wildcard + 1) == 0)
91 return MZ_OK;
92
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -070093 while (*path != 0) {
Nathan Moinvaziri65a87022018-07-31 12:48:31 -070094 if (mz_path_compare_wc(path, (wildcard + 1), ignore_case) == MZ_OK)
95 return MZ_OK;
96
97 path += 1;
98 }
99
100 return MZ_EXIST_ERROR;
101
102 default:
Nathan Moinvazirib16ab562018-11-20 16:56:21 -0800103 /* Ignore differences in path slashes on platforms */
Nathan Moinvaziri65a87022018-07-31 12:48:31 -0700104 if ((*path == '\\' && *wildcard == '/') || (*path == '/' && *wildcard == '\\'))
105 break;
106
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700107 if (ignore_case) {
Nathan Moinvaziri65a87022018-07-31 12:48:31 -0700108 if (tolower(*path) != tolower(*wildcard))
109 return MZ_EXIST_ERROR;
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700110 } else {
Nathan Moinvaziri65a87022018-07-31 12:48:31 -0700111 if (*path != *wildcard)
112 return MZ_EXIST_ERROR;
113 }
114
115 break;
116 }
117
118 path += 1;
119 wildcard += 1;
120 }
121
122 if ((*wildcard != 0) && (*wildcard != '*'))
123 return MZ_EXIST_ERROR;
124
125 return MZ_OK;
126}
127
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700128int32_t mz_path_resolve(const char *path, char *output, int32_t max_output) {
Nathan Moinvaziridd808232018-06-11 07:38:58 -0700129 const char *source = path;
Nathan Moinvaziri957f2e92018-06-19 09:44:06 -0700130 const char *check = output;
Nathan Moinvaziridd808232018-06-11 07:38:58 -0700131 char *target = output;
Nathan Moinvaziridd808232018-06-11 07:38:58 -0700132
133 if (max_output <= 0)
134 return MZ_PARAM_ERROR;
135
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700136 while (*source != 0 && max_output > 1) {
Nathan Moinvaziri957f2e92018-06-19 09:44:06 -0700137 check = source;
138 if ((*check == '\\') || (*check == '/'))
139 check += 1;
140
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700141 if ((source == path) || (target == output) || (check != source)) {
Nathan Moinvazirib16ab562018-11-20 16:56:21 -0800142 /* Skip double paths */
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700143 if ((*check == '\\') || (*check == '/')) {
Nathan Moinvaziridd808232018-06-11 07:38:58 -0700144 source += 1;
Nathan Moinvaziri957f2e92018-06-19 09:44:06 -0700145 continue;
Nathan Moinvaziridd808232018-06-11 07:38:58 -0700146 }
Nathan Moinvaziriea9d9862020-06-14 15:35:14 -0700147 if (*check == '.') {
Nathan Moinvaziri957f2e92018-06-19 09:44:06 -0700148 check += 1;
149
Nathan Moinvazirid82ea2c2019-10-29 17:02:46 -0700150 /* Remove . if at end of string and not at the beginning */
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700151 if ((*check == 0) && (source != path && target != output)) {
Nathan Moinvazirib16ab562018-11-20 16:56:21 -0800152 /* Copy last slash */
Nathan Moinvaziri957f2e92018-06-19 09:44:06 -0700153 *target = *source;
154 target += 1;
155 max_output -= 1;
156 source += (check - source);
157 continue;
Nathan Moinvaziridd808232018-06-11 07:38:58 -0700158 }
Nathan Moinvazirid82ea2c2019-10-29 17:02:46 -0700159 /* Remove . if not at end of string */
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700160 else if ((*check == '\\') || (*check == '/')) {
Nathan Moinvazirid82ea2c2019-10-29 17:02:46 -0700161 source += (check - source);
162 /* Skip slash if at beginning of string */
163 if (target == output && *source != 0)
164 source += 1;
165 continue;
Nathan Moinvaziri957f2e92018-06-19 09:44:06 -0700166 }
Nathan Moinvazirib16ab562018-11-20 16:56:21 -0800167 /* Go to parent directory .. */
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700168 else if (*check == '.') {
Nathan Moinvaziri957f2e92018-06-19 09:44:06 -0700169 check += 1;
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700170 if ((*check == 0) || (*check == '\\' || *check == '/')) {
Nathan Moinvaziri957f2e92018-06-19 09:44:06 -0700171 source += (check - source);
172
Nathan Moinvazirib16ab562018-11-20 16:56:21 -0800173 /* Search backwards for previous slash */
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700174 if (target != output) {
Nathan Moinvaziri957f2e92018-06-19 09:44:06 -0700175 target -= 1;
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700176 do {
Nathan Moinvaziri957f2e92018-06-19 09:44:06 -0700177 if ((*target == '\\') || (*target == '/'))
178 break;
179
180 target -= 1;
181 max_output += 1;
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700182 } while (target > output);
Nathan Moinvaziri957f2e92018-06-19 09:44:06 -0700183 }
Viktor Szakatse7215072018-09-04 15:06:53 +0000184
Nathan Moinvaziri957f2e92018-06-19 09:44:06 -0700185 if ((target == output) && (*source != 0))
186 source += 1;
187 if ((*target == '\\' || *target == '/') && (*source == 0))
188 target += 1;
189
190 *target = 0;
191 continue;
192 }
193 }
Nathan Moinvaziridd808232018-06-11 07:38:58 -0700194 }
Nathan Moinvaziridd808232018-06-11 07:38:58 -0700195 }
196
197 *target = *source;
198
199 source += 1;
200 target += 1;
201 max_output -= 1;
202 }
203
204 *target = 0;
205
206 if (*path == 0)
207 return MZ_INTERNAL_ERROR;
208
209 return MZ_OK;
210}
211
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700212int32_t mz_path_remove_filename(char *path) {
Nathan Moinvaziri3431a662018-05-06 16:59:31 -0700213 char *path_ptr = NULL;
214
215 if (path == NULL)
216 return MZ_PARAM_ERROR;
217
Viktor Szakatse7215072018-09-04 15:06:53 +0000218 path_ptr = path + strlen(path) - 1;
Nathan Moinvaziri3431a662018-05-06 16:59:31 -0700219
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700220 while (path_ptr > path) {
221 if ((*path_ptr == '/') || (*path_ptr == '\\')) {
Nathan Moinvaziri3431a662018-05-06 16:59:31 -0700222 *path_ptr = 0;
223 break;
224 }
225
226 path_ptr -= 1;
227 }
Nathan Moinvazirib1504322019-01-07 13:09:16 -0800228
229 if (path_ptr == path)
230 *path_ptr = 0;
231
Nathan Moinvaziri3431a662018-05-06 16:59:31 -0700232 return MZ_OK;
233}
234
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700235int32_t mz_path_remove_extension(char *path) {
Nathan Moinvaziri3c438162019-04-28 09:23:56 -0700236 char *path_ptr = NULL;
237
238 if (path == NULL)
239 return MZ_PARAM_ERROR;
240
241 path_ptr = path + strlen(path) - 1;
242
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700243 while (path_ptr > path) {
Nathan Moinvaziri3c438162019-04-28 09:23:56 -0700244 if ((*path_ptr == '/') || (*path_ptr == '\\'))
245 break;
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700246 if (*path_ptr == '.') {
Nathan Moinvaziri3c438162019-04-28 09:23:56 -0700247 *path_ptr = 0;
248 break;
249 }
250
251 path_ptr -= 1;
252 }
253
254 if (path_ptr == path)
255 *path_ptr = 0;
256
257 return MZ_OK;
258}
259
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700260int32_t mz_path_get_filename(const char *path, const char **filename) {
Nathan Moinvaziri03881242018-05-09 20:03:26 -0700261 const char *match = NULL;
262
263 if (path == NULL || filename == NULL)
264 return MZ_PARAM_ERROR;
265
266 *filename = NULL;
267
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700268 for (match = path; *match != 0; match += 1) {
Nathan Moinvaziri03881242018-05-09 20:03:26 -0700269 if ((*match == '\\') || (*match == '/'))
270 *filename = match + 1;
271 }
272
273 if (*filename == NULL)
274 return MZ_EXIST_ERROR;
275
276 return MZ_OK;
277}
278
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700279int32_t mz_dir_make(const char *path) {
Nathan Moinvaziri638f31f2018-08-27 08:17:16 -0700280 int32_t err = MZ_OK;
Peter Harris27f2ff22022-02-17 10:53:10 -0500281 size_t len = 0;
Nathan Moinvaziri638f31f2018-08-27 08:17:16 -0700282 char *current_dir = NULL;
283 char *match = NULL;
284 char hold = 0;
285
Peter Harris27f2ff22022-02-17 10:53:10 -0500286 len = strlen(path);
287 if (len <= 0 || len > INT16_MAX)
Nathan Moinvaziri638f31f2018-08-27 08:17:16 -0700288 return 0;
289
Peter Harris27f2ff22022-02-17 10:53:10 -0500290 current_dir = (char *)MZ_ALLOC(len + 1);
Nathan Moinvaziri638f31f2018-08-27 08:17:16 -0700291 if (current_dir == NULL)
292 return MZ_MEM_ERROR;
293
294 strcpy(current_dir, path);
Nathan Moinvaziri3a941ef2019-05-08 19:24:09 -0700295 mz_path_remove_slash(current_dir);
Nathan Moinvaziri638f31f2018-08-27 08:17:16 -0700296
297 err = mz_os_make_dir(current_dir);
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700298 if (err != MZ_OK) {
Nathan Moinvaziri638f31f2018-08-27 08:17:16 -0700299 match = current_dir + 1;
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700300 while (1) {
Nathan Moinvaziri638f31f2018-08-27 08:17:16 -0700301 while (*match != 0 && *match != '\\' && *match != '/')
302 match += 1;
303 hold = *match;
304 *match = 0;
305
306 err = mz_os_make_dir(current_dir);
307 if (err != MZ_OK)
308 break;
309 if (hold == 0)
310 break;
311
312 *match = hold;
313 match += 1;
314 }
315 }
316
317 MZ_FREE(current_dir);
318 return err;
319}
320
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700321int32_t mz_file_get_crc(const char *path, uint32_t *result_crc) {
Nathan Moinvaziri70d41f62017-10-23 22:12:07 -0700322 void *stream = NULL;
Nathan Moinvazirie63d2312018-11-03 19:45:41 -0700323 uint32_t crc32 = 0;
Nathan Moinvaziriec6d4532017-10-26 17:52:36 -0700324 int32_t read = 0;
Nathan Moinvaziri70d41f62017-10-23 22:12:07 -0700325 int32_t err = MZ_OK;
Nathan Moinvaziri5d9f95f2018-08-30 16:22:25 -0700326 uint8_t buf[16384];
Nathan Moinvaziri70d41f62017-10-23 22:12:07 -0700327
328 mz_stream_os_create(&stream);
329
330 err = mz_stream_os_open(stream, path, MZ_OPEN_MODE_READ);
331
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700332 if (err == MZ_OK) {
333 do {
Nathan Moinvazirie63d2312018-11-03 19:45:41 -0700334 read = mz_stream_os_read(stream, buf, sizeof(buf));
Nathan Moinvaziri70d41f62017-10-23 22:12:07 -0700335
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700336 if (read < 0) {
Nathan Moinvaziri70d41f62017-10-23 22:12:07 -0700337 err = read;
338 break;
339 }
Nathan Moinvazirie63d2312018-11-03 19:45:41 -0700340
341 crc32 = mz_crypt_crc32_update(crc32, buf, read);
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700342 } while ((err == MZ_OK) && (read > 0));
Nathan Moinvaziri70d41f62017-10-23 22:12:07 -0700343
344 mz_stream_os_close(stream);
345 }
346
Nathan Moinvazirie63d2312018-11-03 19:45:41 -0700347 *result_crc = crc32;
Nathan Moinvaziri70d41f62017-10-23 22:12:07 -0700348
349 mz_stream_os_delete(&stream);
350
351 return err;
Viktor Szakats447dd062018-05-02 19:59:38 +0000352}
Nathan Moinvaziri638f31f2018-08-27 08:17:16 -0700353
Nathan Moinvaziri638f31f2018-08-27 08:17:16 -0700354/***************************************************************************/