#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); }