aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--demos/modules/gdisp/images/gfxconf.h3
-rw-r--r--demos/modules/gdisp/images/main.c5
-rw-r--r--demos/modules/gdisp/images_animated/gfxconf.h3
-rw-r--r--demos/modules/gdisp/images_animated/main.c5
-rw-r--r--demos/modules/gwin/widgets/gfxconf.h4
-rw-r--r--demos/modules/gwin/widgets/main.c3
-rw-r--r--gfx.mk2
-rw-r--r--gfxconf.example.h25
-rw-r--r--include/gdisp/image.h209
-rw-r--r--include/gfile/gfile.h169
-rw-r--r--include/gfile/options.h158
-rw-r--r--include/gfx.h12
-rw-r--r--include/gfx_rules.h12
-rw-r--r--include/gos/win32.h4
-rw-r--r--include/gwin/image.h53
-rw-r--r--src/gdisp/image.c180
-rw-r--r--src/gdisp/image_bmp.c93
-rw-r--r--src/gdisp/image_gif.c105
-rw-r--r--src/gdisp/image_native.c29
-rw-r--r--src/gfile/gfile.c998
-rw-r--r--src/gfile/gfile.mk1
-rw-r--r--src/gfile/inc_chibiosfs.c46
-rw-r--r--src/gfile/inc_fatfs.c15
-rw-r--r--src/gfile/inc_memfs.c43
-rw-r--r--src/gfile/inc_nativefs.c98
-rw-r--r--src/gfile/inc_ramfs.c15
-rw-r--r--src/gfile/inc_romfs.c87
-rw-r--r--src/gwin/gimage.c55
-rw-r--r--src/gwin/list.c4
-rwxr-xr-xtools/file2c/binaries/linux/file2cbin10801 -> 9700 bytes
-rw-r--r--tools/file2c/binaries/windows/file2c.exebin9728 -> 22030 bytes
-rw-r--r--tools/file2c/src/Makefile.mingw3210
-rw-r--r--tools/file2c/src/file2c.c95
33 files changed, 2063 insertions, 478 deletions
diff --git a/demos/modules/gdisp/images/gfxconf.h b/demos/modules/gdisp/images/gfxconf.h
index 6cd78b37..09dbe30c 100644
--- a/demos/modules/gdisp/images/gfxconf.h
+++ b/demos/modules/gdisp/images/gfxconf.h
@@ -51,5 +51,8 @@
#define GDISP_NEED_IMAGE_JPG FALSE
#define GDISP_NEED_IMAGE_PNG FALSE
+#define GFX_USE_GFILE TRUE
+#define GFILE_NEED_MEMFS TRUE
+
#endif /* _GFXCONF_H */
diff --git a/demos/modules/gdisp/images/main.c b/demos/modules/gdisp/images/main.c
index b87f663c..021bf9f5 100644
--- a/demos/modules/gdisp/images/main.c
+++ b/demos/modules/gdisp/images/main.c
@@ -53,12 +53,11 @@ int main(void) {
// Set up IO for our image
#if USE_MEMORY_FILE
- gdispImageSetMemoryReader(&myImage, test_pal8);
+ gdispImageOpenMemory(&myImage, test_pal8);
#else
- gdispImageSetSimulFileReader(&myImage, "test-pal8.bmp");
+ gdispImageOpenFile(&myImage, "test-pal8.bmp");
#endif
- gdispImageOpen(&myImage);
gdispImageDraw(&myImage, 0, 0, swidth, sheight, 0, 0);
gdispImageClose(&myImage);
diff --git a/demos/modules/gdisp/images_animated/gfxconf.h b/demos/modules/gdisp/images_animated/gfxconf.h
index cc38ed36..b2dcaf92 100644
--- a/demos/modules/gdisp/images_animated/gfxconf.h
+++ b/demos/modules/gdisp/images_animated/gfxconf.h
@@ -51,5 +51,8 @@
#define GDISP_NEED_IMAGE_JPG FALSE
#define GDISP_NEED_IMAGE_PNG FALSE
+#define GFX_USE_GFILE TRUE
+#define GFILE_NEED_MEMFS TRUE
+
#endif /* _GFXCONF_H */
diff --git a/demos/modules/gdisp/images_animated/main.c b/demos/modules/gdisp/images_animated/main.c
index 9b2b5d2c..bf49f692 100644
--- a/demos/modules/gdisp/images_animated/main.c
+++ b/demos/modules/gdisp/images_animated/main.c
@@ -76,12 +76,11 @@ int main(void) {
// Set up IO for our image
#if USE_MEMORY_FILE
- gdispImageSetMemoryReader(&myImage, testanim);
+ if (!(gdispImageOpenMemory(&myImage, testanim) & GDISP_IMAGE_ERR_UNRECOVERABLE)) {
#else
- gdispImageSetFileReader(&myImage, "testanim.gif");
+ if (!(gdispImageOpenFile(&myImage, "testanim.gif") & GDISP_IMAGE_ERR_UNRECOVERABLE)) {
#endif
- if (gdispImageOpen(&myImage) == GDISP_IMAGE_ERR_OK) {
gdispImageSetBgColor(&myImage, MY_BG_COLOR);
// Adjust the error indicator area if necessary
if (myImage.width > errx && myImage.height < sheight) {
diff --git a/demos/modules/gwin/widgets/gfxconf.h b/demos/modules/gwin/widgets/gfxconf.h
index b22af659..b536de4c 100644
--- a/demos/modules/gwin/widgets/gfxconf.h
+++ b/demos/modules/gwin/widgets/gfxconf.h
@@ -79,6 +79,10 @@
#define GWIN_NEED_RADIO TRUE
#define GWIN_NEED_LIST TRUE
+/* Features for the GFILE subsystem. */
+#define GFX_USE_GFILE TRUE
+#define GFILE_NEED_MEMFS TRUE
+
/* Features for the GINPUT subsystem. */
#define GINPUT_NEED_MOUSE TRUE
diff --git a/demos/modules/gwin/widgets/main.c b/demos/modules/gwin/widgets/main.c
index af2926d7..80c39dd9 100644
--- a/demos/modules/gwin/widgets/main.c
+++ b/demos/modules/gwin/widgets/main.c
@@ -184,8 +184,7 @@ static void createWidgets(void) {
wi.g.x = 0+2*(LIST_WIDTH+1); wi.text = "L3"; ghList3 = gwinListCreate(0, &wi, TRUE);
gwinListAddItem(ghList3, "Item 0", FALSE); gwinListAddItem(ghList3, "Item 1", FALSE);
gwinListAddItem(ghList3, "Item 2", FALSE); gwinListAddItem(ghList3, "Item 3", FALSE);
- gdispImageSetMemoryReader(&imgYesNo, image_yesno);
- gdispImageOpen(&imgYesNo);
+ gdispImageOpenMemory(&imgYesNo, image_yesno);
gwinListItemSetImage(ghList3, 1, &imgYesNo);
gwinListItemSetImage(ghList3, 3, &imgYesNo);
diff --git a/gfx.mk b/gfx.mk
index aaea245a..0ee3e3f1 100644
--- a/gfx.mk
+++ b/gfx.mk
@@ -12,4 +12,4 @@ include $(GFXLIB)/src/gadc/gadc.mk
include $(GFXLIB)/src/gaudin/gaudin.mk
include $(GFXLIB)/src/gaudout/gaudout.mk
include $(GFXLIB)/src/gmisc/gmisc.mk
-
+include $(GFXLIB)/src/gfile/gfile.mk
diff --git a/gfxconf.example.h b/gfxconf.example.h
index e6a3381e..d9dcf88b 100644
--- a/gfxconf.example.h
+++ b/gfxconf.example.h
@@ -9,6 +9,8 @@
/**
* Copy this file into your project directory and rename it as gfxconf.h
* Edit your copy to turn on the uGFX features you want to use.
+ * The values below are the defaults. You should delete anything
+ * you are leaving as default.
*
* Please use spaces instead of tabs in this file.
*/
@@ -26,7 +28,7 @@
///////////////////////////////////////////////////////////////////////////
// GDISP //
///////////////////////////////////////////////////////////////////////////
-#define GFX_USE_GDISP TRUE
+#define GFX_USE_GDISP FALSE
#define GDISP_NEED_AUTOFLUSH FALSE
#define GDISP_NEED_TIMERFLUSH FALSE
@@ -186,6 +188,27 @@
///////////////////////////////////////////////////////////////////////////
+// GFILE //
+///////////////////////////////////////////////////////////////////////////
+#define GFX_USE_GFILE FALSE
+
+#define GFILE_NEED_PRINTG FALSE
+#define GFILE_NEED_SCANG FALSE
+#define GFILE_NEED_STRINGS FALSE
+#define GFILE_NEED_STDIO FALSE
+ #define GFILE_ALLOW_FLOATS FALSE
+ #define GFILE_ALLOW_DEVICESPECIFIC FALSE
+ #define GFILE_MAX_GFILES 3
+
+#define GFILE_NEED_MEMFS FALSE
+#define GFILE_NEED_ROMFS FALSE
+#define GFILE_NEED_RAMFS FALSE
+#define GFILE_NEED_FATFS FALSE
+#define GFILE_NEED_NATIVEFS FALSE
+#define GFILE_NEED_CHBIOSFS FALSE
+
+
+///////////////////////////////////////////////////////////////////////////
// GADC //
///////////////////////////////////////////////////////////////////////////
#define GFX_USE_GADC FALSE
diff --git a/include/gdisp/image.h b/include/gdisp/image.h
index ff2e9d85..bcf9c497 100644
--- a/include/gdisp/image.h
+++ b/include/gdisp/image.h
@@ -40,6 +40,7 @@ typedef uint16_t gdispImageError;
#define GDISP_IMAGE_ERR_UNSUPPORTED (GDISP_IMAGE_ERR_UNRECOVERABLE+3)
#define GDISP_IMAGE_ERR_UNSUPPORTED_OK 3
#define GDISP_IMAGE_ERR_NOMEMORY (GDISP_IMAGE_ERR_UNRECOVERABLE+4)
+ #define GDISP_IMAGE_ERR_NOSUCHFILE (GDISP_IMAGE_ERR_UNRECOVERABLE+5)
/**
* @brief Image flags
@@ -103,10 +104,10 @@ typedef struct gdispImage {
gdispImageFlags flags; /* @< The image flags */
color_t bgcolor; /* @< The default background color */
coord_t width, height; /* @< The image dimensions */
- gdispImageIO io; /* @< The image IO functions */
+ GFILE * f; /* @< The underlying GFILE */
#if GDISP_NEED_IMAGE_ACCOUNTING
- uint32_t memused; /* @< How much RAM is currently allocated */
- uint32_t maxmemused; /* @< How much RAM has been allocated (maximum) */
+ uint32_t memused; /* @< How much RAM is currently allocated */
+ uint32_t maxmemused; /* @< How much RAM has been allocated (maximum) */
#endif
const struct gdispImageHandlers * fns; /* @< Don't mess with this! */
struct gdispImagePrivate * priv; /* @< Don't mess with this! */
@@ -117,58 +118,27 @@ extern "C" {
#endif
/**
- * @brief Sets the io fields in the image structure to routines
- * that support reading from an image stored in RAM or Flash.
- *
- * @return TRUE if the IO open function succeeds
- *
- * @param[in] img The image structure
- * @param[in] memimage A pointer to the image in RAM or Flash
- *
- * @note Always returns TRUE for a Memory Reader
+ * Deprecated Functions.
*/
- bool_t gdispImageSetMemoryReader(gdispImage *img, const void *memimage);
-
- #if GFX_USE_OS_CHIBIOS || defined(__DOXYGEN__)
- /**
- * @brief Sets the io fields in the image structure to routines
- * that support reading from an image stored on a BaseFileStream (eg SDCard).
- *
- * @return TRUE if the IO open function succeeds
- *
- * @param[in] img The image structure
- * @param[in] BaseFileStreamPtr A pointer to the (open) BaseFileStream object.
- *
- */
- bool_t gdispImageSetBaseFileStreamReader(gdispImage *img, void *BaseFileStreamPtr);
+ gdispImageError DEPRECATED("Use gdispImageOpenGFile() instead") gdispImageOpen(gdispImage *img);
+ bool_t DEPRECATED("Use gdispImageOpenMemory() instead") gdispImageSetMemoryReader(gdispImage *img, const void *memimage);
+ #if GFX_USE_OS_CHIBIOS
+ bool_t DEPRECATED("Use gdispImageOpenBaseFileStream() instead") gdispImageSetBaseFileStreamReader(gdispImage *img, void *BaseFileStreamPtr);
#endif
-
- #if defined(WIN32) || GFX_USE_OS_WIN32 || GFX_USE_OS_LINUX || GFX_USE_OS_OSX || defined(__DOXYGEN__)
- /**
- * @brief Sets the io fields in the image structure to routines
- * that support reading from an image stored in Win32 simulators native
- * file system.
- * @pre Only available on the Win32 simulator
- *
- * @return TRUE if the IO open function succeeds
- *
- * @param[in] img The image structure
- * @param[in] filename The filename to open
- *
- */
- bool_t gdispImageSetFileReader(gdispImage *img, const char *filename);
- /* Old definition */
+ #if defined(WIN32) || GFX_USE_OS_WIN32 || GFX_USE_OS_LINUX || GFX_USE_OS_OSX
+ bool_t DEPRECATED("Please use gdispImageOpenFile() instead") gdispImageSetFileReader(gdispImage *img, const char *filename);
#define gdispImageSetSimulFileReader(img, fname) gdispImageSetFileReader(img, fname)
#endif
-
+
/**
- * @brief Open an image ready for drawing
+ * @brief Open an image using an open GFILE and get it ready for drawing
* @details Determine the image format and get ready to decode the first image frame
* @return GDISP_IMAGE_ERR_OK (0) on success or an error code.
- *
- * @param[in] img The image structure
- *
- * @pre The io fields should be filled in before calling gdispImageOpen()
+ *
+ * @param[in] img The image structure
+ * @param[in] f The open GFILE stream.
+ *
+ * @pre The GFILE must be open for reading.
*
* @note This determines which decoder to use and then initialises all other fields
* in the gdispImage structure.
@@ -179,17 +149,62 @@ extern "C" {
* bit in the error code.
* A partial success return code means an image can still be drawn but perhaps with
* reduced functionality eg only the first page of a multi-page image.
- * @note @p gdispImageClose() can be called even after a failure to open the image to ensure
- * that the IO close routine gets called.
+ * @note @p gdispImageClose() should be called when finished with the image. This will close
+ * the image and its underlying GFILE file. Note that images opened with partial success
+ * (eg GDISP_IMAGE_ERR_UNSUPPORTED_OK)
+ * still need to be closed when you are finished with them.
*/
- gdispImageError gdispImageOpen(gdispImage *img);
-
+ gdispImageError gdispImageOpenGFile(gdispImage *img, GFILE *filename);
+
+ /**
+ * @brief Open an image in a file and get it ready for drawing
+ * @details Determine the image format and get ready to decode the first image frame
+ * @return GDISP_IMAGE_ERR_OK (0) on success or an error code.
+ *
+ * @pre You must have included the file-system support into GFILE that you want to use.
+ *
+ * @param[in] img The image structure
+ * @param[in] filename The filename to open
+ *
+ * @note This function just opens the GFILE using the filename and passes it to @p gdispImageOpenGFile().
+ */
+ #define gdispImageOpenFile(img, filename) gdispImageOpenGFile((img), gfileOpen((filename), "rb"))
+
+ /**
+ * @brief Open an image in a ChibiOS basefilestream and get it ready for drawing
+ * @details Determine the image format and get ready to decode the first image frame
+ * @return GDISP_IMAGE_ERR_OK (0) on success or an error code.
+ *
+ * @pre GFILE_NEED_CHIBIOSFS and GFX_USE_OS_CHIBIOS must be TRUE. This only makes sense on the ChibiOS
+ * operating system.
+ *
+ * @param[in] img The image structure
+ * @param[in] BaseFileStreamPtr A pointer to an open BaseFileStream
+ *
+ * @note This function just opens the GFILE using the basefilestream and passes it to @p gdispImageOpenGFile().
+ */
+ #define gdispImageOpenBaseFileStream(img, BaseFileStreamPtr) gdispImageOpenGFile((img), gfileOpenBaseFileStream((BaseFileStreamPtr), "rb"))
+
+ /**
+ * @brief Open an image in memory and get it ready for drawing
+ * @details Determine the image format and get ready to decode the first image frame
+ * @return GDISP_IMAGE_ERR_OK (0) on success or an error code.
+ *
+ * @pre GFILE_NEED_MEMFS must be TRUE
+ *
+ * @param[in] img The image structure
+ * @param[in] ptr A pointer to the image bytes in memory
+ *
+ * @note This function just opens the GFILE using the basefilestream and passes it to @p gdispImageOpenGFile().
+ */
+ #define gdispImageOpenMemory(img, ptr) gdispImageOpenGFile((img), gfileOpenMemory((void *)(ptr), "rb"))
+
/**
* @brief Close an image and release any dynamically allocated working storage.
*
* @param[in] img The image structure
*
- * @pre gdispImageOpen() must have returned successfully.
+ * @pre gdispImageOpenFile() must have returned successfully.
*
* @note Also calls the IO close function (if it hasn't already been called).
*/
@@ -282,94 +297,6 @@ extern "C" {
*/
delaytime_t gdispImageNext(gdispImage *img);
- #if GDISP_NEED_IMAGE_NATIVE
- /**
- * @brief The image drawing routines for a NATIVE format image.
- *
- * @note Only use these functions if you absolutely know the format
- * of the image you are decoding. Generally you should use the
- * generic functions and it will auto-detect the format.
- * @note A NATIVE format image is defined as an 8 byte header described below, immediately
- * followed by the bitmap data. The bitmap data is stored in the native format for
- * the display controller. If the pixel format specified in the header does not
- * match the controller native format then the image is rejected.
- * @note The 8 byte header:
- * { 'N', 'I', width.hi, width.lo, height.hi, height.lo, format.hi, format.lo }
- * The format word = GDISP_PIXELFORMAT
- * @{
- */
- gdispImageError gdispImageOpen_NATIVE(gdispImage *img);
- void gdispImageClose_NATIVE(gdispImage *img);
- gdispImageError gdispImageCache_NATIVE(gdispImage *img);
- gdispImageError gdispGImageDraw_NATIVE(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy);
- delaytime_t gdispImageNext_NATIVE(gdispImage *img);
- /* @} */
- #endif
-
- #if GDISP_NEED_IMAGE_GIF
- /**
- * @brief The image drawing routines for a GIF image.
- * @note Only use these functions if you absolutely know the format
- * of the image you are decoding. Generally you should use the
- * generic functions and it will auto-detect the format.
- * @{
- */
- gdispImageError gdispImageOpen_GIF(gdispImage *img);
- void gdispImageClose_GIF(gdispImage *img);
- gdispImageError gdispImageCache_GIF(gdispImage *img);
- gdispImageError gdispGImageDraw_GIF(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy);
- delaytime_t gdispImageNext_GIF(gdispImage *img);
- /* @} */
- #endif
-
- #if GDISP_NEED_IMAGE_BMP
- /**
- * @brief The image drawing routines for a BMP image.
- * @note Only use these functions if you absolutely know the format
- * of the image you are decoding. Generally you should use the
- * generic functions and it will auto-detect the format.
- * @{
- */
- gdispImageError gdispImageOpen_BMP(gdispImage *img);
- void gdispImageClose_BMP(gdispImage *img);
- gdispImageError gdispImageCache_BMP(gdispImage *img);
- gdispImageError gdispGImageDraw_BMP(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy);
- delaytime_t gdispImageNext_BMP(gdispImage *img);
- /* @} */
- #endif
-
- #if GDISP_NEED_IMAGE_JPG
- /**
- * @brief The image drawing routines for a JPG image.
- * @note Only use these functions if you absolutely know the format
- * of the image you are decoding. Generally you should use the
- * generic functions and it will auto-detect the format.
- * @{
- */
- gdispImageError gdispImageOpen_JPG(gdispImage *img);
- void gdispImageClose_JPG(gdispImage *img);
- gdispImageError gdispImageCache_JPG(gdispImage *img);
- gdispImageError gdispGImageDraw_JPG(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy);
- delaytime_t gdispImageNext_JPG(gdispImage *img);
- /* @} */
- #endif
-
- #if GDISP_NEED_IMAGE_PNG
- /**
- * @brief The image drawing routines for a PNG image.
- * @note Only use these functions if you absolutely know the format
- * of the image you are decoding. Generally you should use the
- * generic functions and it will auto-detect the format.
- * @{
- */
- gdispImageError gdispImageOpen_PNG(gdispImage *img);
- void gdispImageClose_PNG(gdispImage *img);
- gdispImageError gdispImageCache_PNG(gdispImage *img);
- gdispImageError gdispGImageDraw_PNG(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy);
- delaytime_t gdispImageNext_PNG(gdispImage *img);
- /* @} */
- #endif
-
#ifdef __cplusplus
}
#endif
diff --git a/include/gfile/gfile.h b/include/gfile/gfile.h
new file mode 100644
index 00000000..62972c47
--- /dev/null
+++ b/include/gfile/gfile.h
@@ -0,0 +1,169 @@
+/*
+ * 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_GFILE || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Type definitions */
+/*===========================================================================*/
+
+/**
+ * @brief A file pointer
+ */
+
+#ifndef GFILE_IMPLEMENTATION
+ typedef void GFILE;
+#else
+ typedef struct GFILE GFILE;
+#endif
+
+extern GFILE *gfileStdIn;
+extern GFILE *gfileStdErr;
+extern GFILE *gfileStdOut;
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#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, void *buf, size_t len);
+ size_t gfileWrite(GFILE *f, const void *buf, size_t len);
+ long int gfileGetPos(GFILE *f);
+ bool_t gfileSetPos(GFILE *f, long int pos);
+ long int gfileGetSize(GFILE *f);
+ bool_t gfileEOF(GFILE *f);
+
+ #if GFILE_NEED_CHIBIOSFS && GFX_USE_OS_CHIBIOS
+ GFILE * gfileOpenBaseFileStream(void *BaseFileStreamPtr, const char *mode);
+ #endif
+ #if GFILE_NEED_MEMFS
+ GFILE * gfileOpenMemory(void *memptr, const char *mode);
+ #endif
+
+ #if GFILE_NEED_PRINTG
+ int vfnprintg(GFILE *f, int maxlen, const char *fmt, va_list arg);
+ int fnprintg(GFILE *f, int 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,...)
+
+ #if GFILE_NEED_STRINGS
+ int vsnprintg(char *buf, int maxlen, const char *fmt, va_list arg);
+ int snprintg(char *buf, int maxlen, const char *fmt, ...);
+ #define vsprintg(s,m,a) vsnprintg(s,0,m,a)
+ #define sprintg(s,m,...) snprintg(s,0,m,...)
+ #endif
+ #endif
+
+ #if GFILE_NEED_SCANG
+ int vfscang(GFILE *f, const char *fmt, va_list arg);
+ int fscang(GFILE *f, const char *fmt, ...);
+ #define vscang(f,a) vfscang(gfileStdIn,f,a)
+ #define scang(f,...) fscang(gfileStdIn,f,...)
+
+ #if GFILE_NEED_STRINGS
+ int vsscang(const char *buf, const char *fmt, va_list arg);
+ int sscang(const char *buf, const char *fmt, ...);
+ #endif
+ #endif
+
+ #if GFILE_NEED_STDIO && !defined(GFILE_IMPLEMENTATION)
+ #define stdin gfileStdIn
+ #define stdout gfileStdOut
+ #define stderr gfileStdErr
+ #define FILENAME_MAX 256 // Use a relatively small number for an embedded platform
+ #define L_tmpnam FILENAME_MAX
+ #define FOPEN_MAX GFILE_MAX_GFILES
+ #define TMP_MAX GFILE_MAX_GFILES
+ #define P_tmpdir "/tmp/"
+ #define FILE GFILE
+ #define fopen(n,m) gfileOpen(n,m)
+ #define fclose(f) gfileClose(f)
+ size_t gstdioRead(void * ptr, size_t size, size_t count, FILE *f);
+ size_t gstdioWrite(const void * ptr, size_t size, size_t count, FILE *f);
+ #define fread(p,sz,cnt,f) gstdioRead(p,sz,cnt,f)
+ #define fwrite(p,sz,cnt,f) gstdioWrite(p,sz,cnt,f)
+ int gstdioSeek(FILE *f, size_t offset, int origin);
+ #define fseek(f,ofs,org) gstdioSeek(f,ofs,org)
+ #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)
+ #define fpos_t long int
+ int gstdioGetpos(FILE *f, long int *pos);
+ #define fgetpos(f,pos) gstdioGetpos(f,pos)
+ #define fsetpos(f, pos) (!gfileSetPos(f, *pos))
+ #define rewind(f) gfileSetPos(f, 0);
+ #define feof(f) gfileEOF(f)
+
+ #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,...)
+ //TODO
+ //void clearerr ( FILE * stream );
+ //int ferror ( FILE * stream );
+ //FILE * tmpfile ( void ); // Auto-deleting
+ //char * tmpnam ( char * str );
+ //char * mktemp (char *template);
+ //FILE * freopen ( const char * filename, const char * mode, FILE * stream );
+ //setbuf
+ //setvbuf
+ //fflush
+ //fgetc
+ //fgets
+ //fputc
+ //fputs
+ //getc
+ //getchar
+ //puts
+ //ungetc
+ //void perror (const char * str);
+ #endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_USE_GFILE */
+
+#endif /* _GFILE_H */
+/** @} */
+
diff --git a/include/gfile/options.h b/include/gfile/options.h
new file mode 100644
index 00000000..d73af02c
--- /dev/null
+++ b/include/gfile/options.h
@@ -0,0 +1,158 @@
+/*
+ * 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 etc functions
+ * @details Defaults to FALSE
+ */
+ #ifndef GFILE_NEED_PRINTG
+ #define GFILE_NEED_PRINTG FALSE
+ #endif
+ /**
+ * @brief Include scang, fscang etc functions
+ * @details Defaults to FALSE
+ */
+ #ifndef GFILE_NEED_SCANG
+ #define GFILE_NEED_SCANG FALSE
+ #endif
+ /**
+ * @brief Include the string sprintg/sscang functions
+ * @details Defaults to FALSE
+ * @pre To get sprintg functions you also need to define @p GFILE_NEED_PRINTG
+ * @pre To get sscang functions you also need to define @p GFILE_NEED_SCANG
+ */
+ #ifndef GFILE_NEED_STRINGS
+ #define GFILE_NEED_STRINGS FALSE
+ #endif
+ /**
+ * @brief Map many 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 If GFILE_ALLOW_DEVICESPECIFIC is on then you can ensure that you are
+ * opening a file on the ROM file system by prefixing
+ * its name with "S|" (the letter 'S', followed by a vertical bar).
+ * @note This requires a file called romfs_files.h to be in the
+ * users project include path. This file should include all the files
+ * converted to .h files using the file2c utility (using flags "-dbcs").
+ */
+ #ifndef GFILE_NEED_ROMFS
+ #define GFILE_NEED_ROMFS FALSE
+ #endif
+ /**
+ * @brief Include the RAM file system
+ * @details Defaults to FALSE
+ * @note If GFILE_ALLOW_DEVICESPECIFIC is on then you can ensure that you are
+ * opening a file on the RAM file system by prefixing
+ * 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 If GFILE_ALLOW_DEVICESPECIFIC is on then you can ensure that you are
+ * opening a file on the FAT file system by prefixing
+ * 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 If GFILE_ALLOW_DEVICESPECIFIC is on then you can ensure that you are
+ * opening a file on the native file system by prefixing
+ * 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
+ /**
+ * @brief Include ChibiOS BaseFileStream support
+ * @details Defaults to FALSE
+ * @pre This is only relevant on the ChibiOS operating system.
+ * @note Use the @p gfileOpenBaseFileStream() call to open a GFILE based on a
+ * BaseFileStream. The BaseFileStream must already be open.
+ * @note A GFile of this type cannot be opened by filename. The BaseFileStream
+ * must be pre-opened using the operating system.
+ */
+ #ifndef GFILE_NEED_CHIBIOSFS
+ #define GFILE_NEED_CHIBIOSFS FALSE
+ #endif
+ /**
+ * @brief Include raw memory pointer support
+ * @details Defaults to FALSE
+ * @note Use the @p gfileOpenMemory() call to open a GFILE based on a
+ * memory pointer. The GFILE opened appears to be of unlimited size.
+ * @note A GFile of this type cannot be opened by filename.
+ */
+ #ifndef GFILE_NEED_MEMFS
+ #define GFILE_NEED_MEMFS FALSE
+ #endif
+/**
+ * @}
+ *
+ * @name GFILE Optional Parameters
+ * @{
+ */
+ /**
+ * @brief Add floating point support to printg/scang etc.
+ */
+ #ifndef GFILE_ALLOW_FLOATS
+ #define GFILE_ALLOW_FLOATS
+ #endif
+ /**
+ * @brief Can the device be specified as part of the file name.
+ * @note If this is on then a device letter and a vertical bar can be
+ * prefixed on a file name to specify that it must be on a
+ * specific device.
+ */
+ #ifndef GFILE_ALLOW_DEVICESPECIFIC
+ #define GFILE_ALLOW_DEVICESPECIFIC FALSE
+ #endif
+ /**
+ * @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
+/** @} */
+
+#endif /* _GFILE_OPTIONS_H */
+/** @} */
diff --git a/include/gfx.h b/include/gfx.h
index d261a6ce..0c922669 100644
--- a/include/gfx.h
+++ b/include/gfx.h
@@ -150,6 +150,13 @@
#ifndef GFX_USE_GMISC
#define GFX_USE_GMISC FALSE
#endif
+ /**
+ * @brief GFX File API
+ * @details Defaults to FALSE
+ */
+ #ifndef GFX_USE_GFILE
+ #define GFX_USE_GFILE FALSE
+ #endif
/** @} */
/**
@@ -157,6 +164,7 @@
*
*/
#include "gos/options.h"
+#include "gfile/options.h"
#include "gmisc/options.h"
#include "gqueue/options.h"
#include "gevent/options.h"
@@ -169,7 +177,7 @@
#include "gaudout/options.h"
/**
- * Inter-dependancy safety checks on the sub-systems.
+ * Interdependency safety checks on the sub-systems.
*
*/
#include "gfx_rules.h"
@@ -178,6 +186,7 @@
* Include the sub-system header files
*/
#include "gos/gos.h"
+#include "gfile/gfile.h"
#include "gmisc/gmisc.h"
#include "gqueue/gqueue.h"
#include "gevent/gevent.h"
@@ -208,7 +217,6 @@ extern "C" {
* @brief The one call to end it all
*
* @note This will deinitialise each sub-system that has been turned on.
- * @note Do not call this without a previous @p gfxInit();
*
* @api
*/
diff --git a/include/gfx_rules.h b/include/gfx_rules.h
index a129ef76..817ff749 100644
--- a/include/gfx_rules.h
+++ b/include/gfx_rules.h
@@ -187,6 +187,15 @@
#undef GDISP_INCLUDE_FONT_UI2
#define GDISP_INCLUDE_FONT_UI2 TRUE
#endif
+ #if GDISP_NEED_IMAGE
+ #if !GFX_USE_GFILE
+ #if GFX_DISPLAY_RULE_WARNINGS
+ #warning "GDISP: GFX_USE_GFILE is required when GDISP_NEED_IMAGE is TRUE. It has been turned on for you."
+ #endif
+ #undef GFX_USE_GFILE
+ #define GFX_USE_GFILE TRUE
+ #endif
+ #endif
#endif
#if GFX_USE_GAUDIN
@@ -230,5 +239,8 @@
#if GFX_USE_GMISC
#endif
+#if GFX_USE_GFILE
+#endif
+
#endif /* _GFX_H */
/** @} */
diff --git a/include/gos/win32.h b/include/gos/win32.h
index 2840ffcf..c704a288 100644
--- a/include/gos/win32.h
+++ b/include/gos/win32.h
@@ -69,11 +69,11 @@ typedef HANDLE gfxThreadHandle;
#define gfxSystemTicks() GetTickCount()
#define gfxMillisecondsToTicks(ms) (ms)
#define gfxMutexInit(pmutex) *(pmutex) = CreateMutex(0, FALSE, 0)
-#define gfxMutexDestory(pmutex) CloseHandle(*(pmutex))
+#define gfxMutexDestroy(pmutex) CloseHandle(*(pmutex))
#define gfxMutexEnter(pmutex) WaitForSingleObject(*(pmutex), INFINITE)
#define gfxMutexExit(pmutex) ReleaseMutex(*(pmutex))
#define gfxSemInit(psem, val, limit) *(psem) = CreateSemaphore(0, val, limit, 0)
-#define gfxSemDestory(psem) CloseHandle(*(psem))
+#define gfxSemDestroy(psem) CloseHandle(*(psem))
#define gfxSemSignal(psem) ReleaseSemaphore(*(psem), 1, 0)
#define gfxSemSignalI(psem) ReleaseSemaphore(*(psem), 1, 0)
#define gfxSemCounterI(psem) gfxSemCounter(psem)
diff --git a/include/gwin/image.h b/include/gwin/image.h
index 66dd0b94..66aba3d1 100644
--- a/include/gwin/image.h
+++ b/include/gwin/image.h
@@ -60,42 +60,51 @@ GHandle gwinGImageCreate(GDisplay *g, GImageObject *widget, GWindowInit *pInit);
#define gwinImageCreate(w, pInit) gwinGImageCreate(GDISP, w, pInit)
/**
- * @brief Sets the input routines that support reading the image from memory
- * in RAM or flash.
- * @return TRUE if the IO open function succeeds
+ * @brief Opens the image using a GFILE
+ * @return TRUE if the image can be opened
*
* @param[in] gh The widget (must be an image widget)
- * @param[in] memory A pointer to the image in RAM or Flash
+ * @param[in] f The open (for reading) GFILE to use
*
* @api
*/
-bool_t gwinImageOpenMemory(GHandle gh, const void* memory);
+bool_t gwinImageOpenGFile(GHandle gh, GFILE *f);
-#if defined(WIN32) || GFX_USE_OS_WIN32 || GFX_USE_OS_LINUX || GFX_USE_OS_OSX || defined(__DOXYGEN__)
- /**
- * @brief Sets the input routines that support reading the image from a file
- * @return TRUE if the IO open function succeeds
- *
- * @param[in] gh The widget (must be an image widget)
- * @param[in] filename The filename to open
- *
- * @api
- */
- bool_t gwinImageOpenFile(GHandle gh, const char* filename);
-#endif
+/**
+ * @brief Opens the image using the specified filename
+ * @return TRUE if the open succeeds
+ *
+ * @param[in] gh The widget (must be an image widget)
+ * @param[in] filename The filename to open
+ *
+ * @api
+ */
+#define gwinImageOpenFile(gh, filename) gwinImageOpenGFile((gh), gfileOpen((filename), "rb"))
-#if GFX_USE_OS_CHIBIOS || defined(__DOXYGEN__)
/**
- * @brief Sets the input routines that support reading the image from a BaseFileStream (eg. an SD-Card).
+ * @brief Sets the input routines that support reading the image from memory
+ * in RAM or flash.
+ * @pre GFILE_NEED_MEMFS must be TRUE
* @return TRUE if the IO open function succeeds
*
* @param[in] gh The widget (must be an image widget)
- * @param[in] streamPtr A pointer to the (open) BaseFileStream object.
+ * @param[in] ptr A pointer to the image in RAM or Flash
*
* @api
*/
- bool_t gwinImageOpenStream(GHandle gh, void *streamPtr);
-#endif
+#define gwinImageOpenMemory(gh, ptr) gwinImageOpenGFile((gh), gfileOpenMemory((void *)(ptr), "rb"))
+
+/**
+ * @brief Sets the input routines that support reading the image from a BaseFileStream (eg. an SD-Card).
+ * @return TRUE if the IO open function succeeds
+ * @pre GFILE_NEED_CHIBIOSFS and GFX_USE_OS_CHIBIOS must be TRUE
+ *
+ * @param[in] gh The widget (must be an image widget)
+ * @param[in] streamPtr A pointer to the (open) BaseFileStream object.
+ *
+ * @api
+ */
+#define gwinImageOpenStream(gh, streamPtr) gwinImageOpenGFile((gh), gfileOpenBaseFIleStream((streamPtr), "rb"))
/**
* @brief Cache the image.
diff --git a/src/gdisp/image.c b/src/gdisp/image.c
index 62af0aeb..2b8395b0 100644
--- a/src/gdisp/image.c
+++ b/src/gdisp/image.c
@@ -16,7 +16,45 @@
#if GFX_USE_GDISP && GDISP_NEED_IMAGE
-#include <string.h>
+#if GDISP_NEED_IMAGE_NATIVE
+ extern gdispImageError gdispImageOpen_NATIVE(gdispImage *img);
+ extern void gdispImageClose_NATIVE(gdispImage *img);
+ extern gdispImageError gdispImageCache_NATIVE(gdispImage *img);
+ extern gdispImageError gdispGImageDraw_NATIVE(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy);
+ extern delaytime_t gdispImageNext_NATIVE(gdispImage *img);
+#endif
+
+#if GDISP_NEED_IMAGE_GIF
+ extern gdispImageError gdispImageOpen_GIF(gdispImage *img);
+ extern void gdispImageClose_GIF(gdispImage *img);
+ extern gdispImageError gdispImageCache_GIF(gdispImage *img);
+ extern gdispImageError gdispGImageDraw_GIF(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy);
+ extern delaytime_t gdispImageNext_GIF(gdispImage *img);
+#endif
+
+#if GDISP_NEED_IMAGE_BMP
+ extern gdispImageError gdispImageOpen_BMP(gdispImage *img);
+ extern void gdispImageClose_BMP(gdispImage *img);
+ extern gdispImageError gdispImageCache_BMP(gdispImage *img);
+ extern gdispImageError gdispGImageDraw_BMP(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy);
+ extern delaytime_t gdispImageNext_BMP(gdispImage *img);
+#endif
+
+#if GDISP_NEED_IMAGE_JPG
+ extern gdispImageError gdispImageOpen_JPG(gdispImage *img);
+ extern void gdispImageClose_JPG(gdispImage *img);
+ extern gdispImageError gdispImageCache_JPG(gdispImage *img);
+ extern gdispImageError gdispGImageDraw_JPG(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy);
+ extern delaytime_t gdispImageNext_JPG(gdispImage *img);
+#endif
+
+#if GDISP_NEED_IMAGE_PNG
+ extern gdispImageError gdispImageOpen_PNG(gdispImage *img);
+ extern void gdispImageClose_PNG(gdispImage *img);
+ extern gdispImageError gdispImageCache_PNG(gdispImage *img);
+ extern gdispImageError gdispGImageDraw_PNG(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy);
+ extern delaytime_t gdispImageNext_PNG(gdispImage *img);
+#endif
/* The structure defining the routines for image drawing */
typedef struct gdispImageHandlers {
@@ -59,134 +97,76 @@ static gdispImageHandlers ImageHandlers[] = {
#endif
};
-static size_t ImageMemoryRead(struct gdispImageIO *pio, void *buf, size_t len) {
- if (pio->fd == (void *)-1) return 0;
- memcpy(buf, ((const char *)pio->fd)+pio->pos, len);
- pio->pos += len;
- return len;
+gdispImageError
+ DEPRECATED("Use gdispImageOpenGFile() instead")
+ gdispImageOpen(gdispImage *img) {
+ return gdispImageOpenGFile(img, img->f);
}
-static void ImageMemorySeek(struct gdispImageIO *pio, size_t pos) {
- if (pio->fd == (void *)-1) return;
- pio->pos = pos;
-}
-
-static void ImageMemoryClose(struct gdispImageIO *pio) {
- pio->fd = (void *)-1;
- pio->pos = 0;
-}
-
-static const gdispImageIOFunctions ImageMemoryFunctions =
- { ImageMemoryRead, ImageMemorySeek, ImageMemoryClose };
-
-bool_t gdispImageSetMemoryReader(gdispImage *img, const void *memimage) {
- img->io.fns = &ImageMemoryFunctions;
- img->io.pos = 0;
- img->io.fd = memimage;
- return TRUE;
-}
-
-#if GFX_USE_OS_CHIBIOS
- static size_t ImageBaseFileStreamRead(struct gdispImageIO *pio, void *buf, size_t len) {
- if (pio->fd == (void *)-1) return 0;
- len = chSequentialStreamRead(((BaseFileStream *)pio->fd), (uint8_t *)buf, len);
- pio->pos += len;
- return len;
- }
-
- static void ImageBaseFileStreamSeek(struct gdispImageIO *pio, size_t pos) {
- if (pio->fd == (void *)-1) return;
- if (pio->pos != pos) {
- chFileStreamSeek(((BaseFileStream *)pio->fd), pos);
- pio->pos = pos;
- }
- }
-
- static void ImageBaseFileStreamClose(struct gdispImageIO *pio) {
- if (pio->fd == (void *)-1) return;
- chFileStreamClose(((BaseFileStream *)pio->fd));
- pio->fd = (void *)-1;
- pio->pos = 0;
- }
-
- static const gdispImageIOFunctions ImageBaseFileStreamFunctions =
- { ImageBaseFileStreamRead, ImageBaseFileStreamSeek, ImageBaseFileStreamClose };
-
- bool_t gdispImageSetBaseFileStreamReader(gdispImage *img, void *BaseFileStreamPtr) {
- img->io.fns = &ImageBaseFileStreamFunctions;
- img->io.pos = 0;
- img->io.fd = BaseFileStreamPtr;
- return TRUE;
+#if GFILE_NEED_MEMFS
+ bool_t
+ DEPRECATED("Use gdispImageOpenMemory() instead")
+ gdispImageSetMemoryReader(gdispImage *img, const void *memimage) {
+ img->f = gfileOpenMemory((void *)memimage, "rb");
+ return img->f != 0;
}
#endif
#if defined(WIN32) || GFX_USE_OS_WIN32 || GFX_USE_OS_LINUX || GFX_USE_OS_OSX
- #include <stdio.h>
-
- static size_t ImageFileRead(struct gdispImageIO *pio, void *buf, size_t len) {
- if (!pio->fd) return 0;
- len = fread(buf, 1, len, (FILE *)pio->fd);
- if ((int)len < 0) len = 0;
- pio->pos += len;
- return len;
- }
-
- static void ImageFileSeek(struct gdispImageIO *pio, size_t pos) {
- if (!pio->fd) return;
- if (pio->pos != pos) {
- fseek((FILE *)pio->fd, pos, SEEK_SET);
- pio->pos = pos;
- }
+ bool_t
+ DEPRECATED("Use gdispImageOpenFile() instead")
+ gdispImageSetFileReader(gdispImage *img, const char *filename) {
+ img->f = gfileOpen(filename, "rb");
+ return img->f != 0;
}
+#endif
- static void ImageFileClose(struct gdispImageIO *pio) {
- if (!pio->fd) return;
- fclose((FILE *)pio->fd);
- pio->fd = 0;
- pio->pos = 0;
- }
-
- static const gdispImageIOFunctions ImageFileFunctions =
- { ImageFileRead, ImageFileSeek, ImageFileClose };
-
- bool_t gdispImageSetFileReader(gdispImage *img, const char *filename) {
- img->io.fns = &ImageFileFunctions;
- img->io.pos = 0;
- #if defined(WIN32) || GFX_USE_OS_WIN32
- img->io.fd = (void *)fopen(filename, "rb");
- #else
- img->io.fd = (void *)fopen(filename, "r");
- #endif
-
- return img->io.fd != 0;
+#if GFILE_NEED_CHIBIOSFS && GFX_USE_OS_CHIBIOS
+ bool_t
+ DEPRECATED("Use gdispImageOpenBaseFileStream() instead")
+ gdispImageSetBaseFileStreamReader(gdispImage *img, void *BaseFileStreamPtr) {
+ img->f = gfileOpenBaseFileStream(BaseFileStreamPtr, "rb");
+ return img->f != 0;
}
#endif
-gdispImageError gdispImageOpen(gdispImage *img) {
+gdispImageError gdispImageOpenGFile(gdispImage *img, GFILE *f) {
gdispImageError err;
+ if (!f)
+ return GDISP_IMAGE_ERR_NOSUCHFILE;
+ img->f = f;
img->bgcolor = White;
for(img->fns = ImageHandlers; img->fns < ImageHandlers+sizeof(ImageHandlers)/sizeof(ImageHandlers[0]); img->fns++) {
err = img->fns->open(img);
if (err != GDISP_IMAGE_ERR_BADFORMAT) {
if ((err & GDISP_IMAGE_ERR_UNRECOVERABLE))
- img->fns = 0;
+ goto unrecoverable;
+
+ // Everything is possible
return err;
}
- img->io.fns->seek(&img->io, 0);
+
+ // Try the next decoder
+ gfileSetPos(img->f, 0);
}
+
+ err = GDISP_IMAGE_ERR_BADFORMAT;
img->type = GDISP_IMAGE_TYPE_UNKNOWN;
+
+unrecoverable:
+ gfileClose(img->f);
+ img->f = 0;
img->flags = 0;
img->fns = 0;
img->priv = 0;
- return GDISP_IMAGE_ERR_BADFORMAT;
+ return err;
}
void gdispImageClose(gdispImage *img) {
if (img->fns)
img->fns->close(img);
- else
- img->io.fns->close(&img->io);
+ gfileClose(img->f);
img->type = GDISP_IMAGE_TYPE_UNKNOWN;
img->flags = 0;
img->fns = 0;
@@ -194,7 +174,7 @@ void gdispImageClose(gdispImage *img) {
}
bool_t gdispImageIsOpen(gdispImage *img) {
- return img->type != GDISP_IMAGE_TYPE_UNKNOWN && img->fns != 0;
+ return img->fns != 0;
}
void gdispImageSetBgColor(gdispImage *img, color_t bgcolor) {
diff --git a/src/gdisp/image_bmp.c b/src/gdisp/image_bmp.c
index 158d6edc..8ff40ca0 100644
--- a/src/gdisp/image_bmp.c
+++ b/src/gdisp/image_bmp.c
@@ -118,6 +118,19 @@ typedef struct gdispImagePrivate {
pixel_t buf[BLIT_BUFFER_SIZE];
} gdispImagePrivate;
+void gdispImageClose_BMP(gdispImage *img) {
+ if (img->priv) {
+#if GDISP_NEED_IMAGE_BMP_1 || GDISP_NEED_IMAGE_BMP_4 || GDISP_NEED_IMAGE_BMP_4_RLE || GDISP_NEED_IMAGE_BMP_8 || GDISP_NEED_IMAGE_BMP_8_RLE
+ if (img->priv->palette)
+ gdispImageFree(img, (void *)img->priv->palette, img->priv->palsize*sizeof(color_t));
+#endif
+ if (img->priv->frame0cache)
+ gdispImageFree(img, (void *)img->priv->frame0cache, img->width*img->height*sizeof(pixel_t));
+ gdispImageFree(img, (void *)img->priv, sizeof(gdispImagePrivate));
+ img->priv = 0;
+ }
+}
+
gdispImageError gdispImageOpen_BMP(gdispImage *img) {
gdispImagePrivate *priv;
uint8_t hdr[2];
@@ -126,7 +139,7 @@ gdispImageError gdispImageOpen_BMP(gdispImage *img) {
uint32_t offsetColorTable;
/* Read the file identifier */
- if (img->io.fns->read(&img->io, hdr, 2) != 2)
+ if (gfileRead(img->f, hdr, 2) != 2)
return GDISP_IMAGE_ERR_BADFORMAT; // It can't be us
/* Process the BITMAPFILEHEADER structure */
@@ -154,18 +167,18 @@ gdispImageError gdispImageOpen_BMP(gdispImage *img) {
#endif
/* Skip the size field and the 2 reserved fields */
- if (img->io.fns->read(&img->io, priv->buf, 8) != 8)
+ if (gfileRead(img->f, priv->buf, 8) != 8)
goto baddatacleanup;
/* Get the offset to the bitmap data */
- if (img->io.fns->read(&img->io, &priv->frame0pos, 4) != 4)
+ if (gfileRead(img->f, &priv->frame0pos, 4) != 4)
goto baddatacleanup;
CONVERT_FROM_DWORD_LE(priv->frame0pos);
/* Process the BITMAPCOREHEADER structure */
/* Get the offset to the colour data */
- if (img->io.fns->read(&img->io, &offsetColorTable, 4) != 4)
+ if (gfileRead(img->f, &offsetColorTable, 4) != 4)
goto baddatacleanup;
CONVERT_FROM_DWORD_LE(offsetColorTable);
offsetColorTable += 14; // Add the size of the BITMAPFILEHEADER
@@ -175,7 +188,7 @@ gdispImageError gdispImageOpen_BMP(gdispImage *img) {
img->priv->bmpflags |= BMP_V2;
// Read the header
- if (img->io.fns->read(&img->io, priv->buf, 12-4) != 12-4)
+ if (gfileRead(img->f, priv->buf, 12-4) != 12-4)
goto baddatacleanup;
// Get the width
img->width = *(uint16_t *)(((uint8_t *)priv->buf)+0);
@@ -224,7 +237,7 @@ gdispImageError gdispImageOpen_BMP(gdispImage *img) {
priv->bmpflags |= BMP_V4;
// Read the header
- if (img->io.fns->read(&img->io, priv->buf, 40-4) != 40-4)
+ if (gfileRead(img->f, priv->buf, 40-4) != 40-4)
goto baddatacleanup;
// Get the width
adword = *(uint32_t *)(((uint8_t *)priv->buf)+0);
@@ -327,18 +340,18 @@ gdispImageError gdispImageOpen_BMP(gdispImage *img) {
#if GDISP_NEED_IMAGE_BMP_1 || GDISP_NEED_IMAGE_BMP_4 || GDISP_NEED_IMAGE_BMP_4_RLE || GDISP_NEED_IMAGE_BMP_8 || GDISP_NEED_IMAGE_BMP_8_RLE
/* Load the palette tables */
if (priv->bmpflags & BMP_PALETTE) {
- img->io.fns->seek(&img->io, offsetColorTable);
+ gfileSetPos(img->f, offsetColorTable);
if (!(priv->palette = (color_t *)gdispImageAlloc(img, priv->palsize*sizeof(color_t))))
return GDISP_IMAGE_ERR_NOMEMORY;
if (priv->bmpflags & BMP_V2) {
for(aword = 0; aword < priv->palsize; aword++) {
- if (img->io.fns->read(&img->io, &priv->buf, 3) != 3) goto baddatacleanup;
+ if (gfileRead(img->f, &priv->buf, 3) != 3) goto baddatacleanup;
priv->palette[aword] = RGB2COLOR(((uint8_t *)priv->buf)[2], ((uint8_t *)priv->buf)[1], ((uint8_t *)priv->buf)[0]);
}
} else {
for(aword = 0; aword < priv->palsize; aword++) {
- if (img->io.fns->read(&img->io, &priv->buf, 4) != 4) goto baddatacleanup;
+ if (gfileRead(img->f, &priv->buf, 4) != 4) goto baddatacleanup;
priv->palette[aword] = RGB2COLOR(((uint8_t *)priv->buf)[2], ((uint8_t *)priv->buf)[1], ((uint8_t *)priv->buf)[0]);
}
}
@@ -349,15 +362,15 @@ gdispImageError gdispImageOpen_BMP(gdispImage *img) {
#if GDISP_NEED_IMAGE_BMP_16 || GDISP_NEED_IMAGE_BMP_32
/* Load the bit masks */
if (priv->bmpflags & BMP_COMP_MASK) {
- img->io.fns->seek(&img->io, offsetColorTable);
- if (img->io.fns->read(&img->io, &priv->maskred, 4) != 4) goto baddatacleanup;
+ gfileSetPos(img->f, offsetColorTable);
+ if (gfileRead(img->f, &priv->maskred, 4) != 4) goto baddatacleanup;
CONVERT_FROM_DWORD_LE(priv->maskred);
- if (img->io.fns->read(&img->io, &priv->maskgreen, 4) != 4) goto baddatacleanup;
+ if (gfileRead(img->f, &priv->maskgreen, 4) != 4) goto baddatacleanup;
CONVERT_FROM_DWORD_LE(priv->maskgreen);
- if (img->io.fns->read(&img->io, &priv->maskblue, 4) != 4) goto baddatacleanup;
+ if (gfileRead(img->f, &priv->maskblue, 4) != 4) goto baddatacleanup;
CONVERT_FROM_DWORD_LE(priv->maskblue);
if (priv->bmpflags & BMP_V4) {
- if (img->io.fns->read(&img->io, &priv->maskalpha, 4) != 4) goto baddatacleanup;
+ if (gfileRead(img->f, &priv->maskalpha, 4) != 4) goto baddatacleanup;
CONVERT_FROM_DWORD_LE(priv->maskalpha);
} else
priv->maskalpha = 0;
@@ -419,20 +432,6 @@ unsupportedcleanup:
return GDISP_IMAGE_ERR_UNSUPPORTED; // Not supported
}
-void gdispImageClose_BMP(gdispImage *img) {
- if (img->priv) {
-#if GDISP_NEED_IMAGE_BMP_1 || GDISP_NEED_IMAGE_BMP_4 || GDISP_NEED_IMAGE_BMP_4_RLE || GDISP_NEED_IMAGE_BMP_8 || GDISP_NEED_IMAGE_BMP_8_RLE
- if (img->priv->palette)
- gdispImageFree(img, (void *)img->priv->palette, img->priv->palsize*sizeof(color_t));
-#endif
- if (img->priv->frame0cache)
- gdispImageFree(img, (void *)img->priv->frame0cache, img->width*img->height*sizeof(pixel_t));
- gdispImageFree(img, (void *)img->priv, sizeof(gdispImagePrivate));
- img->priv = 0;
- }
- img->io.fns->close(&img->io);
-}
-
static coord_t getPixels(gdispImage *img, coord_t x) {
gdispImagePrivate * priv;
color_t * pc;
@@ -454,7 +453,7 @@ static coord_t getPixels(gdispImage *img, coord_t x) {
len = 0;
while(x < img->width && len <= BLIT_BUFFER_SIZE-32) {
- if (img->io.fns->read(&img->io, &b, 4) != 4)
+ if (gfileRead(img->f, &b, 4) != 4)
return 0;
for(m=0x80; m; m >>= 1, pc++)
@@ -499,7 +498,7 @@ static coord_t getPixels(gdispImage *img, coord_t x) {
return len;
} else if (priv->bmpflags & BMP_RLE_ABS) {
while (priv->rlerun && len <= BLIT_BUFFER_SIZE-2 && x < img->width) {
- if (img->io.fns->read(&img->io, &b, 1) != 1)
+ if (gfileRead(img->f, &b, 1) != 1)
return 0;
*pc++ = priv->palette[b[0] >> 4];
priv->rlerun--;
@@ -514,8 +513,8 @@ static coord_t getPixels(gdispImage *img, coord_t x) {
}
if (priv->rlerun) // Return if we have more run to do
return len;
- if ((img->io.pos - priv->frame0pos)&1) { // Make sure we are on a word boundary
- if (img->io.fns->read(&img->io, &b, 1) != 1)
+ if ((gfileGetPos(img->f) - priv->frame0pos)&1) { // Make sure we are on a word boundary
+ if (gfileRead(img->f, &b, 1) != 1)
return 0;
}
}
@@ -524,7 +523,7 @@ static coord_t getPixels(gdispImage *img, coord_t x) {
priv->bmpflags &= ~(BMP_RLE_ENC|BMP_RLE_ABS);
// There are always at least 2 bytes in an RLE code
- if (img->io.fns->read(&img->io, &b, 2) != 2)
+ if (gfileRead(img->f, &b, 2) != 2)
return 0;
if (b[0]) { // Encoded mode
@@ -541,7 +540,7 @@ static coord_t getPixels(gdispImage *img, coord_t x) {
return len;
} else if (b[1] == 2) { // Delta x, y
// There are always at least 2 bytes in an RLE code
- if (img->io.fns->read(&img->io, &b, 2) != 2)
+ if (gfileRead(img->f, &b, 2) != 2)
return 0;
priv->rlerun = b[0] + (uint16_t)b[1] * img->width;
priv->rlecode = 0; // Who knows what color this should really be
@@ -559,7 +558,7 @@ static coord_t getPixels(gdispImage *img, coord_t x) {
uint8_t b[4];
while(x < img->width && len <= BLIT_BUFFER_SIZE-8) {
- if (img->io.fns->read(&img->io, &b, 4) != 4)
+ if (gfileRead(img->f, &b, 4) != 4)
return 0;
*pc++ = priv->palette[b[0] >> 4];
@@ -599,7 +598,7 @@ static coord_t getPixels(gdispImage *img, coord_t x) {
return len;
} else if (priv->bmpflags & BMP_RLE_ABS) {
while (priv->rlerun && len < BLIT_BUFFER_SIZE && x < img->width) {
- if (img->io.fns->read(&img->io, &b, 1) != 1)
+ if (gfileRead(img->f, &b, 1) != 1)
return 0;
*pc++ = priv->palette[b[0]];
priv->rlerun--;
@@ -608,8 +607,8 @@ static coord_t getPixels(gdispImage *img, coord_t x) {
}
if (priv->rlerun) // Return if we have more run to do
return len;
- if ((img->io.pos - priv->frame0pos)&1) { // Make sure we are on a word boundary
- if (img->io.fns->read(&img->io, &b, 1) != 1)
+ if ((gfileGetPos(img->f) - priv->frame0pos)&1) { // Make sure we are on a word boundary
+ if (gfileRead(img->f, &b, 1) != 1)
return 0;
}
}
@@ -618,7 +617,7 @@ static coord_t getPixels(gdispImage *img, coord_t x) {
priv->bmpflags &= ~(BMP_RLE_ENC|BMP_RLE_ABS);
// There are always at least 2 bytes in an RLE code
- if (img->io.fns->read(&img->io, &b, 2) != 2)
+ if (gfileRead(img->f, &b, 2) != 2)
return 0;
if (b[0]) { // Encoded mode
@@ -635,7 +634,7 @@ static coord_t getPixels(gdispImage *img, coord_t x) {
return len;
} else if (b[1] == 2) { // Delta x, y
// There are always at least 2 bytes in an RLE code
- if (img->io.fns->read(&img->io, &b, 2) != 2)
+ if (gfileRead(img->f, &b, 2) != 2)
return GDISP_IMAGE_ERR_BADDATA;
priv->rlerun = b[0] + (uint16_t)b[1] * img->width;
priv->rlecode = 0; // Who knows what color this should really be
@@ -653,7 +652,7 @@ static coord_t getPixels(gdispImage *img, coord_t x) {
uint8_t b[4];
while(x < img->width && len <= BLIT_BUFFER_SIZE-4) {
- if (img->io.fns->read(&img->io, &b, 4) != 4)
+ if (gfileRead(img->f, &b, 4) != 4)
return 0;
*pc++ = priv->palette[b[0]];
@@ -675,7 +674,7 @@ static coord_t getPixels(gdispImage *img, coord_t x) {
color_t r, g, b;
while(x < img->width && len <= BLIT_BUFFER_SIZE-2) {
- if (img->io.fns->read(&img->io, &w, 4) != 4)
+ if (gfileRead(img->f, &w, 4) != 4)
return 0;
CONVERT_FROM_WORD_LE(w[0]);
CONVERT_FROM_WORD_LE(w[1]);
@@ -720,7 +719,7 @@ static coord_t getPixels(gdispImage *img, coord_t x) {
uint8_t b[3];
while(x < img->width && len < BLIT_BUFFER_SIZE) {
- if (img->io.fns->read(&img->io, &b, 3) != 3)
+ if (gfileRead(img->f, &b, 3) != 3)
return 0;
*pc++ = RGB2COLOR(b[2], b[1], b[0]);
x++;
@@ -729,7 +728,7 @@ static coord_t getPixels(gdispImage *img, coord_t x) {
if (x >= img->width) {
// Make sure we have read a multiple of 4 bytes for the line
- if ((x & 3) && img->io.fns->read(&img->io, &b, x & 3) != (x & 3))
+ if ((x & 3) && gfileRead(img->f, &b, x & 3) != (x & 3))
return 0;
}
}
@@ -743,7 +742,7 @@ static coord_t getPixels(gdispImage *img, coord_t x) {
color_t r, g, b;
while(x < img->width && len < BLIT_BUFFER_SIZE) {
- if (img->io.fns->read(&img->io, &dw, 4) != 4)
+ if (gfileRead(img->f, &dw, 4) != 4)
return 0;
CONVERT_FROM_DWORD_LE(dw);
if (priv->shiftred < 0)
@@ -791,7 +790,7 @@ gdispImageError gdispImageCache_BMP(gdispImage *img) {
return GDISP_IMAGE_ERR_NOMEMORY;
/* Read the entire bitmap into cache */
- img->io.fns->seek(&img->io, priv->frame0pos);
+ gfileSetPos(img->f, priv->frame0pos);
#if GDISP_NEED_IMAGE_BMP_4_RLE || GDISP_NEED_IMAGE_BMP_8_RLE
priv->rlerun = 0;
priv->rlecode = 0;
@@ -847,7 +846,7 @@ gdispImageError gdispGImageDraw_BMP(GDisplay *g, gdispImage *img, coord_t x, coo
}
/* Start decoding from the beginning */
- img->io.fns->seek(&img->io, priv->frame0pos);
+ gfileSetPos(img->f, priv->frame0pos);
#if GDISP_NEED_IMAGE_BMP_4_RLE || GDISP_NEED_IMAGE_BMP_8_RLE
priv->rlerun = 0;
priv->rlecode = 0;
diff --git a/src/gdisp/image_gif.c b/src/gdisp/image_gif.c
index 1ff72ff0..06f4ef6a 100644
--- a/src/gdisp/image_gif.c
+++ b/src/gdisp/image_gif.c
@@ -172,9 +172,9 @@ static gdispImageError startDecode(gdispImage *img) {
// Local palette
decode->maxpixel = priv->frame.palsize-1;
decode->palette = (color_t *)(decode+1);
- img->io.fns->seek(&img->io, priv->frame.pospal);
+ gfileSetPos(img->f, priv->frame.pospal);
for(cnt = 0; cnt < priv->frame.palsize; cnt++) {
- if (img->io.fns->read(&img->io, &decode->buf, 3) != 3)
+ if (gfileRead(img->f, &decode->buf, 3) != 3)
goto baddatacleanup;
decode->palette[cnt] = RGB2COLOR(decode->buf[0], decode->buf[1], decode->buf[2]);
}
@@ -188,8 +188,8 @@ static gdispImageError startDecode(gdispImage *img) {
}
// Get the initial lzw code size and values
- img->io.fns->seek(&img->io, priv->frame.posimg);
- if (img->io.fns->read(&img->io, &decode->bitsperpixel, 1) != 1 || decode->bitsperpixel >= MAX_CODE_BITS)
+ gfileSetPos(img->f, priv->frame.posimg);
+ if (gfileRead(img->f, &decode->bitsperpixel, 1) != 1 || decode->bitsperpixel >= MAX_CODE_BITS)
goto baddatacleanup;
decode->code_clear = 1 << decode->bitsperpixel;
decode->code_eof = decode->code_clear + 1;
@@ -273,8 +273,8 @@ static uint16_t getbytes(gdispImage *img) {
// Get another code - a code is made up of decode->bitspercode bits.
while (decode->shiftbits < decode->bitspercode) {
// Get a byte - we may have to start a new data block
- if ((!decode->blocksz && (img->io.fns->read(&img->io, &decode->blocksz, 1) != 1 || !decode->blocksz))
- || img->io.fns->read(&img->io, &bdata, 1) != 1) {
+ if ((!decode->blocksz && (gfileRead(img->f, &decode->blocksz, 1) != 1 || !decode->blocksz))
+ || gfileRead(img->f, &bdata, 1) != 1) {
// Pretend we got the EOF code - some encoders seem to just end the file
decode->code_last = decode->code_eof;
return cnt;
@@ -302,8 +302,8 @@ static uint16_t getbytes(gdispImage *img) {
if (code == decode->code_eof) {
// Skip to the end of the data blocks
do {
- img->io.fns->seek(&img->io, img->io.pos+decode->blocksz);
- } while (img->io.fns->read(&img->io, &decode->blocksz, 1) == 1 && decode->blocksz);
+ gfileSetPos(img->f, gfileGetPos(img->f)+decode->blocksz);
+ } while (gfileRead(img->f, &decode->blocksz, 1) == 1 && decode->blocksz);
// Mark the end
decode->code_last = decode->code_eof;
@@ -398,8 +398,8 @@ static gdispImageError initFrame(gdispImage *img) {
priv->dispose.height = priv->frame.height;
// Check for a cached version of this image
- for(cache=priv->cache; cache && cache->frame.posstart <= img->io.pos; cache=cache->next) {
- if (cache->frame.posstart == img->io.pos) {
+ for(cache=priv->cache; cache && cache->frame.posstart <= (size_t)gfileGetPos(img->f); cache=cache->next) {
+ if (cache->frame.posstart == (size_t)gfileGetPos(img->f)) {
priv->frame = cache->frame;
priv->curcache = cache;
return GDISP_IMAGE_ERR_OK;
@@ -408,20 +408,20 @@ static gdispImageError initFrame(gdispImage *img) {
// Get ready for a new image
priv->curcache = 0;
- priv->frame.posstart = img->io.pos;
+ priv->frame.posstart = gfileGetPos(img->f);
priv->frame.flags = 0;
priv->frame.delay = 0;
priv->frame.palsize = 0;
// Process blocks until we reach the image descriptor
while(1) {
- if (img->io.fns->read(&img->io, &blocktype, 1) != 1)
+ if (gfileRead(img->f, &blocktype, 1) != 1)
return GDISP_IMAGE_ERR_BADDATA;
switch(blocktype) {
case 0x2C: //',' - IMAGE_DESC_RECORD_TYPE;
// Read the Image Descriptor
- if (img->io.fns->read(&img->io, priv->buf, 9) != 9)
+ if (gfileRead(img->f, priv->buf, 9) != 9)
return GDISP_IMAGE_ERR_BADDATA;
priv->frame.x = *(uint16_t *)(((uint8_t *)priv->buf)+0);
CONVERT_FROM_WORD_LE(priv->frame.x);
@@ -437,7 +437,7 @@ static gdispImageError initFrame(gdispImage *img) {
priv->frame.flags |= GIFL_INTERLACE;
// We are ready to go for the actual palette read and image decode
- priv->frame.pospal = img->io.pos;
+ priv->frame.pospal = gfileGetPos(img->f);
priv->frame.posimg = priv->frame.pospal+priv->frame.palsize*3;
priv->frame.posend = 0;
@@ -448,13 +448,13 @@ static gdispImageError initFrame(gdispImage *img) {
case 0x21: //'!' - EXTENSION_RECORD_TYPE;
// Read the extension type
- if (img->io.fns->read(&img->io, &blocktype, 1) != 1)
+ if (gfileRead(img->f, &blocktype, 1) != 1)
return GDISP_IMAGE_ERR_BADDATA;
switch(blocktype) {
case 0xF9: // EXTENSION - Graphics Control Block
// Read the GCB
- if (img->io.fns->read(&img->io, priv->buf, 6) != 6)
+ if (gfileRead(img->f, priv->buf, 6) != 6)
return GDISP_IMAGE_ERR_BADDATA;
// Check we have read a 4 byte data block and a data block terminator (0)
if (((uint8_t *)priv->buf)[0] != 4 || ((uint8_t *)priv->buf)[5] != 0)
@@ -485,7 +485,7 @@ static gdispImageError initFrame(gdispImage *img) {
if (priv->flags & GIF_LOOP)
goto skipdatablocks;
// Read the Application header
- if (img->io.fns->read(&img->io, priv->buf, 16) != 16)
+ if (gfileRead(img->f, priv->buf, 16) != 16)
return GDISP_IMAGE_ERR_BADDATA;
// Check we have read a 11 byte data block
if (((uint8_t *)priv->buf)[0] != 11 && ((uint8_t *)priv->buf)[12] != 3)
@@ -516,11 +516,11 @@ static gdispImageError initFrame(gdispImage *img) {
// We don't understand this extension - just skip it by skipping data blocks
skipdatablocks:
while(1) {
- if (img->io.fns->read(&img->io, &blocksz, 1) != 1)
+ if (gfileRead(img->f, &blocksz, 1) != 1)
return GDISP_IMAGE_ERR_BADDATA;
if (!blocksz)
break;
- img->io.fns->seek(&img->io, img->io.pos + blocksz);
+ gfileSetPos(img->f, gfileGetPos(img->f) + blocksz);
}
break;
}
@@ -537,7 +537,7 @@ static gdispImageError initFrame(gdispImage *img) {
}
// Seek back to frame0
- img->io.fns->seek(&img->io, priv->frame0pos);
+ gfileSetPos(img->f, priv->frame0pos);
return GDISP_IMAGE_LOOP;
default: // UNDEFINED_RECORD_TYPE;
@@ -546,13 +546,34 @@ static gdispImageError initFrame(gdispImage *img) {
}
}
+void gdispImageClose_GIF(gdispImage *img) {
+ gdispImagePrivate * priv;
+ imgcache * cache;
+ imgcache * ncache;
+
+ priv = img->priv;
+ if (priv) {
+ // Free any stored frames
+ cache = priv->cache;
+ while(cache) {
+ ncache = cache->next;
+ gdispImageFree(img, (void *)cache, sizeof(imgcache)+cache->frame.width*cache->frame.height+cache->frame.palsize*sizeof(color_t));
+ cache = ncache;
+ }
+ if (priv->palette)
+ gdispImageFree(img, (void *)priv->palette, priv->palsize*sizeof(color_t));
+ gdispImageFree(img, (void *)img->priv, sizeof(gdispImagePrivate));
+ img->priv = 0;
+ }
+}
+
gdispImageError gdispImageOpen_GIF(gdispImage *img) {
gdispImagePrivate *priv;
uint8_t hdr[6];
uint16_t aword;
/* Read the file identifier */
- if (img->io.fns->read(&img->io, hdr, 6) != 6)
+ if (gfileRead(img->f, hdr, 6) != 6)
return GDISP_IMAGE_ERR_BADFORMAT; // It can't be us
/* Process the GIFFILEHEADER structure */
@@ -580,7 +601,7 @@ gdispImageError gdispImageOpen_GIF(gdispImage *img) {
/* Process the Screen Descriptor structure */
// Read the screen descriptor
- if (img->io.fns->read(&img->io, priv->buf, 7) != 7)
+ if (gfileRead(img->f, priv->buf, 7) != 7)
goto baddatacleanup;
// Get the width
img->width = *(uint16_t *)(((uint8_t *)priv->buf)+0);
@@ -596,7 +617,7 @@ gdispImageError gdispImageOpen_GIF(gdispImage *img) {
goto nomemcleanup;
// Read the global palette
for(aword = 0; aword < priv->palsize; aword++) {
- if (img->io.fns->read(&img->io, &priv->buf, 3) != 3)
+ if (gfileRead(img->f, &priv->buf, 3) != 3)
goto baddatacleanup;
priv->palette[aword] = RGB2COLOR(((uint8_t *)priv->buf)[0], ((uint8_t *)priv->buf)[1], ((uint8_t *)priv->buf)[2]);
}
@@ -604,7 +625,7 @@ gdispImageError gdispImageOpen_GIF(gdispImage *img) {
priv->bgcolor = ((uint8_t *)priv->buf)[5];
// Save the fram0pos
- priv->frame0pos = img->io.pos;
+ priv->frame0pos = gfileGetPos(img->f);
// Read the first frame descriptor
switch(initFrame(img)) {
@@ -628,28 +649,6 @@ gdispImageError gdispImageOpen_GIF(gdispImage *img) {
}
}
-void gdispImageClose_GIF(gdispImage *img) {
- gdispImagePrivate * priv;
- imgcache * cache;
- imgcache * ncache;
-
- priv = img->priv;
- if (priv) {
- // Free any stored frames
- cache = priv->cache;
- while(cache) {
- ncache = cache->next;
- gdispImageFree(img, (void *)cache, sizeof(imgcache)+cache->frame.width*cache->frame.height+cache->frame.palsize*sizeof(color_t));
- cache = ncache;
- }
- if (priv->palette)
- gdispImageFree(img, (void *)priv->palette, priv->palsize*sizeof(color_t));
- gdispImageFree(img, (void *)img->priv, sizeof(gdispImagePrivate));
- img->priv = 0;
- }
- img->io.fns->close(&img->io);
-}
-
gdispImageError gdispImageCache_GIF(gdispImage *img) {
gdispImagePrivate * priv;
imgcache * cache;
@@ -786,7 +785,7 @@ gdispImageError gdispImageCache_GIF(gdispImage *img) {
}
// We could be pedantic here but extra bytes won't hurt us
while(getbytes(img));
- priv->frame.posend = cache->frame.posend = img->io.pos;
+ priv->frame.posend = cache->frame.posend = gfileGetPos(img->f);
// Save everything
priv->curcache = cache;
@@ -1150,7 +1149,7 @@ gdispImageError gdispGImageDraw_GIF(GDisplay *g, gdispImage *img, coord_t x, coo
}
// We could be pedantic here but extra bytes won't hurt us
while (getbytes(img));
- priv->frame.posend = img->io.pos;
+ priv->frame.posend = gfileGetPos(img->f);
stopDecode(img);
return GDISP_IMAGE_ERR_OK;
@@ -1173,19 +1172,19 @@ delaytime_t gdispImageNext_GIF(gdispImage *img) {
// We need to get to the end of this frame
if (!priv->frame.posend) {
// We don't know where the end of the frame is yet - find it!
- img->io.fns->seek(&img->io, priv->frame.posimg+1); // Skip the code size byte too
+ gfileSetPos(img->f, priv->frame.posimg+1); // Skip the code size byte too
while(1) {
- if (img->io.fns->read(&img->io, &blocksz, 1) != 1)
+ if (gfileRead(img->f, &blocksz, 1) != 1)
return TIME_INFINITE;
if (!blocksz)
break;
- img->io.fns->seek(&img->io, img->io.pos + blocksz);
+ gfileSetPos(img->f, gfileGetPos(img->f) + blocksz);
}
- priv->frame.posend = img->io.pos;
+ priv->frame.posend = gfileGetPos(img->f);
}
// Seek to the end of this frame
- img->io.fns->seek(&img->io, priv->frame.posend);
+ gfileSetPos(img->f, priv->frame.posend);
// Read the next frame descriptor
for(blocksz=0; blocksz < 2; blocksz++) { // 2 loops max to prevent cycling forever with a bad file
diff --git a/src/gdisp/image_native.c b/src/gdisp/image_native.c
index 7f249ae8..c458531e 100644
--- a/src/gdisp/image_native.c
+++ b/src/gdisp/image_native.c
@@ -33,11 +33,20 @@ typedef struct gdispImagePrivate {
pixel_t buf[BLIT_BUFFER_SIZE];
} gdispImagePrivate;
+void gdispImageClose_NATIVE(gdispImage *img) {
+ if (img->priv) {
+ if (img->priv->frame0cache)
+ gdispImageFree(img, (void *)img->priv->frame0cache, img->width * img->height * sizeof(pixel_t));
+ gdispImageFree(img, (void *)img->priv, sizeof(gdispImagePrivate));
+ img->priv = 0;
+ }
+}
+
gdispImageError gdispImageOpen_NATIVE(gdispImage *img) {
uint8_t hdr[HEADER_SIZE];
/* Read the 8 byte header */
- if (img->io.fns->read(&img->io, hdr, 8) != 8)
+ if (gfileRead(img->f, hdr, 8) != 8)
return GDISP_IMAGE_ERR_BADFORMAT; // It can't be us
if (hdr[0] != 'N' || hdr[1] != 'I')
@@ -60,16 +69,6 @@ gdispImageError gdispImageOpen_NATIVE(gdispImage *img) {
return GDISP_IMAGE_ERR_OK;
}
-void gdispImageClose_NATIVE(gdispImage *img) {
- if (img->priv) {
- if (img->priv->frame0cache)
- gdispImageFree(img, (void *)img->priv->frame0cache, img->width * img->height * sizeof(pixel_t));
- gdispImageFree(img, (void *)img->priv, sizeof(gdispImagePrivate));
- img->priv = 0;
- }
- img->io.fns->close(&img->io);
-}
-
gdispImageError gdispImageCache_NATIVE(gdispImage *img) {
size_t len;
@@ -84,8 +83,8 @@ gdispImageError gdispImageCache_NATIVE(gdispImage *img) {
return GDISP_IMAGE_ERR_NOMEMORY;
/* Read the entire bitmap into cache */
- img->io.fns->seek(&img->io, FRAME0POS);
- if (img->io.fns->read(&img->io, img->priv->frame0cache, len) != len)
+ gfileSetPos(img->f, FRAME0POS);
+ if (gfileRead(img->f, img->priv->frame0cache, len) != len)
return GDISP_IMAGE_ERR_BADDATA;
return GDISP_IMAGE_ERR_OK;
@@ -112,12 +111,12 @@ gdispImageError gdispImageGDraw_NATIVE(GDisplay *g, gdispImage *img, coord_t x,
/* Cycle through the lines */
for(;cy;cy--, y++) {
/* Move to the start of the line */
- img->io.fns->seek(&img->io, pos);
+ gfileSetPos(img->f, pos);
/* Draw the line in chunks using BitBlt */
for(mx = x, mcx = cx; mcx > 0; mcx -= len, mx += len) {
// Read the data
- len = img->io.fns->read(&img->io,
+ len = gfileRead(img->f,
img->priv->buf,
mcx > BLIT_BUFFER_SIZE ? (BLIT_BUFFER_SIZE*sizeof(pixel_t)) : (mcx * sizeof(pixel_t)))
/ sizeof(pixel_t);
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..390a885d
--- /dev/null
+++ b/src/gfile/inc_nativefs.c
@@ -0,0 +1,98 @@
+/*
+ * 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 char *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 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) {
+ FILE *fd;
+ char mode[5];
+
+ if (!(fd = fopen(fname, mode)))
+ return FALSE;
+ f->obj = (void *)fd;
+ return 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 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..8d0e32c1
--- /dev/null
+++ b/src/gfile/inc_romfs.c
@@ -0,0 +1,87 @@
+/*
+ * 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);
+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 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 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; }
diff --git a/src/gwin/gimage.c b/src/gwin/gimage.c
index b1f8e078..e4032b96 100644
--- a/src/gwin/gimage.c
+++ b/src/gwin/gimage.c
@@ -139,37 +139,11 @@ GHandle gwinGImageCreate(GDisplay *g, GImageObject *gobj, GWindowInit *pInit) {
return (GHandle)gobj;
}
-bool_t gwinImageOpenMemory(GHandle gh, const void* memory) {
+bool_t gwinImageOpenGFile(GHandle gh, GFILE *f) {
if (gdispImageIsOpen(&widget(gh)->image))
gdispImageClose(&widget(gh)->image);
- if (!gdispImageSetMemoryReader(&widget(gh)->image, memory))
- return FALSE;
-
- if (gdispImageOpen(&widget(gh)->image) != GDISP_IMAGE_ERR_OK)
- return FALSE;
-
- if ((gh->flags & GWIN_FLG_VISIBLE)) {
- // Setting the clip here shouldn't be necessary if the redraw doesn't overdraw
- // but we put it in for safety anyway
- #if GDISP_NEED_CLIP
- gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height);
- #endif
- _redraw(gh);
- }
-
- return TRUE;
-}
-
-#if defined(WIN32) || GFX_USE_OS_WIN32 || GFX_USE_OS_LINUX || GFX_USE_OS_OSX || defined(__DOXYGEN__)
-bool_t gwinImageOpenFile(GHandle gh, const char* filename) {
- if (gdispImageIsOpen(&widget(gh)->image))
- gdispImageClose(&widget(gh)->image);
-
- if (!gdispImageSetFileReader(&widget(gh)->image, filename))
- return FALSE;
-
- if (gdispImageOpen(&widget(gh)->image) != GDISP_IMAGE_ERR_OK)
+ if ((gdispImageOpenGFile(&widget(gh)->image, f) & GDISP_IMAGE_ERR_UNRECOVERABLE))
return FALSE;
if ((gh->flags & GWIN_FLG_VISIBLE)) {
@@ -183,31 +157,6 @@ bool_t gwinImageOpenFile(GHandle gh, const char* filename) {
return TRUE;
}
-#endif
-
-#if GFX_USE_OS_CHIBIOS || defined(__DOXYGEN__)
-bool_t gwinImageOpenStream(GHandle gh, void *streamPtr) {
- if (gdispImageIsOpen(&widget(gh)->image))
- gdispImageClose(&widget(gh)->image);
-
- if (!gdispImageSetBaseFileStreamReader(&widget(gh)->image, streamPtr))
- return FALSE;
-
- if (gdispImageOpen(&widget(gh)->image) != GDISP_IMAGE_ERR_OK)
- return FALSE;
-
- if ((gh->flags & GWIN_FLG_VISIBLE)) {
- // Setting the clip here shouldn't be necessary if the redraw doesn't overdraw
- // but we put it in for safety anyway
- #if GDISP_NEED_CLIP
- gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height);
- #endif
- _redraw(gh);
- }
-
- return TRUE;
-}
-#endif
gdispImageError gwinImageCache(GHandle gh) {
return gdispImageCache(&widget(gh)->image);
diff --git a/src/gwin/list.c b/src/gwin/list.c
index 972ea1ab..08e6a96d 100644
--- a/src/gwin/list.c
+++ b/src/gwin/list.c
@@ -172,6 +172,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
const gfxQueueASyncItem* qi;
int item, i;
coord_t iheight;
+ (void) x;
iheight = gdispGetFontMetric(gw->g.font, fontHeight) + VERTICAL_PADDING;
@@ -202,8 +203,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
// a mouse down has occurred over the list area
static void MouseDown(GWidgetObject* gw, coord_t x, coord_t y) {
- const gfxQueueASyncItem* qi;
- int item, i, pgsz;
+ int pgsz;
coord_t iheight;
(void) x;
diff --git a/tools/file2c/binaries/linux/file2c b/tools/file2c/binaries/linux/file2c
index 403c7d8f..5a2a5de7 100755
--- a/tools/file2c/binaries/linux/file2c
+++ b/tools/file2c/binaries/linux/file2c
Binary files differ
diff --git a/tools/file2c/binaries/windows/file2c.exe b/tools/file2c/binaries/windows/file2c.exe
index 333b1138..dc530bf9 100644
--- a/tools/file2c/binaries/windows/file2c.exe
+++ b/tools/file2c/binaries/windows/file2c.exe
Binary files differ
diff --git a/tools/file2c/src/Makefile.mingw32 b/tools/file2c/src/Makefile.mingw32
new file mode 100644
index 00000000..470330bd
--- /dev/null
+++ b/tools/file2c/src/Makefile.mingw32
@@ -0,0 +1,10 @@
+
+CC = i686-pc-mingw32-gcc
+CFLAGS = -Wall -O2
+
+all:
+ $(CC) $(CFLAGS) -o file2c.exe file2c.c
+
+clean:
+ @rm file2c.exe
+
diff --git a/tools/file2c/src/file2c.c b/tools/file2c/src/file2c.c
index f7bc1e9c..1c279ff2 100644
--- a/tools/file2c/src/file2c.c
+++ b/tools/file2c/src/file2c.c
@@ -8,11 +8,14 @@
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
+#include <stdlib.h>
+#include <time.h>
#ifdef WIN32
#include <io.h>
#endif
-static unsigned char buf[1024];
+static unsigned char buf[1024];
+static char tname[FILENAME_MAX];
static char *filenameof(char *fname) {
char *p;
@@ -25,6 +28,13 @@ static char *filenameof(char *fname) {
#endif
p = strrchr(fname, '/');
if (p) fname = p+1;
+ return fname;
+}
+
+static char *basenameof(char *fname) {
+ char *p;
+
+ fname = filenameof(fname);
p = strchr(fname, '.');
if (p) *p = 0;
return fname;
@@ -43,34 +53,35 @@ char * opt_progname;
char * opt_inputfile;
char * opt_outputfile;
char * opt_arrayname;
+char * opt_dirname;
int opt_breakblocks;
+int opt_romdir;
char * opt_static;
char * opt_const;
FILE * f_input;
FILE * f_output;
unsigned blocknum;
-size_t len;
+size_t len, totallen;
size_t i;
/* Default values for our parameters */
- opt_progname = filenameof(argv[0]);
- opt_inputfile = 0;
- opt_outputfile = 0;
- opt_arrayname = 0;
- opt_breakblocks = 0;
- opt_static = "";
- opt_const = "";
+ opt_progname = basenameof(argv[0]);
+ opt_inputfile = opt_outputfile = opt_arrayname = opt_dirname = 0;
+ opt_breakblocks = opt_romdir = 0;
+ opt_static = opt_const = "";
/* Read the arguments */
while(*++argv) {
if (argv[0][0] == '-') {
while (*++(argv[0])) {
switch(argv[0][0]) {
- case '?': case 'h': goto usage;
- case 'b': opt_breakblocks = 1; break;
- case 'c': opt_const = "const "; break;
- case 's': opt_static = "static "; break;
- case 'n': opt_arrayname = *++argv; goto nextarg;
+ case '?': case 'h': goto usage;
+ case 'd': opt_romdir = 1; break;
+ case 'b': opt_breakblocks = 1; break;
+ case 'c': opt_const = "const "; break;
+ case 's': opt_static = "static "; break;
+ case 'n': opt_arrayname = *++argv; goto nextarg;
+ case 'f': opt_romdir = 1; opt_dirname = *++argv; goto nextarg;
default:
fprintf(stderr, "Unknown flag -%c\n", argv[0][0]);
goto usage;
@@ -82,20 +93,28 @@ size_t i;
opt_outputfile = argv[0];
else {
usage:
- fprintf(stderr, "Usage:\n\t%s -?\n"
- "\t%s [-bs] [-n name] [inputfile] [outputfile]\n"
- "\t\t-?\tThis help\n"
- "\t\t-h\tThis help\n"
- "\t\t-b\tBreak the arrays for compilers that won't handle large arrays\n"
- "\t\t-c\tDeclare the arrays as const (useful to ensure they end up in Flash)\n"
- "\t\t-s\tDeclare the arrays as static\n"
- "\t\t-n name\tUse \"name\" as the name of the array\n"
+ fprintf(stderr, "Usage:\n\n%s -?\n"
+ "%s [-dbcs] [-n name] [-f file] [inputfile] [outputfile]\n"
+ "\t-?\tThis help\n"
+ "\t-h\tThis help\n"
+ "\t-d\tAdd a directory entry for the ROM file system\n"
+ "\t-b\tBreak the arrays for compilers that won't handle large arrays\n"
+ "\t-c\tDeclare as const (useful to ensure they end up in Flash)\n"
+ "\t-s\tDeclare as static\n"
+ "\t-n name\tUse \"name\" as the name of the array\n"
+ "\t-f file\tUse \"file\" as the filename in the ROM directory entry\n"
, opt_progname, opt_progname);
return 1;
}
nextarg: ;
}
+ /* Make sure we can generate a default directory name if required */
+ if (opt_romdir && !opt_dirname && !opt_inputfile) {
+ fprintf(stderr, "If using -d you must either specify an input filename or use -f to specify a directory entry filename\n");
+ goto usage;
+ }
+
/* Open the input file */
if (opt_inputfile) {
f_input = fopen(opt_inputfile,
@@ -129,43 +148,57 @@ size_t i;
fprintf(f_output, "/**\n * This file was generated ");
if (opt_inputfile) fprintf(f_output, "from \"%s\" ", opt_inputfile);
fprintf(f_output, "using...\n *\n *\t%s", opt_progname);
- if (opt_arrayname || opt_static[0] || opt_const[0] || opt_breakblocks) {
+ if (opt_arrayname || opt_static[0] || opt_const[0] || opt_breakblocks || opt_romdir) {
fprintf(f_output, " -");
+ if (opt_romdir) fprintf(f_output, "b");
if (opt_breakblocks) fprintf(f_output, "b");
if (opt_const[0]) fprintf(f_output, "c");
if (opt_static[0]) fprintf(f_output, "s");
if (opt_arrayname) fprintf(f_output, "n %s", opt_arrayname);
+ if (opt_dirname) fprintf(f_output, (opt_arrayname ? " -f %s" : "f %s"), opt_dirname);
}
if (opt_inputfile) fprintf(f_output, " %s", opt_inputfile);
if (opt_outputfile) fprintf(f_output, " %s", opt_outputfile);
fprintf(f_output, "\n *\n */\n");
/*
- * Set the array name.
- * We do this after printing opt_inputfile for the last time as we
- * modify opt_inputfile in place to generate opt_arrayname.
+ * Set the array name and dir name
*/
if (!opt_arrayname) {
if (opt_inputfile)
- opt_arrayname = filenameof(opt_inputfile);
- if (!opt_arrayname || !opt_arrayname[0])
- opt_arrayname = "filearray";
+ opt_arrayname = basenameof(strcpy(tname, opt_inputfile));
+ if (!opt_arrayname || !opt_arrayname[0]) {
+ srand(time(NULL));
+ sprintf(tname, "filearray%u", rand());
+ opt_arrayname = tname;
+ }
}
opt_arrayname = clean4c(opt_arrayname);
+ if (opt_romdir && !opt_dirname)
+ opt_dirname = filenameof(opt_inputfile);
/* Read the file processing 1K at a time */
blocknum = 0;
+ totallen = 0;
while((len = fread(buf, 1, sizeof(buf), f_input))) {
if (!blocknum++)
- fprintf(f_output, "%s%sunsigned char %s[] = {", opt_static, opt_const, opt_arrayname);
+ fprintf(f_output, "%s%schar %s[] = {", opt_static, opt_const, opt_arrayname);
else if (opt_breakblocks)
- fprintf(f_output, "\n};\n%s%sunsigned char %s_p%u[] = {", opt_static, opt_const, opt_arrayname, blocknum);
+ fprintf(f_output, "\n};\n%s%schar %s_p%u[] = {", opt_static, opt_const, opt_arrayname, blocknum);
for(i = 0; i < len; i++) {
fprintf(f_output, (i & 0x0F) ? " 0x%02X," : "\n\t0x%02X,", buf[i]);
}
+ totallen += len;
}
fprintf(f_output, "\n};\n");
+ /* Add the directory entry if required */
+ if (opt_romdir) {
+ fprintf(f_output, "\n#ifdef ROMFS_DIRENTRY_HEAD\n");
+ fprintf(f_output, "\t%s%sROMFS_DIRENTRY %s_dir = { ROMFS_DIRENTRY_HEAD, \"%s\", %u, %s };\n", opt_static, opt_const, opt_arrayname, opt_dirname, totallen, opt_arrayname);
+ fprintf(f_output, "\t#undef ROMFS_DIRENTRY_HEAD\n\t#define ROMFS_DIRENTRY_HEAD &%s_dir\n#endif\n", opt_arrayname);
+ }
+
/* Clean up */
if (ferror(f_input))
fprintf(stderr, "Input file read error\n");