version 2.8
gfile.c
1 /*
2  * This file is subject to the terms of the GFX License. If a copy of
3  * the license was not distributed with this file, you can obtain one at:
4  *
5  * http://ugfx.org/license.html
6  */
7 
8 #include "../../gfx.h"
9 
10 #if GFX_USE_GFILE
11 
12 #include "gfile_fs.h"
13 
14 /**
15  * Define the VMT's for the file-systems we want to search for files.
16  * Virtual file-systems that have special open() calls do not need to
17  * be in this list.
18  */
19 #if GFILE_NEED_USERFS
20  extern const GFILEVMT FsUSERVMT;
21 #endif
22 #if GFILE_NEED_ROMFS
23  extern const GFILEVMT FsROMVMT;
24 #endif
25 #if GFILE_NEED_NATIVEFS
26  extern const GFILEVMT FsNativeVMT;
27 #endif
28 #if GFILE_NEED_FATFS
29  extern const GFILEVMT FsFatFSVMT;
30 #endif
31 #if GFILE_NEED_RAMFS
32  extern const GFILEVMT FsRAMVMT;
33 #endif
34 
35 
36 /**
37  * The order of the file-systems below determines the order
38  * that they are searched to find a file.
39  */
40 static const GFILEVMT const * FsArray[] = {
41  #if GFILE_NEED_USERFS
42  &FsUSERVMT,
43  #endif
44  #if GFILE_NEED_ROMFS
45  &FsROMVMT,
46  #endif
47  #if GFILE_NEED_NATIVEFS
48  &FsNativeVMT,
49  #endif
50  #if GFILE_NEED_FATFS
51  &FsFatFSVMT,
52  #endif
53  #if GFILE_NEED_RAMFS
54  &FsRAMVMT,
55  #endif
56 };
57 
58 /*
59  * The table of GFILE's
60  */
61 static GFILE gfileArr[GFILE_MAX_GFILES];
62 GFILE *gfileStdIn;
63 GFILE *gfileStdOut;
64 GFILE *gfileStdErr;
65 
66 /**
67  * The init routine
68  */
69 void _gfileInit(void) {
70  #if GFILE_NEED_NATIVEFS
71  extern void _gfileNativeAssignStdio(void);
72  _gfileNativeAssignStdio();
73  #endif
74 }
75 
76 void _gfileDeinit(void)
77 {
78  GFILE * f;
79  for (f = gfileArr; f < &gfileArr[GFILE_MAX_GFILES]; f++) {
80  if (f->flags & GFILEFLG_OPEN)
81  gfileClose(f);
82  }
83 }
84 
85 /**
86  * Internal routine to find an empty GFILE slot and interpret flags.
87  */
88 GFILE *_gfileFindSlot(const char *mode) {
89  GFILE * f;
90 
91  // First find an available GFILE slot.
92  for (f = gfileArr; f < &gfileArr[GFILE_MAX_GFILES]; f++) {
93  if (!(f->flags & GFILEFLG_OPEN)) {
94  // Get the flags
95  switch(mode[0]) {
96  case 'r':
97  f->flags = GFILEFLG_READ|GFILEFLG_MUSTEXIST;
98  while (*++mode) {
99  switch(mode[0]) {
100  case '+': f->flags |= GFILEFLG_WRITE; break;
101  case 'b': f->flags |= GFILEFLG_BINARY; break;
102  }
103  }
104  break;
105  case 'w':
106  f->flags = GFILEFLG_WRITE|GFILEFLG_TRUNC;
107  while (*++mode) {
108  switch(mode[0]) {
109  case '+': f->flags |= GFILEFLG_READ; break;
110  case 'b': f->flags |= GFILEFLG_BINARY; break;
111  case 'x': f->flags |= GFILEFLG_MUSTNOTEXIST; break;
112  }
113  }
114  break;
115  case 'a':
116  f->flags = GFILEFLG_WRITE|GFILEFLG_APPEND;
117  while (*++mode) {
118  switch(mode[0]) {
119  case '+': f->flags |= GFILEFLG_READ; break;
120  case 'b': f->flags |= GFILEFLG_BINARY; break;
121  case 'x': f->flags |= GFILEFLG_MUSTNOTEXIST; break;
122  }
123  }
124  break;
125  default:
126  return 0;
127  }
128  return f;
129  }
130  }
131  return 0;
132 }
133 
134 /********************************************************
135  * IO routines
136  ********************************************************/
137 
138 bool_t gfileExists(const char *fname) {
139  const GFILEVMT * const *p;
140 
141  #if GFILE_ALLOW_DEVICESPECIFIC
142  if (fname[0] && fname[1] == '|') {
143  for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
144  if (p[0]->prefix == fname[0])
145  return p[0]->exists && p[0]->exists(fname+2);
146  }
147  return FALSE;
148  }
149  #endif
150 
151  for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
152  if (p[0]->exists && p[0]->exists(fname))
153  return TRUE;
154  }
155  return FALSE;
156 }
157 
158 bool_t gfileDelete(const char *fname) {
159  const GFILEVMT **p;
160 
161  #if GFILE_ALLOW_DEVICESPECIFIC
162  if (fname[0] && fname[1] == '|') {
163  for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
164  if (p[0]->prefix == fname[0])
165  return p[0]->del && p[0]->del(fname+2);
166  }
167  return FALSE;
168  }
169  #endif
170 
171  for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
172  if (p[0]->del && p[0]->del(fname))
173  return TRUE;
174  }
175  return FALSE;
176 }
177 
178 long int gfileGetFilesize(const char *fname) {
179  const GFILEVMT * const *p;
180  long int res;
181 
182  #if GFILE_ALLOW_DEVICESPECIFIC
183  if (fname[0] && fname[1] == '|') {
184  for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
185  if (p[0]->prefix == fname[0])
186  return p[0]->filesize ? p[0]->filesize(fname+2) : -1;
187  }
188  return -1;
189  }
190  #endif
191 
192  for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
193  if (p[0]->filesize && (res = p[0]->filesize(fname)) != -1)
194  return res;
195  }
196  return -1;
197 }
198 
199 bool_t gfileRename(const char *oldname, const char *newname) {
200  const GFILEVMT * const *p;
201 
202  #if GFILE_ALLOW_DEVICESPECIFIC
203  if ((oldname[0] && oldname[1] == '|') || (newname[0] && newname[1] == '|')) {
204  char ch;
205 
206  if (oldname[0] && oldname[1] == '|') {
207  ch = oldname[0];
208  oldname += 2;
209  if (newname[0] && newname[1] == '|') {
210  if (newname[0] != ch)
211  // Both oldname and newname are fs specific but different ones.
212  return FALSE;
213  newname += 2;
214  }
215  } else {
216  ch = newname[0];
217  newname += 2;
218  }
219  for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
220  if (p[0]->prefix == ch)
221  return p[0]->ren && p[0]->ren(oldname, newname);
222  }
223  return FALSE;
224  }
225  #endif
226 
227  for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
228  if (p[0]->ren && p[0]->ren(oldname,newname))
229  return TRUE;
230  }
231  return FALSE;
232 }
233 
234 static bool_t testopen(const GFILEVMT *p, GFILE *f, const char *fname) {
235  // If we want write but the fs doesn't allow it then return
236  if ((f->flags & GFILEFLG_WRITE) && !(p->flags & GFSFLG_WRITEABLE))
237  return FALSE;
238 
239  // Try to open
240  if (!p->open || !p->open(f, fname))
241  return FALSE;
242 
243  // File is open - fill in all the details
244  f->vmt = p;
245  f->pos = 0;
246  f->flags |= GFILEFLG_OPEN;
247  if (p->flags & GFSFLG_SEEKABLE)
248  f->flags |= GFILEFLG_CANSEEK;
249  return TRUE;
250 }
251 
252 GFILE *gfileOpen(const char *fname, const char *mode) {
253  GFILE * f;
254  const GFILEVMT * const *p;
255 
256  // Get an empty file and set the flags
257  if (!(f = _gfileFindSlot(mode)))
258  return 0;
259 
260  #if GFILE_ALLOW_DEVICESPECIFIC
261  if (fname[0] && fname[1] == '|') {
262  for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
263  if (p[0]->prefix == fname[0])
264  return testopen(p[0], f, fname+2) ? f : 0;
265  }
266 
267  // File not found
268  return 0;
269  }
270  #endif
271 
272  for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
273  if (testopen(p[0], f, fname))
274  return f;
275  }
276 
277  // File not found
278  return 0;
279 }
280 
281 void gfileClose(GFILE *f) {
282  if (!f || !(f->flags & GFILEFLG_OPEN))
283  return;
284  if (f->vmt->close)
285  f->vmt->close(f);
286  f->flags = 0;
287 }
288 
289 size_t gfileRead(GFILE *f, void *buf, size_t len) {
290  size_t res;
291 
292  if (!f || (f->flags & (GFILEFLG_OPEN|GFILEFLG_READ)) != (GFILEFLG_OPEN|GFILEFLG_READ))
293  return 0;
294  if (!f->vmt->read)
295  return 0;
296  if ((res = f->vmt->read(f, buf, len)) <= 0)
297  return 0;
298  f->pos += res;
299  return res;
300 }
301 
302 size_t gfileWrite(GFILE *f, const void *buf, size_t len) {
303  size_t res;
304 
305  if (!f || (f->flags & (GFILEFLG_OPEN|GFILEFLG_WRITE)) != (GFILEFLG_OPEN|GFILEFLG_WRITE))
306  return 0;
307  if (!f->vmt->write)
308  return 0;
309  if ((res = f->vmt->write(f, buf, len)) <= 0)
310  return 0;
311  f->pos += res;
312  return res;
313 }
314 
315 long int gfileGetPos(GFILE *f) {
316  if (!f || !(f->flags & GFILEFLG_OPEN))
317  return 0;
318  return f->pos;
319 }
320 
321 bool_t gfileSetPos(GFILE *f, long int pos) {
322  if (!f || !(f->flags & GFILEFLG_OPEN))
323  return FALSE;
324  if (!f->vmt->setpos || !f->vmt->setpos(f, pos))
325  return FALSE;
326  f->pos = pos;
327  return TRUE;
328 }
329 
330 long int gfileGetSize(GFILE *f) {
331  if (!f || !(f->flags & GFILEFLG_OPEN))
332  return 0;
333  if (!f->vmt->getsize)
334  return 0;
335  return f->vmt->getsize(f);
336 }
337 
338 bool_t gfileEOF(GFILE *f) {
339  if (!f || !(f->flags & GFILEFLG_OPEN))
340  return TRUE;
341  if (!f->vmt->eof)
342  return FALSE;
343  return f->vmt->eof(f);
344 }
345 
346 bool_t gfileMount(char fs, const char* drive) {
347  const GFILEVMT * const *p;
348 
349  // Find the correct VMT
350  for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
351  if (p[0]->prefix == fs) {
352  if (!p[0]->mount)
353  return FALSE;
354  return p[0]->mount(drive);
355  }
356  }
357  return FALSE;
358 }
359 
360 bool_t gfileUnmount(char fs, const char* drive) {
361  const GFILEVMT * const *p;
362 
363  // Find the correct VMT
364  for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
365  if (p[0]->prefix == fs) {
366  if (!p[0]->mount)
367  return FALSE;
368  return p[0]->unmount(drive);
369  }
370  }
371  return FALSE;
372 }
373 
374 bool_t gfileSync(GFILE *f) {
375  if (!f->vmt->sync)
376  return FALSE;
377  return f->vmt->sync(f);
378 }
379 
380 #if GFILE_NEED_FILELISTS
381  gfileList *gfileOpenFileList(char fs, const char *path, bool_t dirs) {
382  const GFILEVMT * const *p;
383  gfileList * pfl;
384 
385  // Find the correct VMT
386  for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
387  if (p[0]->prefix == fs) {
388  if (!p[0]->flopen)
389  return 0;
390  pfl = p[0]->flopen(path, dirs);
391  if (pfl) {
392  pfl->vmt = p[0];
393  pfl->dirs = dirs;
394  }
395  return pfl;
396  }
397  }
398  return 0;
399  }
400 
401  const char *gfileReadFileList(gfileList *pfl) {
402  return pfl->vmt->flread ? pfl->vmt->flread(pfl) : 0;
403  }
404 
405  void gfileCloseFileList(gfileList *pfl) {
406  if (pfl->vmt->flclose)
407  pfl->vmt->flclose(pfl);
408  }
409 #endif
410 
411 #endif /* GFX_USE_GFILE */
bool_t gfileUnmount(char fs, const char *drive)
Unmount a logical drive (aka partition)
long int gfileGetPos(GFILE *f)
Get the current position of the read/write cursor.
bool_t gfileRename(const char *oldname, const char *newname)
Rename file.
size_t gfileWrite(GFILE *f, const void *buf, size_t len)
Write to file.
bool_t gfileDelete(const char *fname)
Delete file.
struct GFILE GFILE
A file pointer.
Definition: gfile.h:34
bool_t gfileEOF(GFILE *f)
Check for EOF.
#define FALSE
Generic &#39;false&#39; boolean constant.
Definition: gfx.h:31
long int gfileGetSize(GFILE *f)
Get the size of file.
gfileList * gfileOpenFileList(char fs, const char *path, bool_t dirs)
Open a file list.
#define GFILE_MAX_GFILES
The maximum number of open files.
const char * gfileReadFileList(gfileList *pfl)
Get the next file in a file list.
size_t gfileRead(GFILE *f, void *buf, size_t len)
Read from file.
bool_t gfileSync(GFILE *f)
Syncs the file object (flushes the buffer)
bool_t gfileSetPos(GFILE *f, long int pos)
Set the position of the read/write cursor.
void gfileCloseFileList(gfileList *pfl)
Close a file list.
long int gfileGetFilesize(const char *fname)
Get the size of a file.
void gfileClose(GFILE *f)
Close file.
GFILE * gfileOpen(const char *fname, const char *mode)
Open file.
bool_t gfileMount(char fs, const char *drive)
Mount a logical drive (aka partition)
GFILE file system header.
#define TRUE
Generic &#39;true&#39; boolean constant.
Definition: gfx.h:38
bool_t gfileExists(const char *fname)
Check if file exists.