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); +} | 
