mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-30 17:24:31 +01:00
121 lines
3.7 KiB
C++
121 lines
3.7 KiB
C++
#include <glib.h>
|
|
#include <cstdlib>
|
|
|
|
#include <libaudcore/plugin.h>
|
|
|
|
extern "C" {
|
|
#include "../src/vgmstream.h"
|
|
}
|
|
#include "plugin.h"
|
|
#include "vfs.h"
|
|
|
|
typedef struct {
|
|
STREAMFILE sf;
|
|
VFSFile *vfsFile;
|
|
off_t offset;
|
|
char name[32768];
|
|
} VFS_STREAMFILE;
|
|
|
|
static STREAMFILE *open_vfs_by_VFSFILE(VFSFile *file, const char *path);
|
|
|
|
static size_t read_vfs(VFS_STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length) {
|
|
size_t bytes_read;
|
|
|
|
if (/*!streamfile->vfsFile ||*/ !dest || length <= 0 || offset < 0)
|
|
return 0;
|
|
|
|
// if the offsets don't match, then we need to perform a seek
|
|
if (streamfile->offset != offset) {
|
|
int ok = streamfile->vfsFile->fseek(offset, VFS_SEEK_SET);
|
|
if (ok != 0) return 0;
|
|
streamfile->offset = offset;
|
|
}
|
|
|
|
bytes_read = streamfile->vfsFile->fread(dest, 1, length);
|
|
streamfile->offset += bytes_read;
|
|
|
|
return bytes_read;
|
|
}
|
|
|
|
static void close_vfs(VFS_STREAMFILE *streamfile) {
|
|
//if (streamfile->vfsFile)
|
|
delete streamfile->vfsFile; //fcloses the internal file too
|
|
free(streamfile);
|
|
}
|
|
|
|
static size_t get_size_vfs(VFS_STREAMFILE *streamfile) {
|
|
//if (!streamfile->vfsFile)
|
|
// return 0;
|
|
return streamfile->vfsFile->fsize();
|
|
}
|
|
|
|
static size_t get_offset_vfs(VFS_STREAMFILE *streamfile) {
|
|
return streamfile->offset;
|
|
}
|
|
|
|
static void get_name_vfs(VFS_STREAMFILE *streamfile, char *buffer, size_t length) {
|
|
strncpy(buffer, streamfile->name, length);
|
|
buffer[length - 1] = '\0';
|
|
}
|
|
|
|
static STREAMFILE *open_vfs_impl(VFS_STREAMFILE *streamfile, const char *const filename, size_t buffersize) {
|
|
if (!filename)
|
|
return NULL;
|
|
|
|
return open_vfs(filename);
|
|
}
|
|
|
|
STREAMFILE *open_vfs_by_VFSFILE(VFSFile *file, const char *path) {
|
|
VFS_STREAMFILE *streamfile = (VFS_STREAMFILE *)malloc(sizeof(VFS_STREAMFILE));
|
|
if (!streamfile)
|
|
return NULL;
|
|
|
|
// success, set our pointers
|
|
memset(streamfile, 0, sizeof(VFS_STREAMFILE));
|
|
|
|
streamfile->sf.read = (size_t (*)(STREAMFILE *, uint8_t *, off_t, size_t))read_vfs;
|
|
streamfile->sf.get_size = (size_t (*)(STREAMFILE *))get_size_vfs;
|
|
streamfile->sf.get_offset = (off_t (*)(STREAMFILE *))get_offset_vfs;
|
|
streamfile->sf.get_name = (void (*)(STREAMFILE *, char *, size_t))get_name_vfs;
|
|
streamfile->sf.open = (STREAMFILE *(*)(STREAMFILE *, const char *, size_t))open_vfs_impl;
|
|
streamfile->sf.close = (void (*)(STREAMFILE *))close_vfs;
|
|
|
|
streamfile->vfsFile = file;
|
|
streamfile->offset = 0;
|
|
strncpy(streamfile->name, path, sizeof(streamfile->name));
|
|
streamfile->name[sizeof(streamfile->name) - 1] = '\0';
|
|
|
|
// for reference, actual file path ("name" has protocol path, file://...).
|
|
// name should work for all situations but in case it's needed again maybe
|
|
// get_name should always return realname, as it's used to open companion VFSFiles
|
|
//{
|
|
// gchar *realname = g_filename_from_uri(path, NULL, NULL);
|
|
// strncpy(streamfile->realname, realname, sizeof(streamfile->realname));
|
|
// streamfile->realname[sizeof(streamfile->realname) - 1] = '\0';
|
|
// g_free(realname);
|
|
//}
|
|
|
|
return &streamfile->sf;
|
|
}
|
|
|
|
STREAMFILE *open_vfs(const char *path) {
|
|
VFSFile *vfsFile = new VFSFile(path, "rb");
|
|
if (!vfsFile || !*vfsFile) {
|
|
delete vfsFile;
|
|
return NULL;
|
|
}
|
|
|
|
#if 0 // files that don't exist seem blocked by probe.cc before reaching here
|
|
bool infile_exists = vfsFile && *vfsFile;
|
|
if (!infile_exists) {
|
|
/* allow non-existing files in some cases */
|
|
if (!vgmstream_is_virtual_filename(path)) {
|
|
delete vfsFile;
|
|
return NULL;
|
|
}
|
|
vfsFile = NULL;
|
|
}
|
|
#endif
|
|
return open_vfs_by_VFSFILE(vfsFile, path);
|
|
}
|