diff options
38 files changed, 2181 insertions, 514 deletions
| diff --git a/demos/modules/gdisp/images/gfxconf.h b/demos/modules/gdisp/images/gfxconf.h index 6cd78b37..4ef9ab9e 100644 --- a/demos/modules/gdisp/images/gfxconf.h +++ b/demos/modules/gdisp/images/gfxconf.h @@ -51,5 +51,9 @@  #define GDISP_NEED_IMAGE_JPG		FALSE  #define GDISP_NEED_IMAGE_PNG		FALSE +#define GFX_USE_GFILE				TRUE +#define GFILE_NEED_ROMFS			TRUE +//#define GFILE_NEED_NATIVEFS		TRUE +  #endif /* _GFXCONF_H */ diff --git a/demos/modules/gdisp/images/main.c b/demos/modules/gdisp/images/main.c index b87f663c..6a2e4418 100644 --- a/demos/modules/gdisp/images/main.c +++ b/demos/modules/gdisp/images/main.c @@ -29,15 +29,12 @@  #include "gfx.h" -#ifdef WIN32 -	#define USE_MEMORY_FILE		TRUE				// Can be true or false for Win32 -#else -	#define USE_MEMORY_FILE		TRUE				// Non-Win32 - use the compiled in image -#endif - -#if USE_MEMORY_FILE -	#include "test-pal8.h" -#endif +/** + * The image file must be stored on a GFILE file-system. + * Use either GFILE_NEED_NATIVEFS or GFILE_NEED_ROMFS (or both). + * + * The ROMFS uses the file "romfs_files.h" to describe the set of files in the ROMFS. + */  static gdispImage myImage; @@ -52,13 +49,7 @@ int main(void) {  	sheight = gdispGetHeight();  	// Set up IO for our image -#if USE_MEMORY_FILE -	gdispImageSetMemoryReader(&myImage, test_pal8); -#else -	gdispImageSetSimulFileReader(&myImage, "test-pal8.bmp"); -#endif - -	gdispImageOpen(&myImage); +	gdispImageOpenFile(&myImage, "test-pal8.bmp");  	gdispImageDraw(&myImage, 0, 0, swidth, sheight, 0, 0);  	gdispImageClose(&myImage); diff --git a/demos/modules/gdisp/images/romfs_files.h b/demos/modules/gdisp/images/romfs_files.h new file mode 100644 index 00000000..a31dc7bf --- /dev/null +++ b/demos/modules/gdisp/images/romfs_files.h @@ -0,0 +1,7 @@ +/** + * This file contains the list of files for the ROMFS. + * + * The files have been converted using... + * 		file2c -dbcs infile outfile + */ +#include "romfs_testpal8.h" diff --git a/demos/modules/gdisp/images/test-pal8.h b/demos/modules/gdisp/images/romfs_testpal8.h index 9d1d7e0f..a7844b0d 100644 --- a/demos/modules/gdisp/images/test-pal8.h +++ b/demos/modules/gdisp/images/romfs_testpal8.h @@ -1,10 +1,10 @@  /**   * This file was generated from "test-pal8.bmp" using...   * - *	file2c -cs test-pal8.bmp test-pal8.h + *	file2c -bbcs test-pal8.bmp romfs_testpal8.h   *   */ -static const unsigned char test_pal8[] = { +static const char test_pal8[] = {  	0x42, 0x4D, 0x26, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x04, 0x00, 0x00, 0x28, 0x00,  	0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00,  	0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x13, 0x0B, 0x00, 0x00, 0xFC, 0x00, @@ -69,6 +69,8 @@ static const unsigned char test_pal8[] = {  	0x66, 0x00, 0xFF, 0x80, 0x99, 0x00, 0xFF, 0x80, 0xCC, 0x00, 0xFF, 0x80, 0xFF, 0x00, 0xFF, 0xAA,  	0x00, 0x00, 0xFF, 0xAA, 0x33, 0x00, 0xFF, 0xAA, 0x66, 0x00, 0xFF, 0xAA, 0x99, 0x00, 0xFF, 0xAA,  	0xCC, 0x00, 0xFF, 0xAA, 0xFF, 0x00, 0xFF, 0xD5, 0x00, 0x00, 0xFF, 0xD5, 0x33, 0x00, 0xFF, 0xD5, +}; +static const char test_pal8_p2[] = {  	0x66, 0x00, 0xFF, 0xD5, 0x99, 0x00, 0xFF, 0xD5, 0xCC, 0x00, 0xFF, 0xD5, 0xFF, 0x00, 0xFF, 0xFF,  	0x00, 0x00, 0xFF, 0xFF, 0x33, 0x00, 0xFF, 0xFF, 0x66, 0x00, 0xFF, 0xFF, 0x99, 0x00, 0xFF, 0xFF,  	0xCC, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x30, 0x30, 0x30, 0x30, 0x36, @@ -133,6 +135,8 @@ static const unsigned char test_pal8[] = {  	0x5C, 0x2B, 0x5C, 0x56, 0x5C, 0x56, 0x87, 0x56, 0x87, 0x81, 0xB2, 0x81, 0xB2, 0x81, 0xB2, 0xAC,  	0xB2, 0xAC, 0xDD, 0xAC, 0xDD, 0xD7, 0x2A, 0x00, 0x30, 0x00, 0x31, 0x06, 0x31, 0x07, 0x38, 0x07,  	0x38, 0x0D, 0x3E, 0x0E, 0x3E, 0x0E, 0x45, 0x14, 0x45, 0x15, 0x46, 0x1B, 0x46, 0x1B, 0x4C, 0x22, +}; +static const char test_pal8_p3[] = {  	0x4C, 0x22, 0x53, 0x22, 0x53, 0x29, 0x93, 0x62, 0x68, 0x62, 0x92, 0x62, 0x68, 0x62, 0x93, 0x62,  	0x68, 0x62, 0x92, 0x62, 0x92, 0x62, 0x93, 0x62, 0x92, 0x62, 0x92, 0x62, 0x92, 0x62, 0x93, 0x62,  	0x92, 0x62, 0x92, 0x62, 0x92, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, 0x31, 0x30, 0x31, 0x30, 0x37, @@ -197,6 +201,8 @@ static const unsigned char test_pal8[] = {  	0x62, 0x31, 0x62, 0x5C, 0x62, 0x5C, 0x8D, 0x5C, 0x8D, 0x87, 0xB8, 0x87, 0xB8, 0x87, 0xB8, 0xB2,  	0xB8, 0xB2, 0xE3, 0xB2, 0xE3, 0xDD, 0x54, 0x2A, 0x30, 0x2A, 0x5B, 0x30, 0x31, 0x31, 0x62, 0x31,  	0x38, 0x37, 0x68, 0x38, 0x3E, 0x38, 0x6F, 0x3E, 0x45, 0x3F, 0x70, 0x45, 0x46, 0x45, 0x76, 0x4C, +}; +static const char test_pal8_p4[] = {  	0x4C, 0x4C, 0x7D, 0x4C, 0x53, 0x53, 0x93, 0x62, 0x68, 0x62, 0x93, 0x62, 0x92, 0x62, 0x93, 0x62,  	0x92, 0x62, 0x93, 0x62, 0x92, 0x62, 0x93, 0x62, 0x92, 0x62, 0x93, 0x62, 0x92, 0x62, 0x93, 0x62,  	0x92, 0x62, 0x93, 0x62, 0x92, 0x00, 0x01, 0x01, 0x01, 0x07, 0x01, 0x31, 0x31, 0x31, 0x31, 0x37, @@ -261,6 +267,8 @@ static const unsigned char test_pal8[] = {  	0x00, 0x00, 0xFB, 0xFB, 0xFB, 0x00, 0x00, 0x62, 0x8D, 0x8D, 0x00, 0x00, 0xFB, 0xFB, 0x00, 0x00,  	0xB8, 0xB8, 0xE9, 0xB8, 0xE3, 0xE3, 0x54, 0x54, 0x5A, 0x2A, 0x5B, 0x30, 0x00, 0x00, 0xFB, 0xFB,  	0x00, 0x00, 0x68, 0x38, 0x68, 0x00, 0x00, 0xFB, 0xFB, 0x00, 0x00, 0x45, 0x70, 0x45, 0x76, 0x76, +}; +static const char test_pal8_p5[] = {  	0x76, 0x4C, 0x7D, 0x4C, 0x7D, 0x53, 0x93, 0x68, 0x93, 0x62, 0x93, 0x62, 0x93, 0x62, 0x93, 0x68,  	0x93, 0x62, 0x93, 0x62, 0x93, 0x62, 0x93, 0x68, 0x93, 0x62, 0x93, 0x62, 0x93, 0x62, 0x93, 0x92,  	0x93, 0x62, 0x93, 0x8C, 0x93, 0x00, 0x02, 0x02, 0x02, 0x08, 0x02, 0x32, 0x32, 0x32, 0x32, 0x38, @@ -325,6 +333,8 @@ static const unsigned char test_pal8[] = {  	0xFB, 0xFB, 0x00, 0x00, 0x68, 0x62, 0x93, 0x68, 0x93, 0x8D, 0x00, 0x00, 0xFB, 0xFB, 0x00, 0x00,  	0xBE, 0xB8, 0xE9, 0x00, 0x00, 0xFB, 0xFB, 0x00, 0x00, 0x54, 0x85, 0x5A, 0x00, 0x00, 0xFB, 0xFB,  	0x00, 0x00, 0x92, 0x62, 0x92, 0x00, 0x00, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, +}; +static const char test_pal8_p6[] = {  	0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0x00, 0x00, 0x00, 0x93, 0x62, 0x93, 0x68,  	0x93, 0x68, 0x93, 0x68, 0x93, 0x62, 0x93, 0x92, 0x93, 0x68, 0x93, 0x92, 0x93, 0x62, 0x93, 0x92,  	0x93, 0x92, 0x93, 0x92, 0x93, 0x00, 0x02, 0x03, 0x02, 0x09, 0x02, 0x33, 0x32, 0x33, 0x32, 0x39, @@ -389,6 +399,8 @@ static const unsigned char test_pal8[] = {  	0x00, 0x00, 0x00, 0xFB, 0xFB, 0x00, 0x00, 0x68, 0x99, 0x93, 0x00, 0x00, 0xFB, 0xFB, 0xFB, 0x00,  	0x00, 0xBE, 0xEF, 0xBE, 0xEF, 0xE9, 0xA8, 0x7E, 0x84, 0x7E, 0xAF, 0x00, 0x00, 0xFB, 0xFB, 0xFB,  	0x00, 0x00, 0xBC, 0x8C, 0x92, 0x00, 0x00, 0xFB, 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +static const char test_pal8_p7[] = {  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFB, 0xFB, 0x00, 0x00, 0x68, 0x99, 0x92,  	0x93, 0x68, 0x99, 0x92, 0x93, 0x68, 0x99, 0x92, 0x93, 0x92, 0x99, 0x92, 0x93, 0x92, 0xC3, 0x92,  	0x93, 0x92, 0xC3, 0x92, 0x93, 0x00, 0x03, 0x03, 0x03, 0x09, 0x03, 0x33, 0x33, 0x33, 0x33, 0x39, @@ -453,6 +465,8 @@ static const unsigned char test_pal8[] = {  	0x74, 0x43, 0x74, 0x6E, 0x74, 0x6E, 0x9F, 0x6E, 0x9F, 0x99, 0xCA, 0x99, 0xCA, 0x99, 0xCA, 0xC4,  	0xCA, 0xC4, 0xF5, 0xC4, 0xF5, 0xEF, 0xA8, 0x7E, 0xAE, 0x7E, 0xAF, 0x84, 0xAF, 0x85, 0xB6, 0x85,  	0xB6, 0x8B, 0xBC, 0x8C, 0xBC, 0x8C, 0xC3, 0x92, 0xC3, 0x93, 0xC4, 0x99, 0xC4, 0x99, 0xCA, 0xA0, +}; +static const char test_pal8_p8[] = {  	0xCA, 0xA0, 0xD1, 0xA0, 0xD1, 0xA7, 0x99, 0x93, 0x99, 0x68, 0x99, 0x92, 0x99, 0x68, 0x99, 0x93,  	0x99, 0x92, 0x99, 0x92, 0x99, 0x92, 0xC3, 0x93, 0x99, 0x92, 0xC3, 0x92, 0x99, 0x92, 0xC3, 0x93,  	0xC3, 0x92, 0xC3, 0x92, 0xC3, 0x00, 0x04, 0x04, 0x04, 0x0A, 0x04, 0x34, 0x34, 0x34, 0x34, 0x3A, @@ -517,6 +531,8 @@ static const unsigned char test_pal8[] = {  	0x7A, 0x49, 0x7A, 0x74, 0x74, 0x74, 0xA5, 0x74, 0xA5, 0x9F, 0xD0, 0x9F, 0xCA, 0x9F, 0xD0, 0xCA,  	0xD0, 0xCA, 0xFB, 0xCA, 0xF5, 0xF5, 0xD2, 0xA8, 0xD8, 0xA8, 0xD9, 0xAE, 0xD9, 0xAF, 0xE0, 0xAF,  	0xE0, 0xB5, 0xE6, 0xB6, 0xE6, 0xB6, 0xED, 0xBC, 0xED, 0xBD, 0xEE, 0xC3, 0xEE, 0xC3, 0xF4, 0xCA, +}; +static const char test_pal8_p9[] = {  	0xF4, 0xCA, 0xFB, 0xCA, 0xFB, 0xD1, 0x99, 0x93, 0x99, 0x93, 0x99, 0x93, 0x99, 0x92, 0xC3, 0x93,  	0x99, 0x93, 0xC3, 0x93, 0x99, 0x92, 0xC3, 0x93, 0xC3, 0x93, 0xC3, 0x93, 0xC3, 0x92, 0xC3, 0x93,  	0xC3, 0x93, 0xC3, 0x93, 0xC3, 0x00, 0x04, 0x04, 0x04, 0x0B, 0x04, 0x35, 0x34, 0x35, 0x34, 0x3A, @@ -581,7 +597,15 @@ static const unsigned char test_pal8[] = {  	0x7A, 0x4F, 0x7A, 0x7A, 0x7A, 0x7A, 0xA5, 0x7A, 0xA5, 0xA5, 0xD0, 0xA5, 0xD0, 0xA5, 0xD0, 0xD0,  	0xD0, 0xD0, 0xFB, 0xD0, 0xFB, 0xFB, 0xD2, 0xD2, 0xD8, 0xD2, 0xD9, 0xD8, 0xD9, 0xD9, 0xE0, 0xD9,  	0xE0, 0xDF, 0xE6, 0xE0, 0xE6, 0xE0, 0xED, 0xE6, 0xED, 0xE7, 0xEE, 0xED, 0xEE, 0xED, 0xF4, 0xF4, +}; +static const char test_pal8_p10[] = {  	0xF4, 0xF4, 0xFB, 0xF4, 0xFB, 0xFB, 0xC4, 0x93, 0x99, 0x93, 0xC4, 0x93, 0x99, 0x93, 0xC4, 0x93,  	0xC3, 0x93, 0xC4, 0x93, 0xC3, 0x93, 0xC4, 0x93, 0xC3, 0x93, 0xC4, 0x93, 0xC3, 0x93, 0xC4, 0x93,  	0xC3, 0x93, 0xC4, 0x93, 0xC3, 0x00,  }; + +#ifdef ROMFS_DIRENTRY_HEAD +	static const ROMFS_DIRENTRY test_pal8_dir = { 0, 0, ROMFS_DIRENTRY_HEAD, "test-pal8.bmp", 9254, test_pal8 }; +	#undef ROMFS_DIRENTRY_HEAD +	#define ROMFS_DIRENTRY_HEAD &test_pal8_dir +#endif diff --git a/demos/modules/gdisp/images_animated/gfxconf.h b/demos/modules/gdisp/images_animated/gfxconf.h index cc38ed36..fddda437 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_ROMFS			TRUE +  #endif /* _GFXCONF_H */ diff --git a/demos/modules/gdisp/images_animated/main.c b/demos/modules/gdisp/images_animated/main.c index 9b2b5d2c..039cf584 100644 --- a/demos/modules/gdisp/images_animated/main.c +++ b/demos/modules/gdisp/images_animated/main.c @@ -29,23 +29,20 @@  #include "gfx.h" +/** + * The image file must be stored on a GFILE file-system. + * Use either GFILE_NEED_NATIVEFS or GFILE_NEED_ROMFS (or both). + * + * The ROMFS uses the file "romfs_files.h" to describe the set of files in the ROMFS. + */ +  #define USE_IMAGE_CACHE			FALSE						// Only if you want to get performance at the expense of RAM  #define MY_BG_COLOR				RGB2COLOR(220, 220, 255)	// Pale blue so we can see the transparent parts -#ifdef WIN32 -	#define USE_MEMORY_FILE		TRUE				// Can be true or false for Win32 -#else -	#define USE_MEMORY_FILE		TRUE				// Non-Win32 - use the compiled in image -#endif +static gdispImage myImage;  #define SHOW_ERROR(color)		gdispFillArea(errx, erry, errcx, errcy, color) -#if USE_MEMORY_FILE -	#include "testanim.h" -#endif - -static gdispImage myImage; -  /**   * This demo display the animated gif (either directly from a file or from a   * file encoded in flash. @@ -75,13 +72,8 @@ int main(void) {  	errcy = sheight;  	// Set up IO for our image -#if USE_MEMORY_FILE -	gdispImageSetMemoryReader(&myImage, testanim); -#else -	gdispImageSetFileReader(&myImage, "testanim.gif"); -#endif +	if (!(gdispImageOpenFile(&myImage, "testanim.gif") & GDISP_IMAGE_ERR_UNRECOVERABLE)) { -	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/gdisp/images_animated/romfs_files.h b/demos/modules/gdisp/images_animated/romfs_files.h new file mode 100644 index 00000000..9cd40491 --- /dev/null +++ b/demos/modules/gdisp/images_animated/romfs_files.h @@ -0,0 +1,7 @@ +/** + * This file contains the list of files for the ROMFS. + * + * The files have been converted using... + * 		file2c -dbcs infile outfile + */ +#include "romfs_testanim.h" diff --git a/demos/modules/gdisp/images_animated/testanim.h b/demos/modules/gdisp/images_animated/romfs_testanim.h index ce2ba8c7..3b35b120 100644 --- a/demos/modules/gdisp/images_animated/testanim.h +++ b/demos/modules/gdisp/images_animated/romfs_testanim.h @@ -1,10 +1,10 @@  /**   * This file was generated from "testanim.gif" using...   * - *	file2c -cs testanim.gif testanim.h + *	file2c -bbcs testanim.gif romfs_testanim.h   *   */ -static const unsigned char testanim[] = { +static const char testanim[] = {  	0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x99, 0x00, 0x73, 0x00, 0xE6, 0x46, 0x00, 0x04, 0x07, 0x00,  	0x10, 0x0F, 0x04, 0x1D, 0x1E, 0x29, 0x20, 0x23, 0x08, 0x2E, 0x2C, 0x18, 0x31, 0x32, 0x01, 0x2E,  	0x32, 0x2A, 0x35, 0x37, 0x3B, 0x20, 0x28, 0x42, 0x2B, 0x37, 0x53, 0x3E, 0x41, 0x03, 0x3C, 0x44, @@ -69,6 +69,8 @@ static const unsigned char testanim[] = {  	0x84, 0x61, 0x8E, 0x71, 0x05, 0x63, 0xE6, 0x5C, 0x85, 0x80, 0x80, 0xD7, 0x60, 0xB3, 0x10, 0x70,  	0x40, 0x00, 0xB5, 0x61, 0xA0, 0x40, 0x04, 0x18, 0x30, 0x70, 0x80, 0x01, 0x09, 0x88, 0x35, 0xDA,  	0x82, 0xD1, 0x58, 0xA0, 0xC8, 0x31, 0x79, 0xED, 0x48, 0x61, 0x95, 0x71, 0x5D, 0x68, 0xC0, 0x47, +}; +static const char testanim_p2[] = {  	0x14, 0x52, 0x18, 0xD7, 0x8C, 0x0B, 0x78, 0x80, 0xC1, 0x00, 0x95, 0x65, 0xB8, 0xA5, 0x3E, 0xDF,  	0x08, 0xF3, 0x4F, 0x02, 0xC9, 0x4D, 0x76, 0x90, 0x9D, 0x91, 0xCD, 0xE5, 0x81, 0x07, 0x2D, 0xE4,  	0xE4, 0xD6, 0x9B, 0x23, 0x79, 0x08, 0x82, 0x7A, 0x4A, 0xC5, 0x45, 0x80, 0x04, 0x03, 0x10, 0x40, @@ -133,6 +135,8 @@ static const unsigned char testanim[] = {  	0x8D, 0x34, 0xE6, 0x9E, 0x0E, 0x08, 0x87, 0xEB, 0x62, 0xC5, 0x1D, 0x67, 0x16, 0x00, 0x9A, 0xF3,  	0xA8, 0x00, 0xE9, 0x6E, 0x68, 0xC0, 0xF1, 0x21, 0x85, 0xA1, 0xCF, 0xA3, 0x9E, 0xE9, 0x70, 0xC3,  	0xD0, 0x56, 0xF9, 0xB0, 0x9C, 0xD5, 0x1A, 0x08, 0x86, 0x16, 0xC0, 0x81, 0x0D, 0x38, 0xD1, 0x08, +}; +static const char testanim_p3[] = {  	0x21, 0xC5, 0x2A, 0x86, 0x5C, 0xF7, 0x35, 0x48, 0x74, 0x55, 0x07, 0xBE, 0xD4, 0x4A, 0x14, 0x27,  	0x47, 0x49, 0x84, 0x0D, 0xB3, 0x61, 0xC0, 0x88, 0xD6, 0x5C, 0x4E, 0x51, 0x9F, 0x48, 0xCE, 0x48,  	0x79, 0x85, 0xC0, 0x88, 0x01, 0x62, 0x95, 0xC3, 0x34, 0x0E, 0xC0, 0xA7, 0x35, 0x2C, 0xDD, 0x51, @@ -197,6 +201,8 @@ static const unsigned char testanim[] = {  	0x83, 0xB2, 0x64, 0xAA, 0xF2, 0x4D, 0x4C, 0x67, 0x38, 0x33, 0x61, 0x1F, 0x1D, 0x71, 0x67, 0xAE,  	0x63, 0x4A, 0x86, 0x13, 0x68, 0x7F, 0x01, 0x65, 0xAC, 0x17, 0x5F, 0x40, 0x62, 0x68, 0xBB, 0x66,  	0x77, 0x53, 0xA6, 0x77, 0xA8, 0x20, 0x2B, 0xA5, 0xC3, 0x34, 0xF2, 0x86, 0x0A, 0xEC, 0xD2, 0x24, +}; +static const char testanim_p4[] = {  	0xE0, 0x67, 0x2E, 0x2B, 0x24, 0x0E, 0x6B, 0x93, 0x27, 0x4B, 0x43, 0x0F, 0x5D, 0x26, 0x7C, 0x59,  	0xB7, 0x21, 0x71, 0x41, 0x2F, 0x01, 0x24, 0x7B, 0xBD, 0x55, 0x3E, 0x7E, 0x38, 0x1B, 0x40, 0xE1,  	0x3A, 0x08, 0x70, 0x85, 0x82, 0xE0, 0x73, 0x7A, 0x32, 0x3A, 0x06, 0xC8, 0x6E, 0xD3, 0x73, 0x6B, @@ -261,6 +267,8 @@ static const unsigned char testanim[] = {  	0x32, 0xA0, 0x03, 0x1D, 0x40, 0x03, 0x0B, 0x00, 0x03, 0x71, 0xFA, 0x02, 0x7A, 0x9A, 0x97, 0x40,  	0x40, 0x02, 0x78, 0x69, 0x9B, 0x31, 0x26, 0x03, 0xE2, 0x33, 0x51, 0xF4, 0x30, 0xA5, 0xB3, 0x81,  	0x35, 0x77, 0x42, 0x5D, 0x58, 0x5A, 0x19, 0xE5, 0xEA, 0x66, 0x27, 0x2A, 0x0B, 0x33, 0xE6, 0x6B, +}; +static const char testanim_p5[] = {  	0x0A, 0x89, 0x65, 0xB3, 0x35, 0xA0, 0xA5, 0xE9, 0x93, 0xBC, 0x78, 0x9D, 0xEA, 0xFA, 0x1D, 0xAE,  	0xD3, 0x88, 0x05, 0x1A, 0x00, 0x9E, 0xDA, 0x02, 0x33, 0xE2, 0x01, 0x16, 0xFA, 0x02, 0x42, 0xF0,  	0x02, 0x3E, 0x90, 0x97, 0x3A, 0x80, 0x97, 0xA4, 0xEA, 0x03, 0x24, 0x45, 0x3E, 0xAC, 0x64, 0xAB, @@ -325,6 +333,8 @@ static const unsigned char testanim[] = {  	0xBD, 0xFC, 0x56, 0x2E, 0xE0, 0x28, 0x7B, 0xE9, 0xB4, 0xF5, 0x1A, 0x63, 0xD1, 0x1A, 0x63, 0x5D,  	0x3C, 0xC3, 0x1C, 0xBD, 0xA4, 0x61, 0x79, 0x67, 0xBB, 0xA2, 0x24, 0x71, 0xE5, 0x3B, 0x3B, 0x02,  	0x29, 0x2B, 0x0A, 0xD2, 0xFA, 0x8C, 0x65, 0x6F, 0x8D, 0xCD, 0xEA, 0x06, 0x6F, 0x71, 0x69, 0x4D, +}; +static const char testanim_p6[] = {  	0xDD, 0x5C, 0xB4, 0x61, 0x8A, 0x55, 0x78, 0xF8, 0xD2, 0xDB, 0xD6, 0xC4, 0x2F, 0x90, 0x9E, 0xCC,  	0x5A, 0xAF, 0x35, 0xD0, 0xA6, 0x82, 0xBD, 0x8A, 0xB9, 0x82, 0xA5, 0xF3, 0x59, 0x21, 0xE9, 0x04,  	0x26, 0xA8, 0xA5, 0x23, 0x4A, 0xD1, 0xDA, 0x56, 0x13, 0x01, 0x74, 0x86, 0x0A, 0xD0, 0x10, 0xD9, @@ -389,6 +399,8 @@ static const unsigned char testanim[] = {  	0x11, 0x88, 0x8B, 0x2A, 0x2A, 0xE0, 0xE7, 0x8D, 0x05, 0xE7, 0x90, 0xA3, 0x98, 0xDF, 0x96, 0x90,  	0xDD, 0xA6, 0x82, 0x9D, 0xD4, 0xD0, 0xD1, 0x98, 0x02, 0x06, 0x0C, 0xB0, 0x72, 0xB5, 0x20, 0x96,  	0x87, 0x16, 0x32, 0x6C, 0xE9, 0xD2, 0x25, 0xE3, 0x85, 0x8E, 0x5E, 0x1D, 0x30, 0x6C, 0x08, 0xC6, +}; +static const char testanim_p7[] = {  	0xEA, 0x40, 0x83, 0x03, 0x19, 0x1A, 0x28, 0x1B, 0xD0, 0x60, 0x9A, 0xB2, 0x4D, 0x04, 0x04, 0x39,  	0xF3, 0x64, 0xA9, 0x94, 0xB7, 0x7D, 0xFB, 0xB6, 0xA9, 0x9C, 0x00, 0xCF, 0x54, 0x3E, 0x70, 0x88,  	0x06, 0x88, 0x73, 0x34, 0x80, 0x82, 0x0A, 0x46, 0x88, 0x2A, 0x35, 0x6A, 0xC4, 0xA8, 0x52, 0x24, @@ -453,6 +465,8 @@ static const unsigned char testanim[] = {  	0x01, 0x1F, 0x50, 0x50, 0x18, 0x09, 0x67, 0x9D, 0x03, 0x6B, 0xCF, 0x18, 0x8A, 0x4F, 0x4C, 0x51,  	0x8C, 0x59, 0x80, 0xC0, 0x00, 0x64, 0xAA, 0x8F, 0x04, 0x2C, 0x00, 0x9F, 0x5C, 0x60, 0x60, 0x65,  	0x35, 0x78, 0x48, 0x69, 0x3A, 0xD0, 0x82, 0x91, 0x6D, 0x20, 0x22, 0x4F, 0xEC, 0x00, 0xA8, 0xD4, +}; +static const char testanim_p8[] = {  	0xA2, 0x23, 0x5A, 0xE1, 0x26, 0x47, 0xC9, 0x23, 0x89, 0x63, 0x46, 0x32, 0x80, 0xB2, 0x64, 0x69,  	0x50, 0xF9, 0xE8, 0x4E, 0x27, 0xCA, 0xE1, 0x38, 0x14, 0xDE, 0x30, 0x02, 0xD2, 0xB2, 0x10, 0x00,  	0x70, 0xF7, 0xB3, 0xEA, 0xF0, 0xA5, 0x12, 0x56, 0xB2, 0xC4, 0x8E, 0xB2, 0x36, 0x94, 0x4C, 0xD1, @@ -517,6 +531,8 @@ static const unsigned char testanim[] = {  	0x12, 0x42, 0x3C, 0x6C, 0xF3, 0x51, 0x92, 0x20, 0x33, 0x82, 0x42, 0x68, 0xB4, 0xB0, 0xD5, 0x68,  	0x40, 0xA2, 0x1A, 0x21, 0x87, 0x78, 0x80, 0x11, 0xD4, 0x18, 0xCC, 0x5C, 0x46, 0x80, 0xB4, 0xD0,  	0x90, 0x40, 0xD2, 0x82, 0x1A, 0xDB, 0x2E, 0xCC, 0x33, 0xC2, 0x52, 0xC6, 0x0F, 0x5C, 0x32, 0x6A, +}; +static const char testanim_p9[] = {  	0x0C, 0x01, 0xE2, 0xA3, 0x05, 0x86, 0x0E, 0x92, 0x0E, 0x90, 0x78, 0x61, 0x61, 0xC1, 0x0B, 0x1B,  	0xFE, 0x2F, 0x3C, 0xD1, 0x20, 0x08, 0xE4, 0xE3, 0x8F, 0x17, 0x35, 0x6A, 0xB4, 0x70, 0x61, 0xD5,  	0xC8, 0x82, 0xBF, 0x5C, 0x49, 0xB8, 0xF0, 0xF1, 0x71, 0x88, 0x8C, 0x8F, 0x3E, 0x78, 0x1A, 0x21, @@ -565,3 +581,9 @@ static const unsigned char testanim[] = {  	0xD7, 0x82, 0xFC, 0x87, 0xAE, 0x20, 0x04, 0x10, 0xA0, 0x48, 0xA0, 0x86, 0xCC, 0x05, 0x0C, 0x30,  	0x87, 0x2C, 0x38, 0x88, 0xED, 0x86, 0x04, 0x02, 0x00, 0x3B,  }; + +#ifdef ROMFS_DIRENTRY_HEAD +	static const ROMFS_DIRENTRY testanim_dir = { 0, 0, ROMFS_DIRENTRY_HEAD, "testanim.gif", 8938, testanim }; +	#undef ROMFS_DIRENTRY_HEAD +	#define ROMFS_DIRENTRY_HEAD &testanim_dir +#endif diff --git a/demos/modules/gwin/widgets/gfxconf.h b/demos/modules/gwin/widgets/gfxconf.h index b22af659..60de8d8b 100644 --- a/demos/modules/gwin/widgets/gfxconf.h +++ b/demos/modules/gwin/widgets/gfxconf.h @@ -79,6 +79,11 @@  #define GWIN_NEED_RADIO			TRUE  #define GWIN_NEED_LIST			TRUE +/* Features for the GFILE subsystem. */ +#define GFX_USE_GFILE				TRUE +#define GFILE_NEED_ROMFS			TRUE +//#define GFILE_NEED_NATIVEFS			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..7c06f3bf 100644 --- a/demos/modules/gwin/widgets/main.c +++ b/demos/modules/gwin/widgets/main.c @@ -28,16 +28,19 @@  #include "gfx.h" -// include our chibios logo in a .gif format -#include "image_chibios.h" -#include "image_yesno.h" -  /**   * This demo demonstrates many of the GWIN widgets.   * On the "Radio" tab try playing with the color radio buttons.   * On the "Checkbox" tab try playing with the "Disable All" checkbox.   */ +/** + * The image files must be stored on a GFILE file-system. + * Use either GFILE_NEED_NATIVEFS or GFILE_NEED_ROMFS (or both). + * + * The ROMFS uses the file "romfs_files.h" to describe the set of files in the ROMFS. + */ +  /* Our custom yellow style */  static const GWidgetStyle YellowWidgetStyle = {  	Yellow,							// window background @@ -184,15 +187,14 @@ 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); +	gdispImageOpenFile(&imgYesNo, "image_yesno.gif");  	gwinListItemSetImage(ghList3, 1, &imgYesNo);  	gwinListItemSetImage(ghList3, 3, &imgYesNo);  	// Image  	wi.g.x = ScrWidth-210; wi.g.y = TAB_HEIGHT + 10; wi.g.width = 200; wi.g.height = 200;  	ghImage1 = gwinImageCreate(0, &wi.g); -	gwinImageOpenMemory(ghImage1, image_chibios); +	gwinImageOpenFile(ghImage1, "chibios.bmp");  	gwinImageCache(ghImage1);  	// Console - we apply some special colors before making it visible diff --git a/demos/modules/gwin/widgets/romfs_files.h b/demos/modules/gwin/widgets/romfs_files.h new file mode 100644 index 00000000..b503765d --- /dev/null +++ b/demos/modules/gwin/widgets/romfs_files.h @@ -0,0 +1,8 @@ +/** + * This file contains the list of files for the ROMFS. + * + * The files have been converted using... + * 		file2c -dbcs infile outfile + */ +#include "romfs_img_chibios.h" +#include "romfs_img_yesno.h" diff --git a/demos/modules/gwin/widgets/image_chibios.h b/demos/modules/gwin/widgets/romfs_img_chibios.h index a052395f..14007610 100644 --- a/demos/modules/gwin/widgets/image_chibios.h +++ b/demos/modules/gwin/widgets/romfs_img_chibios.h @@ -1,4 +1,4 @@ -static const unsigned char image_chibios[] = { +static const char image_chibios[] = {  	0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x74, 0x00, 0x74, 0x00, 0xE7, 0xFE, 0x00, 0x08, 0x07, 0x02,  	0x00, 0x0A, 0x03, 0x08, 0x07, 0x0E, 0x05, 0x0D, 0x00, 0x00, 0x11, 0x02, 0x03, 0x16, 0x01, 0x09,  	0x15, 0x00, 0x00, 0x19, 0x03, 0x14, 0x16, 0x06, 0x00, 0x1D, 0x02, 0x07, 0x1C, 0x01, 0x0F, 0x1A, @@ -635,3 +635,9 @@ static const unsigned char image_chibios[] = {  	0xE0, 0x3F, 0x62, 0xE0, 0x07, 0x86, 0xE0, 0x08, 0x96, 0xE0, 0x09, 0xA6, 0xE0, 0x0A, 0xB6, 0xE0,  	0x0B, 0xC6, 0x60, 0xF0, 0x08, 0x08, 0x00, 0x3B,  }; + +#ifdef ROMFS_DIRENTRY_HEAD +	static const ROMFS_DIRENTRY image_chibios_dir = { 0, 0, ROMFS_DIRENTRY_HEAD, "chibios.bmp", 634*16+8, image_chibios }; +	#undef ROMFS_DIRENTRY_HEAD +	#define ROMFS_DIRENTRY_HEAD &image_chibios_dir +#endif diff --git a/demos/modules/gwin/widgets/image_yesno.h b/demos/modules/gwin/widgets/romfs_img_yesno.h index c3150ea7..0559330e 100644 --- a/demos/modules/gwin/widgets/image_yesno.h +++ b/demos/modules/gwin/widgets/romfs_img_yesno.h @@ -1,10 +1,10 @@  /** - * This file was generated from "yesno.gif" using... + * This file was generated from "image_yesno.gif" using...   * - *	file2c -bcs image_yesno.gif image_yesno.h + *	file2c -bbcs image_yesno.gif romfs_img_yesno.h   *   */ -static const unsigned char image_yesno[] = { +static const char image_yesno[] = {  	0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x0B, 0x00, 0x2C, 0x00, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00,  	0x00, 0xC6, 0x00, 0xC6, 0xFF, 0xC6, 0xCE, 0xFF, 0xCE, 0xFF, 0x08, 0x18, 0xFF, 0xCE, 0xDE, 0xFF,  	0xDE, 0xDE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, @@ -19,3 +19,9 @@ static const unsigned char image_yesno[] = {  	0x05, 0x35, 0x81, 0x84, 0x86, 0x83, 0x14, 0x8B, 0x07, 0x86, 0x79, 0x8F, 0x82, 0x8F, 0x8E, 0x17,  	0x8E, 0x62, 0x8B, 0x8C, 0x8A, 0x87, 0x05, 0x11, 0x00, 0x3B,  }; + +#ifdef ROMFS_DIRENTRY_HEAD +	static const ROMFS_DIRENTRY image_yesno_dir = { 0, 0, ROMFS_DIRENTRY_HEAD, "image_yesno.gif", 202, image_yesno }; +	#undef ROMFS_DIRENTRY_HEAD +	#define ROMFS_DIRENTRY_HEAD &image_yesno_dir +#endif @@ -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/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..4ecb2004 --- /dev/null +++ b/src/gfile/inc_nativefs.c @@ -0,0 +1,102 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + *              http://ugfx.org/license.html + */ + +/** + * This file is included by src/gfile/gfile.c + */ + +/******************************************************** + * The native file-system + ********************************************************/ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +//#include <unistd.h> + +static GFILE NativeStdIn; +static GFILE NativeStdOut; +static GFILE NativeStdErr; + +static bool_t NativeDel(const char *fname); +static bool_t NativeExists(const char *fname); +static long int	NativeFilesize(const char *fname); +static bool_t NativeRen(const char *oldname, const char *newname); +static bool_t NativeOpen(GFILE *f, const char *fname); +static void NativeClose(GFILE *f); +static int NativeRead(GFILE *f, void *buf, int size); +static int NativeWrite(GFILE *f, const void *buf, int size); +static bool_t NativeSetpos(GFILE *f, long int pos); +static long int NativeGetsize(GFILE *f); +static bool_t NativeEof(GFILE *f); + +static const GFILEVMT FsNativeVMT = { +	GFILE_CHAINHEAD,									// next +	#if defined(WIN32) || GFX_USE_OS_WIN32 +		GFSFLG_TEXTMODES| +	#else +		GFSFLG_CASESENSITIVE| +	#endif +	GFSFLG_WRITEABLE|GFSFLG_SEEKABLE|GFSFLG_FAST,		// flags +	'N',												// prefix +	NativeDel, NativeExists, NativeFilesize, NativeRen, +	NativeOpen, NativeClose, NativeRead, NativeWrite, +	NativeSetpos, NativeGetsize, NativeEof, +}; +#undef GFILE_CHAINHEAD +#define GFILE_CHAINHEAD		&FsNativeVMT + +static void flags2mode(char *buf, uint16_t flags) { +	if (flags & GFILEFLG_MUSTEXIST) +		*buf = 'r'; +	else if (flags & GFILEFLG_APPEND) +		*buf = 'a'; +	else +		*buf = 'w'; +	buf++; +	if ((flags & (GFILEFLG_READ|GFILEFLG_WRITE)) == (GFILEFLG_READ|GFILEFLG_WRITE)) +		*buf++ = '+'; +	if (flags & GFILEFLG_BINARY) +		*buf++ = 'b'; +	if (flags & GFILEFLG_MUSTNOTEXIST) +		*buf++ = 'x'; +	*buf++ = 0; +} + +static bool_t NativeDel(const char *fname)							{ return remove(fname) ? FALSE : TRUE; } +static void NativeClose(GFILE *f)									{ fclose((FILE *)f->obj); } +static int NativeRead(GFILE *f, void *buf, int size)				{ return fread(buf, 1, size, (FILE *)f->obj); } +static int NativeWrite(GFILE *f, const void *buf, int size)			{ return fwrite(buf, 1, size, (FILE *)f->obj); } +static bool_t NativeSetpos(GFILE *f, long int pos)					{ return fseek((FILE *)f->obj, pos, SEEK_SET) ?  FALSE : TRUE; } +static bool_t NativeEof(GFILE *f)									{ return feof((FILE *)f->obj) ? TRUE : FALSE; } +static bool_t NativeRen(const char *oldname, const char *newname)	{ return rename(oldname, newname) ? FALSE : TRUE; } +static bool_t NativeExists(const char *fname) { +	// We define access this way so we don't have to include <unistd.h> which may +	//	(and does under windows) contain conflicting definitions for types such as uint16_t. +	extern int access(const char *pathname, int mode); +	return access(fname, 0) ? FALSE : TRUE; +} +static long int	NativeFilesize(const char *fname) { +	struct stat st; +	if (stat(fname, &st)) return -1; +	return st.st_size; +} +static bool_t NativeOpen(GFILE *f, const char *fname) { +	FILE *fd; +	char mode[5]; + +	flags2mode(mode, f->flags); +	if (!(fd = fopen(fname, mode))) +		return FALSE; +	f->obj = (void *)fd; +	return TRUE; +} +static long int NativeGetsize(GFILE *f) { +	struct stat st; +	if (fstat(fileno((FILE *)f->obj), &st)) return -1; +	return st.st_size; +} diff --git a/src/gfile/inc_ramfs.c b/src/gfile/inc_ramfs.c new file mode 100644 index 00000000..b0f0d052 --- /dev/null +++ b/src/gfile/inc_ramfs.c @@ -0,0 +1,15 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + *              http://ugfx.org/license.html + */ + +/** + * This file is included by src/gfile/gfile.c + */ + +/******************************************************** + * The RAM file-system VMT + ********************************************************/ +#error "GFILE: RAMFS Not implemented yet" diff --git a/src/gfile/inc_romfs.c b/src/gfile/inc_romfs.c new file mode 100644 index 00000000..49c1b173 --- /dev/null +++ b/src/gfile/inc_romfs.c @@ -0,0 +1,95 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + *              http://ugfx.org/license.html + */ + +/** + * This file is included by src/gfile/gfile.c + */ + +/******************************************************** + * The ROM file-system VMT + ********************************************************/ + +#include <string.h> + +// What directory file formats do we understand +#define ROMFS_DIR_VER_MAX			0x0000 + +// Compression Formats +#define ROMFS_CMP_UNCOMPRESSED		0 + +typedef struct ROMFS_DIRENTRY { +	uint16_t						ver;			// Directory Entry Version +	uint16_t						cmp;			// Compression format +	const struct ROMFS_DIRENTRY *	next;			// The next entry +	const char *					name;			// The file name +	long int						size;			// The file size +	const char *					file;			// The file data +} ROMFS_DIRENTRY; + +#define ROMFS_DIRENTRY_HEAD		0 + +#include "romfs_files.h" + +static const ROMFS_DIRENTRY const *FsROMHead = ROMFS_DIRENTRY_HEAD; + +static bool_t ROMExists(const char *fname); +static long int	ROMFilesize(const char *fname); +static bool_t ROMOpen(GFILE *f, const char *fname); +static void ROMClose(GFILE *f); +static int ROMRead(GFILE *f, void *buf, int size); +static bool_t ROMSetpos(GFILE *f, long int pos); +static long int ROMGetsize(GFILE *f); +static bool_t ROMEof(GFILE *f); + +static const GFILEVMT FsROMVMT = { +	GFILE_CHAINHEAD,									// next +	GFSFLG_CASESENSITIVE|GFSFLG_SEEKABLE|GFSFLG_FAST,	// flags +	'S',												// prefix +	0, ROMExists, ROMFilesize, 0, +	ROMOpen, ROMClose, ROMRead, 0, +	ROMSetpos, ROMGetsize, ROMEof, +}; +#undef GFILE_CHAINHEAD +#define GFILE_CHAINHEAD		&FsROMVMT + +static const ROMFS_DIRENTRY *ROMFindFile(const char *fname) { +	const ROMFS_DIRENTRY *p; + +	for(p = FsROMHead; p; p = p->next) { +		if (p->ver <= ROMFS_DIR_VER_MAX && p->cmp == ROMFS_CMP_UNCOMPRESSED && !strcmp(p->name, fname)) +			break; +	} +	return p; +} +static bool_t ROMExists(const char *fname) { return ROMFindFile(fname) != 0; } +static long int	ROMFilesize(const char *fname) { +	const ROMFS_DIRENTRY *p; + +	if (!(p = ROMFindFile(fname))) return -1; +	return p->size; +} +static bool_t ROMOpen(GFILE *f, const char *fname) { +	const ROMFS_DIRENTRY *p; + +	if (!(p = ROMFindFile(fname))) return FALSE; +	f->obj = (void *)p; +	return TRUE; +} +static void ROMClose(GFILE *f) { (void)f; } +static int ROMRead(GFILE *f, void *buf, int size) { +	const ROMFS_DIRENTRY *p; + +	p = (const ROMFS_DIRENTRY *)f->obj; +	if (p->size - f->pos < size) +		size = p->size - f->pos; +	if (size <= 0)	return 0; +	memcpy(buf, p->file+f->pos, size); +	return size; +} +static bool_t ROMSetpos(GFILE *f, long int pos) { return pos <= ((const ROMFS_DIRENTRY *)f->obj)->size; } +static long int ROMGetsize(GFILE *f) { return ((const ROMFS_DIRENTRY *)f->obj)->size; } +static bool_t ROMEof(GFILE *f) { return f->pos >= ((const ROMFS_DIRENTRY *)f->obj)->size; } 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/tools/file2c/binaries/linux/file2c b/tools/file2c/binaries/linux/file2cBinary files differ index 403c7d8f..9d33e817 100755 --- a/tools/file2c/binaries/linux/file2c +++ b/tools/file2c/binaries/linux/file2c diff --git a/tools/file2c/binaries/windows/file2c.exe b/tools/file2c/binaries/windows/file2c.exeBinary files differ index 333b1138..28e9a329 100644 --- a/tools/file2c/binaries/windows/file2c.exe +++ b/tools/file2c/binaries/windows/file2c.exe 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..f1415fe7 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 = { 0, 0, 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"); | 
