mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-12-18 17:35:53 +01:00
105 lines
4.0 KiB
C
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);
|
|
}
|