minizip-ng/src/mz_strm_buf.c

391 lines
12 KiB
C
Raw Normal View History

/* mz_strm_buf.c -- Stream for buffering reads/writes
2018-01-03 10:13:28 -08:00
Version 2.2.5, January 3rd, 2018
part of the MiniZip project
2012-05-06 13:04:17 -07:00
This version of ioapi is designed to buffer IO.
Copyright (C) 2012-2017 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
2012-05-06 13:04:17 -07:00
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
2012-05-06 13:04:17 -07:00
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
2012-06-28 02:02:57 -07:00
#include <stdarg.h>
2012-05-06 13:04:17 -07:00
#include "mz.h"
2017-10-04 22:10:11 -07:00
#include "mz_strm.h"
#include "mz_strm_buf.h"
2012-05-06 13:04:17 -07:00
2017-10-03 21:56:07 -07:00
/***************************************************************************/
2018-01-03 10:13:28 -08:00
#if 1
# define mz_stream_buffered_print(s,f,...) printf(f,__VA_ARGS__);
2012-08-06 17:53:01 -07:00
#else
# define mz_stream_buffered_print(s,f,...)
2012-05-06 13:04:17 -07:00
#endif
2017-10-03 21:56:07 -07:00
/***************************************************************************/
mz_stream_vtbl mz_stream_buffered_vtbl = {
mz_stream_buffered_open,
mz_stream_buffered_is_open,
mz_stream_buffered_read,
mz_stream_buffered_write,
mz_stream_buffered_tell,
mz_stream_buffered_seek,
mz_stream_buffered_close,
mz_stream_buffered_error,
mz_stream_buffered_create,
mz_stream_buffered_delete
};
/***************************************************************************/
2017-10-01 21:43:24 -07:00
typedef struct mz_stream_buffered_s {
mz_stream stream;
int32_t error;
char readbuf[INT16_MAX];
int32_t readbuf_len;
int32_t readbuf_pos;
int32_t readbuf_hits;
int32_t readbuf_misses;
char writebuf[INT16_MAX];
int32_t writebuf_len;
int32_t writebuf_pos;
int32_t writebuf_hits;
int32_t writebuf_misses;
int64_t position;
2017-10-01 21:43:24 -07:00
} mz_stream_buffered;
2012-06-28 02:02:57 -07:00
2017-10-03 21:56:07 -07:00
/***************************************************************************/
2012-06-28 02:02:57 -07:00
2017-10-05 21:26:34 -07:00
int32_t mz_stream_buffered_open(void *stream, const char *path, int32_t mode)
{
mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
2018-01-02 13:10:04 -08:00
mz_stream_buffered_print(buffered, "open [mode %d]\n", mode);
return mz_stream_open(buffered->stream.base, path, mode);
}
2017-11-10 15:04:39 +03:00
int32_t mz_stream_buffered_is_open(void *stream)
{
mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
return mz_stream_is_open(buffered->stream.base);
2017-11-10 15:04:39 +03:00
}
2017-12-26 12:40:30 -08:00
static int32_t mz_stream_buffered_flush(void *stream, int32_t *written)
2012-05-06 13:04:17 -07:00
{
2017-10-01 21:43:24 -07:00
mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
int32_t total_bytes_written = 0;
int32_t bytes_to_write = buffered->writebuf_len;
int32_t bytes_left_to_write = buffered->writebuf_len;
int32_t bytes_written = 0;
2012-05-06 13:04:17 -07:00
2017-09-29 21:02:09 -07:00
*written = 0;
while (bytes_left_to_write > 0)
{
bytes_written = mz_stream_write(buffered->stream.base,
buffered->writebuf + (bytes_to_write - bytes_left_to_write), bytes_left_to_write);
2017-09-29 21:02:09 -07:00
if (bytes_written != bytes_left_to_write)
2017-10-03 21:56:07 -07:00
return MZ_STREAM_ERROR;
2017-09-29 21:02:09 -07:00
buffered->writebuf_misses += 1;
mz_stream_buffered_print(stream, "write flush [%d:%d len %d]\n",
bytes_to_write, bytes_left_to_write, buffered->writebuf_len);
2017-09-29 21:02:09 -07:00
total_bytes_written += bytes_written;
bytes_left_to_write -= bytes_written;
2017-09-29 21:02:09 -07:00
buffered->position += bytes_written;
}
2017-09-29 21:02:09 -07:00
buffered->writebuf_len = 0;
buffered->writebuf_pos = 0;
*written = total_bytes_written;
2017-10-03 21:56:07 -07:00
return MZ_OK;
}
2017-10-05 21:26:34 -07:00
int32_t mz_stream_buffered_read(void *stream, void *buf, int32_t size)
2012-05-06 13:04:17 -07:00
{
2017-10-01 21:43:24 -07:00
mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
int32_t buf_len = 0;
int32_t bytes_to_read = 0;
int32_t bytes_to_copy = 0;
int32_t bytes_left_to_read = size;
int32_t bytes_read = 0;
2012-05-06 13:04:17 -07:00
mz_stream_buffered_print(stream, "read [size %ld pos %lld]\n", size, buffered->position);
2012-05-06 13:04:17 -07:00
2017-09-29 21:02:09 -07:00
if (buffered->writebuf_len > 0)
mz_stream_buffered_print(stream, "switch from write to read, not yet supported [%lld]\n",
buffered->position);
while (bytes_left_to_read > 0)
2012-05-06 13:04:17 -07:00
{
2017-09-29 21:02:09 -07:00
if ((buffered->readbuf_len == 0) || (buffered->readbuf_pos == buffered->readbuf_len))
2012-05-06 13:04:17 -07:00
{
2017-10-15 22:22:19 -07:00
if (buffered->readbuf_len == sizeof(buffered->readbuf))
2012-06-28 02:02:57 -07:00
{
2017-09-29 21:02:09 -07:00
buffered->readbuf_pos = 0;
buffered->readbuf_len = 0;
2012-06-28 02:02:57 -07:00
}
2017-10-15 22:22:19 -07:00
bytes_to_read = sizeof(buffered->readbuf) - (buffered->readbuf_len - buffered->readbuf_pos);
bytes_read = mz_stream_read(buffered->stream.base, buffered->readbuf + buffered->readbuf_pos, bytes_to_read);
if (bytes_read < 0)
return bytes_read;
2012-06-28 02:02:57 -07:00
2017-09-29 21:02:09 -07:00
buffered->readbuf_misses += 1;
buffered->readbuf_len += bytes_read;
buffered->position += bytes_read;
2012-06-28 02:02:57 -07:00
mz_stream_buffered_print(stream, "filled [read %d/%d buf %d:%d pos %lld]\n",
bytes_read, bytes_to_read, buffered->readbuf_pos, buffered->readbuf_len, buffered->position);
if (bytes_read == 0)
2012-05-10 15:59:36 -07:00
break;
2012-05-06 13:04:17 -07:00
}
2017-09-29 21:02:09 -07:00
if ((buffered->readbuf_len - buffered->readbuf_pos) > 0)
2012-05-06 13:04:17 -07:00
{
2017-10-02 22:17:35 -07:00
bytes_to_copy = (uint32_t)(buffered->readbuf_len - buffered->readbuf_pos);
if (bytes_to_copy > bytes_left_to_read)
bytes_to_copy = bytes_left_to_read;
2017-09-29 21:02:09 -07:00
memcpy((char *)buf + buf_len, buffered->readbuf + buffered->readbuf_pos, bytes_to_copy);
2012-05-06 13:04:17 -07:00
buf_len += bytes_to_copy;
bytes_left_to_read -= bytes_to_copy;
2012-05-06 13:04:17 -07:00
2017-09-29 21:02:09 -07:00
buffered->readbuf_hits += 1;
buffered->readbuf_pos += bytes_to_copy;
2012-06-28 02:02:57 -07:00
mz_stream_buffered_print(stream, "emptied [copied %d remaining %d buf %d:%d pos %lld]\n",
bytes_to_copy, bytes_left_to_read, buffered->readbuf_pos, buffered->readbuf_len, buffered->position);
2012-05-06 13:04:17 -07:00
}
}
return size - bytes_left_to_read;
2012-05-06 13:04:17 -07:00
}
2017-10-05 21:26:34 -07:00
int32_t mz_stream_buffered_write(void *stream, const void *buf, int32_t size)
2012-05-06 13:04:17 -07:00
{
2017-10-01 21:43:24 -07:00
mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
int32_t bytes_to_write = size;
int32_t bytes_left_to_write = size;
int32_t bytes_to_copy = 0;
int32_t bytes_used = 0;
int32_t bytes_flushed = 0;
2012-05-06 13:04:17 -07:00
mz_stream_buffered_print(stream, "write [size %ld len %d pos %lld]\n",
size, buffered->writebuf_len, buffered->position);
2017-09-29 21:02:09 -07:00
if (buffered->readbuf_len > 0)
{
buffered->position -= buffered->readbuf_len;
buffered->position += buffered->readbuf_pos;
2017-09-29 21:02:09 -07:00
buffered->readbuf_len = 0;
buffered->readbuf_pos = 0;
mz_stream_buffered_print(stream, "switch from read to write [%lld]\n", buffered->position);
if (mz_stream_seek(buffered->stream.base, buffered->position, MZ_SEEK_SET) != MZ_OK)
2017-10-03 21:56:07 -07:00
return MZ_STREAM_ERROR;
}
while (bytes_left_to_write > 0)
2012-05-06 13:04:17 -07:00
{
2017-10-02 22:17:35 -07:00
bytes_used = buffered->writebuf_len;
if (bytes_used > buffered->writebuf_pos)
bytes_used = buffered->writebuf_pos;
2017-10-15 22:22:19 -07:00
bytes_to_copy = (uint32_t)(sizeof(buffered->writebuf) - bytes_used);
2017-10-02 22:17:35 -07:00
if (bytes_to_copy > bytes_left_to_write)
bytes_to_copy = bytes_left_to_write;
if (bytes_to_copy == 0)
2012-05-06 13:04:17 -07:00
{
2017-10-03 21:56:07 -07:00
if (mz_stream_buffered_flush(stream, &bytes_flushed) != MZ_OK)
return MZ_STREAM_ERROR;
2017-09-29 21:02:09 -07:00
if (bytes_flushed == 0)
2012-05-10 15:59:36 -07:00
return 0;
continue;
2012-05-06 13:04:17 -07:00
}
2017-09-29 21:02:09 -07:00
memcpy(buffered->writebuf + buffered->writebuf_pos, (char *)buf + (bytes_to_write - bytes_left_to_write), bytes_to_copy);
2012-05-06 13:04:17 -07:00
mz_stream_buffered_print(stream, "write copy [remaining %d write %d:%d len %d]\n",
bytes_to_copy, bytes_to_write, bytes_left_to_write, buffered->writebuf_len);
2012-05-06 13:04:17 -07:00
bytes_left_to_write -= bytes_to_copy;
2012-05-06 13:04:17 -07:00
2017-09-29 21:02:09 -07:00
buffered->writebuf_pos += bytes_to_copy;
buffered->writebuf_hits += 1;
if (buffered->writebuf_pos > buffered->writebuf_len)
buffered->writebuf_len += buffered->writebuf_pos - buffered->writebuf_len;
2012-05-06 13:04:17 -07:00
}
return size - bytes_left_to_write;
2012-05-06 13:04:17 -07:00
}
int64_t mz_stream_buffered_tell(void *stream)
2012-06-28 02:02:57 -07:00
{
2017-10-01 21:43:24 -07:00
mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
int64_t position = mz_stream_tell(buffered->stream.base);
2017-09-29 21:02:09 -07:00
buffered->position = position;
mz_stream_buffered_print(stream, "tell [pos %llu readpos %d writepos %d err %d]\n",
buffered->position, buffered->readbuf_pos, buffered->writebuf_pos, errno);
2017-09-29 21:02:09 -07:00
if (buffered->readbuf_len > 0)
position -= (buffered->readbuf_len - buffered->readbuf_pos);
if (buffered->writebuf_len > 0)
position += buffered->writebuf_pos;
2012-06-28 02:02:57 -07:00
return position;
}
int32_t mz_stream_buffered_seek(void *stream, int64_t offset, int32_t origin)
2012-05-06 13:04:17 -07:00
{
2017-10-01 21:43:24 -07:00
mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
int32_t bytes_flushed = 0;
2012-05-06 13:04:17 -07:00
mz_stream_buffered_print(stream, "seek [origin %d offset %llu pos %lld]\n", origin, offset, buffered->position);
2012-06-28 02:02:57 -07:00
switch (origin)
2012-05-06 23:52:22 -07:00
{
case MZ_SEEK_SET:
2012-06-28 02:02:57 -07:00
2017-09-29 21:02:09 -07:00
if (buffered->writebuf_len > 0)
2012-06-28 02:02:57 -07:00
{
2017-09-29 21:02:09 -07:00
if ((offset >= buffered->position) && (offset <= buffered->position + buffered->writebuf_len))
2012-06-28 02:02:57 -07:00
{
2017-09-29 21:02:09 -07:00
buffered->writebuf_pos = (uint32_t)(offset - buffered->position);
2017-10-03 21:56:07 -07:00
return MZ_OK;
2012-06-28 02:02:57 -07:00
}
}
if ((buffered->readbuf_len > 0) && (offset < buffered->position) &&
(offset >= buffered->position - buffered->readbuf_len))
2012-05-07 00:39:30 -07:00
{
2017-09-29 21:02:09 -07:00
buffered->readbuf_pos = (uint32_t)(offset - (buffered->position - buffered->readbuf_len));
2017-10-03 21:56:07 -07:00
return MZ_OK;
2012-05-07 00:39:30 -07:00
}
2017-09-29 21:02:09 -07:00
2017-10-03 21:56:07 -07:00
if (mz_stream_buffered_flush(stream, &bytes_flushed) != MZ_OK)
return MZ_STREAM_ERROR;
2017-09-29 21:02:09 -07:00
buffered->position = offset;
2012-06-28 02:02:57 -07:00
break;
case MZ_SEEK_CUR:
2012-06-28 02:02:57 -07:00
2017-09-29 21:02:09 -07:00
if (buffered->readbuf_len > 0)
2012-06-28 02:02:57 -07:00
{
2017-09-29 21:02:09 -07:00
if (offset <= (buffered->readbuf_len - buffered->readbuf_pos))
2012-06-28 02:02:57 -07:00
{
2017-09-29 21:02:09 -07:00
buffered->readbuf_pos += (uint32_t)offset;
2017-10-03 21:56:07 -07:00
return MZ_OK;
}
2017-09-29 21:02:09 -07:00
offset -= (buffered->readbuf_len - buffered->readbuf_pos);
buffered->position += offset;
2012-06-28 02:02:57 -07:00
}
2017-09-29 21:02:09 -07:00
if (buffered->writebuf_len > 0)
2012-06-28 02:02:57 -07:00
{
2017-09-29 21:02:09 -07:00
if (offset <= (buffered->writebuf_len - buffered->writebuf_pos))
2012-06-28 02:02:57 -07:00
{
2017-09-29 21:02:09 -07:00
buffered->writebuf_pos += (uint32_t)offset;
2017-10-03 21:56:07 -07:00
return MZ_OK;
2012-06-28 02:02:57 -07:00
}
2017-09-29 21:02:09 -07:00
//offset -= (buffered->writebuf_len - buffered->writebuf_pos);
2012-06-28 02:02:57 -07:00
}
2017-10-03 21:56:07 -07:00
if (mz_stream_buffered_flush(stream, &bytes_flushed) != MZ_OK)
return MZ_STREAM_ERROR;
2012-06-28 02:02:57 -07:00
break;
case MZ_SEEK_END:
2012-06-28 02:02:57 -07:00
2017-09-29 21:02:09 -07:00
if (buffered->writebuf_len > 0)
2012-06-28 02:02:57 -07:00
{
2017-09-29 21:02:09 -07:00
buffered->writebuf_pos = buffered->writebuf_len;
2017-10-03 21:56:07 -07:00
return MZ_OK;
2012-06-28 02:02:57 -07:00
}
break;
2012-05-06 23:52:22 -07:00
}
2012-06-28 02:02:57 -07:00
2017-09-29 21:02:09 -07:00
buffered->readbuf_len = 0;
buffered->readbuf_pos = 0;
buffered->writebuf_len = 0;
buffered->writebuf_pos = 0;
2012-06-28 02:02:57 -07:00
2017-10-01 21:43:24 -07:00
return mz_stream_seek(buffered->stream.base, offset, origin);
2012-05-06 13:04:17 -07:00
}
int32_t mz_stream_buffered_close(void *stream)
2012-05-06 13:04:17 -07:00
{
2017-10-01 21:43:24 -07:00
mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
int32_t bytes_flushed = 0;
2017-10-01 21:43:24 -07:00
mz_stream_buffered_flush(stream, &bytes_flushed);
mz_stream_buffered_print(stream, "close\n");
2017-09-29 21:02:09 -07:00
if (buffered->readbuf_hits + buffered->readbuf_misses > 0)
mz_stream_buffered_print(stream, "read efficency %.02f%%\n",
(buffered->readbuf_hits / ((float)buffered->readbuf_hits + buffered->readbuf_misses)) * 100);
2017-09-29 21:02:09 -07:00
if (buffered->writebuf_hits + buffered->writebuf_misses > 0)
mz_stream_buffered_print(stream, "write efficency %.02f%%\n",
(buffered->writebuf_hits / ((float)buffered->writebuf_hits + buffered->writebuf_misses)) * 100);
return mz_stream_close(buffered->stream.base);
2012-05-06 13:04:17 -07:00
}
int32_t mz_stream_buffered_error(void *stream)
2012-05-06 13:04:17 -07:00
{
2017-10-01 21:43:24 -07:00
mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
return mz_stream_error(buffered->stream.base);
2012-05-06 13:04:17 -07:00
}
void *mz_stream_buffered_create(void **stream)
2012-05-06 13:04:17 -07:00
{
2017-10-01 21:43:24 -07:00
mz_stream_buffered *buffered = NULL;
2012-05-06 13:04:17 -07:00
2017-10-01 21:43:24 -07:00
buffered = (mz_stream_buffered *)malloc(sizeof(mz_stream_buffered));
if (buffered != NULL)
{
memset(buffered, 0, sizeof(mz_stream_buffered));
buffered->stream.vtbl = &mz_stream_buffered_vtbl;
2017-10-01 21:43:24 -07:00
}
if (stream != NULL)
2017-10-01 21:43:24 -07:00
*stream = buffered;
2017-09-29 21:02:09 -07:00
return buffered;
2012-05-06 13:04:17 -07:00
}
void mz_stream_buffered_delete(void **stream)
2012-05-06 13:04:17 -07:00
{
2017-10-01 21:43:24 -07:00
mz_stream_buffered *buffered = NULL;
if (stream == NULL)
return;
buffered = (mz_stream_buffered *)*stream;
2017-09-29 21:02:09 -07:00
if (buffered != NULL)
free(buffered);
*stream = NULL;
2012-05-06 13:04:17 -07:00
}
void *mz_stream_buffered_get_interface(void)
{
return (void *)&mz_stream_buffered_vtbl;
}