aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/gfile/gfile.h185
-rw-r--r--include/gfile/options.h114
-rw-r--r--src/gfile/gfile.c225
-rw-r--r--src/gfile/gfile.mk1
-rw-r--r--src/gfile/inc_fatfs.c15
-rw-r--r--src/gfile/inc_nativefs.c81
-rw-r--r--src/gfile/inc_ramfs.c15
-rw-r--r--src/gfile/inc_romfs.c97
8 files changed, 733 insertions, 0 deletions
diff --git a/include/gfile/gfile.h b/include/gfile/gfile.h
new file mode 100644
index 00000000..675342fb
--- /dev/null
+++ b/include/gfile/gfile.h
@@ -0,0 +1,185 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+/**
+ * @file include/gfile/gfile.h
+ * @brief GFILE - File IO Routines header file.
+ *
+ * @addtogroup GFILE
+ *
+ * @brief Module which contains Operating system independent FILEIO
+ *
+ * @{
+ */
+
+#ifndef _GFILE_H
+#define _GFILE_H
+
+#include "gfx.h"
+
+#if GFX_USE_GMISC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Type definitions */
+/*===========================================================================*/
+
+/**
+ * @brief A file pointer
+ */
+
+typedef struct GFILE {
+ const struct GFILEVMT * vmt;
+ uint16_t flags;
+ #define GFILEFLG_OPEN 0x0001
+ #define GFILEFLG_READ 0x0002
+ #define GFILEFLG_WRITE 0x0004
+ #define GFILEFLG_APPEND 0x0008
+ #define GFILEFLG_CANSEEK 0x0010
+ #define GFILEFLG_DELONCLOSE 0x0020
+ #define GFILEFLG_FAILONBLOCK 0x0040
+ short err;
+ void * obj;
+ long int pos;
+} GFILE;
+
+typedef struct GFILEVMT {
+ const struct GFILEVMT * next;
+ char prefix;
+ uint16_t flags;
+ #define GFSFLG_WRITEABLE 0x0001
+ #define GFSFLG_CASESENSITIVE 0x0002
+ #define GFSFLG_SEEKABLE 0x0004
+ #define GFSFLG_FAST 0x0010
+ #define GFSFLG_SMALL 0x0020
+ bool_t del(const char *fname);
+ bool_t exists(const char *fname);
+ long int filesize(const char *fname);
+ bool_t ren(const char *oldname, const char *newname);
+ bool_t open(GFILE *f, const char *fname, const char *mode);
+ void close(GFILE *f);
+ int read(GFILE *f, char *buf, int size);
+ int write(GFILE *f, char *buf, int size);
+ bool_t setpos(GFILE *f, long int pos);
+ long int getsize(GFILE *f);
+ bool_t eof(GFILE *f);
+} GFILEVMT;
+
+typedef void GFILE;
+
+extern GFILE *gfileStdIn;
+extern GFILE *gfileStdErr;
+extern GFILE *gfileStdOut;
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+//TODO
+//FILE * tmpfile ( void ); // Auto-deleting
+//char * tmpnam ( char * str );
+//L_tmpnam - Minimum length for temporary file name
+//FILENAME_MAX - Maximum length of file names (constant )
+// FOPEN_MAX - Potential limit of simultaneous open streams (constant )
+// TMP_MAX - Number of temporary files (constant )
+//FILE * freopen ( const char * filename, const char * mode, FILE * stream );
+//setbuf
+//setvbuf
+//fflush
+//fscanf
+//scanf
+//sscanf
+//vscanf
+//vsscanf
+//fgetc
+//fgets
+//fputc
+//fputs
+//getc
+//getchar
+//puts
+//ungetc
+//void perror (const char * str);
+
+//"r" read: Open file for input operations. The file must exist.
+//"w" write: Create an empty file for output operations. If a file with the same name already exists, its contents are discarded and the file is treated as a new empty file.
+//"a" append: Open file for output at the end of a file. Output operations always write data at the end of the file, expanding it. Repositioning operations (fseek, fsetpos, rewind) are ignored. The file is created if it does not exist.
+//"r+" read/update: Open a file for update (both for input and output). The file must exist.
+//"w+" write/update: Create an empty file and open it for update (both for input and output). If a file with the same name already exists its contents are discarded and the file is treated as a new empty file.
+//"a+" append/update: Open a file for update (both for input and output) with all output operations writing data at the end of the file. Repositioning operations (fseek, fsetpos, rewind) affects the next input operations, but output operations move the position back to the end of file. The file is created if it does not exist.
+//"...b" A binary stream
+//"...x" Added to "w" - fail if file exists
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ bool_t gfileExists(const char *fname);
+ bool_t gfileDelete(const char *fname);
+ long int gfileGetFilesize(const char *fname);
+ bool_t gfileRename(const char *oldname, const char *newname);
+ GFILE *gfileOpen(const char *fname, const char *mode);
+ void gfileClose(GFILE *f);
+ size_t gfileRead(GFILE *f, char *buf, size_t len);
+ size_t gfileWrite(GFILE *f, const char *buf, size_t len);
+ long int gfileGetPos(GFILE *f);
+ bool_t gfileSetPos(GFILE *f, long int pos);
+ long int gfileGetSize(GFILE *f);
+
+ int vfnprintg(GFILE *f, size_t maxlen, const char *fmt, va_list arg);
+ int fnprintg(GFILE *f, size_t maxlen, const char *fmt, ...);
+ #define vfprintg(f,m,a) vfnprintg(f,0,m,a)
+ #define fprintg(f,m,...) fnprintg(f,0,m,...)
+ #define vprintg(m,a) vfnprintg(gfileStdOut,0,m,a)
+ #define printg(m,...) fnprintg(gfileStdOut,0,m,...)
+
+ int vsnprintg(char *buf, size_t maxlen, const char *fmt, va_list arg);
+ int snprintg(char *buf, size_t maxlen, const char *fmt, ...);
+ #define vsprintg(s,m,a) vsnprintg(s,0,m,a)
+ #define sprintg(s,m,...) snprintg(s,0,m,...)
+
+ #if GFILE_NEED_STDIO && !defined(GFILE_IMPLEMENTATION)
+ #define FILE GFILE
+ #define fopen(n,m) gfileOpen(n,m)
+ #define fclose(f) gfileClose(f)
+ size_t fread(void * ptr, size_t size, size_t count, FILE *f);
+ size_t fwrite(const void * ptr, size_t size, size_t count, FILE *f);
+ int fseek(FILE *f, size_t offset, int origin);
+ #define SEEK_SET 0
+ #define SEEK_CUR 1
+ #define SEEK_END 2
+ #define remove(n) (!gfileDelete(n))
+ #define rename(o,n) (!gfileRename(o,n))
+ #define fflush(f) (0)
+ #define ftell(f) gfileGetPos(f)
+ typedef long int fpos_t;
+ int fgetpos(FILE *f, fpos_t *pos);
+ #define fsetpos(f, pos) (!gfileSetPos(f, *pos))
+ #define rewind(f) gfileSetPos(f, 0);
+ #define clearerr(f) do {f->err = 0; } while(0)
+ #define feof(f) (f->flags & GFILEFLG_EOF)
+ #define ferror(f) (f->err)
+
+ #define vfprintf(f,m,a) vfnprintg(f,0,m,a)
+ #define fprintf(f,m,...) fnprintg(f,0,m,...)
+ #define vprintf(m,a) vfnprintg(gfileStdOut,0,m,a)
+ #define printf(m,...) fnprintg(gfileStdOut,0,m,...)
+ #define vsnprintf(s,n,m,a) vsnprintg(s,n,m,a)
+ #define snprintf(s,n,m,...) snprintg(s,n,m,...)
+ #define vsprintf(s,m,a) vsnprintg(s,0,m,a)
+ #define sprintf(s,m,...) snprintg(s,0,m,...)
+ #endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_USE_MISC */
+
+#endif /* _GMISC_H */
+/** @} */
+
diff --git a/include/gfile/options.h b/include/gfile/options.h
new file mode 100644
index 00000000..176c6270
--- /dev/null
+++ b/include/gfile/options.h
@@ -0,0 +1,114 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+/**
+ * @file include/gfile/options.h
+ * @brief GFILE - File IO options header file.
+ *
+ * @addtogroup GFILE
+ * @{
+ */
+
+#ifndef _GFILE_OPTIONS_H
+#define _GFILE_OPTIONS_H
+
+/**
+ * @name GFILE Functionality to be included
+ * @{
+ */
+ /**
+ * @brief Include printg, fprintg, sprintg etc functions
+ * @details Defaults to FALSE
+ */
+ #ifndef GFILE_NEED_PRINTG
+ #define GFILE_NEED_PRINTG FALSE
+ #endif
+ /**
+ * @brief Include scang, fscang, sscang etc functions
+ * @details Defaults to FALSE
+ */
+ #ifndef GFILE_NEED_SCANG
+ #define GFILE_NEED_SCANG FALSE
+ #endif
+ /**
+ * @brief Map all the stdio functions to their GFILE equivalent
+ * @details Defaults to FALSE
+ * @note This replaces the functions in stdio.h with equivalents
+ * - Do not include stdio.h as it has different conflicting definitions.
+ */
+ #ifndef GFILE_NEED_STDIO
+ #define GFILE_NEED_STDIO FALSE
+ #endif
+ /**
+ * @brief Include the ROM file system
+ * @details Defaults to FALSE
+ * @note To ensure that you are opening a file on the ROM file system, prefix
+ * its name with "S|" (the letter 'S', followed by a vertical bar).
+ * @note This requires a file called romfs_files.h to be included in the
+ * users project. This file includes all the files converted to .h files
+ * using the file2c utility using the "-r" flag.
+ */
+ #ifndef GFILE_NEED_ROMFS
+ #define GFILE_NEED_ROMFS FALSE
+ #endif
+ /**
+ * @brief Include the RAM file system
+ * @details Defaults to FALSE
+ * @note To ensure that you are opening a file on the RAM file system, prefix
+ * its name with "R|" (the letter 'R', followed by a vertical bar).
+ * @note You must also define GFILE_RAMFS_SIZE with the size of the file system
+ * to be allocated in RAM.
+ */
+ #ifndef GFILE_NEED_RAMFS
+ #define GFILE_NEED_RAMFS FALSE
+ #endif
+ /**
+ * @brief Include the FAT file system driver
+ * @details Defaults to FALSE
+ * @note To ensure that you are opening a file on the FAT file system, prefix
+ * its name with "F|" (the letter 'F', followed by a vertical bar).
+ * @note You must separately include the FATFS library and code.
+ */
+ #ifndef GFILE_NEED_FATFS
+ #define GFILE_NEED_FATFS FALSE
+ #endif
+ /**
+ * @brief Include the operating system's native file system
+ * @details Defaults to FALSE
+ * @note To ensure that you are opening a file on the native file system, prefix
+ * its name with "N|" (the letter 'N', followed by a vertical bar).
+ * @note If defined then the gfileStdOut and gfileStdErr handles
+ * use the operating system equivalent stdio and stderr.
+ * If it is not defined the gfileStdOut and gfileStdErr io is discarded.
+ */
+ #ifndef GFILE_NEED_NATIVEFS
+ #define GFILE_NEED_NATIVEFS FALSE
+ #endif
+/**
+ * @}
+ *
+ * @name GFILE Optional Parameters
+ * @{
+ */
+ /**
+ * @brief The maximum number of open files
+ * @note This count excludes gfileStdIn, gfileStdOut and gfileStdErr
+ * (if open by default).
+ */
+ #ifndef GFILE_MAX_GFILES
+ #define GFILE_MAX_GFILES 3
+ #endif
+ /**
+ * @brief The size in bytes of the RAM file system
+ */
+ #ifndef GFILE_RAMFS_SIZE
+ #define GFILE_RAMFS_SIZE 0
+ #endif
+/** @} */
+
+#endif /* _GFILE_OPTIONS_H */
+/** @} */
diff --git a/src/gfile/gfile.c b/src/gfile/gfile.c
new file mode 100644
index 00000000..bf76e8bc
--- /dev/null
+++ b/src/gfile/gfile.c
@@ -0,0 +1,225 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+/**
+ * @file src/gfile/gfile.c
+ * @brief GFILE code.
+ *
+ */
+
+#define GFILE_IMPLEMENTATION
+#include "gfx.h"
+
+#if GFX_USE_GFILE
+
+// The chain of FileSystems
+#define GFILE_CHAINHEAD 0
+
+// The table of GFILE's
+static GFILE gfileArr[GFILE_MAX_GFILES];
+GFILE *gfileStdIn;
+GFILE *gfileStdOut;
+GFILE *gfileStdErr;
+
+/**
+ * The order of the file-systems below determines the order
+ * that they are searched to find a file.
+ * The last defined is the first searched.
+ */
+
+/********************************************************
+ * The RAM file-system VMT
+ ********************************************************/
+#if GFILE_NEED_RAMFS
+ #include "../src/gfile/inc_ramfs.c"
+#endif
+
+/********************************************************
+ * The FAT file-system VMT
+ ********************************************************/
+#ifndef GFILE_NEED_FATFS
+ #include "../src/gfile/inc_fatfs.c"
+#endif
+
+/********************************************************
+ * The native file-system
+ ********************************************************/
+#if GFILE_NEED_NATIVEFS
+ #include "../src/gfile/inc_nativefs.c"
+#endif
+
+/********************************************************
+ * The ROM file-system VMT
+ ********************************************************/
+#if GFILE_NEED_ROMFS
+ #include "../src/gfile/inc_romfs.c"
+#endif
+
+/********************************************************
+ * IO routines
+ ********************************************************/
+
+/**
+ * The chain of file systems.
+ */
+static const GFILEVMT const * FsChain = GFILE_CHAINHEAD;
+
+/**
+ * The init routine
+ */
+void _gfileInit(void) {
+ #if GFILE_NEED_NATIVEFS
+ NativeStdIn.flags = GFILEFLG_OPEN|GFILEFLG_READ;
+ NativeStdIn.vmt = &FsNativeVMT;
+ NativeStdIn.obj = (void *)stdin;
+ NativeStdIn.pos = 0;
+ gfileStdIn = &NativeStdIn;
+ NativeStdOut.flags = GFILEFLG_OPEN|GFILEFLG_WRITE|GFILEFLG_APPEND;
+ NativeStdOut.vmt = &FsNativeVMT;
+ NativeStdOut.obj = (void *)stdout;
+ NativeStdOut.pos = 0;
+ gfileStdOut = &NativeStdOut;
+ NativeStdErr.flags = GFILEFLG_OPEN|GFILEFLG_WRITE|GFILEFLG_APPEND;
+ NativeStdErr.vmt = &FsNativeVMT;
+ NativeStdErr.obj = (void *)stderr;
+ NativeStdErr.pos = 0;
+ gfileStdErr = &NativeStdErr;
+ #endif
+}
+
+bool_t gfileExists(const char *fname) {
+ const GFILEVMT *p;
+
+ if (fname[0] && fname[1] == '|') {
+ for(p = FsChain; p; p = p->next) {
+ if (p->prefix == fname[0])
+ return p->exists && p->exists(fname+2);
+ }
+ } else {
+ for(p = FsChain; p; p = p->next) {
+ if (p->exists && p->exists(fname))
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+bool_t gfileDelete(const char *fname) {
+ const GFILEVMT *p;
+
+ if (fname[0] && fname[1] == '|') {
+ for(p = FsChain; p; p = p->next) {
+ if (p->prefix == fname[0])
+ return p->del && p->del(fname+2);
+ }
+ } else {
+ for(p = FsChain; p; p = p->next) {
+ if (p->del && p->del(fname))
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+long int gfileGetFilesize(const char *fname) {
+ const GFILEVMT *p;
+
+ if (fname[0] && fname[1] == '|') {
+ for(p = FsChain; p; p = p->next) {
+ if (p->prefix == fname[0])
+ return p->filesize ? p->filesize(fname+2) : -1;
+ }
+ } else {
+ long int res;
+
+ for(p = FsChain; p; p = p->next) {
+ if (p->filesize && (res = p->filesize(fname)) != -1)
+ return res;
+ }
+ }
+ return -1;
+}
+
+bool_t gfileRename(const char *oldname, const char *newname) {
+ const GFILEVMT *p;
+
+ if ((oldname[0] && oldname[1] == '|') || (newname[0] && newname[1])) {
+ char ch;
+
+ if (oldname[0] && oldname[1] == '|') {
+ ch = oldname[0];
+ oldname += 2;
+ if (newname[0] && newname[1] == '|') {
+ if (newname[0] != ch)
+ return FALSE;
+ newname += 2;
+ }
+ } else {
+ ch = newname[0];
+ newname += 2;
+ }
+ for(p = FsChain; p; p = p->next) {
+ if (p->prefix == ch)
+ return p->ren && p->ren(oldname, newname);
+ }
+ } else {
+ for(p = FsChain; p; p = p->next) {
+ if (p->ren && p->ren(oldname,newname))
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+GFILE *gfileOpen(const char *fname, const char *mode) {
+
+}
+
+void gfileClose(GFILE *f) {
+
+}
+
+size_t gfileRead(GFILE *f, char *buf, size_t len) {
+
+}
+
+size_t gfileWrite(GFILE *f, const char *buf, size_t len) {
+
+}
+
+long int gfileGetPos(GFILE *f) {
+
+}
+
+bool_t gfileSetPos(GFILE *f, long int pos) {
+
+}
+
+long int gfileGetSize(GFILE *f) {
+
+}
+
+/********************************************************
+ * printg routines
+ ********************************************************/
+#if GFILE_NEED_PRINTG
+#endif
+
+/********************************************************
+ * scang routines
+ ********************************************************/
+#if GFILE_NEED_SCANG
+#endif
+
+/********************************************************
+ * stdio emulation routines
+ ********************************************************/
+#ifndef GFILE_NEED_STDIO
+ #define GFILE_NEED_STDIO FALSE
+#endif
+
+#endif /* GFX_USE_GFILE */
diff --git a/src/gfile/gfile.mk b/src/gfile/gfile.mk
new file mode 100644
index 00000000..381bd6f6
--- /dev/null
+++ b/src/gfile/gfile.mk
@@ -0,0 +1 @@
+GFXSRC += $(GFXLIB)/src/gfile/gfile.c
diff --git a/src/gfile/inc_fatfs.c b/src/gfile/inc_fatfs.c
new file mode 100644
index 00000000..d49cfe7a
--- /dev/null
+++ b/src/gfile/inc_fatfs.c
@@ -0,0 +1,15 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+/**
+ * This file is included by src/gfile/gfile.c
+ */
+
+/********************************************************
+ * The FAT file-system VMT
+ ********************************************************/
+#error "GFILE: FATFS Not implemented yet"
diff --git a/src/gfile/inc_nativefs.c b/src/gfile/inc_nativefs.c
new file mode 100644
index 00000000..7828ff84
--- /dev/null
+++ b/src/gfile/inc_nativefs.c
@@ -0,0 +1,81 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+/**
+ * This file is included by src/gfile/gfile.c
+ */
+
+/********************************************************
+ * The native file-system
+ ********************************************************/
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+static GFILE NativeStdIn;
+static GFILE NativeStdOut;
+static GFILE NativeStdErr;
+
+static bool_t NativeDel(const char *fname);
+static bool_t NativeExists(const char *fname);
+static long int NativeFilesize(const char *fname);
+static bool_t NativeRen(const char *oldname, const char *newname);
+static bool_t NativeOpen(GFILE *f, const char *fname, const char *mode);
+static void NativeClose(GFILE *f);
+static int NativeRead(GFILE *f, char *buf, int size);
+static int NativeWrite(GFILE *f, char *buf, int size);
+static bool_t NativeSetpos(GFILE *f, long int pos);
+static long int NativeGetsize(GFILE *f);
+static bool_t NativeEof(GFILE *f);
+
+static const GFILEVMT FsNativeVMT = {
+ GFILE_CHAINHEAD, // next
+ 'N', // prefix
+ #if !defined(WIN32) && !GFX_USE_OS_WIN32
+ GFSFLG_CASESENSITIVE|
+ #endif
+ GFSFLG_WRITEABLE|GFSFLG_SEEKABLE|GFSFLG_FAST, // flags
+ NativeDel, NativeExists, NativeFilesize, NativeRen,
+ NativeOpen, NativeClose, NativeRead, NativeWrite,
+ NativeSetpos, NativeGetsize, NativeEof,
+};
+#undef GFILE_CHAINHEAD
+#define GFILE_CHAINHEAD &FsNativeVMT
+
+static bool_t NativeDel(const char *fname) { return remove(fname) ? FALSE : TRUE; }
+static bool_t NativeExists(const char *fname) { return access(fname, 0) ? FALSE : TRUE; }
+static long int NativeFilesize(const char *fname) {
+ struct stat st;
+ if (stat(fname, &st)) return -1;
+ return st.st_size;
+}
+static bool_t NativeRen(const char *oldname, const char *newname) { return rename(oldname, newname) ? FALSE : TRUE };
+static bool_t NativeOpen(GFILE *f, const char *fname, const char *mode) {
+ FILE *fd;
+
+ if (!(fd = fopen(fname, mode)))
+ return FALSE;
+ f->vmt = &FsNativeVMT;
+ f->obj = (void *)fd;
+ return TRUE;
+}
+static void NativeClose(GFILE *f) { fclose((FILE *)f->obj); }
+static int NativeRead(GFILE *f, char *buf, int size) { return fread(buf, 1, size, (FILE *)f->obj); }
+static int NativeWrite(GFILE *f, char *buf, int size) { return fwrite(buf, 1, size, (FILE *)f->obj); }
+static bool_t NativeSetpos(GFILE *f, long int pos) {
+ if (fseek((FILE *)f->obj, pos, SEEK_SET)) return FALSE;
+ f->pos = pos;
+ return TRUE;
+}
+static long int NativeGetsize(GFILE *f) {
+ struct stat st;
+ if (fstat(fileno((FILE *)f->obj), &st)) return -1;
+ return st.st_size;
+}
+static bool_t NativeEof(GFILE *f) { return feof((FILE *)f->obj) ? TRUE : FALSE; }
diff --git a/src/gfile/inc_ramfs.c b/src/gfile/inc_ramfs.c
new file mode 100644
index 00000000..b0f0d052
--- /dev/null
+++ b/src/gfile/inc_ramfs.c
@@ -0,0 +1,15 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+/**
+ * This file is included by src/gfile/gfile.c
+ */
+
+/********************************************************
+ * The RAM file-system VMT
+ ********************************************************/
+#error "GFILE: RAMFS Not implemented yet"
diff --git a/src/gfile/inc_romfs.c b/src/gfile/inc_romfs.c
new file mode 100644
index 00000000..321dc9b1
--- /dev/null
+++ b/src/gfile/inc_romfs.c
@@ -0,0 +1,97 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+/**
+ * This file is included by src/gfile/gfile.c
+ */
+
+/********************************************************
+ * The ROM file-system VMT
+ ********************************************************/
+
+#include <string.h>
+
+typedef struct ROMFS_DIRENTRY {
+ const struct ROMFS_DIRENTRY * next;
+ const char * name;
+ long int size;
+ const char * file;
+} ROMFS_DIRENTRY;
+
+#define ROMFS_DIRENTRY_HEAD 0
+
+#include "romfs_files.h"
+
+static const ROMFS_DIRENTRY const *FsROMHead = ROMFS_DIRENTRY_HEAD;
+
+static bool_t ROMExists(const char *fname);
+static long int ROMFilesize(const char *fname);
+static bool_t ROMOpen(GFILE *f, const char *fname, const char *mode);
+static void ROMClose(GFILE *f);
+static int ROMRead(GFILE *f, char *buf, int size);
+static bool_t ROMSetpos(GFILE *f, long int pos);
+static long int ROMGetsize(GFILE *f);
+static bool_t ROMEof(GFILE *f);
+
+static const GFILEVMT FsROMVMT = {
+ GFILE_CHAINHEAD, // next
+ 'S', // prefix
+ GFSFLG_CASESENSITIVE|GFSFLG_SEEKABLE|GFSFLG_FAST, // flags
+ 0, ROMExists, ROMFilesize, 0,
+ ROMOpen, ROMClose, ROMRead, 0,
+ ROMSetpos, ROMGetsize, ROMEof,
+};
+#undef GFILE_CHAINHEAD
+#define GFILE_CHAINHEAD &FsROMVMT
+
+static ROMFS_DIRENTRY *ROMFindFile(const char *fname) {
+ const ROMFS_DIRENTRY *p;
+
+ for(p = FsROMHead; p; p = p->next) {
+ if (!strcmp(p->name, fname))
+ break;
+ }
+ return p;
+}
+static bool_t ROMExists(const char *fname) { return ROMFindFile(fname) != 0; }
+static long int ROMFilesize(const char *fname) {
+ const ROMFS_DIRENTRY *p;
+
+ if (!(p = ROMFindFile(fname))) return -1;
+ return p->size;
+}
+static bool_t ROMOpen(GFILE *f, const char *fname, const char *mode) {
+ const ROMFS_DIRENTRY *p;
+
+ // Check mode
+ if (mode[0] != 'r') return FALSE;
+ while(*++mode) {
+ switch(*mode) {
+ case '+': case 'w': case 'a':
+ return FALSE;
+ }
+ }
+
+ if (!(p = ROMFindFile(fname))) return FALSE;
+ f->vmt = &FsROMVMT;
+ f->obj = (void *)p;
+ return TRUE;
+}
+static void ROMClose(GFILE *f) { (void)f; }
+static int ROMRead(GFILE *f, char *buf, int size) {
+ const ROMFS_DIRENTRY *p;
+
+ p = (const ROMFS_DIRENTRY *)f->obj;
+ if (p->size - f->pos < size)
+ size = p->size - f->pos;
+ if (size <= 0) return 0;
+ memcpy(buf, p->file+f->pos, size);
+ return size;
+}
+static bool_t ROMSetpos(GFILE *f, long int pos) { return pos <= ((const ROMFS_DIRENTRY *)f->obj)->size; }
+static long int ROMGetsize(GFILE *f) { return ((const ROMFS_DIRENTRY *)f->obj)->size; }
+static bool_t ROMEof(GFILE *f) { return f->pos >= ((const ROMFS_DIRENTRY *)f->obj)->size; }