Files
kaizen/common/stream.c
SimoneN64 ee861bc6cf Squashed 'external/unarr/' content from commit f243d72fb3
git-subtree-dir: external/unarr
git-subtree-split: f243d72fb3fe418c26a19514609ac7167d089df4
2024-09-14 16:23:23 +02:00

218 lines
4.9 KiB
C

/* Copyright 2015 the unarr project authors (see AUTHORS file).
License: LGPLv3 */
#include "unarr-imp.h"
ar_stream *ar_open_stream(void *data, ar_stream_close_fn close, ar_stream_read_fn read, ar_stream_seek_fn seek, ar_stream_tell_fn tell)
{
ar_stream *stream = malloc(sizeof(ar_stream));
if (!stream) {
close(data);
return NULL;
}
stream->data = data;
stream->close = close;
stream->read = read;
stream->seek = seek;
stream->tell = tell;
return stream;
}
void ar_close(ar_stream *stream)
{
if (stream)
stream->close(stream->data);
free(stream);
}
size_t ar_read(ar_stream *stream, void *buffer, size_t count)
{
return stream->read(stream->data, buffer, count);
}
bool ar_seek(ar_stream *stream, off64_t offset, int origin)
{
return stream->seek(stream->data, offset, origin);
}
bool ar_skip(ar_stream *stream, off64_t count)
{
return stream->seek(stream->data, count, SEEK_CUR);
}
off64_t ar_tell(ar_stream *stream)
{
return stream->tell(stream->data);
}
/***** stream based on FILE *****/
static void file_close(void *data)
{
fclose(data);
}
static size_t file_read(void *data, void *buffer, size_t count)
{
return fread(buffer, 1, count, data);
}
static bool file_seek(void *data, off64_t offset, int origin)
{
#ifdef _WIN32
return _fseeki64(data, offset, origin) == 0;
#else
#if _POSIX_C_SOURCE >= 200112L
if (sizeof(off_t) == 8)
return fseeko(data, offset, origin) == 0;
#endif
if (offset > INT32_MAX || offset < INT32_MIN)
return false;
return fseek(data, (long)offset, origin) == 0;
#endif
}
static off64_t file_tell(void *data)
{
#ifdef _WIN32
return _ftelli64(data);
#elif _POSIX_C_SOURCE >= 200112L
return ftello(data);
#else
return ftell(data);
#endif
}
ar_stream *ar_open_file(const char *path)
{
FILE *f = path ? fopen(path, "rb") : NULL;
if (!f)
return NULL;
return ar_open_stream(f, file_close, file_read, file_seek, file_tell);
}
#ifdef _WIN32
ar_stream *ar_open_file_w(const wchar_t *path)
{
FILE *f = path ? _wfopen(path, L"rb") : NULL;
if (!f)
return NULL;
return ar_open_stream(f, file_close, file_read, file_seek, file_tell);
}
#endif
/***** stream based on preallocated memory *****/
struct MemoryStream {
const uint8_t *data;
size_t length;
size_t offset;
};
static void memory_close(void *data)
{
struct MemoryStream *stm = data;
free(stm);
}
static size_t memory_read(void *data, void *buffer, size_t count)
{
struct MemoryStream *stm = data;
if (count > stm->length - stm->offset)
count = stm->length - stm->offset;
memcpy(buffer, stm->data + stm->offset, count);
stm->offset += count;
return count;
}
static bool memory_seek(void *data, off64_t offset, int origin)
{
struct MemoryStream *stm = data;
if (origin == SEEK_CUR)
offset += stm->offset;
else if (origin == SEEK_END)
offset += stm->length;
if (offset < 0 || offset > (off64_t)stm->length || (size_t)offset > stm->length)
return false;
stm->offset = (size_t)offset;
return true;
}
static off64_t memory_tell(void *data)
{
struct MemoryStream *stm = data;
return stm->offset;
}
ar_stream *ar_open_memory(const void *data, size_t datalen)
{
struct MemoryStream *stm = malloc(sizeof(struct MemoryStream));
if (!stm)
return NULL;
stm->data = data;
stm->length = datalen;
stm->offset = 0;
return ar_open_stream(stm, memory_close, memory_read, memory_seek, memory_tell);
}
#ifdef _WIN32
/***** stream based on IStream *****/
#define COBJMACROS
#include <windows.h>
static void stream_close(void *data)
{
IUnknown_Release((IStream *)data);
}
static size_t stream_read(void *data, void *buffer, size_t count)
{
size_t read = 0;
HRESULT res;
ULONG cbRead;
#ifdef _WIN64
while (count > ULONG_MAX) {
res = IStream_Read((IStream *)data, buffer, ULONG_MAX, &cbRead);
if (FAILED(res))
return read;
read += cbRead;
buffer = (BYTE *)buffer + ULONG_MAX;
count -= ULONG_MAX;
}
#endif
res = IStream_Read((IStream *)data, buffer, (ULONG)count, &cbRead);
if (SUCCEEDED(res))
read += cbRead;
return read;
}
static bool stream_seek(void *data, off64_t offset, int origin)
{
LARGE_INTEGER off;
ULARGE_INTEGER n;
HRESULT res;
off.QuadPart = offset;
res = IStream_Seek((IStream *)data, off, origin, &n);
return SUCCEEDED(res);
}
static off64_t stream_tell(void *data)
{
LARGE_INTEGER zero = { 0 };
ULARGE_INTEGER n = { 0 };
IStream_Seek((IStream *)data, zero, SEEK_CUR, &n);
return (off64_t)n.QuadPart;
}
ar_stream *ar_open_istream(IStream *stream)
{
LARGE_INTEGER zero = { 0 };
HRESULT res = IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL);
if (FAILED(res))
return NULL;
IUnknown_AddRef(stream);
return ar_open_stream(stream, stream_close, stream_read, stream_seek, stream_tell);
}
#endif