mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-24 15:00:11 +01:00
cleanup: separte sf code
This commit is contained in:
parent
442084cc85
commit
5d9b4ed827
@ -3,7 +3,7 @@
|
||||
#include "../coding/coding.h"
|
||||
#include "mixing.h"
|
||||
#include "../util/channel_mappings.h"
|
||||
|
||||
#include "../util/sf_utils.h"
|
||||
|
||||
/*******************************************************************************/
|
||||
/* TEXT */
|
||||
|
@ -285,7 +285,6 @@ int render_layout(sample_t* buf, int32_t sample_count, VGMSTREAM* vgmstream) {
|
||||
case layout_blocked_ivaud:
|
||||
case layout_blocked_ea_swvr:
|
||||
case layout_blocked_adm:
|
||||
case layout_blocked_bdsp:
|
||||
case layout_blocked_ps2_iab:
|
||||
case layout_blocked_vs_str:
|
||||
case layout_blocked_rws:
|
||||
|
@ -185,6 +185,7 @@
|
||||
<ClInclude Include="util\reader_sf.h" />
|
||||
<ClInclude Include="util\reader_text.h" />
|
||||
<ClInclude Include="util\samples_ops.h" />
|
||||
<ClInclude Include="util\sf_utils.h" />
|
||||
<ClInclude Include="util\text_reader.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -745,6 +746,7 @@
|
||||
<ClCompile Include="util\paths.c" />
|
||||
<ClCompile Include="util\reader.c" />
|
||||
<ClCompile Include="util\samples_ops.c" />
|
||||
<ClCompile Include="util\sf_utils.c" />
|
||||
<ClCompile Include="util\text_reader.c" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
@ -380,6 +380,9 @@
|
||||
<ClInclude Include="util\samples_ops.h">
|
||||
<Filter>util\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\sf_utils.h">
|
||||
<Filter>util\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\text_reader.h">
|
||||
<Filter>util\Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -2056,6 +2059,9 @@
|
||||
<ClCompile Include="util\samples_ops.c">
|
||||
<Filter>util\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util\sf_utils.c">
|
||||
<Filter>util\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util\text_reader.c">
|
||||
<Filter>util\Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "../vgmstream.h"
|
||||
#include "../util/reader_sf.h"
|
||||
#include "../util/reader_text.h"
|
||||
#include "../util/sf_utils.h"
|
||||
|
||||
typedef VGMSTREAM* (*init_vgmstream_t)(STREAMFILE* sf);
|
||||
|
||||
|
189
src/streamfile.c
189
src/streamfile.c
@ -1,8 +1,8 @@
|
||||
#include "streamfile.h"
|
||||
#include "util.h"
|
||||
#include "vgmstream.h"
|
||||
#include "util/reader_sf.h"
|
||||
#include "util/paths.h"
|
||||
#include "util/sf_utils.h"
|
||||
#include <string.h>
|
||||
|
||||
/* for dup/fdopen in some systems */
|
||||
@ -985,92 +985,10 @@ STREAMFILE* open_multifile_streamfile_f(STREAMFILE** sfs, size_t sfs_size) {
|
||||
|
||||
/* **************************************************** */
|
||||
|
||||
/* change pathname's extension to another (or add it if extensionless) */
|
||||
static void swap_extension(char* pathname, /*size_t*/ int pathname_len, const char* swap) {
|
||||
char* extension = (char*)filename_extension(pathname);
|
||||
//todo safeops
|
||||
if (extension[0] == '\0') {
|
||||
strcat(pathname, ".");
|
||||
strcat(pathname, swap);
|
||||
}
|
||||
else {
|
||||
strcpy(extension, swap);
|
||||
}
|
||||
}
|
||||
|
||||
STREAMFILE* open_streamfile(STREAMFILE* sf, const char* pathname) {
|
||||
return sf->open(sf, pathname, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
STREAMFILE* open_streamfile_by_ext(STREAMFILE* sf, const char* ext) {
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
get_streamfile_name(sf, filename, sizeof(filename));
|
||||
|
||||
swap_extension(filename, sizeof(filename), ext);
|
||||
|
||||
return open_streamfile(sf, filename);
|
||||
}
|
||||
|
||||
STREAMFILE* open_streamfile_by_filename(STREAMFILE* sf, const char* filename) {
|
||||
char fullname[PATH_LIMIT];
|
||||
char partname[PATH_LIMIT];
|
||||
char *path, *name, *otherpath;
|
||||
|
||||
if (!sf || !filename || !filename[0]) return NULL;
|
||||
|
||||
get_streamfile_name(sf, fullname, sizeof(fullname));
|
||||
|
||||
//todo normalize separators in a better way, safeops, improve copying
|
||||
|
||||
/* check for non-normalized paths first (ex. txth) */
|
||||
path = strrchr(fullname, '/');
|
||||
otherpath = strrchr(fullname, '\\');
|
||||
if (otherpath > path) { //todo cast to ptr?
|
||||
/* foobar makes paths like "(fake protocol)://(windows path with \)".
|
||||
* Hack to work around both separators, though probably foo_streamfile
|
||||
* should just return and handle normalized paths without protocol. */
|
||||
path = otherpath;
|
||||
}
|
||||
|
||||
if (path) {
|
||||
path[1] = '\0'; /* remove name after separator */
|
||||
|
||||
strcpy(partname, filename);
|
||||
fix_dir_separators(partname); /* normalize to DIR_SEPARATOR */
|
||||
|
||||
/* normalize relative paths as don't work ok in some plugins */
|
||||
if (partname[0] == '.' && partname[1] == DIR_SEPARATOR) { /* './name' */
|
||||
name = partname + 2; /* ignore './' */
|
||||
}
|
||||
else if (partname[0] == '.' && partname[1] == '.' && partname[2] == DIR_SEPARATOR) { /* '../name' */
|
||||
char* pathprev;
|
||||
|
||||
path[0] = '\0'; /* remove last separator so next call works */
|
||||
pathprev = strrchr(fullname,DIR_SEPARATOR);
|
||||
if (pathprev) {
|
||||
pathprev[1] = '\0'; /* remove prev dir after separator */
|
||||
name = partname + 3; /* ignore '../' */
|
||||
}
|
||||
else { /* let plugin handle? */
|
||||
path[0] = DIR_SEPARATOR;
|
||||
name = partname;
|
||||
}
|
||||
/* could work with more relative paths but whatevs */
|
||||
}
|
||||
else {
|
||||
name = partname;
|
||||
}
|
||||
|
||||
strcat(fullname, name);
|
||||
}
|
||||
else {
|
||||
strcpy(fullname, filename);
|
||||
}
|
||||
|
||||
return open_streamfile(sf, fullname);
|
||||
}
|
||||
|
||||
STREAMFILE* reopen_streamfile(STREAMFILE* sf, size_t buffer_size) {
|
||||
char pathname[PATH_LIMIT];
|
||||
|
||||
@ -1084,111 +1002,6 @@ STREAMFILE* reopen_streamfile(STREAMFILE* sf, size_t buffer_size) {
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
int check_extensions(STREAMFILE* sf, const char* cmp_exts) {
|
||||
char filename[PATH_LIMIT];
|
||||
const char* ext = NULL;
|
||||
const char* cmp_ext = NULL;
|
||||
const char* ststr_res = NULL;
|
||||
size_t ext_len, cmp_len;
|
||||
|
||||
sf->get_name(sf, filename, sizeof(filename));
|
||||
ext = filename_extension(filename);
|
||||
ext_len = strlen(ext);
|
||||
|
||||
cmp_ext = cmp_exts;
|
||||
do {
|
||||
ststr_res = strstr(cmp_ext, ",");
|
||||
cmp_len = ststr_res == NULL
|
||||
? strlen(cmp_ext) /* total length if more not found */
|
||||
: (intptr_t)ststr_res - (intptr_t)cmp_ext; /* find next ext; ststr_res should always be greater than cmp_ext, resulting in a positive cmp_len */
|
||||
|
||||
if (ext_len == cmp_len && strncasecmp(ext,cmp_ext, ext_len) == 0)
|
||||
return 1;
|
||||
|
||||
cmp_ext = ststr_res;
|
||||
if (cmp_ext != NULL)
|
||||
cmp_ext = cmp_ext + 1; /* skip comma */
|
||||
|
||||
} while (cmp_ext != NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
/* copies name as-is (may include full path included) */
|
||||
void get_streamfile_name(STREAMFILE* sf, char* buffer, size_t size) {
|
||||
sf->get_name(sf, buffer, size);
|
||||
}
|
||||
|
||||
/* copies the filename without path */
|
||||
void get_streamfile_filename(STREAMFILE* sf, char* buffer, size_t size) {
|
||||
char foldername[PATH_LIMIT];
|
||||
const char* path;
|
||||
|
||||
|
||||
get_streamfile_name(sf, foldername, sizeof(foldername));
|
||||
|
||||
//todo Windows CMD accepts both \\ and /, better way to handle this?
|
||||
path = strrchr(foldername,'\\');
|
||||
if (!path)
|
||||
path = strrchr(foldername,'/');
|
||||
if (path != NULL)
|
||||
path = path+1;
|
||||
|
||||
//todo validate sizes and copy sensible max
|
||||
if (path) {
|
||||
strcpy(buffer, path);
|
||||
} else {
|
||||
strcpy(buffer, foldername);
|
||||
}
|
||||
}
|
||||
|
||||
/* copies the filename without path or extension */
|
||||
void get_streamfile_basename(STREAMFILE* sf, char* buffer, size_t size) {
|
||||
char* ext;
|
||||
|
||||
get_streamfile_filename(sf, buffer, size);
|
||||
|
||||
ext = strrchr(buffer,'.');
|
||||
if (ext) {
|
||||
ext[0] = '\0'; /* remove .ext from buffer */
|
||||
}
|
||||
}
|
||||
|
||||
/* copies path removing name (NULL when if filename has no path) */
|
||||
void get_streamfile_path(STREAMFILE* sf, char* buffer, size_t size) {
|
||||
const char* path;
|
||||
|
||||
get_streamfile_name(sf, buffer, size);
|
||||
|
||||
path = strrchr(buffer,DIR_SEPARATOR);
|
||||
if (path!=NULL) path = path+1; /* includes "/" */
|
||||
|
||||
if (path) {
|
||||
buffer[path - buffer] = '\0';
|
||||
} else {
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* copies extension only */
|
||||
void get_streamfile_ext(STREAMFILE* sf, char* buffer, size_t size) {
|
||||
char filename[PATH_LIMIT];
|
||||
const char* extension = NULL;
|
||||
|
||||
get_streamfile_name(sf, filename, sizeof(filename));
|
||||
extension = filename_extension(filename);
|
||||
if (!extension) {
|
||||
buffer[0] = '\n';
|
||||
}
|
||||
else {
|
||||
strncpy(buffer, extension, size); //todo use something better
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
/* debug util, mainly for custom IO testing */
|
||||
void dump_streamfile(STREAMFILE* sf, int num) {
|
||||
#ifdef VGM_DEBUG_OUTPUT
|
||||
|
@ -130,15 +130,6 @@ STREAMFILE* open_multifile_streamfile_f(STREAMFILE** sfs, size_t sfs_size);
|
||||
* Just a wrapper, to avoid having to access the STREAMFILE's callbacks directly. */
|
||||
STREAMFILE* open_streamfile(STREAMFILE* sf, const char* pathname);
|
||||
|
||||
/* Opens a STREAMFILE from a base pathname + new extension
|
||||
* Can be used to get companion headers. */
|
||||
STREAMFILE* open_streamfile_by_ext(STREAMFILE* sf, const char* ext);
|
||||
|
||||
/* Opens a STREAMFILE from a base path + new filename.
|
||||
* Can be used to get companion files. Relative paths like
|
||||
* './filename', '../filename', 'dir/filename' also work. */
|
||||
STREAMFILE* open_streamfile_by_filename(STREAMFILE* sf, const char* filename);
|
||||
|
||||
/* Reopen a STREAMFILE with a different buffer size, for fine-tuned bigfile parsing.
|
||||
* Uses default buffer size when buffer_size is 0 */
|
||||
STREAMFILE* reopen_streamfile(STREAMFILE* sf, size_t buffer_size);
|
||||
@ -161,18 +152,6 @@ static inline size_t get_streamfile_size(STREAMFILE* sf) {
|
||||
}
|
||||
|
||||
|
||||
/* various STREAMFILE helpers functions */
|
||||
|
||||
/* Checks if the stream filename is one of the extensions (comma-separated, ex. "adx" or "adx,aix").
|
||||
* Empty is ok to accept files without extension ("", "adx,,aix"). Returns 0 on failure */
|
||||
int check_extensions(STREAMFILE* sf, const char* cmp_exts);
|
||||
|
||||
/* filename helpers */
|
||||
void get_streamfile_name(STREAMFILE* sf, char* buf, size_t size);
|
||||
void get_streamfile_filename(STREAMFILE* sf, char* buf, size_t size);
|
||||
void get_streamfile_basename(STREAMFILE* sf, char* buf, size_t size);
|
||||
void get_streamfile_path(STREAMFILE* sf, char* buf, size_t size);
|
||||
void get_streamfile_ext(STREAMFILE* sf, char* buf, size_t size);
|
||||
|
||||
void dump_streamfile(STREAMFILE* sf, int num);
|
||||
|
||||
#endif
|
||||
|
@ -1,7 +1,8 @@
|
||||
#include "companion_files.h"
|
||||
#include "paths.h"
|
||||
#include "../vgmstream.h"
|
||||
#include "../util/reader_text.h"
|
||||
#include "reader_text.h"
|
||||
#include "sf_utils.h"
|
||||
|
||||
|
||||
size_t read_key_file(uint8_t* buf, size_t buf_size, STREAMFILE* sf) {
|
||||
|
192
src/util/sf_utils.c
Normal file
192
src/util/sf_utils.c
Normal file
@ -0,0 +1,192 @@
|
||||
#include "sf_utils.h"
|
||||
#include "../vgmstream.h"
|
||||
#include "reader_sf.h"
|
||||
#include "paths.h"
|
||||
|
||||
|
||||
/* change pathname's extension to another (or add it if extensionless) */
|
||||
static void swap_extension(char* pathname, /*size_t*/ int pathname_len, const char* swap) {
|
||||
char* extension = (char*)filename_extension(pathname);
|
||||
//todo safeops
|
||||
if (extension[0] == '\0') {
|
||||
strcat(pathname, ".");
|
||||
strcat(pathname, swap);
|
||||
}
|
||||
else {
|
||||
strcpy(extension, swap);
|
||||
}
|
||||
}
|
||||
|
||||
STREAMFILE* open_streamfile_by_ext(STREAMFILE* sf, const char* ext) {
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
get_streamfile_name(sf, filename, sizeof(filename));
|
||||
|
||||
swap_extension(filename, sizeof(filename), ext);
|
||||
|
||||
return open_streamfile(sf, filename);
|
||||
}
|
||||
|
||||
STREAMFILE* open_streamfile_by_filename(STREAMFILE* sf, const char* filename) {
|
||||
char fullname[PATH_LIMIT];
|
||||
char partname[PATH_LIMIT];
|
||||
char *path, *name, *otherpath;
|
||||
|
||||
if (!sf || !filename || !filename[0]) return NULL;
|
||||
|
||||
get_streamfile_name(sf, fullname, sizeof(fullname));
|
||||
|
||||
//todo normalize separators in a better way, safeops, improve copying
|
||||
|
||||
/* check for non-normalized paths first (ex. txth) */
|
||||
path = strrchr(fullname, '/');
|
||||
otherpath = strrchr(fullname, '\\');
|
||||
if (otherpath > path) { //todo cast to ptr?
|
||||
/* foobar makes paths like "(fake protocol)://(windows path with \)".
|
||||
* Hack to work around both separators, though probably foo_streamfile
|
||||
* should just return and handle normalized paths without protocol. */
|
||||
path = otherpath;
|
||||
}
|
||||
|
||||
if (path) {
|
||||
path[1] = '\0'; /* remove name after separator */
|
||||
|
||||
strcpy(partname, filename);
|
||||
fix_dir_separators(partname); /* normalize to DIR_SEPARATOR */
|
||||
|
||||
/* normalize relative paths as don't work ok in some plugins */
|
||||
if (partname[0] == '.' && partname[1] == DIR_SEPARATOR) { /* './name' */
|
||||
name = partname + 2; /* ignore './' */
|
||||
}
|
||||
else if (partname[0] == '.' && partname[1] == '.' && partname[2] == DIR_SEPARATOR) { /* '../name' */
|
||||
char* pathprev;
|
||||
|
||||
path[0] = '\0'; /* remove last separator so next call works */
|
||||
pathprev = strrchr(fullname,DIR_SEPARATOR);
|
||||
if (pathprev) {
|
||||
pathprev[1] = '\0'; /* remove prev dir after separator */
|
||||
name = partname + 3; /* ignore '../' */
|
||||
}
|
||||
else { /* let plugin handle? */
|
||||
path[0] = DIR_SEPARATOR;
|
||||
name = partname;
|
||||
}
|
||||
/* could work with more relative paths but whatevs */
|
||||
}
|
||||
else {
|
||||
name = partname;
|
||||
}
|
||||
|
||||
strcat(fullname, name);
|
||||
}
|
||||
else {
|
||||
strcpy(fullname, filename);
|
||||
}
|
||||
|
||||
return open_streamfile(sf, fullname);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
int check_extensions(STREAMFILE* sf, const char* cmp_exts) {
|
||||
char filename[PATH_LIMIT];
|
||||
const char* ext = NULL;
|
||||
const char* cmp_ext = NULL;
|
||||
const char* ststr_res = NULL;
|
||||
size_t ext_len, cmp_len;
|
||||
|
||||
sf->get_name(sf, filename, sizeof(filename));
|
||||
ext = filename_extension(filename);
|
||||
ext_len = strlen(ext);
|
||||
|
||||
cmp_ext = cmp_exts;
|
||||
do {
|
||||
ststr_res = strstr(cmp_ext, ",");
|
||||
cmp_len = ststr_res == NULL
|
||||
? strlen(cmp_ext) /* total length if more not found */
|
||||
: (intptr_t)ststr_res - (intptr_t)cmp_ext; /* find next ext; ststr_res should always be greater than cmp_ext, resulting in a positive cmp_len */
|
||||
|
||||
if (ext_len == cmp_len && strncasecmp(ext,cmp_ext, ext_len) == 0)
|
||||
return 1;
|
||||
|
||||
cmp_ext = ststr_res;
|
||||
if (cmp_ext != NULL)
|
||||
cmp_ext = cmp_ext + 1; /* skip comma */
|
||||
|
||||
} while (cmp_ext != NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
/* copies name as-is (may include full path included) */
|
||||
void get_streamfile_name(STREAMFILE* sf, char* buffer, size_t size) {
|
||||
sf->get_name(sf, buffer, size);
|
||||
}
|
||||
|
||||
/* copies the filename without path */
|
||||
void get_streamfile_filename(STREAMFILE* sf, char* buffer, size_t size) {
|
||||
char foldername[PATH_LIMIT];
|
||||
const char* path;
|
||||
|
||||
|
||||
get_streamfile_name(sf, foldername, sizeof(foldername));
|
||||
|
||||
//todo Windows CMD accepts both \\ and /, better way to handle this?
|
||||
path = strrchr(foldername,'\\');
|
||||
if (!path)
|
||||
path = strrchr(foldername,'/');
|
||||
if (path != NULL)
|
||||
path = path+1;
|
||||
|
||||
//todo validate sizes and copy sensible max
|
||||
if (path) {
|
||||
strcpy(buffer, path);
|
||||
} else {
|
||||
strcpy(buffer, foldername);
|
||||
}
|
||||
}
|
||||
|
||||
/* copies the filename without path or extension */
|
||||
void get_streamfile_basename(STREAMFILE* sf, char* buffer, size_t size) {
|
||||
char* ext;
|
||||
|
||||
get_streamfile_filename(sf, buffer, size);
|
||||
|
||||
ext = strrchr(buffer,'.');
|
||||
if (ext) {
|
||||
ext[0] = '\0'; /* remove .ext from buffer */
|
||||
}
|
||||
}
|
||||
|
||||
/* copies path removing name (NULL when if filename has no path) */
|
||||
void get_streamfile_path(STREAMFILE* sf, char* buffer, size_t size) {
|
||||
const char* path;
|
||||
|
||||
get_streamfile_name(sf, buffer, size);
|
||||
|
||||
path = strrchr(buffer,DIR_SEPARATOR);
|
||||
if (path!=NULL) path = path+1; /* includes "/" */
|
||||
|
||||
if (path) {
|
||||
buffer[path - buffer] = '\0';
|
||||
} else {
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* copies extension only */
|
||||
void get_streamfile_ext(STREAMFILE* sf, char* buffer, size_t size) {
|
||||
char filename[PATH_LIMIT];
|
||||
const char* extension = NULL;
|
||||
|
||||
get_streamfile_name(sf, filename, sizeof(filename));
|
||||
extension = filename_extension(filename);
|
||||
if (!extension) {
|
||||
buffer[0] = '\n';
|
||||
}
|
||||
else {
|
||||
strncpy(buffer, extension, size); //todo use something better
|
||||
}
|
||||
}
|
29
src/util/sf_utils.h
Normal file
29
src/util/sf_utils.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef _SF_UTILS_H
|
||||
#define _SF_UTILS_H
|
||||
#include "../streamfile.h"
|
||||
|
||||
|
||||
|
||||
/* Opens a STREAMFILE from a base pathname + new extension
|
||||
* Can be used to get companion headers. */
|
||||
STREAMFILE* open_streamfile_by_ext(STREAMFILE* sf, const char* ext);
|
||||
|
||||
/* Opens a STREAMFILE from a base path + new filename.
|
||||
* Can be used to get companion files. Relative paths like
|
||||
* './filename', '../filename', 'dir/filename' also work. */
|
||||
STREAMFILE* open_streamfile_by_filename(STREAMFILE* sf, const char* filename);
|
||||
|
||||
/* various STREAMFILE helpers functions */
|
||||
|
||||
/* Checks if the stream filename is one of the extensions (comma-separated, ex. "adx" or "adx,aix").
|
||||
* Empty is ok to accept files without extension ("", "adx,,aix"). Returns 0 on failure */
|
||||
int check_extensions(STREAMFILE* sf, const char* cmp_exts);
|
||||
|
||||
/* filename helpers */
|
||||
void get_streamfile_name(STREAMFILE* sf, char* buf, size_t size);
|
||||
void get_streamfile_filename(STREAMFILE* sf, char* buf, size_t size);
|
||||
void get_streamfile_basename(STREAMFILE* sf, char* buf, size_t size);
|
||||
void get_streamfile_path(STREAMFILE* sf, char* buf, size_t size);
|
||||
void get_streamfile_ext(STREAMFILE* sf, char* buf, size_t size);
|
||||
|
||||
#endif
|
@ -12,6 +12,7 @@
|
||||
#include "base/decode.h"
|
||||
#include "base/render.h"
|
||||
#include "base/mixing.h"
|
||||
#include "util/sf_utils.h"
|
||||
|
||||
typedef VGMSTREAM* (*init_vgmstream_t)(STREAMFILE*);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user