diff options
Diffstat (limited to 'src/gfile')
-rw-r--r-- | src/gfile/gfile.c | 998 | ||||
-rw-r--r-- | src/gfile/gfile.mk | 1 | ||||
-rw-r--r-- | src/gfile/inc_chibiosfs.c | 46 | ||||
-rw-r--r-- | src/gfile/inc_fatfs.c | 15 | ||||
-rw-r--r-- | src/gfile/inc_memfs.c | 43 | ||||
-rw-r--r-- | src/gfile/inc_nativefs.c | 102 | ||||
-rw-r--r-- | src/gfile/inc_ramfs.c | 15 | ||||
-rw-r--r-- | src/gfile/inc_romfs.c | 95 |
8 files changed, 1315 insertions, 0 deletions
diff --git a/src/gfile/gfile.c b/src/gfile/gfile.c new file mode 100644 index 00000000..9edafea4 --- /dev/null +++ b/src/gfile/gfile.c @@ -0,0 +1,998 @@ +/* + * 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 + +struct GFILE { + const struct GFILEVMT * vmt; + uint16_t flags; + #define GFILEFLG_OPEN 0x0001 // File is open + #define GFILEFLG_READ 0x0002 // Read the file + #define GFILEFLG_WRITE 0x0004 // Write the file + #define GFILEFLG_APPEND 0x0008 // Append on each write + #define GFILEFLG_BINARY 0x0010 // Treat as a binary file + #define GFILEFLG_DELONCLOSE 0x0020 // Delete on close + #define GFILEFLG_CANSEEK 0x0040 // Seek operations are valid + #define GFILEFLG_FAILONBLOCK 0x0080 // Fail on a blocking call + #define GFILEFLG_MUSTEXIST 0x0100 // On open file must exist + #define GFILEFLG_MUSTNOTEXIST 0x0200 // On open file must not exist + #define GFILEFLG_TRUNC 0x0400 // On open truncate the file + void * obj; + long int pos; +}; + +typedef struct GFILEVMT { + const struct GFILEVMT * next; + uint8_t flags; + #define GFSFLG_WRITEABLE 0x0001 + #define GFSFLG_CASESENSITIVE 0x0002 + #define GFSFLG_SEEKABLE 0x0004 + #define GFSFLG_FAST 0x0010 + #define GFSFLG_SMALL 0x0020 + #define GFSFLG_TEXTMODES 0x0040 + char prefix; + 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); + void (*close) (GFILE *f); + int (*read) (GFILE *f, void *buf, int size); + int (*write) (GFILE *f, const void *buf, int size); + bool_t (*setpos) (GFILE *f, long int pos); + long int (*getsize) (GFILE *f); + bool_t (*eof) (GFILE *f); +} GFILEVMT; + +// 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 ChibiOS BaseFileStream VMT + ********************************************************/ +#if GFILE_NEED_CHIBIOSFS && GFX_USE_OS_CHIBIOS + #include "../src/gfile/inc_chibiosfs.c" +#endif + +/******************************************************** + * The Memory Pointer VMT + ********************************************************/ +#if GFILE_NEED_MEMFS + #include "../src/gfile/inc_memfs.c" +#endif + +/******************************************************** + * 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 +} + +void _gfileDeinit(void) +{ + /* ToDo */ +} + +bool_t gfileExists(const char *fname) { + const GFILEVMT *p; + + #if GFILE_ALLOW_DEVICESPECIFIC + if (fname[0] && fname[1] == '|') { + for(p = FsChain; p; p = p->next) { + if (p->prefix == fname[0]) + return p->exists && p->exists(fname+2); + } + return FALSE; + } + #endif + + 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 GFILE_ALLOW_DEVICESPECIFIC + if (fname[0] && fname[1] == '|') { + for(p = FsChain; p; p = p->next) { + if (p->prefix == fname[0]) + return p->del && p->del(fname+2); + } + return FALSE; + } + #endif + + 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; + long int res; + + #if GFILE_ALLOW_DEVICESPECIFIC + 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; + } + return -1; + } + #endif + + 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 GFILE_ALLOW_DEVICESPECIFIC + 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) + // Both oldname and newname are fs specific but different ones. + 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); + } + return FALSE; + } + #endif + + for(p = FsChain; p; p = p->next) { + if (p->ren && p->ren(oldname,newname)) + return TRUE; + } + return FALSE; +} + +static uint16_t mode2flags(const char *mode) { + uint16_t flags; + + switch(mode[0]) { + case 'r': + flags = GFILEFLG_READ|GFILEFLG_MUSTEXIST; + while (*++mode) { + switch(mode[0]) { + case '+': flags |= GFILEFLG_WRITE; break; + case 'b': flags |= GFILEFLG_BINARY; break; + } + } + return flags; + case 'w': + flags = GFILEFLG_WRITE|GFILEFLG_TRUNC; + while (*++mode) { + switch(mode[0]) { + case '+': flags |= GFILEFLG_READ; break; + case 'b': flags |= GFILEFLG_BINARY; break; + case 'x': flags |= GFILEFLG_MUSTNOTEXIST; break; + } + } + return flags; + case 'a': + flags = GFILEFLG_WRITE|GFILEFLG_APPEND; + while (*++mode) { + switch(mode[0]) { + case '+': flags |= GFILEFLG_READ; break; + case 'b': flags |= GFILEFLG_BINARY; break; + case 'x': flags |= GFILEFLG_MUSTNOTEXIST; break; + } + } + return flags; + } + return 0; +} + +static bool_t testopen(const GFILEVMT *p, GFILE *f, const char *fname) { + // If we want write but the fs doesn't allow it then return + if ((f->flags & GFILEFLG_WRITE) && !(p->flags & GFSFLG_WRITEABLE)) + return FALSE; + + // Try to open + if (!p->open || !p->open(f, fname)) + return FALSE; + + // File is open - fill in all the details + f->vmt = p; + f->pos = 0; + f->flags |= GFILEFLG_OPEN; + if (p->flags & GFSFLG_SEEKABLE) + f->flags |= GFILEFLG_CANSEEK; + return TRUE; +} + +GFILE *gfileOpen(const char *fname, const char *mode) { + uint16_t flags; + GFILE * f; + const GFILEVMT *p; + + // Get the requested mode + if (!(flags = mode2flags(mode))) + return 0; + + #if GFILE_ALLOW_DEVICESPECIFIC + if (fname[0] && fname[1] == '|') { + // First find an available GFILE slot. + for (f = gfileArr; f < &gfileArr[GFILE_MAX_GFILES]; f++) { + if (!(f->flags & GFILEFLG_OPEN)) { + // Try to open the file + f->flags = flags; + for(p = FsChain; p; p = p->next) { + if (p->prefix == fname[0]) + return testopen(p, f, fname+2) ? f : 0; + } + // File not found + break; + } + } + + // No available slot + return 0; + } + #endif + + // First find an available GFILE slot. + for (f = gfileArr; f < &gfileArr[GFILE_MAX_GFILES]; f++) { + if (!(f->flags & GFILEFLG_OPEN)) { + + // Try to open the file + f->flags = flags; + for(p = FsChain; p; p = p->next) { + if (testopen(p, f, fname)) + return f; + } + // File not found + break; + } + } + + // No available slot + return 0; +} + +#if GFILE_NEED_CHIBIOSFS && GFX_USE_OS_CHIBIOS + GFILE * gfileOpenBaseFileStream(void *BaseFileStreamPtr, const char *mode) { + GFILE * f; + + // First find an available GFILE slot. + for (f = gfileArr; f < &gfileArr[GFILE_MAX_GFILES]; f++) { + if (!(f->flags & GFILEFLG_OPEN)) { + // Get the flags + if (!(f->flags = mode2flags(mode))) + return 0; + + // If we want write but the fs doesn't allow it then return + if ((f->flags & GFILEFLG_WRITE) && !(FsCHIBIOSVMT.flags & GFSFLG_WRITEABLE)) + return 0; + + // File is open - fill in all the details + f->vmt = &FsCHIBIOSVMT; + f->obj = BaseFileStreamPtr; + f->pos = 0; + f->flags |= GFILEFLG_OPEN|GFILEFLG_CANSEEK; + return f; + } + } + + // No available slot + return 0; + } +#endif + +#if GFILE_NEED_MEMFS + GFILE * gfileOpenMemory(void *memptr, const char *mode) { + GFILE * f; + + // First find an available GFILE slot. + for (f = gfileArr; f < &gfileArr[GFILE_MAX_GFILES]; f++) { + if (!(f->flags & GFILEFLG_OPEN)) { + // Get the flags + if (!(f->flags = mode2flags(mode))) + return 0; + + // If we want write but the fs doesn't allow it then return + if ((f->flags & GFILEFLG_WRITE) && !(FsMemVMT.flags & GFSFLG_WRITEABLE)) + return 0; + + // File is open - fill in all the details + f->vmt = &FsMemVMT; + f->obj = memptr; + f->pos = 0; + f->flags |= GFILEFLG_OPEN|GFILEFLG_CANSEEK; + return f; + } + } + + // No available slot + return 0; + } +#endif + +void gfileClose(GFILE *f) { + if (!f || !(f->flags & GFILEFLG_OPEN)) + return; + if (f->vmt->close) + f->vmt->close(f); + f->flags = 0; +} + +size_t gfileRead(GFILE *f, void *buf, size_t len) { + size_t res; + + if (!f || (f->flags & (GFILEFLG_OPEN|GFILEFLG_READ)) != (GFILEFLG_OPEN|GFILEFLG_READ)) + return 0; + if (!f->vmt->read) + return 0; + if ((res = f->vmt->read(f, buf, len)) <= 0) + return 0; + f->pos += res; + return res; +} + +size_t gfileWrite(GFILE *f, const void *buf, size_t len) { + size_t res; + + if (!f || (f->flags & (GFILEFLG_OPEN|GFILEFLG_WRITE)) != (GFILEFLG_OPEN|GFILEFLG_WRITE)) + return 0; + if (!f->vmt->write) + return 0; + if ((res = f->vmt->write(f, buf, len)) <= 0) + return 0; + f->pos += res; + return res; +} + +long int gfileGetPos(GFILE *f) { + if (!f || !(f->flags & GFILEFLG_OPEN)) + return 0; + return f->pos; +} + +bool_t gfileSetPos(GFILE *f, long int pos) { + if (!f || !(f->flags & GFILEFLG_OPEN)) + return FALSE; + if (!f->vmt->setpos || !f->vmt->setpos(f, pos)) + return FALSE; + f->pos = pos; + return TRUE; +} + +long int gfileGetSize(GFILE *f) { + if (!f || !(f->flags & GFILEFLG_OPEN)) + return 0; + if (!f->vmt->getsize) + return 0; + return f->vmt->getsize(f); +} + +bool_t gfileEOF(GFILE *f) { + if (!f || !(f->flags & GFILEFLG_OPEN)) + return TRUE; + if (!f->vmt->eof) + return FALSE; + return f->vmt->eof(f); +} + +/******************************************************** + * String VMT routines + ********************************************************/ +#if GFILE_NEED_STRINGS && (GFILE_NEED_PRINTG || GFILE_NEED_SCANG) + #include <string.h> + + // Special String VMT + static int StringRead(GFILE *f, void *buf, int size) { + // size must be 1 for a complete read + if (!((char *)f->obj)[f->pos]) + return 0; + ((char *)buf)[0] = ((char *)f->obj)[f->pos]; + return 1; + } + static int StringWrite(GFILE *f, const void *buf, int size) { + // size must be 1 for a complete write + ((char *)f->obj)[f->pos] = ((char *)buf)[0]; + return 1; + } + static const GFILEVMT StringVMT = { + 0, // next + 0, // flags + '_', // prefix + 0, 0, 0, 0, + 0, 0, StringRead, StringWrite, + 0, 0, 0, + }; +#endif + +/******************************************************** + * printg routines + ********************************************************/ +#if GFILE_NEED_PRINTG + #include <stdarg.h> + + #define MAX_FILLER 11 + #define FLOAT_PRECISION 100000 + + int fnprintg(GFILE *f, int maxlen, const char *fmt, ...) { + int res; + va_list ap; + + va_start(ap, fmt); + res = vfnprintg(f, maxlen, fmt, ap); + va_end(ap); + return res; + } + + static char *ltoa_wd(char *p, long num, unsigned radix, long divisor) { + int i; + char * q; + + if (!divisor) divisor = num; + + q = p + MAX_FILLER; + do { + i = (int)(num % radix); + i += '0'; + if (i > '9') + i += 'A' - '0' - 10; + *--q = i; + num /= radix; + } while ((divisor /= radix) != 0); + + i = (int)(p + MAX_FILLER - q); + do { + *p++ = *q++; + } while (--i); + + return p; + } + + int vfnprintg(GFILE *f, int maxlen, const char *fmt, va_list arg) { + int ret; + char *p, *s, c, filler; + int i, precision, width; + bool_t is_long, left_align; + long l; + #if GFILE_ALLOW_FLOATS + float f; + char tmpbuf[2*MAX_FILLER + 1]; + #else + char tmpbuf[MAX_FILLER + 1]; + #endif + + ret = 0; + if (maxlen < 0) + return 0; + if (!maxlen) + maxlen = -1; + + while (*fmt) { + if (*fmt != '%') { + gfileWrite(f, fmt, 1); + ret++; if (--maxlen) return ret; + fmt++; + continue; + } + fmt++; + + p = s = tmpbuf; + left_align = FALSE; + filler = ' '; + width = 0; + precision = 0; + + if (*fmt == '-') { + fmt++; + left_align = TRUE; + } + if (*fmt == '.') { + fmt++; + filler = '0'; + } + + while (1) { + c = *fmt++; + if (c >= '0' && c <= '9') + c -= '0'; + else if (c == '*') + c = va_arg(ap, int); + else + break; + width = width * 10 + c; + } + if (c == '.') { + while (1) { + c = *fmt++; + if (c >= '0' && c <= '9') + c -= '0'; + else if (c == '*') + c = va_arg(ap, int); + else + break; + precision = precision * 10 + c; + } + } + /* Long modifier.*/ + if (c == 'l' || c == 'L') { + is_long = TRUE; + if (*fmt) + c = *fmt++; + } + else + is_long = (c >= 'A') && (c <= 'Z'); + + /* Command decoding.*/ + switch (c) { + case 0: + return ret; + case 'c': + filler = ' '; + *p++ = va_arg(ap, int); + break; + case 's': + filler = ' '; + if ((s = va_arg(ap, char *)) == 0) + s = "(null)"; + if (precision == 0) + precision = 32767; + for (p = s; *p && (--precision >= 0); p++); + break; + case 'D': + case 'd': + if (is_long) + l = va_arg(ap, long); + else + l = va_arg(ap, int); + if (l < 0) { + *p++ = '-'; + l = -l; + } + p = ltoa_wd(p, l, 10, 0); + break; + #if GFILE_ALLOW_FLOATS + case 'f': + f = (float) va_arg(ap, double); + if (f < 0) { + *p++ = '-'; + f = -f; + } + l = f; + p = ltoa_wd(p, l, 10, 0); + *p++ = '.'; + l = (f - l) * FLOAT_PRECISION; + p = ltoa_wd(p, l, 10, FLOAT_PRECISION / 10); + break; + #endif + case 'X': + case 'x': + c = 16; + goto unsigned_common; + case 'U': + case 'u': + c = 10; + goto unsigned_common; + case 'O': + case 'o': + c = 8; + unsigned_common: + if (is_long) + l = va_arg(ap, long); + else + l = va_arg(ap, int); + p = ltoa_wd(p, l, c, 0); + break; + default: + *p++ = c; + break; + } + + i = (int)(p - s); + if ((width -= i) < 0) + width = 0; + if (left_align == FALSE) + width = -width; + if (width < 0) { + if (*s == '-' && filler == '0') { + gfileWrite(f, s++, 1); + ret++; if (--maxlen) return ret; + i--; + } + do { + gfileWrite(f, &filler, 1); + ret++; if (--maxlen) return ret; + } while (++width != 0); + } + while (--i >= 0) { + gfileWrite(f, s++, 1); + ret++; if (--maxlen) return ret; + } + while (width) { + gfileWrite(f, &filler, 1); + ret++; if (--maxlen) return ret; + width--; + } + } + return ret; + } + + #if GFILE_NEED_STRINGS + int snprintg(char *buf, int maxlen, const char *fmt, ...) { + int res; + GFILE f; + va_list ap; + + if (maxlen <= 1) { + if (maxlen == 1) + *buf = 0; + return 0; + } + f.flags = GFILEFLG_OPEN|GFILEFLG_WRITE; + f.vmt = &StringVMT; + f.pos = 0; + f.obj = buf; + va_start(ap, fmt); + res = vfnprintg(&f, maxlen-1, fmt, ap); + va_end(ap); + buf[res] = 0; + return res; + } + int vsnprintg(char *buf, int maxlen, const char *fmt, va_list arg) { + int res; + GFILE f; + + if (maxlen <= 1) { + if (maxlen == 1) + *buf = 0; + return 0; + } + f.flags = GFILEFLG_OPEN|GFILEFLG_WRITE; + f.vmt = &StringVMT; + f.pos = 0; + f.obj = buf; + res = vfnprintg(&f, maxlen-1, fmt, arg); + buf[res] = 0; + return res; + } + #endif +#endif + +/******************************************************** + * scang routines + ********************************************************/ +#if GFILE_NEED_SCANG + int fscang(GFILE *f, const char *fmt, ...) { + int res; + va_list ap; + + va_start(ap, fmt); + res = vfscang(f, fmt, ap); + va_end(ap); + return res; + } + + int vfscang(GFILE *f, const char *fmt, va_list arg) { + int res, width, size, base; + char c; + bool_t assign; + void *p; + + for(res = 0; *fmt; fmt++) { + switch(*fmt) { + case ' ': case '\t': case '\r': case '\n': case '\v': case '\f': + break; + + case '%': + fmt++; + assign = TRUE; + width = 0; + size = 1; + + if (*fmt == '*') { + fmt++; + assign = FALSE; + } + while(*fmt >= '0' && *fmt <= '9') + width = width * 10 + (*fmt++ - '0'); + if (*fmt == 'h') { + fmt++; + size = 0; + } else if (*fmt == 'l') { + fmt++; + size = 2; + } else if (*fmt == 'L') { + fmt++; + size = 3; + } + switch(*fmt) { + case 0: + return res; + case '%': + goto matchchar; + case 'c': + if (!width) { + while(1) { + if (!gfileRead(f, &c, 1)) return res; + switch(c) { + case ' ': case '\t': case '\r': + case '\n': case '\v': case '\f': continue; + } + break; + } + width = 1; + } else { + if (!gfileRead(f, &c, 1)) return res; + } + if (assign) { + p = va_arg(ap, char *); + res++; + *((char *)p)++ = c; + } + while(--width) { + if (!gfileRead(f, &c, 1)) return res; + if (assign) *((char *)p)++ = c; + } + break; + case 's': + while(1) { + if (!gfileRead(f, &c, 1)) return res; + switch(c) { + case ' ': case '\t': case '\r': + case '\n': case '\v': case '\f': continue; + } + break; + } + if (assign) { + p = va_arg(ap, char *); + res++; + *((char *)p)++ = c; + } + if (width) { + while(--width) { + if (!gfileRead(f, &c, 1)) { + if (assign) *((char *)p) = 0; + return res; + } + if (assign) *((char *)p)++ = c; + } + } else { + while(1) { + if (!gfileRead(f, &c, 1)) { + if (assign) *((char *)p) = 0; + return res; + } + switch(c) { + case ' ': case '\t': case '\r': + case '\n': case '\v': case '\f': break; + default: + if (assign) *((char *)p)++ = c; + continue; + } + break; + } + //ungetch(c); + } + if (assign) *((char *)p) = 0; + break; + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'b': + /* + while (isspace (*buf)) + buf++; + if (*s == 'd' || *s == 'u') + base = 10; + else if (*s == 'x') + base = 16; + else if (*s == 'o') + base = 8; + else if (*s == 'b') + base = 2; + if (!width) { + if (isspace (*(s + 1)) || *(s + 1) == 0) + width = strcspn (buf, ISSPACE); + else + width = strchr (buf, *(s + 1)) - buf; + } + strncpy (tmp, buf, width); + tmp[width] = '\0'; + buf += width; + if (!noassign) + atob (va_arg (ap, u_int32_t *), tmp, base); + } + if (!noassign) + count++; + */ + + #if GFILE_ALLOW_FLOATS + case 'e': case 'f': case 'g': + #endif + default: + return res; + } + + break; + + default: + matchchar: + while(1) { + if (!gfileRead(f, &c, 1)) return res; + switch(c) { + case ' ': case '\t': case '\r': + case '\n': case '\v': case '\f': continue; + } + break; + } + if (c != *fmt) return res; + break; + } + } + return res; + } + + #if GFILE_NEED_STRINGS + int sscang(const char *buf, const char *fmt, ...) { + int res; + GFILE f; + va_list ap; + + f.flags = GFILEFLG_OPEN|GFILEFLG_READ; + f.vmt = &StringVMT; + f.pos = 0; + f.obj = buf; + va_start(ap, fmt); + res = vfscang(&f, fmt, ap); + va_end(ap); + return res; + } + + int vsscang(const char *buf, const char *fmt, va_list arg) { + int res; + GFILE f; + + f.flags = GFILEFLG_OPEN|GFILEFLG_READ; + f.vmt = &StringVMT; + f.pos = 0; + f.obj = buf; + res = vfscang(&f, fmt, arg); + return res; + } + #endif +#endif + +/******************************************************** + * stdio emulation routines + ********************************************************/ +#if GFILE_NEED_STDIO + size_t gstdioRead(void * ptr, size_t size, size_t count, FILE *f) { + return gfileRead(f, ptr, size*count)/size; + } + size_t gstdioWrite(const void * ptr, size_t size, size_t count, FILE *f) { + return gfileWrite(f, ptr, size*count)/size; + } + int gstdioSeek(FILE *f, size_t offset, int origin) { + switch(origin) { + case SEEK_SET: + break; + case SEEK_CUR: + offset += f->pos; + break; + case SEEK_END: + offset += gfileGetSize(f); + break; + default: + return -1; + } + return gfileSetPos(f, offset) ? 0 : -1; + } + int gstdioGetpos(FILE *f, long int *pos) { + if (!(f->flags & GFILEFLG_OPEN)) + return -1; + *pos = f->pos; + return 0; + } +#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_chibiosfs.c b/src/gfile/inc_chibiosfs.c new file mode 100644 index 00000000..87b8c110 --- /dev/null +++ b/src/gfile/inc_chibiosfs.c @@ -0,0 +1,46 @@ +/* + * 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 ChibiOS BaseFileStream file-system VMT + ********************************************************/ + +static void ChibiOSBFSClose(GFILE *f); +static int ChibiOSBFSRead(GFILE *f, void *buf, int size); +static int ChibiOSBFSWrite(GFILE *f, const void *buf, int size); +static bool_t ChibiOSBFSSetpos(GFILE *f, long int pos); +static long int ChibiOSBFSGetsize(GFILE *f); +static bool_t ChibiOSBFSEof(GFILE *f); + +static const GFILEVMT FsCHIBIOSVMT = { + 0, // next + GFSFLG_SEEKABLE|GFSFLG_WRITEABLE, // flags + 0, // prefix + 0, 0, 0, 0, + 0, ChibiOSBFSClose, ChibiOSBFSRead, ChibiOSBFSWrite, + ChibiOSBFSSetpos, ChibiOSBFSGetsize, ChibiOSBFSEof, +}; + +static void ChibiOSBFSClose(GFILE *f) { + chFileStreamClose(((BaseFileStream *)f->fd)); +} +static int ChibiOSBFSRead(GFILE *f, void *buf, int size) { + return chSequentialStreamRead(((BaseFileStream *)f->fd), (uint8_t *)buf, size); +} +static int ChibiOSBFSWrite(GFILE *f, const void *buf, int size) { + return chSequentialStreamWrite(((BaseFileStream *)f->fd), (uint8_t *)buf, size); +} +static bool_t ChibiOSBFSSetpos(GFILE *f, long int pos) { + chFileStreamSeek(((BaseFileStream *)f->fd), pos); + return TRUE; +} +static long int ChibiOSBFSGetsize(GFILE *f) { return chFileStreamGetSize(((BaseFileStream *)f->fd)); } +static bool_t ChibiOSBFSEof(GFILE *f) { return f->pos >= chFileStreamGetSize(((BaseFileStream *)f->fd)); } 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_memfs.c b/src/gfile/inc_memfs.c new file mode 100644 index 00000000..434150d8 --- /dev/null +++ b/src/gfile/inc_memfs.c @@ -0,0 +1,43 @@ +/* + * 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 Memory pointer file-system VMT + ********************************************************/ + +#include <string.h> + +static int MEMRead(GFILE *f, void *buf, int size); +static int MEMWrite(GFILE *f, const void *buf, int size); +static bool_t MEMSetpos(GFILE *f, long int pos); + +static const GFILEVMT FsMemVMT = { + 0, // next + GFSFLG_SEEKABLE|GFSFLG_WRITEABLE, // flags + 0, // prefix + 0, 0, 0, 0, + 0, 0, MEMRead, MEMWrite, + MEMSetpos, 0, 0, +}; + +static int MEMRead(GFILE *f, void *buf, int size) { + memcpy(buf, ((char *)f->obj)+f->pos, size); + return size; +} +static int MEMWrite(GFILE *f, const void *buf, int size) { + memcpy(((char *)f->obj)+f->pos, buf, size); + return size; +} +static bool_t MEMSetpos(GFILE *f, long int pos) { + (void) f; + (void) pos; + return TRUE; +} diff --git a/src/gfile/inc_nativefs.c b/src/gfile/inc_nativefs.c new file mode 100644 index 00000000..4ecb2004 --- /dev/null +++ b/src/gfile/inc_nativefs.c @@ -0,0 +1,102 @@ +/* + * 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); +static void NativeClose(GFILE *f); +static int NativeRead(GFILE *f, void *buf, int size); +static int NativeWrite(GFILE *f, const void *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 + #if defined(WIN32) || GFX_USE_OS_WIN32 + GFSFLG_TEXTMODES| + #else + GFSFLG_CASESENSITIVE| + #endif + GFSFLG_WRITEABLE|GFSFLG_SEEKABLE|GFSFLG_FAST, // flags + 'N', // prefix + NativeDel, NativeExists, NativeFilesize, NativeRen, + NativeOpen, NativeClose, NativeRead, NativeWrite, + NativeSetpos, NativeGetsize, NativeEof, +}; +#undef GFILE_CHAINHEAD +#define GFILE_CHAINHEAD &FsNativeVMT + +static void flags2mode(char *buf, uint16_t flags) { + if (flags & GFILEFLG_MUSTEXIST) + *buf = 'r'; + else if (flags & GFILEFLG_APPEND) + *buf = 'a'; + else + *buf = 'w'; + buf++; + if ((flags & (GFILEFLG_READ|GFILEFLG_WRITE)) == (GFILEFLG_READ|GFILEFLG_WRITE)) + *buf++ = '+'; + if (flags & GFILEFLG_BINARY) + *buf++ = 'b'; + if (flags & GFILEFLG_MUSTNOTEXIST) + *buf++ = 'x'; + *buf++ = 0; +} + +static bool_t NativeDel(const char *fname) { return remove(fname) ? FALSE : TRUE; } +static void NativeClose(GFILE *f) { fclose((FILE *)f->obj); } +static int NativeRead(GFILE *f, void *buf, int size) { return fread(buf, 1, size, (FILE *)f->obj); } +static int NativeWrite(GFILE *f, const void *buf, int size) { return fwrite(buf, 1, size, (FILE *)f->obj); } +static bool_t NativeSetpos(GFILE *f, long int pos) { return fseek((FILE *)f->obj, pos, SEEK_SET) ? FALSE : TRUE; } +static bool_t NativeEof(GFILE *f) { return feof((FILE *)f->obj) ? TRUE : FALSE; } +static bool_t NativeRen(const char *oldname, const char *newname) { return rename(oldname, newname) ? FALSE : TRUE; } +static bool_t NativeExists(const char *fname) { + // We define access this way so we don't have to include <unistd.h> which may + // (and does under windows) contain conflicting definitions for types such as uint16_t. + extern int access(const char *pathname, int mode); + 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 NativeOpen(GFILE *f, const char *fname) { + FILE *fd; + char mode[5]; + + flags2mode(mode, f->flags); + if (!(fd = fopen(fname, mode))) + return FALSE; + f->obj = (void *)fd; + return TRUE; +} +static long int NativeGetsize(GFILE *f) { + struct stat st; + if (fstat(fileno((FILE *)f->obj), &st)) return -1; + return st.st_size; +} 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..49c1b173 --- /dev/null +++ b/src/gfile/inc_romfs.c @@ -0,0 +1,95 @@ +/* + * 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> + +// What directory file formats do we understand +#define ROMFS_DIR_VER_MAX 0x0000 + +// Compression Formats +#define ROMFS_CMP_UNCOMPRESSED 0 + +typedef struct ROMFS_DIRENTRY { + uint16_t ver; // Directory Entry Version + uint16_t cmp; // Compression format + const struct ROMFS_DIRENTRY * next; // The next entry + const char * name; // The file name + long int size; // The file size + const char * file; // The file data +} 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); +static void ROMClose(GFILE *f); +static int ROMRead(GFILE *f, void *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 + GFSFLG_CASESENSITIVE|GFSFLG_SEEKABLE|GFSFLG_FAST, // flags + 'S', // prefix + 0, ROMExists, ROMFilesize, 0, + ROMOpen, ROMClose, ROMRead, 0, + ROMSetpos, ROMGetsize, ROMEof, +}; +#undef GFILE_CHAINHEAD +#define GFILE_CHAINHEAD &FsROMVMT + +static const ROMFS_DIRENTRY *ROMFindFile(const char *fname) { + const ROMFS_DIRENTRY *p; + + for(p = FsROMHead; p; p = p->next) { + if (p->ver <= ROMFS_DIR_VER_MAX && p->cmp == ROMFS_CMP_UNCOMPRESSED && !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 ROMFS_DIRENTRY *p; + + if (!(p = ROMFindFile(fname))) return FALSE; + f->obj = (void *)p; + return TRUE; +} +static void ROMClose(GFILE *f) { (void)f; } +static int ROMRead(GFILE *f, void *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; } |