vgmstream/src/api_streamfile.h
2024-07-14 20:31:50 +02:00

72 lines
2.8 KiB
C

#ifndef _API_STREAMFILE_H_
#define _API_STREAMFILE_H_
#include "api.h"
#if LIBVGMSTREAM_ENABLE
/* vgmstream's IO API, defined as a "streamfile" (SF).
*
* Compared to typical IO, vgmstream has some extra needs that roughly assume there is an underlying filesystem (as usual in games):
* - seeking + reading from arbitrary offsets: header not in the beginning of a stream, rewinding back when looping, etc
* - opening other streamfiles: reopening a copy of the current SF, formats with split header + data, decryption files, etc
* - extracting the filename: opening similarly named companion files, basic extension sanity checks, heuristics for odd cases, etc
*
* If your IO can't fully satisfy those constraints, it may still be possible to create a streamfile that just simulates part of it.
* For example, returning a fake filename, and only handling "open" that reopens itself (same filename), while returning default/incorrect
* values for non-handled operations. Simpler formats will probably work just fine.
*/
enum {
LIBVGMSTREAM_STREAMFILE_SEEK_SET = 0,
LIBVGMSTREAM_STREAMFILE_SEEK_CUR = 1,
LIBVGMSTREAM_STREAMFILE_SEEK_END = 2,
//LIBVGMSTREAM_STREAMFILE_SEEK_GET_OFFSET = 3,
//LIBVGMSTREAM_STREAMFILE_SEEK_GET_SIZE = 5,
};
typedef struct libvgmstream_streamfile_t {
//uint32_t flags; // info flags for vgmstream
void* user_data; // any internal structure
/* read 'length' data at internal offset to 'dst' (implicit seek if needed)
* - assumes 0 = failure/EOF
*/
int (*read)(void* user_data, uint8_t* dst, int dst_size);
/* seek to offset
* - note that due to how vgmstream works this is a fairly common operation (to be optimized later)
*/
int64_t (*seek)(void* user_data, int64_t offset, int whence);
/* get max offset
*/
int64_t (*get_size)(void* user_data);
/* copy current filename to name buf
*/
void (*get_name)(void* user_data, char* name, int name_size); //TODO return char*?
/* open another streamfile from filename (may be some path/protocol, or same as current get_name = reopen)
* - vgmstream mainly opens stuff based on current get_name (relative), so there shouldn't be need to transform this path
*/
struct libvgmstream_streamfile_t* (*open)(void* user_data, const char* filename);
/* free current SF (needed for copied streamfiles) */
void (*close)(struct libvgmstream_streamfile_t* libsf);
} libvgmstream_streamfile_t;
/* helper */
static inline void libvgmstream_streamfile_close(libvgmstream_streamfile_t* libsf) {
if (!libsf || !libsf->close)
return;
libsf->close(libsf);
}
LIBVGMSTREAM_API libvgmstream_streamfile_t* libvgmstream_streamfile_from_filename(const char* filename);
#endif
#endif