vgmstream/xmplay/xmp_streamfile.c
2024-07-18 23:50:22 +02:00

87 lines
2.7 KiB
C

#include "xmp_vgmstream.h"
/* a STREAMFILE that operates via XMPlay's XMPFUNC_FILE+XMPFILE */
typedef struct _XMPLAY_STREAMFILE {
STREAMFILE sf; /* callbacks */
XMPFILE infile; /* actual FILE */
XMPFUNC_FILE* xmpf_file; /* helper */
char name[0x8000]; /* path limit */
off_t offset; /* current offset */
int internal_xmpfile; /* infile was not supplied externally and can be closed */
} XMPLAY_STREAMFILE;
static size_t xmpsf_read(XMPLAY_STREAMFILE* sf, uint8_t* dst, offv_t offset, size_t length) {
size_t read;
if (sf->offset != offset) {
if (sf->xmpf_file->Seek(sf->infile, offset))
sf->offset = offset;
else
sf->offset = sf->xmpf_file->Tell(sf->infile);
}
read = sf->xmpf_file->Read(sf->infile, dst, length);
if (read > 0)
sf->offset += read;
return read;
}
static off_t xmpsf_get_size(XMPLAY_STREAMFILE* sf) {
return sf->xmpf_file->GetSize(sf->infile);
}
static off_t xmpsf_get_offset(XMPLAY_STREAMFILE* sf) {
return sf->xmpf_file->Tell(sf->infile);
}
static void xmpsf_get_name(XMPLAY_STREAMFILE* sf, char* buffer, size_t length) {
snprintf(buffer, length, "%s", sf->name);
buffer[length - 1] = '\0';
}
static STREAMFILE* xmpsf_open(XMPLAY_STREAMFILE* sf, const char* const filename, size_t buffersize) {
XMPFILE newfile;
if (!filename)
return NULL;
newfile = sf->xmpf_file->Open(filename);
if (!newfile) return NULL;
return open_xmplay_streamfile_by_xmpfile(newfile, sf->xmpf_file, filename, true); /* internal XMPFILE */
}
static void xmpsf_close(XMPLAY_STREAMFILE* sf) {
/* Close XMPFILE, but only if we opened it (ex. for subfiles inside metas).
* Otherwise must be left open as other parts of XMPlay need it and would crash. */
if (sf->internal_xmpfile) {
sf->xmpf_file->Close(sf->infile);
}
free(sf);
}
STREAMFILE* open_xmplay_streamfile_by_xmpfile(XMPFILE infile, XMPFUNC_FILE* xmpf_file, const char* path, bool internal) {
XMPLAY_STREAMFILE* this_sf = calloc(1, sizeof(XMPLAY_STREAMFILE));
if (!this_sf) return NULL;
this_sf->sf.read = (void*)xmpsf_read;
this_sf->sf.get_size = (void*)xmpsf_get_size;
this_sf->sf.get_offset = (void*)xmpsf_get_offset;
this_sf->sf.get_name = (void*)xmpsf_get_name;
this_sf->sf.open = (void*)xmpsf_open;
this_sf->sf.close = (void*)xmpsf_close;
this_sf->infile = infile;
this_sf->offset = 0;
snprintf(this_sf->name, sizeof(this_sf->name), "%s", path);
this_sf->name[sizeof(this_sf->name) - 1] = '\0';
this_sf->internal_xmpfile = internal;
this_sf->xmpf_file = xmpf_file;
return &this_sf->sf; /* pointer to STREAMFILE start = rest of the custom data follows */
}