mz_strm_split.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. /* mz_strm_split.c -- Stream for split files
  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. This program is distributed under the terms of the same license as zlib.
  7. See the accompanying LICENSE file for the full text of the license.
  8. */
  9. #include "mz.h"
  10. #include "mz_os.h"
  11. #include "mz_strm.h"
  12. #include "mz_strm_split.h"
  13. #include <stdio.h> /* snprintf */
  14. #if defined(_MSC_VER) && (_MSC_VER < 1900)
  15. # define snprintf _snprintf
  16. #endif
  17. /***************************************************************************/
  18. #define MZ_ZIP_MAGIC_DISKHEADER (0x08074b50)
  19. /***************************************************************************/
  20. static mz_stream_vtbl mz_stream_split_vtbl = {
  21. mz_stream_split_open,
  22. mz_stream_split_is_open,
  23. mz_stream_split_read,
  24. mz_stream_split_write,
  25. mz_stream_split_tell,
  26. mz_stream_split_seek,
  27. mz_stream_split_close,
  28. mz_stream_split_error,
  29. mz_stream_split_create,
  30. mz_stream_split_delete,
  31. mz_stream_split_get_prop_int64,
  32. mz_stream_split_set_prop_int64
  33. };
  34. /***************************************************************************/
  35. typedef struct mz_stream_split_s {
  36. mz_stream stream;
  37. int32_t is_open;
  38. int64_t disk_size;
  39. int64_t total_in;
  40. int64_t total_in_disk;
  41. int64_t total_out;
  42. int64_t total_out_disk;
  43. int32_t mode;
  44. char *path_cd;
  45. uint32_t path_cd_size;
  46. char *path_disk;
  47. uint32_t path_disk_size;
  48. int32_t number_disk;
  49. int32_t current_disk;
  50. int64_t current_disk_size;
  51. int32_t reached_end;
  52. } mz_stream_split;
  53. /***************************************************************************/
  54. #if 0
  55. # define mz_stream_split_print printf
  56. #else
  57. # define mz_stream_split_print(fmt,...)
  58. #endif
  59. /***************************************************************************/
  60. static int32_t mz_stream_split_open_disk(void *stream, int32_t number_disk)
  61. {
  62. mz_stream_split *split = (mz_stream_split *)stream;
  63. uint32_t magic = 0;
  64. int64_t position = 0;
  65. int32_t i = 0;
  66. int32_t err = MZ_OK;
  67. int16_t disk_part = 0;
  68. /* Check if we are reading or writing a disk part or the cd disk */
  69. if (number_disk >= 0)
  70. {
  71. if ((split->mode & MZ_OPEN_MODE_WRITE) == 0)
  72. disk_part = MZ_OPEN_MODE_READ;
  73. else if (split->disk_size > 0)
  74. disk_part = MZ_OPEN_MODE_WRITE;
  75. }
  76. /* Construct disk path */
  77. if (disk_part > 0)
  78. {
  79. for (i = (int32_t)strlen(split->path_disk) - 1; i >= 0; i -= 1)
  80. {
  81. if (split->path_disk[i] != '.')
  82. continue;
  83. snprintf(&split->path_disk[i], split->path_disk_size - (uint32_t)i,
  84. ".z%02" PRId32, number_disk + 1);
  85. break;
  86. }
  87. }
  88. else
  89. {
  90. strncpy(split->path_disk, split->path_cd, split->path_disk_size - 1);
  91. split->path_disk[split->path_disk_size - 1] = 0;
  92. }
  93. mz_stream_split_print("Split - Goto disk - %s (disk %" PRId32 ")\n", split->path_disk, number_disk);
  94. /* If disk part doesn't exist during reading then return MZ_EXIST_ERROR */
  95. if (disk_part == MZ_OPEN_MODE_READ)
  96. err = mz_os_file_exists(split->path_disk);
  97. if (err == MZ_OK)
  98. err = mz_stream_open(split->stream.base, split->path_disk, split->mode);
  99. if (err == MZ_OK)
  100. {
  101. split->total_in_disk = 0;
  102. split->total_out_disk = 0;
  103. split->current_disk = number_disk;
  104. if (split->mode & MZ_OPEN_MODE_WRITE)
  105. {
  106. if ((split->current_disk == 0) && (split->disk_size > 0))
  107. {
  108. err = mz_stream_write_uint32(split->stream.base, MZ_ZIP_MAGIC_DISKHEADER);
  109. split->total_out_disk += 4;
  110. split->total_out += split->total_out_disk;
  111. }
  112. }
  113. else if (split->mode & MZ_OPEN_MODE_READ)
  114. {
  115. if (split->current_disk == 0)
  116. {
  117. err = mz_stream_read_uint32(split->stream.base, &magic);
  118. if (magic != MZ_ZIP_MAGIC_DISKHEADER)
  119. err = MZ_FORMAT_ERROR;
  120. }
  121. }
  122. }
  123. if (err == MZ_OK)
  124. {
  125. /* Get the size of the current disk we are on */
  126. position = mz_stream_tell(split->stream.base);
  127. mz_stream_seek(split->stream.base, 0, MZ_SEEK_END);
  128. split->current_disk_size = mz_stream_tell(split->stream.base);
  129. mz_stream_seek(split->stream.base, position, MZ_SEEK_SET);
  130. split->is_open = 1;
  131. }
  132. return err;
  133. }
  134. static int32_t mz_stream_split_close_disk(void *stream)
  135. {
  136. mz_stream_split *split = (mz_stream_split *)stream;
  137. if (mz_stream_is_open(split->stream.base) != MZ_OK)
  138. return MZ_OK;
  139. mz_stream_split_print("Split - Close disk\n");
  140. return mz_stream_close(split->stream.base);
  141. }
  142. static int32_t mz_stream_split_goto_disk(void *stream, int32_t number_disk)
  143. {
  144. mz_stream_split *split = (mz_stream_split *)stream;
  145. int32_t err = MZ_OK;
  146. int32_t err_is_open = MZ_OK;
  147. err_is_open = mz_stream_is_open(split->stream.base);
  148. if ((split->disk_size == 0) && (split->mode & MZ_OPEN_MODE_WRITE))
  149. {
  150. if (err_is_open != MZ_OK)
  151. err = mz_stream_split_open_disk(stream, number_disk);
  152. }
  153. else if ((number_disk != split->current_disk) || (err_is_open != MZ_OK))
  154. {
  155. err = mz_stream_split_close_disk(stream);
  156. if (err == MZ_OK)
  157. {
  158. err = mz_stream_split_open_disk(stream, number_disk);
  159. if (err == MZ_OK)
  160. split->number_disk = number_disk;
  161. }
  162. }
  163. return err;
  164. }
  165. int32_t mz_stream_split_open(void *stream, const char *path, int32_t mode)
  166. {
  167. mz_stream_split *split = (mz_stream_split *)stream;
  168. int32_t number_disk = 0;
  169. split->mode = mode;
  170. split->path_cd_size = (uint32_t)strlen(path) + 1;
  171. split->path_cd = (char *)MZ_ALLOC(split->path_cd_size);
  172. if (split->path_cd == NULL)
  173. return MZ_MEM_ERROR;
  174. strncpy(split->path_cd, path, split->path_cd_size - 1);
  175. split->path_cd[split->path_cd_size - 1] = 0;
  176. mz_stream_split_print("Split - Open - %s (disk %" PRId32 ")\n", split->path_cd, number_disk);
  177. split->path_disk_size = (uint32_t)strlen(path) + 10;
  178. split->path_disk = (char *)MZ_ALLOC(split->path_disk_size);
  179. if (split->path_disk == NULL)
  180. {
  181. MZ_FREE(split->path_cd);
  182. return MZ_MEM_ERROR;
  183. }
  184. strncpy(split->path_disk, path, split->path_disk_size - 1);
  185. split->path_disk[split->path_disk_size - 1] = 0;
  186. if ((mode & MZ_OPEN_MODE_WRITE) && ((mode & MZ_OPEN_MODE_APPEND) == 0))
  187. {
  188. number_disk = 0;
  189. split->current_disk = -1;
  190. }
  191. else
  192. {
  193. number_disk = -1;
  194. split->current_disk = 0;
  195. }
  196. return mz_stream_split_goto_disk(stream, number_disk);
  197. }
  198. int32_t mz_stream_split_is_open(void *stream)
  199. {
  200. mz_stream_split *split = (mz_stream_split *)stream;
  201. if (split->is_open != 1)
  202. return MZ_OPEN_ERROR;
  203. return MZ_OK;
  204. }
  205. int32_t mz_stream_split_read(void *stream, void *buf, int32_t size)
  206. {
  207. mz_stream_split *split = (mz_stream_split *)stream;
  208. int32_t bytes_left = size;
  209. int32_t read = 0;
  210. int32_t err = MZ_OK;
  211. uint8_t *buf_ptr = (uint8_t *)buf;
  212. err = mz_stream_split_goto_disk(stream, split->number_disk);
  213. if (err != MZ_OK)
  214. return err;
  215. while (bytes_left > 0)
  216. {
  217. read = mz_stream_read(split->stream.base, buf_ptr, bytes_left);
  218. mz_stream_split_print("Split - Read disk - %" PRId32 "\n", read);
  219. if (read < 0)
  220. return read;
  221. if (read == 0)
  222. {
  223. if (split->current_disk < 0) /* No more disks to goto */
  224. break;
  225. err = mz_stream_split_goto_disk(stream, split->current_disk + 1);
  226. if (err == MZ_EXIST_ERROR)
  227. {
  228. split->current_disk = -1;
  229. break;
  230. }
  231. if (err != MZ_OK)
  232. return err;
  233. }
  234. bytes_left -= read;
  235. buf_ptr += read;
  236. split->total_in += read;
  237. split->total_in_disk += read;
  238. }
  239. return size - bytes_left;
  240. }
  241. int32_t mz_stream_split_write(void *stream, const void *buf, int32_t size)
  242. {
  243. mz_stream_split *split = (mz_stream_split *)stream;
  244. int64_t position = 0;
  245. int32_t written = 0;
  246. int32_t bytes_left = size;
  247. int32_t bytes_to_write = 0;
  248. int32_t bytes_avail = 0;
  249. int32_t number_disk = -1;
  250. int32_t err = MZ_OK;
  251. const uint8_t *buf_ptr = (const uint8_t *)buf;
  252. position = mz_stream_tell(split->stream.base);
  253. while (bytes_left > 0)
  254. {
  255. bytes_to_write = bytes_left;
  256. if (split->disk_size > 0)
  257. {
  258. if ((split->total_out_disk == split->disk_size && split->total_out > 0) ||
  259. (split->number_disk == -1 && split->number_disk != split->current_disk))
  260. {
  261. if (split->number_disk != -1)
  262. number_disk = split->current_disk + 1;
  263. err = mz_stream_split_goto_disk(stream, number_disk);
  264. if (err != MZ_OK)
  265. return err;
  266. }
  267. if (split->number_disk != -1)
  268. {
  269. bytes_avail = (int32_t)(split->disk_size - split->total_out_disk);
  270. if (bytes_to_write > bytes_avail)
  271. bytes_to_write = bytes_avail;
  272. }
  273. }
  274. written = mz_stream_write(split->stream.base, buf_ptr, bytes_to_write);
  275. if (written != bytes_to_write)
  276. return MZ_WRITE_ERROR;
  277. mz_stream_split_print("Split - Write disk - %" PRId32 "\n", written);
  278. bytes_left -= written;
  279. buf_ptr += written;
  280. split->total_out += written;
  281. split->total_out_disk += written;
  282. if (position == split->current_disk_size)
  283. {
  284. split->current_disk_size += written;
  285. position = split->current_disk_size;
  286. }
  287. }
  288. return size - bytes_left;
  289. }
  290. int64_t mz_stream_split_tell(void *stream)
  291. {
  292. mz_stream_split *split = (mz_stream_split *)stream;
  293. int32_t err = MZ_OK;
  294. err = mz_stream_split_goto_disk(stream, split->number_disk);
  295. if (err != MZ_OK)
  296. return err;
  297. return mz_stream_tell(split->stream.base);
  298. }
  299. int32_t mz_stream_split_seek(void *stream, int64_t offset, int32_t origin)
  300. {
  301. mz_stream_split *split = (mz_stream_split *)stream;
  302. int64_t disk_left = 0;
  303. int64_t position = 0;
  304. int32_t err = MZ_OK;
  305. err = mz_stream_split_goto_disk(stream, split->number_disk);
  306. if (err != MZ_OK)
  307. return err;
  308. mz_stream_split_print("Split - Seek disk - %" PRId64 " (origin %" PRId32 ")\n", offset, origin);
  309. if ((origin == MZ_SEEK_CUR) && (split->number_disk != -1))
  310. {
  311. position = mz_stream_tell(split->stream.base);
  312. disk_left = split->current_disk_size - position;
  313. while (offset > disk_left)
  314. {
  315. err = mz_stream_split_goto_disk(stream, split->current_disk + 1);
  316. if (err != MZ_OK)
  317. return err;
  318. offset -= disk_left;
  319. disk_left = split->current_disk_size;
  320. }
  321. }
  322. return mz_stream_seek(split->stream.base, offset, origin);
  323. }
  324. int32_t mz_stream_split_close(void *stream)
  325. {
  326. mz_stream_split *split = (mz_stream_split *)stream;
  327. int32_t err = MZ_OK;
  328. err = mz_stream_split_close_disk(stream);
  329. split->is_open = 0;
  330. return err;
  331. }
  332. int32_t mz_stream_split_error(void *stream)
  333. {
  334. mz_stream_split *split = (mz_stream_split *)stream;
  335. return mz_stream_error(split->stream.base);
  336. }
  337. int32_t mz_stream_split_get_prop_int64(void *stream, int32_t prop, int64_t *value)
  338. {
  339. mz_stream_split *split = (mz_stream_split *)stream;
  340. switch (prop)
  341. {
  342. case MZ_STREAM_PROP_TOTAL_OUT:
  343. *value = split->total_out;
  344. break;
  345. case MZ_STREAM_PROP_DISK_NUMBER:
  346. *value = split->number_disk;
  347. break;
  348. case MZ_STREAM_PROP_DISK_SIZE:
  349. *value = split->disk_size;
  350. break;
  351. default:
  352. return MZ_EXIST_ERROR;
  353. }
  354. return MZ_OK;
  355. }
  356. int32_t mz_stream_split_set_prop_int64(void *stream, int32_t prop, int64_t value)
  357. {
  358. mz_stream_split *split = (mz_stream_split *)stream;
  359. switch (prop)
  360. {
  361. case MZ_STREAM_PROP_DISK_NUMBER:
  362. split->number_disk = (int32_t)value;
  363. break;
  364. case MZ_STREAM_PROP_DISK_SIZE:
  365. split->disk_size = value;
  366. break;
  367. default:
  368. return MZ_EXIST_ERROR;
  369. }
  370. return MZ_OK;
  371. }
  372. void *mz_stream_split_create(void **stream)
  373. {
  374. mz_stream_split *split = NULL;
  375. split = (mz_stream_split *)MZ_ALLOC(sizeof(mz_stream_split));
  376. if (split != NULL)
  377. {
  378. memset(split, 0, sizeof(mz_stream_split));
  379. split->stream.vtbl = &mz_stream_split_vtbl;
  380. }
  381. if (stream != NULL)
  382. *stream = split;
  383. return split;
  384. }
  385. void mz_stream_split_delete(void **stream)
  386. {
  387. mz_stream_split *split = NULL;
  388. if (stream == NULL)
  389. return;
  390. split = (mz_stream_split *)*stream;
  391. if (split != NULL)
  392. {
  393. if (split->path_cd)
  394. MZ_FREE(split->path_cd);
  395. if (split->path_disk)
  396. MZ_FREE(split->path_disk);
  397. MZ_FREE(split);
  398. }
  399. *stream = NULL;
  400. }
  401. void *mz_stream_split_get_interface(void)
  402. {
  403. return (void *)&mz_stream_split_vtbl;
  404. }