vgmstream/src/base/streamfile_io.c
2024-07-14 21:15:52 +02:00

105 lines
4.0 KiB
C

#include "../streamfile.h"
typedef struct {
STREAMFILE vt;
STREAMFILE* inner_sf;
void* data; /* state for custom reads, malloc'ed + copied on open (to re-open streamfiles cleanly) */
size_t data_size;
size_t (*read_callback)(STREAMFILE*, uint8_t*, off_t, size_t, void*); /* custom read to modify data before copying into buffer */
size_t (*size_callback)(STREAMFILE*, void*); /* size when custom reads make data smaller/bigger than underlying streamfile */
int (*init_callback)(STREAMFILE*, void*); /* init the data struct members somehow, return >= 0 if ok */
void (*close_callback)(STREAMFILE*, void*); /* close the data struct members somehow */
/* read doesn't use offv_t since callbacks would need to be modified */
} IO_STREAMFILE;
static size_t io_read(IO_STREAMFILE* sf, uint8_t* dst, offv_t offset, size_t length) {
return sf->read_callback(sf->inner_sf, dst, (off_t)offset, length, sf->data);
}
static size_t io_get_size(IO_STREAMFILE* sf) {
if (sf->size_callback)
return sf->size_callback(sf->inner_sf, sf->data);
else
return sf->inner_sf->get_size(sf->inner_sf); /* default */
}
static offv_t io_get_offset(IO_STREAMFILE* sf) {
return sf->inner_sf->get_offset(sf->inner_sf); /* default */
}
static void io_get_name(IO_STREAMFILE* sf, char* name, size_t name_size) {
sf->inner_sf->get_name(sf->inner_sf, name, name_size); /* default */
}
static STREAMFILE* io_open(IO_STREAMFILE* sf, const char* const filename, size_t buf_size) {
STREAMFILE* new_inner_sf = sf->inner_sf->open(sf->inner_sf,filename,buf_size);
return open_io_streamfile_ex(new_inner_sf, sf->data, sf->data_size, sf->read_callback, sf->size_callback, sf->init_callback, sf->close_callback);
}
static void io_close(IO_STREAMFILE* sf) {
if (sf->close_callback)
sf->close_callback(sf->inner_sf, sf->data);
sf->inner_sf->close(sf->inner_sf);
free(sf->data);
free(sf);
}
STREAMFILE* open_io_streamfile_ex(STREAMFILE* sf, void* data, size_t data_size, void* read_callback, void* size_callback, void* init_callback, void* close_callback) {
IO_STREAMFILE* this_sf = NULL;
if (!sf) goto fail;
if ((data && !data_size) || (!data && data_size)) goto fail;
this_sf = calloc(1, sizeof(IO_STREAMFILE));
if (!this_sf) goto fail;
/* set callbacks and internals */
this_sf->vt.read = (void*)io_read;
this_sf->vt.get_size = (void*)io_get_size;
this_sf->vt.get_offset = (void*)io_get_offset;
this_sf->vt.get_name = (void*)io_get_name;
this_sf->vt.open = (void*)io_open;
this_sf->vt.close = (void*)io_close;
this_sf->vt.stream_index = sf->stream_index;
this_sf->inner_sf = sf;
if (data) {
this_sf->data = malloc(data_size);
if (!this_sf->data) goto fail;
memcpy(this_sf->data, data, data_size);
}
this_sf->data_size = data_size;
this_sf->read_callback = read_callback;
this_sf->size_callback = size_callback;
this_sf->init_callback = init_callback;
this_sf->close_callback = close_callback;
if (this_sf->init_callback) {
int ok = this_sf->init_callback(this_sf->inner_sf, this_sf->data);
if (ok < 0) goto fail;
}
return &this_sf->vt;
fail:
if (this_sf) free(this_sf->data);
free(this_sf);
return NULL;
}
STREAMFILE* open_io_streamfile_ex_f(STREAMFILE* sf, void* data, size_t data_size, void* read_callback, void* size_callback, void* init_callback, void* close_callback) {
STREAMFILE* new_sf = open_io_streamfile_ex(sf, data, data_size, read_callback, size_callback, init_callback, close_callback);
if (!new_sf)
close_streamfile(sf);
return new_sf;
}
STREAMFILE* open_io_streamfile(STREAMFILE* sf, void* data, size_t data_size, void* read_callback, void* size_callback) {
return open_io_streamfile_ex(sf, data, data_size, read_callback, size_callback, NULL, NULL);
}
STREAMFILE* open_io_streamfile_f(STREAMFILE* sf, void* data, size_t data_size, void* read_callback, void* size_callback) {
return open_io_streamfile_ex_f(sf, data, data_size, read_callback, size_callback, NULL, NULL);
}