aboutsummaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorTakamichi Horikawa <takamichiho@gmail.com>2017-03-27 23:32:18 +0900
committerTakamichi Horikawa <takamichiho@gmail.com>2017-03-27 23:32:18 +0900
commit0073f2b8befc6163f2970cb7a01e75fffc95994e (patch)
treeaab8d559720269e65b5ad05c07d98a865ff14e57 /common
parente2ee18347d45e4620a8279afb8b0bc4a809441ef (diff)
refactor common file loading functions
Diffstat (limited to 'common')
-rw-r--r--common/fmplayer_common.h8
-rw-r--r--common/fmplayer_file.c168
-rw-r--r--common/fmplayer_file.h52
-rw-r--r--common/fmplayer_file_gio.c120
-rw-r--r--common/fmplayer_file_win.c87
5 files changed, 435 insertions, 0 deletions
diff --git a/common/fmplayer_common.h b/common/fmplayer_common.h
new file mode 100644
index 0000000..5394293
--- /dev/null
+++ b/common/fmplayer_common.h
@@ -0,0 +1,8 @@
+#ifndef MYON_FMPLAYER_COMMON_H_INCLUDED
+#define MYON_FMPLAYER_COMMON_H_INCLUDED
+
+#include <stddef.h>
+
+void *fmplayer_load_data(const char *name, size_t size);
+
+#endif // MYON_FMPLAYER_COMMON_H_INCLUDED
diff --git a/common/fmplayer_file.c b/common/fmplayer_file.c
new file mode 100644
index 0000000..1080625
--- /dev/null
+++ b/common/fmplayer_file.c
@@ -0,0 +1,168 @@
+#include "common/fmplayer_file.h"
+#include <string.h>
+#include <stdlib.h>
+
+void fmplayer_file_free(const struct fmplayer_file *fmfileptr) {
+ struct fmplayer_file *fmfile = (struct fmplayer_file *)fmfileptr;
+ if (!fmfile) return;
+ free(fmfile->path);
+ free(fmfile->buf);
+ free(fmfile->ppzbuf[0]);
+ free(fmfile->ppzbuf[1]);
+ free(fmfile);
+}
+
+struct fmplayer_file *fmplayer_file_alloc(const void *path, enum fmplayer_file_error *error) {
+ struct fmplayer_file *fmfile = calloc(1, sizeof(*fmfile));
+ if (!fmfile) {
+ if (error) *error = FMPLAYER_FILE_ERR_NOMEM;
+ goto err;
+ }
+ fmfile->path = fmplayer_path_dup(path);
+ if (!fmfile->path) {
+ if (error) *error = FMPLAYER_FILE_ERR_NOMEM;
+ goto err;
+ }
+ size_t filesize;
+ fmfile->buf = fmplayer_fileread(path, 0, 0, 0xffff, &filesize, error);
+ if (!fmfile->buf) goto err;
+ if (pmd_load(&fmfile->driver.pmd, fmfile->buf, filesize)) {
+ fmfile->type = FMPLAYER_FILE_TYPE_PMD;
+ return fmfile;
+ }
+ memset(&fmfile->driver, 0, sizeof(fmfile->driver));
+ if (fmp_load(&fmfile->driver.fmp, fmfile->buf, filesize)) {
+ fmfile->type = FMPLAYER_FILE_TYPE_FMP;
+ return fmfile;
+ }
+ if (error) *error = FMPLAYER_FILE_ERR_BADFILE;
+err:
+ fmplayer_file_free(fmfile);
+ return 0;
+}
+
+static void loadppc(struct fmdriver_work *work, struct fmplayer_file *fmfile) {
+ if (!strlen(fmfile->driver.pmd.ppcfile)) return;
+ size_t filesize;
+ void *ppcbuf = fmplayer_fileread(fmfile->path, fmfile->driver.pmd.ppcfile, ".PPC", 0, &filesize, 0);
+ if (ppcbuf) {
+ fmfile->pmd_ppc_err = !pmd_ppc_load(work, ppcbuf, filesize);
+ free(ppcbuf);
+ } else {
+ fmfile->pmd_ppc_err = true;
+ }
+}
+
+static bool loadppzpvi(struct fmdriver_work *work, struct fmplayer_file *fmfile, const char *name) {
+ size_t filesize;
+ void *pvibuf = 0, *ppzbuf = 0;
+ pvibuf = fmplayer_fileread(fmfile->path, name, ".PVI", 0, &filesize, 0);
+ if (!pvibuf) goto err;
+ ppzbuf = calloc(ppz8_pvi_decodebuf_samples(filesize), 2);
+ if (!ppzbuf) goto err;
+ if (!ppz8_pvi_load(work->ppz8, 0, pvibuf, filesize, ppzbuf)) goto err;
+ free(pvibuf);
+ free(fmfile->ppzbuf[0]);
+ fmfile->ppzbuf[0] = ppzbuf;
+ return true;
+err:
+ free(ppzbuf);
+ free(pvibuf);
+ return false;
+}
+
+static bool loadppzpzi(struct fmdriver_work *work, struct fmplayer_file *fmfile, const char *name) {
+ size_t filesize;
+ void *pzibuf = 0, *ppzbuf = 0;
+ pzibuf = fmplayer_fileread(fmfile->path, name, ".PZI", 0, &filesize, 0);
+ if (!pzibuf) goto err;
+ ppzbuf = calloc(ppz8_pzi_decodebuf_samples(filesize), 2);
+ if (!ppzbuf) goto err;
+ if (!ppz8_pzi_load(work->ppz8, 0, pzibuf, filesize, ppzbuf)) goto err;
+ free(pzibuf);
+ free(fmfile->ppzbuf[0]);
+ fmfile->ppzbuf[0] = ppzbuf;
+ return true;
+err:
+ free(ppzbuf);
+ free(pzibuf);
+ return false;
+}
+
+static void loadpmdppz(struct fmdriver_work *work, struct fmplayer_file *fmfile) {
+ const char *ppzfile = fmfile->driver.pmd.ppzfile;
+ if (!strlen(ppzfile)) return;
+ if (!loadppzpvi(work, fmfile, ppzfile) && !loadppzpzi(work, fmfile, ppzfile)) {
+ fmfile->pmd_ppz_err = true;
+ }
+}
+
+static void loadpvi(struct fmdriver_work *work, struct fmplayer_file *fmfile) {
+ const char *pvifile = fmfile->driver.fmp.pvi_name;
+ if (!strlen(pvifile)) return;
+ size_t filesize;
+ void *pvibuf = fmplayer_fileread(fmfile->path, pvifile, ".PVI", 0, &filesize, 0);
+ if (pvibuf) {
+ fmfile->fmp_pvi_err = !fmp_adpcm_load(work, pvibuf, filesize);
+ free(pvibuf);
+ } else {
+ fmfile->fmp_pvi_err = true;
+ }
+}
+
+static void loadfmpppz(struct fmdriver_work *work, struct fmplayer_file *fmfile) {
+ const char *pvifile = fmfile->driver.fmp.ppz_name;
+ if (!strlen(pvifile)) return;
+ fmfile->fmp_ppz_err = !loadppzpvi(work, fmfile, pvifile);
+}
+
+void fmplayer_file_load(struct fmdriver_work *work, struct fmplayer_file *fmfile) {
+ switch (fmfile->type) {
+ case FMPLAYER_FILE_TYPE_PMD:
+ pmd_init(work, &fmfile->driver.pmd);
+ loadppc(work, fmfile);
+ loadpmdppz(work, fmfile);
+ work->pcmerror[0] = fmfile->pmd_ppc_err;
+ work->pcmerror[1] = fmfile->pmd_ppz_err;
+ break;
+ case FMPLAYER_FILE_TYPE_FMP:
+ fmp_init(work, &fmfile->driver.fmp);
+ loadpvi(work, fmfile);
+ loadfmpppz(work, fmfile);
+ work->pcmerror[0] = fmfile->fmp_pvi_err;
+ work->pcmerror[1] = fmfile->fmp_ppz_err;
+ break;
+ }
+}
+#define MSG_FILE_ERR_UNKNOWN "Unknown error"
+#define MSG_FILE_ERR_NOMEM "Memory allocation error"
+#define MSG_FILE_ERR_FILEIO "File I/O error"
+#define MSG_FILE_ERR_BADFILE_SIZE "Invalid file size"
+#define MSG_FILE_ERR_BADFILE "Invalid file format"
+
+#define XWIDE(x) L ## x
+#define WIDE(x) XWIDE(x)
+
+const char *fmplayer_file_strerror(enum fmplayer_file_error error) {
+ if (error >= FMPLAYER_FILE_ERR_COUNT) return MSG_FILE_ERR_UNKNOWN;
+ static const char *errtable[] = {
+ "",
+ MSG_FILE_ERR_NOMEM,
+ MSG_FILE_ERR_FILEIO,
+ MSG_FILE_ERR_BADFILE_SIZE,
+ MSG_FILE_ERR_BADFILE,
+ };
+ return errtable[error];
+}
+
+const wchar_t *fmplayer_file_strerror_w(enum fmplayer_file_error error) {
+ if (error >= FMPLAYER_FILE_ERR_COUNT) return WIDE(MSG_FILE_ERR_UNKNOWN);
+ static const wchar_t *errtable[] = {
+ L"",
+ WIDE(MSG_FILE_ERR_NOMEM),
+ WIDE(MSG_FILE_ERR_FILEIO),
+ WIDE(MSG_FILE_ERR_BADFILE_SIZE),
+ WIDE(MSG_FILE_ERR_BADFILE),
+ };
+ return errtable[error];
+}
diff --git a/common/fmplayer_file.h b/common/fmplayer_file.h
new file mode 100644
index 0000000..fd7c53e
--- /dev/null
+++ b/common/fmplayer_file.h
@@ -0,0 +1,52 @@
+#ifndef MYON_FMPLAYER_FILE_H_INCLUDED
+#define MYON_FMPLAYER_FILE_H_INCLUDED
+
+#include <stddef.h>
+#include "fmdriver/fmdriver.h"
+#include "fmdriver/fmdriver_pmd.h"
+#include "fmdriver/fmdriver_fmp.h"
+
+enum fmplayer_file_type {
+ FMPLAYER_FILE_TYPE_PMD,
+ FMPLAYER_FILE_TYPE_FMP
+};
+
+enum fmplayer_file_error {
+ FMPLAYER_FILE_ERR_OK,
+ FMPLAYER_FILE_ERR_NOMEM,
+ FMPLAYER_FILE_ERR_FILEIO,
+ FMPLAYER_FILE_ERR_BADFILE_SIZE,
+ FMPLAYER_FILE_ERR_BADFILE,
+ FMPLAYER_FILE_ERR_COUNT
+};
+
+struct fmplayer_file {
+ void *path;
+ enum fmplayer_file_type type;
+ union {
+ struct driver_pmd pmd;
+ struct driver_fmp fmp;
+ } driver;
+ bool pmd_ppc_err;
+ bool pmd_ppz_err;
+ bool fmp_pvi_err;
+ bool fmp_ppz_err;
+ void *buf;
+ void *ppzbuf[2];
+};
+struct fmplayer_file *fmplayer_file_alloc(const void *path, enum fmplayer_file_error *error);
+void fmplayer_file_free(const struct fmplayer_file *fmfile);
+void fmplayer_file_load(struct fmdriver_work *work, struct fmplayer_file *fmfile);
+
+const char *fmplayer_file_strerror(enum fmplayer_file_error error);
+const wchar_t *fmplayer_file_strerror_w(enum fmplayer_file_error error);
+
+// path: wchar_t* on windows, else char*
+// examples:
+// fmplayer_fileread("/home/foo/bar.mz", 0, 0, &filesize);
+// fmplayer_fileread("/home/foo/bar.mz", "BAZ", ".PVI", &filesize);
+void *fmplayer_fileread(const void *path, const char *pcmname, const char *extension, size_t maxsize, size_t *filesize, enum fmplayer_file_error *error);
+
+void *fmplayer_path_dup(const void *path);
+
+#endif // MYON_FMPLAYER_FILE_H_INCLUDED
diff --git a/common/fmplayer_file_gio.c b/common/fmplayer_file_gio.c
new file mode 100644
index 0000000..053e4ae
--- /dev/null
+++ b/common/fmplayer_file_gio.c
@@ -0,0 +1,120 @@
+#include "common/fmplayer_file.h"
+#include <gio/gio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void *fileread(GFile *f, size_t maxsize, size_t *filesize, enum fmplayer_file_error *error) {
+ GFileInfo *finfo = 0;
+ GFileInputStream *fstream = 0;
+ void *buf = 0;
+ finfo = g_file_query_info(f, G_FILE_ATTRIBUTE_STANDARD_SIZE, 0, 0, 0);
+ if (!finfo) {
+ if (error) *error = FMPLAYER_FILE_ERR_FILEIO;
+ goto err;
+ }
+ gsize filelen;
+ {
+ goffset sfilelen = g_file_info_get_size(finfo);
+ if (sfilelen < 0) {
+ if (error) *error = FMPLAYER_FILE_ERR_FILEIO;
+ goto err;
+ }
+ filelen = sfilelen;
+ }
+ if (maxsize && (filelen > maxsize)) {
+ if (error) *error = FMPLAYER_FILE_ERR_BADFILE_SIZE;
+ goto err;
+ }
+ fstream = g_file_read(f, 0, 0);
+ if (!fstream) {
+ if (error) *error = FMPLAYER_FILE_ERR_FILEIO;
+ goto err;
+ }
+ buf = malloc(filelen);
+ if (!buf) {
+ if (error) *error = FMPLAYER_FILE_ERR_NOMEM;
+ goto err;
+ }
+ gsize fileread;
+ g_input_stream_read_all(G_INPUT_STREAM(fstream), buf, filelen, &fileread, 0, 0);
+ if (fileread != filelen) {
+ if (error) *error = FMPLAYER_FILE_ERR_FILEIO;
+ goto err;
+ }
+ *filesize = filelen;
+ g_object_unref(G_OBJECT(fstream));
+ g_object_unref(G_OBJECT(finfo));
+ return buf;
+err:
+ free(buf);
+ if (fstream) g_object_unref(G_OBJECT(fstream));
+ if (finfo) g_object_unref(G_OBJECT(finfo));
+ return 0;
+}
+
+void *fmplayer_fileread(const void *pathptr, const char *pcmname, const char *extension,
+ size_t maxsize, size_t *filesize, enum fmplayer_file_error *error) {
+ GFile *file = 0, *dir = 0;
+ GFileEnumerator *direnum = 0;
+ char *pcmnamebuf = 0;
+ const char *uri = pathptr;
+ file = g_file_new_for_uri(uri);
+ if (!pcmname) {
+ void *buf = fileread(file, maxsize, filesize, error);
+ g_object_unref(G_OBJECT(file));
+ return buf;
+ }
+ if (extension) {
+ size_t namebuflen = strlen(pcmname) + strlen(extension) + 1;
+ pcmnamebuf = malloc(namebuflen);
+ if (!pcmnamebuf) goto err;
+ strcpy(pcmnamebuf, pcmname);
+ strcat(pcmnamebuf, extension);
+ pcmname = pcmnamebuf;
+ }
+
+ dir = g_file_get_parent(file);
+ if (!dir) {
+ if (error) *error = FMPLAYER_FILE_ERR_NOMEM;
+ goto err;
+ }
+ direnum = g_file_enumerate_children(dir,
+ G_FILE_ATTRIBUTE_STANDARD_NAME,
+ G_FILE_QUERY_INFO_NONE,
+ 0, 0);
+ if (!direnum) {
+ if (error) *error = FMPLAYER_FILE_ERR_NOMEM;
+ goto err;
+ }
+ for (;;) {
+ GFileInfo *info;
+ GFile *pcmfile;
+ if (!g_file_enumerator_iterate(direnum, &info, &pcmfile, 0, 0)) {
+ if (error) *error = FMPLAYER_FILE_ERR_FILEIO;
+ goto err;
+ }
+ if (!info || !pcmfile) {
+ if (error) *error = FMPLAYER_FILE_ERR_FILEIO;
+ goto err;
+ }
+ if (!strcasecmp(g_file_info_get_name(info), pcmname)) {
+ void *buf = fileread(pcmfile, maxsize, filesize, error);
+ g_object_unref(G_OBJECT(direnum));
+ g_object_unref(G_OBJECT(dir));
+ g_object_unref(G_OBJECT(file));
+ free(pcmnamebuf);
+ return buf;
+ }
+ }
+ if (error) *error = FMPLAYER_FILE_ERR_FILEIO;
+err:
+ if (direnum) g_object_unref(G_OBJECT(direnum));
+ if (dir) g_object_unref(G_OBJECT(dir));
+ g_object_unref(G_OBJECT(file));
+ free(pcmnamebuf);
+ return 0;
+}
+
+void *fmplayer_path_dup(const void *path) {
+ return strdup(path);
+}
diff --git a/common/fmplayer_file_win.c b/common/fmplayer_file_win.c
new file mode 100644
index 0000000..3397bcc
--- /dev/null
+++ b/common/fmplayer_file_win.c
@@ -0,0 +1,87 @@
+#include "common/fmplayer_file.h"
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <shlwapi.h>
+#include <stdlib.h>
+#include <wchar.h>
+
+static void *fileread(const wchar_t *path,
+ size_t maxsize, size_t *filesize,
+ enum fmplayer_file_error *error) {
+ HANDLE file = INVALID_HANDLE_VALUE;
+ void *buf = 0;
+ file = CreateFile(path, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+ if (file == INVALID_HANDLE_VALUE) {
+ if (error) *error = FMPLAYER_FILE_ERR_FILEIO;
+ goto err;
+ }
+ LARGE_INTEGER li;
+ if (!GetFileSizeEx(file, &li)) {
+ if (error) *error = FMPLAYER_FILE_ERR_FILEIO;
+ goto err;
+ }
+ if (li.HighPart || (maxsize && (li.LowPart > maxsize))) {
+ if (error) *error = FMPLAYER_FILE_ERR_BADFILE_SIZE;
+ goto err;
+ }
+ buf = malloc(li.LowPart);
+ if (!buf) {
+ if (error) *error = FMPLAYER_FILE_ERR_NOMEM;
+ goto err;
+ }
+ DWORD readlen;
+ if (!ReadFile(file, buf, li.LowPart, &readlen, 0) || (readlen != li.LowPart)) {
+ if (error) *error = FMPLAYER_FILE_ERR_FILEIO;
+ goto err;
+ }
+ *filesize = li.QuadPart;
+ CloseHandle(file);
+ return buf;
+err:
+ free(buf);
+ if (file != INVALID_HANDLE_VALUE) CloseHandle(file);
+ return 0;
+}
+
+void *fmplayer_fileread(const void *pathptr, const char *pcmname, const char *extension,
+ size_t maxsize, size_t *filesize, enum fmplayer_file_error *error) {
+ const wchar_t *path = (const wchar_t *)pathptr;
+ wchar_t *wpcmpath = 0, *wpcmname = 0, *wpcmextname = 0;
+ if (!pcmname) return fileread(path, maxsize, filesize, error);
+ int wpcmnamelen = MultiByteToWideChar(932, 0, pcmname, -1, 0, 0);
+ if (!wpcmnamelen) goto err;
+ if (extension) {
+ int wextensionlen = MultiByteToWideChar(932, 0, extension, -1, 0, 0);
+ if (!wextensionlen) goto err;
+ wpcmnamelen += wextensionlen;
+ wpcmnamelen -= 1;
+ wpcmextname = malloc(wextensionlen * sizeof(wchar_t));
+ if (!wpcmextname) goto err;
+ if (!MultiByteToWideChar(932, 0, extension, -1, wpcmextname, wextensionlen)) goto err;
+ }
+ wpcmname = malloc(wpcmnamelen * sizeof(wchar_t));
+ if (!wpcmname) goto err;
+ if (!MultiByteToWideChar(932, 0, pcmname, -1, wpcmname, wpcmnamelen)) goto err;
+ if (wpcmextname) wcscat(wpcmname, wpcmextname);
+ wpcmpath = malloc((wcslen(path) + 1 + wcslen(wpcmname) + 1) * sizeof(wchar_t));
+ if (!wpcmpath) goto err;
+ wcscpy(wpcmpath, path);
+ PathRemoveFileSpec(wpcmpath);
+ wcscat(wpcmpath, L"\\");
+ wcscat(wpcmpath, wpcmname);
+ void *buf = fileread(wpcmpath, maxsize, filesize, error);
+ free(wpcmextname);
+ free(wpcmname);
+ free(wpcmpath);
+ return buf;
+err:
+ free(wpcmextname);
+ free(wpcmname);
+ free(wpcmpath);
+ return 0;
+}
+
+void *fmplayer_path_dup(const void *pathptr) {
+ const wchar_t *path = (const wchar_t *)pathptr;
+ return wcsdup(path);
+}