diff options
author | Takamichi Horikawa <takamichiho@gmail.com> | 2017-03-27 23:32:18 +0900 |
---|---|---|
committer | Takamichi Horikawa <takamichiho@gmail.com> | 2017-03-27 23:32:18 +0900 |
commit | 0073f2b8befc6163f2970cb7a01e75fffc95994e (patch) | |
tree | aab8d559720269e65b5ad05c07d98a865ff14e57 /common | |
parent | e2ee18347d45e4620a8279afb8b0bc4a809441ef (diff) |
refactor common file loading functions
Diffstat (limited to 'common')
-rw-r--r-- | common/fmplayer_common.h | 8 | ||||
-rw-r--r-- | common/fmplayer_file.c | 168 | ||||
-rw-r--r-- | common/fmplayer_file.h | 52 | ||||
-rw-r--r-- | common/fmplayer_file_gio.c | 120 | ||||
-rw-r--r-- | common/fmplayer_file_win.c | 87 |
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); +} |