2024-07-07 21:25:59 +02:00
|
|
|
#ifndef _API_STREAMFILE_H_
|
|
|
|
#define _API_STREAMFILE_H_
|
2024-07-14 20:31:50 +02:00
|
|
|
#include "api.h"
|
|
|
|
#if LIBVGMSTREAM_ENABLE
|
2024-07-07 21:25:59 +02:00
|
|
|
|
|
|
|
/* vgmstream's IO API, defined as a "streamfile" (SF).
|
|
|
|
*
|
2024-07-14 20:31:50 +02:00
|
|
|
* 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
|
2024-07-07 21:25:59 +02:00
|
|
|
*
|
2024-07-14 20:31:50 +02:00
|
|
|
* 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.
|
2024-07-07 21:25:59 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
2024-07-14 20:31:50 +02:00
|
|
|
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,
|
|
|
|
};
|
|
|
|
|
2024-07-07 21:25:59 +02:00
|
|
|
typedef struct libvgmstream_streamfile_t {
|
2024-07-14 20:31:50 +02:00
|
|
|
//uint32_t flags; // info flags for vgmstream
|
|
|
|
void* user_data; // any internal structure
|
2024-07-07 21:25:59 +02:00
|
|
|
|
2024-07-14 20:31:50 +02:00
|
|
|
/* 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);
|
2024-07-07 21:25:59 +02:00
|
|
|
|
2024-07-14 20:31:50 +02:00
|
|
|
/* 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);
|
2024-07-07 21:25:59 +02:00
|
|
|
|
2024-07-14 20:31:50 +02:00
|
|
|
/* get max offset
|
|
|
|
*/
|
|
|
|
int64_t (*get_size)(void* user_data);
|
2024-07-07 21:25:59 +02:00
|
|
|
|
2024-07-14 20:31:50 +02:00
|
|
|
/* copy current filename to name buf
|
|
|
|
*/
|
|
|
|
void (*get_name)(void* user_data, char* name, int name_size); //TODO return char*?
|
2024-07-07 21:25:59 +02:00
|
|
|
|
2024-07-14 20:31:50 +02:00
|
|
|
/* 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);
|
2024-07-07 21:25:59 +02:00
|
|
|
|
|
|
|
} libvgmstream_streamfile_t;
|
|
|
|
|
2024-07-14 20:31:50 +02:00
|
|
|
|
2024-07-07 21:25:59 +02:00
|
|
|
/* helper */
|
2024-07-14 20:31:50 +02:00
|
|
|
static inline void libvgmstream_streamfile_close(libvgmstream_streamfile_t* libsf) {
|
|
|
|
if (!libsf || !libsf->close)
|
2024-07-07 21:25:59 +02:00
|
|
|
return;
|
2024-07-14 20:31:50 +02:00
|
|
|
libsf->close(libsf);
|
2024-07-07 21:25:59 +02:00
|
|
|
}
|
|
|
|
|
2024-07-14 20:31:50 +02:00
|
|
|
|
|
|
|
LIBVGMSTREAM_API libvgmstream_streamfile_t* libvgmstream_streamfile_from_filename(const char* filename);
|
2024-07-07 21:25:59 +02:00
|
|
|
|
|
|
|
#endif
|
|
|
|
#endif
|