mz_strm_buf.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. /* mz_strm_buf.c -- Stream for buffering reads/writes
  2. Version 2.9.2, February 12, 2020
  3. part of the MiniZip project
  4. This version of ioapi is designed to buffer IO.
  5. Copyright (C) 2010-2020 Nathan Moinvaziri
  6. https://github.com/nmoinvaz/minizip
  7. This program is distributed under the terms of the same license as zlib.
  8. See the accompanying LICENSE file for the full text of the license.
  9. */
  10. #include "mz.h"
  11. #include "mz_strm.h"
  12. #include "mz_strm_buf.h"
  13. /***************************************************************************/
  14. static mz_stream_vtbl mz_stream_buffered_vtbl = {
  15. mz_stream_buffered_open,
  16. mz_stream_buffered_is_open,
  17. mz_stream_buffered_read,
  18. mz_stream_buffered_write,
  19. mz_stream_buffered_tell,
  20. mz_stream_buffered_seek,
  21. mz_stream_buffered_close,
  22. mz_stream_buffered_error,
  23. mz_stream_buffered_create,
  24. mz_stream_buffered_delete,
  25. NULL,
  26. NULL
  27. };
  28. /***************************************************************************/
  29. typedef struct mz_stream_buffered_s {
  30. mz_stream stream;
  31. int32_t error;
  32. char readbuf[INT16_MAX];
  33. int32_t readbuf_len;
  34. int32_t readbuf_pos;
  35. int32_t readbuf_hits;
  36. int32_t readbuf_misses;
  37. char writebuf[INT16_MAX];
  38. int32_t writebuf_len;
  39. int32_t writebuf_pos;
  40. int32_t writebuf_hits;
  41. int32_t writebuf_misses;
  42. int64_t position;
  43. } mz_stream_buffered;
  44. /***************************************************************************/
  45. #if 0
  46. # define mz_stream_buffered_print printf
  47. #else
  48. # define mz_stream_buffered_print(fmt,...)
  49. #endif
  50. /***************************************************************************/
  51. static int32_t mz_stream_buffered_reset(void *stream)
  52. {
  53. mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
  54. buffered->readbuf_len = 0;
  55. buffered->readbuf_pos = 0;
  56. buffered->writebuf_len = 0;
  57. buffered->writebuf_pos = 0;
  58. buffered->position = 0;
  59. return MZ_OK;
  60. }
  61. int32_t mz_stream_buffered_open(void *stream, const char *path, int32_t mode)
  62. {
  63. mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
  64. mz_stream_buffered_print("Buffered - Open (mode %" PRId32 ")\n", mode);
  65. mz_stream_buffered_reset(buffered);
  66. return mz_stream_open(buffered->stream.base, path, mode);
  67. }
  68. int32_t mz_stream_buffered_is_open(void *stream)
  69. {
  70. mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
  71. return mz_stream_is_open(buffered->stream.base);
  72. }
  73. static int32_t mz_stream_buffered_flush(void *stream, int32_t *written)
  74. {
  75. mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
  76. int32_t total_bytes_written = 0;
  77. int32_t bytes_to_write = buffered->writebuf_len;
  78. int32_t bytes_left_to_write = buffered->writebuf_len;
  79. int32_t bytes_written = 0;
  80. *written = 0;
  81. while (bytes_left_to_write > 0)
  82. {
  83. bytes_written = mz_stream_write(buffered->stream.base,
  84. buffered->writebuf + (bytes_to_write - bytes_left_to_write), bytes_left_to_write);
  85. if (bytes_written != bytes_left_to_write)
  86. return MZ_WRITE_ERROR;
  87. buffered->writebuf_misses += 1;
  88. mz_stream_buffered_print("Buffered - Write flush (%" PRId32 ":%" PRId32 " len %" PRId32 ")\n",
  89. bytes_to_write, bytes_left_to_write, buffered->writebuf_len);
  90. total_bytes_written += bytes_written;
  91. bytes_left_to_write -= bytes_written;
  92. buffered->position += bytes_written;
  93. }
  94. buffered->writebuf_len = 0;
  95. buffered->writebuf_pos = 0;
  96. *written = total_bytes_written;
  97. return MZ_OK;
  98. }
  99. int32_t mz_stream_buffered_read(void *stream, void *buf, int32_t size)
  100. {
  101. mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
  102. int32_t buf_len = 0;
  103. int32_t bytes_to_read = 0;
  104. int32_t bytes_to_copy = 0;
  105. int32_t bytes_left_to_read = size;
  106. int32_t bytes_read = 0;
  107. mz_stream_buffered_print("Buffered - Read (size %" PRId32 " pos %" PRId64 ")\n", size, buffered->position);
  108. if (buffered->writebuf_len > 0)
  109. {
  110. mz_stream_buffered_print("Buffered - Switch from write to read, not yet supported (pos %" PRId64 ")\n",
  111. buffered->position);
  112. }
  113. while (bytes_left_to_read > 0)
  114. {
  115. if ((buffered->readbuf_len == 0) || (buffered->readbuf_pos == buffered->readbuf_len))
  116. {
  117. if (buffered->readbuf_len == sizeof(buffered->readbuf))
  118. {
  119. buffered->readbuf_pos = 0;
  120. buffered->readbuf_len = 0;
  121. }
  122. bytes_to_read = (int32_t)sizeof(buffered->readbuf) - (buffered->readbuf_len - buffered->readbuf_pos);
  123. bytes_read = mz_stream_read(buffered->stream.base, buffered->readbuf + buffered->readbuf_pos, bytes_to_read);
  124. if (bytes_read < 0)
  125. return bytes_read;
  126. buffered->readbuf_misses += 1;
  127. buffered->readbuf_len += bytes_read;
  128. buffered->position += bytes_read;
  129. mz_stream_buffered_print("Buffered - Filled (read %" PRId32 "/%" PRId32 " buf %" PRId32 ":%" PRId32 " pos %" PRId64 ")\n",
  130. bytes_read, bytes_to_read, buffered->readbuf_pos, buffered->readbuf_len, buffered->position);
  131. if (bytes_read == 0)
  132. break;
  133. }
  134. if ((buffered->readbuf_len - buffered->readbuf_pos) > 0)
  135. {
  136. bytes_to_copy = buffered->readbuf_len - buffered->readbuf_pos;
  137. if (bytes_to_copy > bytes_left_to_read)
  138. bytes_to_copy = bytes_left_to_read;
  139. memcpy((char *)buf + buf_len, buffered->readbuf + buffered->readbuf_pos, bytes_to_copy);
  140. buf_len += bytes_to_copy;
  141. bytes_left_to_read -= bytes_to_copy;
  142. buffered->readbuf_hits += 1;
  143. buffered->readbuf_pos += bytes_to_copy;
  144. mz_stream_buffered_print("Buffered - Emptied (copied %" PRId32 " remaining %" PRId32 " buf %" PRId32 ":%" PRId32 " pos %" PRId64 ")\n",
  145. bytes_to_copy, bytes_left_to_read, buffered->readbuf_pos, buffered->readbuf_len, buffered->position);
  146. }
  147. }
  148. return size - bytes_left_to_read;
  149. }
  150. int32_t mz_stream_buffered_write(void *stream, const void *buf, int32_t size)
  151. {
  152. mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
  153. int32_t bytes_to_write = size;
  154. int32_t bytes_left_to_write = size;
  155. int32_t bytes_to_copy = 0;
  156. int32_t bytes_used = 0;
  157. int32_t bytes_flushed = 0;
  158. int32_t err = MZ_OK;
  159. mz_stream_buffered_print("Buffered - Write (size %" PRId32 " len %" PRId32 " pos %" PRId64 ")\n",
  160. size, buffered->writebuf_len, buffered->position);
  161. if (buffered->readbuf_len > 0)
  162. {
  163. buffered->position -= buffered->readbuf_len;
  164. buffered->position += buffered->readbuf_pos;
  165. buffered->readbuf_len = 0;
  166. buffered->readbuf_pos = 0;
  167. mz_stream_buffered_print("Buffered - Switch from read to write (pos %" PRId64 ")\n", buffered->position);
  168. err = mz_stream_seek(buffered->stream.base, buffered->position, MZ_SEEK_SET);
  169. if (err != MZ_OK)
  170. return err;
  171. }
  172. while (bytes_left_to_write > 0)
  173. {
  174. bytes_used = buffered->writebuf_len;
  175. if (bytes_used > buffered->writebuf_pos)
  176. bytes_used = buffered->writebuf_pos;
  177. bytes_to_copy = (int32_t)sizeof(buffered->writebuf) - bytes_used;
  178. if (bytes_to_copy > bytes_left_to_write)
  179. bytes_to_copy = bytes_left_to_write;
  180. if (bytes_to_copy == 0)
  181. {
  182. err = mz_stream_buffered_flush(stream, &bytes_flushed);
  183. if (err != MZ_OK)
  184. return err;
  185. if (bytes_flushed == 0)
  186. return 0;
  187. continue;
  188. }
  189. memcpy(buffered->writebuf + buffered->writebuf_pos,
  190. (const char *)buf + (bytes_to_write - bytes_left_to_write), bytes_to_copy);
  191. mz_stream_buffered_print("Buffered - Write copy (remaining %" PRId32 " write %" PRId32 ":%" PRId32 " len %" PRId32 ")\n",
  192. bytes_to_copy, bytes_to_write, bytes_left_to_write, buffered->writebuf_len);
  193. bytes_left_to_write -= bytes_to_copy;
  194. buffered->writebuf_pos += bytes_to_copy;
  195. buffered->writebuf_hits += 1;
  196. if (buffered->writebuf_pos > buffered->writebuf_len)
  197. buffered->writebuf_len += buffered->writebuf_pos - buffered->writebuf_len;
  198. }
  199. return size - bytes_left_to_write;
  200. }
  201. int64_t mz_stream_buffered_tell(void *stream)
  202. {
  203. mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
  204. int64_t position = mz_stream_tell(buffered->stream.base);
  205. buffered->position = position;
  206. mz_stream_buffered_print("Buffered - Tell (pos %" PRId64 " readpos %" PRId32 " writepos %" PRId32 ")\n",
  207. buffered->position, buffered->readbuf_pos, buffered->writebuf_pos);
  208. if (buffered->readbuf_len > 0)
  209. position -= ((int64_t)buffered->readbuf_len - buffered->readbuf_pos);
  210. if (buffered->writebuf_len > 0)
  211. position += buffered->writebuf_pos;
  212. return position;
  213. }
  214. int32_t mz_stream_buffered_seek(void *stream, int64_t offset, int32_t origin)
  215. {
  216. mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
  217. int32_t bytes_flushed = 0;
  218. int32_t err = MZ_OK;
  219. mz_stream_buffered_print("Buffered - Seek (origin %" PRId32 " offset %" PRId64 " pos %" PRId64 ")\n",
  220. origin, offset, buffered->position);
  221. switch (origin)
  222. {
  223. case MZ_SEEK_SET:
  224. if (buffered->writebuf_len > 0)
  225. {
  226. if ((offset >= buffered->position) && (offset <= buffered->position + buffered->writebuf_len))
  227. {
  228. buffered->writebuf_pos = (int32_t)(offset - buffered->position);
  229. return MZ_OK;
  230. }
  231. }
  232. if ((buffered->readbuf_len > 0) && (offset < buffered->position) &&
  233. (offset >= buffered->position - buffered->readbuf_len))
  234. {
  235. buffered->readbuf_pos = (int32_t)(offset - (buffered->position - buffered->readbuf_len));
  236. return MZ_OK;
  237. }
  238. err = mz_stream_buffered_flush(stream, &bytes_flushed);
  239. if (err != MZ_OK)
  240. return err;
  241. buffered->position = offset;
  242. break;
  243. case MZ_SEEK_CUR:
  244. if (buffered->readbuf_len > 0)
  245. {
  246. if (offset <= ((int64_t)buffered->readbuf_len - buffered->readbuf_pos))
  247. {
  248. buffered->readbuf_pos += (uint32_t)offset;
  249. return MZ_OK;
  250. }
  251. offset -= ((int64_t)buffered->readbuf_len - buffered->readbuf_pos);
  252. buffered->position += offset;
  253. }
  254. if (buffered->writebuf_len > 0)
  255. {
  256. if (offset <= ((int64_t)buffered->writebuf_len - buffered->writebuf_pos))
  257. {
  258. buffered->writebuf_pos += (uint32_t)offset;
  259. return MZ_OK;
  260. }
  261. /* offset -= (buffered->writebuf_len - buffered->writebuf_pos); */
  262. }
  263. err = mz_stream_buffered_flush(stream, &bytes_flushed);
  264. if (err != MZ_OK)
  265. return err;
  266. break;
  267. case MZ_SEEK_END:
  268. if (buffered->writebuf_len > 0)
  269. {
  270. buffered->writebuf_pos = buffered->writebuf_len;
  271. return MZ_OK;
  272. }
  273. break;
  274. }
  275. buffered->readbuf_len = 0;
  276. buffered->readbuf_pos = 0;
  277. buffered->writebuf_len = 0;
  278. buffered->writebuf_pos = 0;
  279. return mz_stream_seek(buffered->stream.base, offset, origin);
  280. }
  281. int32_t mz_stream_buffered_close(void *stream)
  282. {
  283. mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
  284. int32_t bytes_flushed = 0;
  285. mz_stream_buffered_flush(stream, &bytes_flushed);
  286. mz_stream_buffered_print("Buffered - Close (flushed %" PRId32 ")\n", bytes_flushed);
  287. if (buffered->readbuf_hits + buffered->readbuf_misses > 0)
  288. {
  289. mz_stream_buffered_print("Buffered - Read efficiency %.02f%%\n",
  290. (buffered->readbuf_hits / ((float)buffered->readbuf_hits + buffered->readbuf_misses)) * 100);
  291. }
  292. if (buffered->writebuf_hits + buffered->writebuf_misses > 0)
  293. {
  294. mz_stream_buffered_print("Buffered - Write efficiency %.02f%%\n",
  295. (buffered->writebuf_hits / ((float)buffered->writebuf_hits + buffered->writebuf_misses)) * 100);
  296. }
  297. mz_stream_buffered_reset(buffered);
  298. return mz_stream_close(buffered->stream.base);
  299. }
  300. int32_t mz_stream_buffered_error(void *stream)
  301. {
  302. mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
  303. return mz_stream_error(buffered->stream.base);
  304. }
  305. void *mz_stream_buffered_create(void **stream)
  306. {
  307. mz_stream_buffered *buffered = NULL;
  308. buffered = (mz_stream_buffered *)MZ_ALLOC(sizeof(mz_stream_buffered));
  309. if (buffered != NULL)
  310. {
  311. memset(buffered, 0, sizeof(mz_stream_buffered));
  312. buffered->stream.vtbl = &mz_stream_buffered_vtbl;
  313. }
  314. if (stream != NULL)
  315. *stream = buffered;
  316. return buffered;
  317. }
  318. void mz_stream_buffered_delete(void **stream)
  319. {
  320. mz_stream_buffered *buffered = NULL;
  321. if (stream == NULL)
  322. return;
  323. buffered = (mz_stream_buffered *)*stream;
  324. if (buffered != NULL)
  325. MZ_FREE(buffered);
  326. *stream = NULL;
  327. }
  328. void *mz_stream_buffered_get_interface(void)
  329. {
  330. return (void *)&mz_stream_buffered_vtbl;
  331. }