blob: c93ed04753d5bcf984d3f591e334b0ffa77fcaf6 [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
Nathan Moinvazirie22948c2019-10-29 16:37:12 -0700133
Nathan Moinvaziridd808232018-06-11 07:38:58 -0700134 if (max_output <= 0)
135 return MZ_PARAM_ERROR;
136
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700137 while (*source != 0 && max_output > 1) {
Nathan Moinvaziri957f2e92018-06-19 09:44:06 -0700138 check = source;
139 if ((*check == '\\') || (*check == '/'))
140 check += 1;
141
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700142 if ((source == path) || (target == output) || (check != source)) {
Nathan Moinvazirib16ab562018-11-20 16:56:21 -0800143 /* Skip double paths */
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700144 if ((*check == '\\') || (*check == '/')) {
Nathan Moinvaziridd808232018-06-11 07:38:58 -0700145 source += 1;
Nathan Moinvaziri957f2e92018-06-19 09:44:06 -0700146 continue;
Nathan Moinvaziridd808232018-06-11 07:38:58 -0700147 }
Nathan Moinvaziriea9d9862020-06-14 15:35:14 -0700148 if (*check == '.') {
Nathan Moinvaziri957f2e92018-06-19 09:44:06 -0700149 check += 1;
150
Nathan Moinvazirid82ea2c2019-10-29 17:02:46 -0700151 /* Remove . if at end of string and not at the beginning */
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700152 if ((*check == 0) && (source != path && target != output)) {
Nathan Moinvazirib16ab562018-11-20 16:56:21 -0800153 /* Copy last slash */
Nathan Moinvaziri957f2e92018-06-19 09:44:06 -0700154 *target = *source;
155 target += 1;
156 max_output -= 1;
157 source += (check - source);
158 continue;
Nathan Moinvaziridd808232018-06-11 07:38:58 -0700159 }
Nathan Moinvazirid82ea2c2019-10-29 17:02:46 -0700160 /* Remove . if not at end of string */
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700161 else if ((*check == '\\') || (*check == '/')) {
Nathan Moinvazirid82ea2c2019-10-29 17:02:46 -0700162 source += (check - source);
163 /* Skip slash if at beginning of string */
164 if (target == output && *source != 0)
165 source += 1;
166 continue;
Nathan Moinvaziri957f2e92018-06-19 09:44:06 -0700167 }
Nathan Moinvazirib16ab562018-11-20 16:56:21 -0800168 /* Go to parent directory .. */
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700169 else if (*check == '.') {
Nathan Moinvaziri957f2e92018-06-19 09:44:06 -0700170 check += 1;
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700171 if ((*check == 0) || (*check == '\\' || *check == '/')) {
Nathan Moinvaziri957f2e92018-06-19 09:44:06 -0700172 source += (check - source);
173
Nathan Moinvazirib16ab562018-11-20 16:56:21 -0800174 /* Search backwards for previous slash */
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700175 if (target != output) {
Nathan Moinvaziri957f2e92018-06-19 09:44:06 -0700176 target -= 1;
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700177 do {
Nathan Moinvaziri957f2e92018-06-19 09:44:06 -0700178 if ((*target == '\\') || (*target == '/'))
179 break;
180
181 target -= 1;
182 max_output += 1;
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700183 } while (target > output);
Nathan Moinvaziri957f2e92018-06-19 09:44:06 -0700184 }
Viktor Szakatse7215072018-09-04 15:06:53 +0000185
Nathan Moinvaziri957f2e92018-06-19 09:44:06 -0700186 if ((target == output) && (*source != 0))
187 source += 1;
188 if ((*target == '\\' || *target == '/') && (*source == 0))
189 target += 1;
190
191 *target = 0;
192 continue;
193 }
194 }
Nathan Moinvaziridd808232018-06-11 07:38:58 -0700195 }
Nathan Moinvaziridd808232018-06-11 07:38:58 -0700196 }
197
198 *target = *source;
199
200 source += 1;
201 target += 1;
202 max_output -= 1;
203 }
204
205 *target = 0;
206
207 if (*path == 0)
208 return MZ_INTERNAL_ERROR;
209
210 return MZ_OK;
211}
212
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700213int32_t mz_path_remove_filename(char *path) {
Nathan Moinvaziri3431a662018-05-06 16:59:31 -0700214 char *path_ptr = NULL;
215
216 if (path == NULL)
217 return MZ_PARAM_ERROR;
218
Viktor Szakatse7215072018-09-04 15:06:53 +0000219 path_ptr = path + strlen(path) - 1;
Nathan Moinvaziri3431a662018-05-06 16:59:31 -0700220
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700221 while (path_ptr > path) {
222 if ((*path_ptr == '/') || (*path_ptr == '\\')) {
Nathan Moinvaziri3431a662018-05-06 16:59:31 -0700223 *path_ptr = 0;
224 break;
225 }
226
227 path_ptr -= 1;
228 }
Nathan Moinvazirib1504322019-01-07 13:09:16 -0800229
230 if (path_ptr == path)
231 *path_ptr = 0;
232
Nathan Moinvaziri3431a662018-05-06 16:59:31 -0700233 return MZ_OK;
234}
235
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700236int32_t mz_path_remove_extension(char *path) {
Nathan Moinvaziri3c438162019-04-28 09:23:56 -0700237 char *path_ptr = NULL;
238
239 if (path == NULL)
240 return MZ_PARAM_ERROR;
241
242 path_ptr = path + strlen(path) - 1;
243
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700244 while (path_ptr > path) {
Nathan Moinvaziri3c438162019-04-28 09:23:56 -0700245 if ((*path_ptr == '/') || (*path_ptr == '\\'))
246 break;
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700247 if (*path_ptr == '.') {
Nathan Moinvaziri3c438162019-04-28 09:23:56 -0700248 *path_ptr = 0;
249 break;
250 }
251
252 path_ptr -= 1;
253 }
254
255 if (path_ptr == path)
256 *path_ptr = 0;
257
258 return MZ_OK;
259}
260
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700261int32_t mz_path_get_filename(const char *path, const char **filename) {
Nathan Moinvaziri03881242018-05-09 20:03:26 -0700262 const char *match = NULL;
263
264 if (path == NULL || filename == NULL)
265 return MZ_PARAM_ERROR;
266
267 *filename = NULL;
268
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700269 for (match = path; *match != 0; match += 1) {
Nathan Moinvaziri03881242018-05-09 20:03:26 -0700270 if ((*match == '\\') || (*match == '/'))
271 *filename = match + 1;
272 }
273
274 if (*filename == NULL)
275 return MZ_EXIST_ERROR;
276
277 return MZ_OK;
278}
279
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700280int32_t mz_dir_make(const char *path) {
Nathan Moinvaziri638f31f2018-08-27 08:17:16 -0700281 int32_t err = MZ_OK;
Peter Harris27f2ff22022-02-17 10:53:10 -0500282 size_t len = 0;
Nathan Moinvaziri638f31f2018-08-27 08:17:16 -0700283 char *current_dir = NULL;
284 char *match = NULL;
285 char hold = 0;
286
287
Peter Harris27f2ff22022-02-17 10:53:10 -0500288 len = strlen(path);
289 if (len <= 0 || len > INT16_MAX)
Nathan Moinvaziri638f31f2018-08-27 08:17:16 -0700290 return 0;
291
Peter Harris27f2ff22022-02-17 10:53:10 -0500292 current_dir = (char *)MZ_ALLOC(len + 1);
Nathan Moinvaziri638f31f2018-08-27 08:17:16 -0700293 if (current_dir == NULL)
294 return MZ_MEM_ERROR;
295
296 strcpy(current_dir, path);
Nathan Moinvaziri3a941ef2019-05-08 19:24:09 -0700297 mz_path_remove_slash(current_dir);
Nathan Moinvaziri638f31f2018-08-27 08:17:16 -0700298
299 err = mz_os_make_dir(current_dir);
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700300 if (err != MZ_OK) {
Nathan Moinvaziri638f31f2018-08-27 08:17:16 -0700301 match = current_dir + 1;
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700302 while (1) {
Nathan Moinvaziri638f31f2018-08-27 08:17:16 -0700303 while (*match != 0 && *match != '\\' && *match != '/')
304 match += 1;
305 hold = *match;
306 *match = 0;
307
308 err = mz_os_make_dir(current_dir);
309 if (err != MZ_OK)
310 break;
311 if (hold == 0)
312 break;
313
314 *match = hold;
315 match += 1;
316 }
317 }
318
319 MZ_FREE(current_dir);
320 return err;
321}
322
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700323int32_t mz_file_get_crc(const char *path, uint32_t *result_crc) {
Nathan Moinvaziri70d41f62017-10-23 22:12:07 -0700324 void *stream = NULL;
Nathan Moinvazirie63d2312018-11-03 19:45:41 -0700325 uint32_t crc32 = 0;
Nathan Moinvaziriec6d4532017-10-26 17:52:36 -0700326 int32_t read = 0;
Nathan Moinvaziri70d41f62017-10-23 22:12:07 -0700327 int32_t err = MZ_OK;
Nathan Moinvaziri5d9f95f2018-08-30 16:22:25 -0700328 uint8_t buf[16384];
Nathan Moinvaziri70d41f62017-10-23 22:12:07 -0700329
330 mz_stream_os_create(&stream);
331
332 err = mz_stream_os_open(stream, path, MZ_OPEN_MODE_READ);
333
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700334 if (err == MZ_OK) {
335 do {
Nathan Moinvazirie63d2312018-11-03 19:45:41 -0700336 read = mz_stream_os_read(stream, buf, sizeof(buf));
Nathan Moinvaziri70d41f62017-10-23 22:12:07 -0700337
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700338 if (read < 0) {
Nathan Moinvaziri70d41f62017-10-23 22:12:07 -0700339 err = read;
340 break;
341 }
Nathan Moinvazirie63d2312018-11-03 19:45:41 -0700342
343 crc32 = mz_crypt_crc32_update(crc32, buf, read);
Nathan Moinvaziridc6962b2020-06-14 15:19:14 -0700344 } while ((err == MZ_OK) && (read > 0));
Nathan Moinvaziri70d41f62017-10-23 22:12:07 -0700345
346 mz_stream_os_close(stream);
347 }
348
Nathan Moinvazirie63d2312018-11-03 19:45:41 -0700349 *result_crc = crc32;
Nathan Moinvaziri70d41f62017-10-23 22:12:07 -0700350
351 mz_stream_os_delete(&stream);
352
353 return err;
Viktor Szakats447dd062018-05-02 19:59:38 +0000354}
Nathan Moinvaziri638f31f2018-08-27 08:17:16 -0700355
Nathan Moinvaziri638f31f2018-08-27 08:17:16 -0700356/***************************************************************************/