/* Load a XPM type image from stream */ static bool xpm_create(Fl_IO *xpm_io, uint8 *&data, Fl_PixelFormat &fmt, int &w, int &h, const char **stream) { bool mem = (stream!=0); char line[4096]; char *here; int index; int x, y; int ncolors, cpp; int pixels_len=0; char *pixels = NULL; int indexed; uint8 *dst; struct color_hash *colors; Fl_Colormap_Color *im_colors = NULL; char *keystrings, *nextkey; char *error = NULL; /* Skip to the first string, which describes the image */ if(mem) { here = (char *)stream[0]; } else { do { here = xpm_gets(xpm_io, line, sizeof(line)); if(!here) { fputs("XPM: Premature end of data 1", stderr); return false; } here = skipspace(here); } while(*here != '"'); } /* * The header string of an XPMv3 image has the format * * <width> <height> <ncolors> <cpp> [ <hotspot_x> <hotspot_y> ] * * where the hotspot coords are intended for mouse cursors. * Right now we don't use the hotspots but it should be handled * one day. */ int offset = mem ? 0 : 1; if(sscanf(here + offset, "%d %d %d %d", &w, &h, &ncolors, &cpp) != 4 || w <= 0 || h <= 0 || ncolors <= 0 || cpp <= 0) { fputs("XPM: Invalid format description", stderr); return false; } keystrings = (char *)malloc(ncolors * cpp); if(!keystrings) { fputs("XPM: Out of memory", stderr); } nextkey = keystrings; /* Create the new surface */ if(ncolors <= 256) { indexed = 1; fmt.realloc(8, 0,0,0,0); im_colors = fmt.palette->colors; fmt.palette->ncolors = ncolors; } else { indexed = 0; //fmt.realloc(32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0); fmt.realloc(32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0); } int pitch = Fl_Renderer::calc_pitch(fmt.bytespp, w); data = (uint8*)malloc(h*pitch*sizeof(uint8)); /* Read the colors */ colors = create_colorhash(ncolors); if(!colors) { error = "XPM: Out of memory"; goto done; } for(index = 0; index < ncolors; ++index ) { char *key; int len; if(mem) { strncpy(line, stream[index+1], sizeof(line)); here = line; } else { do { here = xpm_gets(xpm_io, line, sizeof(line)); if(!here) { error = "XPM: Premature end of data 2"; goto done; } here = skipspace(here); } while(*here != '"'); ++here; } len = strlen(here); if(len < cpp + 7) continue; /* cannot be a valid line */ key = here; key[cpp] = '\0'; here += cpp + 1; /* parse a colour definition */ for(;;) { char nametype; char *colname; char delim; uint32 rgb; here = skipspace(here); nametype = *here; here = skipnonspace(here); here = skipspace(here); colname = here; if(mem) { while(*here && !isspace((unsigned char)*here)) here++; } else { while(*here && !isspace((unsigned char)*here) && *here != '"') here++; if(!*here) { error = "XPM: Color parse error"; goto done; } } if(nametype == 's') continue; /* skip symbolic colour names */ delim = *here; *here = '\0'; if(delim) here++; if(!color_to_rgb(colname, &rgb)) { continue; } if(rgb == 0x00000000) { if(!indexed) { if(!fmt.Amask) { fmt.realloc(32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF); fmt.masktype = FL_MASK_ALPHA; } rgb = 0xffffff00; } else { fmt.masktype = FL_MASK_COLORKEY; fmt.colorkey = rgb; } } memcpy(nextkey, key, cpp); if(indexed) { Fl_Colormap_Color *c = im_colors + index; c->r = rgb >> 24; c->g = rgb >> 16; c->b = rgb >> 8; c->a = 0; if(rgb == 0x00000000) c->a = 1; add_colorhash(colors, nextkey, cpp, index); } else add_colorhash(colors, nextkey, cpp, rgb); nextkey += cpp; break; } }
/* read XPM from either array or RWops */ static SDL_Surface *load_xpm(char **xpm, SDL_RWops *src) { int start = 0; SDL_Surface *image = NULL; int index; int x, y; int w, h, ncolors, cpp; int indexed; Uint8 *dst; struct color_hash *colors = NULL; SDL_Color *im_colors = NULL; char *keystrings = NULL, *nextkey; char *line; char ***xpmlines = NULL; int pixels_len; error = NULL; linebuf = NULL; buflen = 0; if ( src ) start = SDL_RWtell(src); if(xpm) xpmlines = &xpm; line = get_next_line(xpmlines, src, 0); if(!line) goto done; /* * The header string of an XPMv3 image has the format * * <width> <height> <ncolors> <cpp> [ <hotspot_x> <hotspot_y> ] * * where the hotspot coords are intended for mouse cursors. * Right now we don't use the hotspots but it should be handled * one day. */ if(sscanf(line, "%d %d %d %d", &w, &h, &ncolors, &cpp) != 4 || w <= 0 || h <= 0 || ncolors <= 0 || cpp <= 0) { error = "Invalid format description"; goto done; } keystrings = malloc(ncolors * cpp); if(!keystrings) { error = "Out of memory"; goto done; } nextkey = keystrings; /* Create the new surface */ if(ncolors <= 256) { indexed = 1; image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8, 0, 0, 0, 0); im_colors = image->format->palette->colors; image->format->palette->ncolors = ncolors; } else { indexed = 0; image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, 0xff0000, 0x00ff00, 0x0000ff, 0); } if(!image) { /* Hmm, some SDL error (out of memory?) */ goto done; } /* Read the colors */ colors = create_colorhash(ncolors); if (!colors) { error = "Out of memory"; goto done; } for(index = 0; index < ncolors; ++index ) { char *p; line = get_next_line(xpmlines, src, 0); if(!line) goto done; p = line + cpp + 1; /* parse a colour definition */ for(;;) { char nametype; char *colname; Uint32 rgb, pixel; SKIPSPACE(p); if(!*p) { error = "colour parse error"; goto done; } nametype = *p; SKIPNONSPACE(p); SKIPSPACE(p); colname = p; SKIPNONSPACE(p); if(nametype == 's') continue; /* skip symbolic colour names */ if(!color_to_rgb(colname, p - colname, &rgb)) continue; memcpy(nextkey, line, cpp); if(indexed) { SDL_Color *c = im_colors + index; c->r = (Uint8)(rgb >> 16); c->g = (Uint8)(rgb >> 8); c->b = (Uint8)(rgb); pixel = index; } else pixel = rgb; add_colorhash(colors, nextkey, cpp, pixel); nextkey += cpp; if(rgb == 0xffffffff) SDL_SetColorKey(image, SDL_SRCCOLORKEY, pixel); break; } }
/* Load a XPM type image from an SDL datasource */ SDL_Surface *IMG_LoadXPM_RW(SDL_RWops *src) { SDL_Surface *image; char line[1024]; char *here; int index; int x, y; int w, h, ncolors, cpp; int pixels_len; char *pixels = NULL; int indexed; Uint8 *dst; struct color_hash *colors; SDL_Color *im_colors = NULL; char *keystrings, *nextkey; char *error = NULL; /* Skip to the first string, which describes the image */ do { here = SDL_RWgets(line, sizeof(line), src); if ( !here ) { IMG_SetError("Premature end of data"); return(NULL); } here = skipspace(here); } while(*here != '"'); /* * The header string of an XPMv3 image has the format * * <width> <height> <ncolors> <cpp> [ <hotspot_x> <hotspot_y> ] * * where the hotspot coords are intended for mouse cursors. * Right now we don't use the hotspots but it should be handled * one day. */ if(sscanf(here + 1, "%d %d %d %d", &w, &h, &ncolors, &cpp) != 4 || w <= 0 || h <= 0 || ncolors <= 0 || cpp <= 0) { IMG_SetError("Invalid format description"); return(NULL); } keystrings = malloc(ncolors * cpp); if(!keystrings) { IMG_SetError("Out of memory"); free(pixels); return NULL; } nextkey = keystrings; /* Create the new surface */ if(ncolors <= 256) { indexed = 1; image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8, 0, 0, 0, 0); im_colors = image->format->palette->colors; image->format->palette->ncolors = ncolors; } else { indexed = 0; image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, 0xff0000, 0x00ff00, 0x0000ff, 0); } if(!image) { /* Hmm, some SDL error (out of memory?) */ free(pixels); return(NULL); } /* Read the colors */ colors = create_colorhash(ncolors); if ( ! colors ) { error = "Out of memory"; goto done; } for(index = 0; index < ncolors; ++index ) { char *key; int len; do { here = SDL_RWgets(line, sizeof(line), src); if(!here) { error = "Premature end of data"; goto done; } here = skipspace(here); } while(*here != '"'); ++here; len = strlen(here); if(len < cpp + 7) continue; /* cannot be a valid line */ key = here; key[cpp] = '\0'; here += cpp + 1; /* parse a colour definition */ for(;;) { char nametype; char *colname; char delim; Uint32 rgb; here = skipspace(here); nametype = *here; here = skipnonspace(here); here = skipspace(here); colname = here; while(*here && !isspace((unsigned char)*here) && *here != '"') here++; if(!*here) { error = "color parse error"; goto done; } if(nametype == 's') continue; /* skip symbolic colour names */ delim = *here; *here = '\0'; if(delim) here++; if(!color_to_rgb(colname, &rgb)) continue; memcpy(nextkey, key, cpp); if(indexed) { SDL_Color *c = im_colors + index; c->r = rgb >> 16; c->g = rgb >> 8; c->b = rgb; add_colorhash(colors, nextkey, cpp, index); } else add_colorhash(colors, nextkey, cpp, rgb); nextkey += cpp; if(rgb == 0xffffffff) SDL_SetColorKey(image, SDL_SRCCOLORKEY, indexed ? index : rgb); break; } }