mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-28 08:20:54 +01:00
87 lines
2.7 KiB
C
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 */
|
||
|
}
|