#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "XpmI.h"
LFUNC(CreateColors, int, (char **dataptr, unsigned int *data_size,
XpmColor *colors, unsigned int ncolors,
unsigned int cpp));
LFUNC(CreatePixels, void, (char **dataptr, unsigned int data_size,
unsigned int width,
unsigned int height, unsigned int cpp,
unsigned int *pixels, XpmColor *colors));
LFUNC(CountExtensions, void, (XpmExtension *ext, unsigned int num,
unsigned int *ext_size,
unsigned int *ext_nlines));
LFUNC(CreateExtensions, void, (char **dataptr, unsigned int data_size,
unsigned int offset,
XpmExtension *ext, unsigned int num,
unsigned int ext_nlines));
int
XpmCreateDataFromImage(display, data_return, image, shapeimage, attributes)
Display *display;
char ***data_return;
XImage *image;
XImage *shapeimage;
XpmAttributes *attributes;
{
XpmImage xpmimage;
XpmInfo info;
int ErrorStatus;
if (data_return)
*data_return = NULL;
ErrorStatus = XpmCreateXpmImageFromImage(display, image, shapeimage,
&xpmimage, attributes);
if (ErrorStatus != XpmSuccess)
return (ErrorStatus);
if (attributes) {
xpmSetInfo(&info, attributes);
ErrorStatus = XpmCreateDataFromXpmImage(data_return, &xpmimage, &info);
} else
ErrorStatus = XpmCreateDataFromXpmImage(data_return, &xpmimage, NULL);
XpmFreeXpmImage(&xpmimage);
return (ErrorStatus);
}
#undef RETURN
#define RETURN(status) \
do \
{ \
ErrorStatus = status; \
goto exit; \
} while(0)
int
XpmCreateDataFromXpmImage(data_return, image, info)
char ***data_return;
XpmImage *image;
XpmInfo *info;
{
int ErrorStatus;
char buf[BUFSIZ];
char **header = NULL, **data, **sptr, **sptr2, *s;
unsigned int header_size, header_nlines;
unsigned int data_size, data_nlines;
unsigned int extensions = 0, ext_size = 0, ext_nlines = 0;
unsigned int offset, l, n;
*data_return = NULL;
extensions = info && (info->valuemask & XpmExtensions)
&& info->nextensions;
if (extensions)
CountExtensions(info->extensions, info->nextensions,
&ext_size, &ext_nlines);
header_nlines = 1 + image->ncolors;
if(header_nlines <= image->ncolors ||
header_nlines >= UINT_MAX / sizeof(char *))
return(XpmNoMemory);
header_size = sizeof(char *) * header_nlines;
if (header_size >= UINT_MAX / sizeof(char *))
return (XpmNoMemory);
header = (char **) XpmCalloc(header_size, sizeof(char *));
if (!header)
return (XpmNoMemory);
s = buf;
#ifndef VOID_SPRINTF
s +=
#endif
sprintf(s, "%d %d %d %d", image->width, image->height,
image->ncolors, image->cpp);
#ifdef VOID_SPRINTF
s += strlen(s);
#endif
if (info && (info->valuemask & XpmHotspot)) {
#ifndef VOID_SPRINTF
s +=
#endif
sprintf(s, " %d %d", info->x_hotspot, info->y_hotspot);
#ifdef VOID_SPRINTF
s += strlen(s);
#endif
}
if (extensions) {
strcpy(s, " XPMEXT");
s += 7;
}
l = s - buf + 1;
*header = (char *) XpmMalloc(l);
if (!*header)
RETURN(XpmNoMemory);
header_size += l;
strcpy(*header, buf);
ErrorStatus = CreateColors(header + 1, &header_size,
image->colorTable, image->ncolors, image->cpp);
if (ErrorStatus != XpmSuccess)
RETURN(ErrorStatus);
offset = image->width * image->cpp + 1;
if(offset <= image->width || offset <= image->cpp)
RETURN(XpmNoMemory);
if( (image->height + ext_nlines) >= UINT_MAX / sizeof(char *))
RETURN(XpmNoMemory);
data_size = (image->height + ext_nlines) * sizeof(char *);
if (image->height > UINT_MAX / offset ||
image->height * offset > UINT_MAX - data_size)
RETURN(XpmNoMemory);
data_size += image->height * offset;
if( (header_size + ext_size) >= (UINT_MAX - data_size) )
RETURN(XpmNoMemory);
data_size += header_size + ext_size;
data = (char **) XpmMalloc(data_size);
if (!data)
RETURN(XpmNoMemory);
data_nlines = header_nlines + image->height + ext_nlines;
*data = (char *) (data + data_nlines);
n = image->ncolors;
for (l = 0, sptr = data, sptr2 = header; l <= n && sptr && sptr2; l++, sptr++, sptr2++) {
strcpy(*sptr, *sptr2);
*(sptr + 1) = *sptr + strlen(*sptr2) + 1;
}
data[header_nlines] = (char *) data + header_size
+ (image->height + ext_nlines) * sizeof(char *);
CreatePixels(data + header_nlines, data_size-header_nlines, image->width, image->height,
image->cpp, image->data, image->colorTable);
if (extensions)
CreateExtensions(data + header_nlines + image->height - 1,
data_size - header_nlines - image->height + 1, offset,
info->extensions, info->nextensions,
ext_nlines);
*data_return = data;
ErrorStatus = XpmSuccess;
exit:
if (header) {
for (l = 0; l < header_nlines; l++)
if (header[l])
XpmFree(header[l]);
XpmFree(header);
}
return(ErrorStatus);
}
static int
CreateColors(dataptr, data_size, colors, ncolors, cpp)
char **dataptr;
unsigned int *data_size;
XpmColor *colors;
unsigned int ncolors;
unsigned int cpp;
{
char buf[BUFSIZ];
unsigned int a, key, l;
char *s, *s2;
char **defaults;
for (a = 0; a < ncolors; a++, colors++, dataptr++) {
defaults = (char **) colors;
if(sizeof(buf) <= cpp)
return(XpmNoMemory);
strncpy(buf, *defaults++, cpp);
s = buf + cpp;
if(sizeof(buf) <= (s-buf))
return XpmNoMemory;
for (key = 1; key <= NKEYS; key++, defaults++) {
if ((s2 = *defaults)) {
#ifndef VOID_SPRINTF
s +=
#endif
snprintf(s, sizeof(buf)-(s-buf), "\t%s %s", xpmColorKeys[key - 1], s2);
#ifdef VOID_SPRINTF
s += strlen(s);
#endif
if(sizeof(buf) < (s-buf))
return XpmNoMemory;
}
}
l = s - buf + 1;
s = (char *) XpmMalloc(l);
if (!s)
return (XpmNoMemory);
*data_size += l;
*dataptr = strcpy(s, buf);
}
return (XpmSuccess);
}
static void
CreatePixels(dataptr, data_size, width, height, cpp, pixels, colors)
char **dataptr;
unsigned int data_size;
unsigned int width;
unsigned int height;
unsigned int cpp;
unsigned int *pixels;
XpmColor *colors;
{
char *s;
unsigned int x, y, h, offset;
if(height <= 1)
return;
h = height - 1;
offset = width * cpp + 1;
if(offset <= width || offset <= cpp)
return;
for (y = 0; y < h; y++, dataptr++) {
s = *dataptr;
for (x = 0; x < width; x++, pixels++) {
if(cpp > (data_size - (s - *dataptr)))
return;
strncpy(s, colors[*pixels].string, cpp);
s += cpp;
}
*s = '\0';
if(offset > data_size)
return;
*(dataptr + 1) = *dataptr + offset;
}
s = *dataptr;
for (x = 0; x < width; x++, pixels++) {
if(cpp > data_size - (s - *dataptr))
return;
strncpy(s, colors[*pixels].string, cpp);
s += cpp;
}
*s = '\0';
}
static void
CountExtensions(ext, num, ext_size, ext_nlines)
XpmExtension *ext;
unsigned int num;
unsigned int *ext_size;
unsigned int *ext_nlines;
{
unsigned int x, y, a, size, nlines;
char **line;
size = 0;
nlines = 0;
for (x = 0; x < num; x++, ext++) {
nlines += ext->nlines + 1;
size += strlen(ext->name) + 8;
a = ext->nlines;
for (y = 0, line = ext->lines; y < a; y++, line++)
size += strlen(*line) + 1;
}
*ext_size = size + 10;
*ext_nlines = nlines + 1;
}
static void
CreateExtensions(dataptr, data_size, offset, ext, num, ext_nlines)
char **dataptr;
unsigned int data_size;
unsigned int offset;
XpmExtension *ext;
unsigned int num;
unsigned int ext_nlines;
{
unsigned int x, y, a, b;
char **line;
*(dataptr + 1) = *dataptr + offset;
dataptr++;
a = 0;
for (x = 0; x < num; x++, ext++) {
snprintf(*dataptr, data_size, "XPMEXT %s", ext->name);
a++;
if (a < ext_nlines)
*(dataptr + 1) = *dataptr + strlen(ext->name) + 8;
dataptr++;
b = ext->nlines;
for (y = 0, line = ext->lines; y < b; y++, line++) {
strcpy(*dataptr, *line);
a++;
if (a < ext_nlines)
*(dataptr + 1) = *dataptr + strlen(*line) + 1;
dataptr++;
}
}
strcpy(*dataptr, "XPMENDEXT");
}