You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

371 lines
7.9 KiB

#include <config.h>
#include <setjmp.h>
#include "gdk_imlib.h"
#define id _gdk_imlib_data
#include "gdk_imlib_private.h"
unsigned char *
loader_xpm(FILE *file, int *w, int *h, int *t)
{
unsigned char *data, *ptr, *end;
int pc, c, i, j, k, ncolors, cpp, comment, transp, quote,
context, len, done;
char *line, s[256], tok[128], col[256];
XColor xcol;
int lsz = 256;
struct _cmap
{
unsigned char str[6];
unsigned char transp;
short r, g, b;
}
*cmap;
short lookup[128 - 32][128 - 32];
transp = 0;
done = 0;
if (!file)
return NULL;
*w = 10;
*h = 10;
ptr = NULL;
end = NULL;
data = NULL;
c = ' ';
comment = 0;
quote = 0;
context = 0;
i = j = 0;
cmap = NULL;
line = malloc(lsz);
while (!done)
{
pc = c;
c = fgetc(file);
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 */
sscanf(line, "%i %i %i %i", w, h, &ncolors, &cpp);
if (ncolors > 32766)
{
fprintf(stderr, "gdk_imlib ERROR: XPM files wth colors > 32766 not supported\n");
free(line);
return NULL;
}
if (cpp > 5)
{
fprintf(stderr, "gdk_imlib ERROR: XPM files with characters per pixel > 5 not supported\n");
free(line);
return NULL;
}
if (*w > 32767)
{
fprintf(stderr, "gdk_imlib ERROR: Image width > 32767 pixels for file\n");
free(line);
return NULL;
}
if (*h > 32767)
{
fprintf(stderr, "gdk_imlib ERROR: Image height > 32767 pixels for file\n");
free(line);
return NULL;
}
cmap = malloc(sizeof(struct _cmap) * ncolors);
if (!cmap)
{
free(line);
return NULL;
}
data = _gdk_malloc_image(*w, *h);
if (!data)
{
free(line);
free(cmap);
return NULL;
}
ptr = data;
end = ptr + (*w ** h * 3);
j = 0;
context++;
}
else if (context == 1)
{
/* Color Table */
if (j < ncolors)
{
int slen;
int hascolor, iscolor;
hascolor = 0;
iscolor = 0;
tok[0] = 0;
col[0] = 0;
s[0] = 0;
len = strlen(line);
strncpy(cmap[j].str, line, cpp);
cmap[j].str[cpp] = 0;
cmap[j].r = -1;
cmap[j].transp = 0;
for (k = cpp; k < len; k++)
{
if (line[k] != ' ')
{
s[0] = 0;
sscanf(&line[k], "%256s", 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])
strcat(col, " ");
if (strlen(col) + strlen(s) < sizeof(col))
strcat(col, s);
}
if (col[0])
{
if (!strcasecmp(col, "none"))
{
transp = 1;
cmap[j].transp = 1;
}
else
{
if (((cmap[j].r < 0) ||
(!strcmp(tok, "c"))) &&
(!hascolor))
{
XParseColor(id->x.disp,
id->x.root_cmap,
col, &xcol);
cmap[j].r = xcol.red >> 8;
cmap[j].g = xcol.green >> 8;
cmap[j].b = xcol.blue >> 8;
if ((cmap[j].r == 255) &&
(cmap[j].g == 0) &&
(cmap[j].b == 255))
cmap[j].r = 254;
if (iscolor)
hascolor = 1;
}
}
}
strcpy(tok, s);
col[0] = 0;
}
else
{
if (col[0])
strcat(col, " ");
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;
else if (cpp == 2)
for (i = 0; i < ncolors; i++)
lookup[(int)cmap[i].str[0] - 32][(int)cmap[i].str[1] - 32] = i;
context++;
}
}
else
{
/* Image Data */
i = 0;
if (cpp == 0)
{
/* Chars per pixel = 0? well u never know */
}
if (cpp == 1)
{
if (transp)
{
for (i = 0; ((i < 65536) && (ptr < end) && (line[i])); i++)
{
col[0] = line[i];
if (cmap[lookup[(int)col[0] - 32][0]].transp)
{
*ptr++ = 255;
*ptr++ = 0;
*ptr++ = 255;
}
else
{
*ptr++ = (unsigned char)cmap[lookup[(int)col[0] - 32][0]].r;
*ptr++ = (unsigned char)cmap[lookup[(int)col[0] - 32][0]].g;
*ptr++ = (unsigned char)cmap[lookup[(int)col[0] - 32][0]].b;
}
}
}
else
{
for (i = 0; ((i < 65536) && (ptr < end) && (line[i])); i++)
{
col[0] = line[i];
*ptr++ = (unsigned char)cmap[lookup[(int)col[0] - 32][0]].r;
*ptr++ = (unsigned char)cmap[lookup[(int)col[0] - 32][0]].g;
*ptr++ = (unsigned char)cmap[lookup[(int)col[0] - 32][0]].b;
}
}
}
else if (cpp == 2)
{
if (transp)
{
for (i = 0; ((i < 65536) && (ptr < end) && (line[i])); i++)
{
col[0] = line[i++];
col[1] = line[i];
if (cmap[lookup[(int)col[0] - 32][(int)col[1] - 32]].transp)
{
*ptr++ = 255;
*ptr++ = 0;
*ptr++ = 255;
}
else
{
*ptr++ = (unsigned char)cmap[lookup[(int)col[0] - 32][(int)col[1] - 32]].r;
*ptr++ = (unsigned char)cmap[lookup[(int)col[0] - 32][(int)col[1] - 32]].g;
*ptr++ = (unsigned char)cmap[lookup[(int)col[0] - 32][(int)col[1] - 32]].b;
}
}
}
else
{
for (i = 0; ((i < 65536) && (ptr < end) && (line[i])); i++)
{
col[0] = line[i++];
col[1] = line[i];
*ptr++ = (unsigned char)cmap[lookup[(int)col[0] - 32][(int)col[1] - 32]].r;
*ptr++ = (unsigned char)cmap[lookup[(int)col[0] - 32][(int)col[1] - 32]].g;
*ptr++ = (unsigned char)cmap[lookup[(int)col[0] - 32][(int)col[1] - 32]].b;
}
}
}
else
{
if (transp)
{
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))
{
if (cmap[j].transp)
{
*ptr++ = 255;
*ptr++ = 0;
*ptr++ = 255;
}
else
{
*ptr++ = (unsigned char)cmap[j].r;
*ptr++ = (unsigned char)cmap[j].g;
*ptr++ = (unsigned char)cmap[j].b;
}
j = ncolors;
}
}
}
}
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))
{
*ptr++ = (unsigned char)cmap[j].r;
*ptr++ = (unsigned char)cmap[j].g;
*ptr++ = (unsigned char)cmap[j].b;
j = ncolors;
}
}
}
}
}
}
}
}
/* Scan in line from XPM file*/
if ((!comment) && (quote) && (c != '"'))
{
if (c < 32)
c = 32;
else if (c > 127)
c = 127;
line[i++] = c;
}
if (i >= lsz)
{
lsz += 256;
line = realloc(line, lsz);
if(line == NULL)
{
free(cmap);
return NULL;
}
}
if ((ptr) && ((ptr - data) >= *w ** h * 3))
done = 1;
}
if (transp)
*t = 1;
else
*t = 0;
free(cmap);
free(line);
return data;
}