From dd7595a3475407a7fa96a97393bae8c5220e8762 Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Wed, 4 Jan 2012 18:41:13 +1000 Subject: Add the base Enlightenment Foundation Libraries - eina, eet, evas, ecore, embryo, and edje. Note that embryo wont be used, but I'm not sure yet if you can build edje without it. --- .../src/modules/loaders/xpm/evas_image_load_xpm.c | 691 +++++++++++++++++++++ 1 file changed, 691 insertions(+) create mode 100644 libraries/evas/src/modules/loaders/xpm/evas_image_load_xpm.c (limited to 'libraries/evas/src/modules/loaders/xpm/evas_image_load_xpm.c') diff --git a/libraries/evas/src/modules/loaders/xpm/evas_image_load_xpm.c b/libraries/evas/src/modules/loaders/xpm/evas_image_load_xpm.c new file mode 100644 index 0000000..3a04f84 --- /dev/null +++ b/libraries/evas/src/modules/loaders/xpm/evas_image_load_xpm.c @@ -0,0 +1,691 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_EVIL +# include +#endif + +#include "evas_common.h" +#include "evas_private.h" + +static int _evas_loader_xpm_log_dom = -1; + +#ifdef ERR +# undef ERR +#endif +#define ERR(...) EINA_LOG_DOM_ERR(_evas_loader_xpm_log_dom, __VA_ARGS__) + +static Eina_Bool evas_image_load_file_head_xpm(Image_Entry *ie, const char *file, const char *key, int *error) EINA_ARG_NONNULL(1, 2, 4); +static Eina_Bool evas_image_load_file_data_xpm(Image_Entry *ie, const char *file, const char *key, int *error) EINA_ARG_NONNULL(1, 2, 4); + +static Evas_Image_Load_Func evas_image_load_xpm_func = +{ + EINA_FALSE, + evas_image_load_file_head_xpm, + evas_image_load_file_data_xpm, + NULL +}; + +// TODO: REWRITE THIS WITH THREAD SAFE VERSION NOT USING THIS HANDLE!!!! +static FILE *rgb_txt = NULL; + +static void +xpm_parse_color(char *color, int *r, int *g, int *b) +{ + char buf[4096]; + + /* is a #ff00ff like color */ + if (color[0] == '#') + { + int len; + char val[32]; + + len = strlen(color) - 1; + if (len < 96) + { + int i; + + len /= 3; + for (i = 0; i < len; i++) + val[i] = color[1 + i + (0 * len)]; + val[i] = 0; + sscanf(val, "%x", r); + for (i = 0; i < len; i++) + val[i] = color[1 + i + (1 * len)]; + val[i] = 0; + sscanf(val, "%x", g); + for (i = 0; i < len; i++) + val[i] = color[1 + i + (2 * len)]; + val[i] = 0; + sscanf(val, "%x", b); + if (len == 1) + { + *r = (*r << 4) | *r; + *g = (*g << 4) | *g; + *b = (*b << 4) | *b; + } + else if (len > 2) + { + *r >>= (len - 2) * 4; + *g >>= (len - 2) * 4; + *b >>= (len - 2) * 4; + } + } + return; + } + /* look in rgb txt database */ + if (!rgb_txt) rgb_txt = fopen("/usr/lib/X11/rgb.txt", "r"); + if (!rgb_txt) rgb_txt = fopen("/usr/X11/lib/X11/rgb.txt", "r"); + if (!rgb_txt) rgb_txt = fopen("/usr/X11R6/lib/X11/rgb.txt", "r"); + if (!rgb_txt) rgb_txt = fopen("/usr/openwin/lib/X11/rgb.txt", "r"); + if (!rgb_txt) return; + fseek(rgb_txt, 0, SEEK_SET); + while (fgets(buf, sizeof(buf), rgb_txt)) + { + buf[sizeof(buf) - 1] = 0; + if (buf[0] != '!') + { + int rr, gg, bb; + char name[4096]; + + if (sscanf(buf, "%i %i %i %[^\n]", &rr, &gg, &bb, name) == 4) + { + if (!strcasecmp(name, color)) + { + *r = rr; + *g = gg; + *b = bb; + return; + } + } + } + } +} + +static void +xpm_parse_done(void) +{ + if (rgb_txt) fclose(rgb_txt); + rgb_txt = NULL; +} + + +/** FIXME: clean this up and make more efficient **/ +static Eina_Bool +evas_image_load_file_xpm(Image_Entry *ie, const char *file, const char *key __UNUSED__, int load_data, int *error) +{ + DATA32 *ptr, *end; + FILE *f; + + int pc, c, i, j, k, w, h, ncolors, cpp, comment, transp, + quote, context, len, done, r, g, b, backslash, lu1, lu2; + char *line, s[256], tok[128], col[256], *tl; + int lsz = 256; + struct _cmap { + char str[6]; + unsigned char transp; + short r, g, b; + } *cmap; + + short lookup[128 - 32][128 - 32]; + int count, pixels; + + done = 0; +// transp = -1; + transp = 1; + + /* if immediate_load is 1, then dont delay image laoding as below, or */ + /* already data in this image - dont load it again */ + + f = fopen(file, "rb"); + if (!f) + { + xpm_parse_done(); + *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST; + return EINA_FALSE; + } + if (fread(s, 9, 1, f) != 1) + { + fclose(f); + xpm_parse_done(); + *error = EVAS_LOAD_ERROR_CORRUPT_FILE; + return EINA_FALSE; + } + rewind(f); + s[9] = 0; + if (strcmp("/* XPM */", s)) + { + fclose(f); + xpm_parse_done(); + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + return EINA_FALSE; + } + + i = 0; + j = 0; + cmap = NULL; + w = 10; + h = 10; + ptr = NULL; + end = NULL; + c = ' '; + comment = 0; + quote = 0; + context = 0; + pixels = 0; + count = 0; + line = malloc(lsz); + if (!line) + { + fclose(f); + xpm_parse_done(); + *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; + return EINA_FALSE; + } + + backslash = 0; + memset(lookup, 0, sizeof(lookup)); + while (!done) + { + pc = c; + c = fgetc(f); + if (c == EOF) break; + if (!quote) + { + if ((pc == '/') && (c == '*')) + comment = 1; + else if ((pc == '*') && (c == '/') && (comment)) + comment = 0; + } + if (!comment) + { + if ((!quote) && (c == '"')) + { + quote = 1; + i = 0; + } + else if ((quote) && (c == '"')) + { + line[i] = 0; + quote = 0; + if (context == 0) + { + /* Header */ + if (sscanf(line, "%i %i %i %i", &w, &h, &ncolors, &cpp) != 4) + { + ERR("XPM ERROR: XPM file malformed header"); + free(line); + fclose(f); + xpm_parse_done(); + *error = EVAS_LOAD_ERROR_CORRUPT_FILE; + return EINA_FALSE; + } + if ((ncolors > 32766) || (ncolors < 1)) + { + ERR("XPM ERROR: XPM files with colors > 32766 or < 1 not supported"); + free(line); + fclose(f); + xpm_parse_done(); + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + return EINA_FALSE; + } + if ((cpp > 5) || (cpp < 1)) + { + ERR("XPM ERROR: XPM files with characters per pixel > 5 or < 1not supported"); + free(line); + fclose(f); + xpm_parse_done(); + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + return EINA_FALSE; + } + if ((w > IMG_MAX_SIZE) || (w < 1)) + { + ERR("XPM ERROR: Image width > IMG_MAX_SIZE or < 1 pixels for file"); + free(line); + fclose(f); + xpm_parse_done(); + *error = EVAS_LOAD_ERROR_GENERIC; + return EINA_FALSE; + } + if ((h > IMG_MAX_SIZE) || (h < 1)) + { + ERR("XPM ERROR: Image height > IMG_MAX_SIZE or < 1 pixels for file"); + free(line); + fclose(f); + xpm_parse_done(); + *error = EVAS_LOAD_ERROR_GENERIC; + return EINA_FALSE; + } + if (IMG_TOO_BIG(w, h)) + { + ERR("XPM ERROR: Image just too big to ever allocate"); + free(line); + fclose(f); + xpm_parse_done(); + *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; + return EINA_FALSE; + } + + if (!cmap) + { + cmap = malloc(sizeof(struct _cmap) * ncolors); + if (!cmap) + { + free(line); + fclose(f); + xpm_parse_done(); + *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; + return EINA_FALSE; + } + } + ie->w = w; + ie->h = h; + + j = 0; + context++; + } + else if (context == 1) + { + /* Color Table */ + if (j < ncolors) + { + int slen; + int hascolor, iscolor; + + iscolor = 0; + hascolor = 0; + tok[0] = 0; + col[0] = 0; + s[0] = 0; + len = strlen(line); + strncpy(cmap[j].str, line, cpp); + cmap[j].str[cpp] = 0; + for (slen = 0; slen < cpp; slen++) + { + /* fix the ascii of the color string - if its < 32 - just limit to 32 */ + if (cmap[j].str[slen] < 32) cmap[j].str[slen] = 0; + } + cmap[j].r = -1; + cmap[j].transp = 0; + for (k = cpp; k < len; k++) + { + if (line[k] != ' ') + { + s[0] = 0; + sscanf(&line[k], "%255s", s); + slen = strlen(s); + k += slen; + if (!strcmp(s, "c")) iscolor = 1; + if ((!strcmp(s, "m")) || (!strcmp(s, "s")) + || (!strcmp(s, "g4")) || (!strcmp(s, "g")) + || (!strcmp(s, "c")) || (k >= len)) + { + if (k >= len) + { + if (col[0]) + { + if (strlen(col) < (sizeof(col) - 2)) + strcat(col, " "); + else + done = 1; + } + if ((strlen(col) + strlen(s)) < (sizeof(col) - 1)) + strcat(col, s); + } + if (col[0]) + { + if (!strcasecmp(col, "none")) + { + transp = 1; + cmap[j].transp = 1; + cmap[j].r = 0; + cmap[j].g = 0; + cmap[j].b = 0; + } + else + { + if ((((cmap[j].r < 0) || (!strcmp(tok, "c"))) && (!hascolor))) + { + r = g = b = 0; + xpm_parse_color(col, &r, &g, &b); + cmap[j].r = r; + cmap[j].g = g; + cmap[j].b = b; + if (iscolor) hascolor = 1; + } + } + } + strcpy(tok, s); + col[0] = 0; + } + else + { + if (col[0]) + { + if (strlen(col) < ( sizeof(col) - 2)) + strcat(col, " "); + else + done = 1; + } + if ((strlen(col) + strlen(s)) < (sizeof(col) - 1)) + strcat(col, s); + } + } + } + } + j++; + if (j >= ncolors) + { + if (cpp == 1) + { + for (i = 0; i < ncolors; i++) + lookup[(int)cmap[i].str[0] - 32][0] = i; + } + if (cpp == 2) + { + for (i = 0; i < ncolors; i++) + lookup[(int)cmap[i].str[0] - 32][(int)cmap[i].str[1] - 32] = i; + } + context++; + } + + if (transp) ie->flags.alpha = 1; + + if (load_data) + { + evas_cache_image_surface_alloc(ie, w, h); + ptr = evas_cache_image_pixels(ie); + if (!ptr) + { + free(cmap); + free(line); + fclose(f); + xpm_parse_done(); + *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; + return EINA_FALSE; + } + pixels = w * h; + end = ptr + pixels; + } + else + { + free(cmap); + free(line); + fclose(f); + xpm_parse_done(); + *error = EVAS_LOAD_ERROR_NONE; + return EINA_TRUE; + } + } + else + { + /* Image Data */ + i = 0; + if (cpp == 0) + { + /* Chars per pixel = 0? well u never know */ + } + /* it's xpm - don't care about speed too much. still faster + * that most xpm loaders anyway */ + else if (cpp == 1) + { + if (transp) + { + for (i = 0; + ((i < 65536) && (ptr < end) && (line[i])); + i++) + { + lu1 = (int)line[i] - 32; + if (lu1 < 0) continue; + if (cmap[lookup[lu1][0]].transp) + { + r = (unsigned char)cmap[lookup[lu1][0]].r; + g = (unsigned char)cmap[lookup[lu1][0]].g; + b = (unsigned char)cmap[lookup[lu1][0]].b; + *ptr = RGB_JOIN(r, g, b); + ptr++; + count++; + } + else + { + r = (unsigned char)cmap[lookup[lu1][0]].r; + g = (unsigned char)cmap[lookup[lu1][0]].g; + b = (unsigned char)cmap[lookup[lu1][0]].b; + *ptr = ARGB_JOIN(0xff, r, g, b); + ptr++; + count++; + } + } + } + else + { + for (i = 0; + ((i < 65536) && (ptr < end) && (line[i])); + i++) + { + lu1 = (int)line[i] - 32; + if (lu1 < 0) continue; + r = (unsigned char)cmap[lookup[lu1][0]].r; + g = (unsigned char)cmap[lookup[lu1][0]].g; + b = (unsigned char)cmap[lookup[lu1][0]].b; + *ptr = ARGB_JOIN(0xff, r, g, b); + ptr++; + count++; + } + } + } + else if (cpp == 2) + { + if (transp) + { + for (i = 0; + ((i < 65536) && (ptr < end) && (line[i])); + i++) + { + lu1 = (int)line[i] - 32; + i++; + lu2 = (int)line[i] - 32; + if (lu1 < 0) continue; + if (lu2 < 0) continue; + if (cmap[lookup[lu1][lu2]].transp) + { + r = (unsigned char)cmap[lookup[lu1][lu2]].r; + g = (unsigned char)cmap[lookup[lu1][lu2]].g; + b = (unsigned char)cmap[lookup[lu1][lu2]].b; + *ptr = RGB_JOIN(r, g, b); + ptr++; + count++; + } + else + { + r = (unsigned char)cmap[lookup[lu1][lu2]].r; + g = (unsigned char)cmap[lookup[lu1][lu2]].g; + b = (unsigned char)cmap[lookup[lu1][lu2]].b; + *ptr = ARGB_JOIN(0xff, r, g, b); + ptr++; + count++; + } + } + } + else + { + for (i = 0; + ((i < 65536) && (ptr < end) && (line[i])); + i++) + { + lu1 = (int)line[i] - 32; + i++; + lu2 = (int)line[i] - 32; + if (lu1 < 0) continue; + if (lu2 < 0) continue; + r = (unsigned char)cmap[lookup[lu1][lu2]].r; + g = (unsigned char)cmap[lookup[lu1][lu2]].g; + b = (unsigned char)cmap[lookup[lu1][lu2]].b; + *ptr = ARGB_JOIN(0xff, r, g, b); + ptr++; + count++; + } + } + } + else + { + if (transp) + { + for (i = 0; + ((i < 65536) && (ptr < end) && (line[i])); + i++) + { + for (j = 0; j < cpp; j++, i++) + { + col[j] = line[i]; + if (col[j] < 32) col[j] = 32; + } + col[j] = 0; + i--; + for (j = 0; j < ncolors; j++) + { + if (!strcmp(col, cmap[j].str)) + { + if (cmap[j].transp) + { + r = (unsigned char)cmap[j].r; + g = (unsigned char)cmap[j].g; + b = (unsigned char)cmap[j].b; + *ptr = RGB_JOIN(r, g, b); + ptr++; + count++; + } + else + { + r = (unsigned char)cmap[j].r; + g = (unsigned char)cmap[j].g; + b = (unsigned char)cmap[j].b; + *ptr = ARGB_JOIN(0xff, r, g, b); + ptr++; + count++; + } + break; + } + } + } + } + else + { + for (i = 0; + ((i < 65536) && (ptr < end) && (line[i])); + i++) + { + for (j = 0; j < cpp; j++, i++) + { + col[j] = line[i]; + } + col[j] = 0; + i--; + for (j = 0; j < ncolors; j++) + { + if (!strcmp(col, cmap[j].str)) + { + r = (unsigned char)cmap[j].r; + g = (unsigned char)cmap[j].g; + b = (unsigned char)cmap[j].b; + *ptr = ARGB_JOIN(0xff, r, g, b); + ptr++; + count++; + break; + } + } + } + } + } + } + } + } + /* Scan in line from XPM file */ + if ((!comment) && (quote) && (c != '"')) + { + if (c < 32) c = 32; + else if (c > 127) c = 127; + if (c =='\\') + { + if (++backslash < 2) + line[i++] = c; + else + backslash = 0; + } + else + { + backslash = 0; + line[i++] = c; + } + } + if (i >= lsz) + { + lsz += 256; + tl = realloc(line, lsz); + if (!tl) break; + line = tl; + } + if (((ptr) && ((ptr - evas_cache_image_pixels(ie)) >= (w * h * (int)sizeof(DATA32)))) || + ((context > 1) && (count >= pixels))) + break; + } + + free(cmap); + free(line); + fclose(f); + + xpm_parse_done(); + *error = EVAS_LOAD_ERROR_NONE; + return EINA_TRUE; +} + +static Eina_Bool +evas_image_load_file_head_xpm(Image_Entry *ie, const char *file, const char *key, int *error) +{ + return evas_image_load_file_xpm(ie, file, key, 0, error); +} + +static Eina_Bool +evas_image_load_file_data_xpm(Image_Entry *ie, const char *file, const char *key, int *error) +{ + return evas_image_load_file_xpm(ie, file, key, 1, error); +} + +static int +module_open(Evas_Module *em) +{ + if (!em) return 0; + _evas_loader_xpm_log_dom = eina_log_domain_register + ("evas-xpm", EVAS_DEFAULT_LOG_COLOR); + if (_evas_loader_xpm_log_dom < 0) + { + EINA_LOG_ERR("Can not create a module log domain."); + return 0; + } + em->functions = (void *)(&evas_image_load_xpm_func); + return 1; +} + +static void +module_close(Evas_Module *em __UNUSED__) +{ + eina_log_domain_unregister(_evas_loader_xpm_log_dom); +} + +static Evas_Module_Api evas_modapi = +{ + EVAS_MODULE_API_VERSION, + "xpm", + "none", + { + module_open, + module_close + } +}; + +EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, xpm); + +#ifndef EVAS_STATIC_BUILD_XPM +EVAS_EINA_MODULE_DEFINE(image_loader, xpm); +#endif -- cgit v1.1