mz_os.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. /* mz_os.c -- System functions
  2. Version 2.9.2, February 12, 2020
  3. part of the MiniZip project
  4. Copyright (C) 2010-2020 Nathan Moinvaziri
  5. https://github.com/nmoinvaz/minizip
  6. Copyright (C) 1998-2010 Gilles Vollant
  7. https://www.winimage.com/zLibDll/minizip.html
  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. #include "mz.h"
  12. #include "mz_crypt.h"
  13. #include "mz_os.h"
  14. #include "mz_strm.h"
  15. #include "mz_strm_os.h"
  16. #include <ctype.h> /* tolower */
  17. /***************************************************************************/
  18. int32_t mz_path_combine(char *path, const char *join, int32_t max_path)
  19. {
  20. int32_t path_len = 0;
  21. if (path == NULL || join == NULL || max_path == 0)
  22. return MZ_PARAM_ERROR;
  23. path_len = (int32_t)strlen(path);
  24. if (path_len == 0)
  25. {
  26. strncpy(path, join, max_path - 1);
  27. path[max_path - 1] = 0;
  28. }
  29. else
  30. {
  31. mz_path_append_slash(path, max_path, MZ_PATH_SLASH_PLATFORM);
  32. strncat(path, join, max_path - path_len);
  33. }
  34. return MZ_OK;
  35. }
  36. int32_t mz_path_append_slash(char *path, int32_t max_path, char slash)
  37. {
  38. int32_t path_len = (int32_t)strlen(path);
  39. if ((path_len + 2) >= max_path)
  40. return MZ_BUF_ERROR;
  41. if (path[path_len - 1] != '\\' && path[path_len - 1] != '/')
  42. {
  43. path[path_len] = slash;
  44. path[path_len + 1] = 0;
  45. }
  46. return MZ_OK;
  47. }
  48. int32_t mz_path_remove_slash(char *path)
  49. {
  50. int32_t path_len = (int32_t)strlen(path);
  51. while (path_len > 0)
  52. {
  53. if (path[path_len - 1] == '\\' || path[path_len - 1] == '/')
  54. path[path_len - 1] = 0;
  55. else
  56. break;
  57. path_len -= 1;
  58. }
  59. return MZ_OK;
  60. }
  61. int32_t mz_path_has_slash(const char *path)
  62. {
  63. int32_t path_len = (int32_t)strlen(path);
  64. if (path[path_len - 1] != '\\' && path[path_len - 1] != '/')
  65. return MZ_EXIST_ERROR;
  66. return MZ_OK;
  67. }
  68. int32_t mz_path_convert_slashes(char *path, char slash)
  69. {
  70. int32_t i = 0;
  71. for (i = 0; i < (int32_t)strlen(path); i += 1)
  72. {
  73. if (path[i] == '\\' || path[i] == '/')
  74. path[i] = slash;
  75. }
  76. return MZ_OK;
  77. }
  78. int32_t mz_path_compare_wc(const char *path, const char *wildcard, uint8_t ignore_case)
  79. {
  80. while (*path != 0)
  81. {
  82. switch (*wildcard)
  83. {
  84. case '*':
  85. if (*(wildcard + 1) == 0)
  86. return MZ_OK;
  87. while (*path != 0)
  88. {
  89. if (mz_path_compare_wc(path, (wildcard + 1), ignore_case) == MZ_OK)
  90. return MZ_OK;
  91. path += 1;
  92. }
  93. return MZ_EXIST_ERROR;
  94. default:
  95. /* Ignore differences in path slashes on platforms */
  96. if ((*path == '\\' && *wildcard == '/') || (*path == '/' && *wildcard == '\\'))
  97. break;
  98. if (ignore_case)
  99. {
  100. if (tolower(*path) != tolower(*wildcard))
  101. return MZ_EXIST_ERROR;
  102. }
  103. else
  104. {
  105. if (*path != *wildcard)
  106. return MZ_EXIST_ERROR;
  107. }
  108. break;
  109. }
  110. path += 1;
  111. wildcard += 1;
  112. }
  113. if ((*wildcard != 0) && (*wildcard != '*'))
  114. return MZ_EXIST_ERROR;
  115. return MZ_OK;
  116. }
  117. int32_t mz_path_resolve(const char *path, char *output, int32_t max_output)
  118. {
  119. const char *source = path;
  120. const char *check = output;
  121. char *target = output;
  122. if (max_output <= 0)
  123. return MZ_PARAM_ERROR;
  124. while (*source != 0 && max_output > 1)
  125. {
  126. check = source;
  127. if ((*check == '\\') || (*check == '/'))
  128. check += 1;
  129. if ((source == path) || (target == output) || (check != source))
  130. {
  131. /* Skip double paths */
  132. if ((*check == '\\') || (*check == '/'))
  133. {
  134. source += 1;
  135. continue;
  136. }
  137. if ((*check != 0) && (*check == '.'))
  138. {
  139. check += 1;
  140. /* Remove . if at end of string and not at the beginning */
  141. if ((*check == 0) && (source != path && target != output))
  142. {
  143. /* Copy last slash */
  144. *target = *source;
  145. target += 1;
  146. max_output -= 1;
  147. source += (check - source);
  148. continue;
  149. }
  150. /* Remove . if not at end of string */
  151. else if ((*check == '\\') || (*check == '/'))
  152. {
  153. source += (check - source);
  154. /* Skip slash if at beginning of string */
  155. if (target == output && *source != 0)
  156. source += 1;
  157. continue;
  158. }
  159. /* Go to parent directory .. */
  160. else if (*check == '.')
  161. {
  162. check += 1;
  163. if ((*check == 0) || (*check == '\\' || *check == '/'))
  164. {
  165. source += (check - source);
  166. /* Search backwards for previous slash */
  167. if (target != output)
  168. {
  169. target -= 1;
  170. do
  171. {
  172. if ((*target == '\\') || (*target == '/'))
  173. break;
  174. target -= 1;
  175. max_output += 1;
  176. }
  177. while (target > output);
  178. }
  179. if ((target == output) && (*source != 0))
  180. source += 1;
  181. if ((*target == '\\' || *target == '/') && (*source == 0))
  182. target += 1;
  183. *target = 0;
  184. continue;
  185. }
  186. }
  187. }
  188. }
  189. *target = *source;
  190. source += 1;
  191. target += 1;
  192. max_output -= 1;
  193. }
  194. *target = 0;
  195. if (*path == 0)
  196. return MZ_INTERNAL_ERROR;
  197. return MZ_OK;
  198. }
  199. int32_t mz_path_remove_filename(char *path)
  200. {
  201. char *path_ptr = NULL;
  202. if (path == NULL)
  203. return MZ_PARAM_ERROR;
  204. path_ptr = path + strlen(path) - 1;
  205. while (path_ptr > path)
  206. {
  207. if ((*path_ptr == '/') || (*path_ptr == '\\'))
  208. {
  209. *path_ptr = 0;
  210. break;
  211. }
  212. path_ptr -= 1;
  213. }
  214. if (path_ptr == path)
  215. *path_ptr = 0;
  216. return MZ_OK;
  217. }
  218. int32_t mz_path_remove_extension(char *path)
  219. {
  220. char *path_ptr = NULL;
  221. if (path == NULL)
  222. return MZ_PARAM_ERROR;
  223. path_ptr = path + strlen(path) - 1;
  224. while (path_ptr > path)
  225. {
  226. if ((*path_ptr == '/') || (*path_ptr == '\\'))
  227. break;
  228. if (*path_ptr == '.')
  229. {
  230. *path_ptr = 0;
  231. break;
  232. }
  233. path_ptr -= 1;
  234. }
  235. if (path_ptr == path)
  236. *path_ptr = 0;
  237. return MZ_OK;
  238. }
  239. int32_t mz_path_get_filename(const char *path, const char **filename)
  240. {
  241. const char *match = NULL;
  242. if (path == NULL || filename == NULL)
  243. return MZ_PARAM_ERROR;
  244. *filename = NULL;
  245. for (match = path; *match != 0; match += 1)
  246. {
  247. if ((*match == '\\') || (*match == '/'))
  248. *filename = match + 1;
  249. }
  250. if (*filename == NULL)
  251. return MZ_EXIST_ERROR;
  252. return MZ_OK;
  253. }
  254. int32_t mz_dir_make(const char *path)
  255. {
  256. int32_t err = MZ_OK;
  257. int16_t len = 0;
  258. char *current_dir = NULL;
  259. char *match = NULL;
  260. char hold = 0;
  261. len = (int16_t)strlen(path);
  262. if (len <= 0)
  263. return 0;
  264. current_dir = (char *)MZ_ALLOC((uint16_t)len + 1);
  265. if (current_dir == NULL)
  266. return MZ_MEM_ERROR;
  267. strcpy(current_dir, path);
  268. mz_path_remove_slash(current_dir);
  269. err = mz_os_make_dir(current_dir);
  270. if (err != MZ_OK)
  271. {
  272. match = current_dir + 1;
  273. while (1)
  274. {
  275. while (*match != 0 && *match != '\\' && *match != '/')
  276. match += 1;
  277. hold = *match;
  278. *match = 0;
  279. err = mz_os_make_dir(current_dir);
  280. if (err != MZ_OK)
  281. break;
  282. if (hold == 0)
  283. break;
  284. *match = hold;
  285. match += 1;
  286. }
  287. }
  288. MZ_FREE(current_dir);
  289. return err;
  290. }
  291. int32_t mz_file_get_crc(const char *path, uint32_t *result_crc)
  292. {
  293. void *stream = NULL;
  294. uint32_t crc32 = 0;
  295. int32_t read = 0;
  296. int32_t err = MZ_OK;
  297. uint8_t buf[16384];
  298. mz_stream_os_create(&stream);
  299. err = mz_stream_os_open(stream, path, MZ_OPEN_MODE_READ);
  300. if (err == MZ_OK)
  301. {
  302. do
  303. {
  304. read = mz_stream_os_read(stream, buf, sizeof(buf));
  305. if (read < 0)
  306. {
  307. err = read;
  308. break;
  309. }
  310. crc32 = mz_crypt_crc32_update(crc32, buf, read);
  311. }
  312. while ((err == MZ_OK) && (read > 0));
  313. mz_stream_os_close(stream);
  314. }
  315. *result_crc = crc32;
  316. mz_stream_os_delete(&stream);
  317. return err;
  318. }
  319. /***************************************************************************/