aboutsummaryrefslogtreecommitdiff
path: root/common/fmplayer_file_unix.c
blob: d2855c3c47b8dc693eebc18cf7d4edbbaa38e4f3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

#define _POSIX_C_SOURCE 200809l
#include "common/fmplayer_file.h"
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
#include <strings.h>

static void *fileread(const char *path, size_t maxsize, size_t *filesize, enum fmplayer_file_error *error) {
  FILE *f = 0;
  void *buf = 0;

  f = fopen(path, "rb");
  if (!f) {
    if (error) *error = FMPLAYER_FILE_ERR_NOTFOUND;
    goto err;
  }
  if (fseek(f, 0, SEEK_END)) {
    *error = FMPLAYER_FILE_ERR_FILEIO;
    goto err;
  }
  size_t fsize;
  {
    long ssize = ftell(f);
    if (ssize < 0) {
      *error = FMPLAYER_FILE_ERR_FILEIO;
      goto err;
    }
    if (maxsize && ((size_t)ssize > maxsize)) {
      *error = FMPLAYER_FILE_ERR_BADFILE_SIZE;
      goto err;
    }
    fsize = ssize;
  }
  if (fseek(f, 0, SEEK_SET)) {
    *error = FMPLAYER_FILE_ERR_FILEIO;
    goto err;
  }
  buf = malloc(fsize);
  if (!buf) {
    if (error) *error = FMPLAYER_FILE_ERR_NOMEM;
    goto err;
  }
  if (fread(buf, 1, fsize, f) != fsize) {
    *error = FMPLAYER_FILE_ERR_FILEIO;
    goto err;
  }
  fclose(f);
  *filesize = fsize;
  return buf;
err:
  free(buf);
  if (f) fclose(f);
  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 char *path = pathptr;
  if (!pcmname) return fileread(path, maxsize, filesize, error);

  char *namebuf = 0;
  char *dirbuf = 0;
  DIR *d = 0;
  
  if (extension) {
    size_t namebuflen = strlen(pcmname) + strlen(extension) + 1;
    namebuf = malloc(namebuflen);
    if (!namebuf) {
      if (error) *error = FMPLAYER_FILE_ERR_NOMEM;
      goto err;
    }
    strcpy(namebuf, pcmname);
    strcat(namebuf, extension);
    pcmname = namebuf;
  }

  const char *slash = strrchr(path, '/');
  const char *dirpath = 0;
  if (slash) {
    dirbuf = strdup(path);
    if (!dirbuf) {
      if (error) *error = FMPLAYER_FILE_ERR_NOMEM;
      goto err;
    }
    *strrchr(dirbuf, '/') = 0;
    dirpath = dirbuf;
  } else {
    dirpath = ".";
  }
  d = opendir(dirpath);
  if (!d) {
    *error = FMPLAYER_FILE_ERR_FILEIO;
    goto err;
  }
  const struct dirent *de;
  while ((de = readdir(d))) {
    if (!strcasecmp(de->d_name, pcmname)) {
      size_t pathlen = strlen(dirpath) + 1 + strlen(de->d_name) + 1;
      char *pcmpath = malloc(pathlen);
      if (!pcmpath) {
        if (error) *error = FMPLAYER_FILE_ERR_NOMEM;
        goto err;
      }
      strcpy(pcmpath, dirpath);
      strcat(pcmpath, "/");
      strcat(pcmpath, de->d_name);
      void *buf = fileread(pcmpath, maxsize, filesize, error);
      free(pcmpath);
      closedir(d);
      free(dirbuf);
      free(namebuf);
      return buf;
    }
  }
  if (error) *error = FMPLAYER_FILE_ERR_NOTFOUND;
err:
  if (d) closedir(d);
  free(dirbuf);
  free(namebuf);
  return 0;
}

void *fmplayer_path_dup(const void *path) {
  return strdup(path);
}