453 lines
12 KiB
C
453 lines
12 KiB
C
/*
|
|
* Copyright (C) 1989-95 GROUPE BULL
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to
|
|
* deal in the Software without restriction, including without limitation the
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
* sell copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* Except as contained in this notice, the name of GROUPE BULL shall not be
|
|
* used in advertising or otherwise to promote the sale, use or other dealings
|
|
* in this Software without prior written authorization from GROUPE BULL.
|
|
*/
|
|
|
|
/*****************************************************************************\
|
|
* CrBufFrI.c: *
|
|
* *
|
|
* XPM library *
|
|
* Scan an image and possibly its mask and create an XPM buffer *
|
|
* *
|
|
* Developed by Arnaud Le Hors *
|
|
\*****************************************************************************/
|
|
|
|
/* October 2004, source code review by Thomas Biege <thomas@suse.de> */
|
|
|
|
/* $XFree86$ */
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
#include "XpmI.h"
|
|
|
|
LFUNC(WriteColors, int, (char **dataptr, unsigned int *data_size,
|
|
unsigned int *used_size, XpmColor *colors,
|
|
unsigned int ncolors, unsigned int cpp));
|
|
|
|
LFUNC(WritePixels, void, (char *dataptr, unsigned int data_size,
|
|
unsigned int *used_size,
|
|
unsigned int width, unsigned int height,
|
|
unsigned int cpp, unsigned int *pixels,
|
|
XpmColor *colors));
|
|
|
|
LFUNC(WriteExtensions, void, (char *dataptr, unsigned int data_size,
|
|
unsigned int *used_size,
|
|
XpmExtension *ext, unsigned int num));
|
|
|
|
LFUNC(ExtensionsSize, unsigned int, (XpmExtension *ext, unsigned int num));
|
|
LFUNC(CommentsSize, int, (XpmInfo *info));
|
|
|
|
int
|
|
XpmCreateBufferFromImage(display, buffer_return, image, shapeimage, attributes)
|
|
Display *display;
|
|
char **buffer_return;
|
|
XImage *image;
|
|
XImage *shapeimage;
|
|
XpmAttributes *attributes;
|
|
{
|
|
XpmImage xpmimage;
|
|
XpmInfo info;
|
|
int ErrorStatus;
|
|
|
|
/* initialize return value */
|
|
if (buffer_return)
|
|
*buffer_return = NULL;
|
|
|
|
/* create an XpmImage from the image */
|
|
ErrorStatus = XpmCreateXpmImageFromImage(display, image, shapeimage,
|
|
&xpmimage, attributes);
|
|
if (ErrorStatus != XpmSuccess)
|
|
return (ErrorStatus);
|
|
|
|
/* create the buffer from the XpmImage */
|
|
if (attributes) {
|
|
xpmSetInfo(&info, attributes);
|
|
ErrorStatus =
|
|
XpmCreateBufferFromXpmImage(buffer_return, &xpmimage, &info);
|
|
} else
|
|
ErrorStatus =
|
|
XpmCreateBufferFromXpmImage(buffer_return, &xpmimage, NULL);
|
|
|
|
/* free the XpmImage */
|
|
XpmFreeXpmImage(&xpmimage);
|
|
|
|
return (ErrorStatus);
|
|
}
|
|
|
|
|
|
#undef RETURN
|
|
#define RETURN(status) \
|
|
do \
|
|
{ \
|
|
ErrorStatus = status; \
|
|
goto error; \
|
|
}while(0)
|
|
|
|
int
|
|
XpmCreateBufferFromXpmImage(buffer_return, image, info)
|
|
char **buffer_return;
|
|
XpmImage *image;
|
|
XpmInfo *info;
|
|
{
|
|
/* calculation variables */
|
|
int ErrorStatus;
|
|
char buf[BUFSIZ];
|
|
unsigned int cmts, extensions, ext_size = 0;
|
|
unsigned int l, cmt_size = 0;
|
|
char *ptr = NULL, *p;
|
|
unsigned int ptr_size, used_size, tmp;
|
|
|
|
*buffer_return = NULL;
|
|
|
|
cmts = info && (info->valuemask & XpmComments);
|
|
extensions = info && (info->valuemask & XpmExtensions)
|
|
&& info->nextensions;
|
|
|
|
/* compute the extensions and comments size */
|
|
if (extensions)
|
|
ext_size = ExtensionsSize(info->extensions, info->nextensions);
|
|
if (cmts)
|
|
cmt_size = CommentsSize(info);
|
|
|
|
/* write the header line */
|
|
#ifndef VOID_SPRINTF
|
|
used_size =
|
|
#endif
|
|
sprintf(buf, "/* XPM */\nstatic char * image_name[] = {\n");
|
|
#ifdef VOID_SPRINTF
|
|
used_size = strlen(buf);
|
|
#endif
|
|
ptr_size = used_size + ext_size + cmt_size + 1; /* ptr_size can't be 0 */
|
|
if(ptr_size <= used_size ||
|
|
ptr_size <= ext_size ||
|
|
ptr_size <= cmt_size)
|
|
{
|
|
return XpmNoMemory;
|
|
}
|
|
ptr = (char *) XpmMalloc(ptr_size);
|
|
if (!ptr)
|
|
return XpmNoMemory;
|
|
strcpy(ptr, buf);
|
|
|
|
/* write the values line */
|
|
if (cmts && info->hints_cmt) {
|
|
#ifndef VOID_SPRINTF
|
|
used_size +=
|
|
#endif
|
|
snprintf(ptr + used_size, ptr_size-used_size, "/*%s*/\n", info->hints_cmt);
|
|
#ifdef VOID_SPRINTF
|
|
used_size += strlen(info->hints_cmt) + 5;
|
|
#endif
|
|
}
|
|
#ifndef VOID_SPRINTF
|
|
l =
|
|
#endif
|
|
sprintf(buf, "\"%d %d %d %d", image->width, image->height,
|
|
image->ncolors, image->cpp);
|
|
#ifdef VOID_SPRINTF
|
|
l = strlen(buf);
|
|
#endif
|
|
|
|
if (info && (info->valuemask & XpmHotspot)) {
|
|
#ifndef VOID_SPRINTF
|
|
l +=
|
|
#endif
|
|
snprintf(buf + l, sizeof(buf)-l, " %d %d", info->x_hotspot, info->y_hotspot);
|
|
#ifdef VOID_SPRINTF
|
|
l = strlen(buf);
|
|
#endif
|
|
}
|
|
if (extensions) {
|
|
#ifndef VOID_SPRINTF
|
|
l +=
|
|
#endif
|
|
sprintf(buf + l, " XPMEXT");
|
|
#ifdef VOID_SPRINTF
|
|
l = strlen(buf);
|
|
#endif
|
|
}
|
|
#ifndef VOID_SPRINTF
|
|
l +=
|
|
#endif
|
|
sprintf(buf + l, "\",\n");
|
|
#ifdef VOID_SPRINTF
|
|
l = strlen(buf);
|
|
#endif
|
|
ptr_size += l;
|
|
if(ptr_size <= l)
|
|
RETURN(XpmNoMemory);
|
|
p = (char *) XpmRealloc(ptr, ptr_size);
|
|
if (!p)
|
|
RETURN(XpmNoMemory);
|
|
ptr = p;
|
|
strcpy(ptr + used_size, buf);
|
|
used_size += l;
|
|
|
|
/* write colors */
|
|
if (cmts && info->colors_cmt) {
|
|
#ifndef VOID_SPRINTF
|
|
used_size +=
|
|
#endif
|
|
snprintf(ptr + used_size, ptr_size-used_size, "/*%s*/\n", info->colors_cmt);
|
|
#ifdef VOID_SPRINTF
|
|
used_size += strlen(info->colors_cmt) + 5;
|
|
#endif
|
|
}
|
|
ErrorStatus = WriteColors(&ptr, &ptr_size, &used_size,
|
|
image->colorTable, image->ncolors, image->cpp);
|
|
|
|
if (ErrorStatus != XpmSuccess)
|
|
RETURN(ErrorStatus);
|
|
|
|
/*
|
|
* now we know the exact size we need, realloc the data
|
|
* 4 = 1 (for '"') + 3 (for '",\n')
|
|
* 1 = - 2 (because the last line does not end with ',\n') + 3 (for '};\n')
|
|
*/
|
|
if(image->width > UINT_MAX / image->cpp ||
|
|
(tmp = image->width * image->cpp + 4) <= 4 ||
|
|
image->height > UINT_MAX / tmp ||
|
|
(tmp = image->height * tmp + 1) <= 1 ||
|
|
(ptr_size += tmp) <= tmp)
|
|
RETURN(XpmNoMemory);
|
|
|
|
p = (char *) XpmRealloc(ptr, ptr_size);
|
|
if (!p)
|
|
RETURN(XpmNoMemory);
|
|
ptr = p;
|
|
|
|
/* print pixels */
|
|
if (cmts && info->pixels_cmt) {
|
|
#ifndef VOID_SPRINTF
|
|
used_size +=
|
|
#endif
|
|
snprintf(ptr + used_size, ptr_size-used_size, "/*%s*/\n", info->pixels_cmt);
|
|
#ifdef VOID_SPRINTF
|
|
used_size += strlen(info->pixels_cmt) + 5;
|
|
#endif
|
|
}
|
|
WritePixels(ptr + used_size, ptr_size - used_size, &used_size, image->width, image->height,
|
|
image->cpp, image->data, image->colorTable);
|
|
|
|
/* print extensions */
|
|
if (extensions)
|
|
WriteExtensions(ptr + used_size, ptr_size-used_size, &used_size,
|
|
info->extensions, info->nextensions);
|
|
|
|
/* close the array */
|
|
strcpy(ptr + used_size, "};\n");
|
|
|
|
*buffer_return = ptr;
|
|
|
|
return (XpmSuccess);
|
|
|
|
/* exit point in case of error, free only locally allocated variables */
|
|
error:
|
|
if (ptr)
|
|
XpmFree(ptr);
|
|
return (ErrorStatus);
|
|
}
|
|
|
|
|
|
static int
|
|
WriteColors(dataptr, data_size, used_size, colors, ncolors, cpp)
|
|
char **dataptr;
|
|
unsigned int *data_size;
|
|
unsigned int *used_size;
|
|
XpmColor *colors;
|
|
unsigned int ncolors;
|
|
unsigned int cpp;
|
|
{
|
|
char buf[BUFSIZ] = {0};
|
|
unsigned int a, key, l;
|
|
char *s, *s2;
|
|
char **defaults;
|
|
|
|
*buf = '"';
|
|
for (a = 0; a < ncolors; a++, colors++) {
|
|
|
|
defaults = (char **) colors;
|
|
s = buf + 1;
|
|
if(cpp > (sizeof(buf) - (s-buf)))
|
|
return(XpmNoMemory);
|
|
strncpy(s, *defaults++, cpp);
|
|
s += cpp;
|
|
|
|
for (key = 1; key <= NKEYS; key++, defaults++) {
|
|
if ((s2 = *defaults)) {
|
|
#ifndef VOID_SPRINTF
|
|
s +=
|
|
#endif
|
|
/* assume C99 compliance */
|
|
snprintf(s, sizeof(buf) - (s-buf), "\t%s %s", xpmColorKeys[key - 1], s2);
|
|
#ifdef VOID_SPRINTF
|
|
s += strlen(s);
|
|
#endif
|
|
/* now let's check if s points out-of-bounds */
|
|
if((s-buf) > sizeof(buf))
|
|
return(XpmNoMemory);
|
|
}
|
|
}
|
|
if(sizeof(buf) - (s-buf) < 4)
|
|
return(XpmNoMemory);
|
|
strcpy(s, "\",\n");
|
|
l = s + 3 - buf;
|
|
if( *data_size >= UINT_MAX-l ||
|
|
*data_size + l <= *used_size ||
|
|
(*data_size + l - *used_size) <= sizeof(buf))
|
|
return(XpmNoMemory);
|
|
s = (char *) XpmRealloc(*dataptr, *data_size + l);
|
|
if (!s)
|
|
return (XpmNoMemory);
|
|
*data_size += l;
|
|
strcpy(s + *used_size, buf);
|
|
*used_size += l;
|
|
*dataptr = s;
|
|
}
|
|
return (XpmSuccess);
|
|
}
|
|
|
|
static void
|
|
WritePixels(dataptr, data_size, used_size, width, height, cpp, pixels, colors)
|
|
char *dataptr;
|
|
unsigned int data_size;
|
|
unsigned int *used_size;
|
|
unsigned int width;
|
|
unsigned int height;
|
|
unsigned int cpp;
|
|
unsigned int *pixels;
|
|
XpmColor *colors;
|
|
{
|
|
char *s = dataptr;
|
|
unsigned int x, y, h;
|
|
|
|
if(height <= 1)
|
|
return;
|
|
|
|
h = height - 1;
|
|
for (y = 0; y < h; y++) {
|
|
*s++ = '"';
|
|
for (x = 0; x < width; x++, pixels++) {
|
|
if(cpp >= (data_size - (s-dataptr)))
|
|
return;
|
|
strncpy(s, colors[*pixels].string, cpp); /* how can we trust *pixels? :-\ */
|
|
s += cpp;
|
|
}
|
|
if((data_size - (s-dataptr)) < 4)
|
|
return;
|
|
strcpy(s, "\",\n");
|
|
s += 3;
|
|
}
|
|
/* duplicate some code to avoid a test in the loop */
|
|
*s++ = '"';
|
|
for (x = 0; x < width; x++, pixels++) {
|
|
if(cpp >= (data_size - (s-dataptr)))
|
|
return;
|
|
strncpy(s, colors[*pixels].string, cpp); /* how can we trust *pixels? */
|
|
s += cpp;
|
|
}
|
|
*s++ = '"';
|
|
*used_size += s - dataptr;
|
|
}
|
|
|
|
static unsigned int
|
|
ExtensionsSize(ext, num)
|
|
XpmExtension *ext;
|
|
unsigned int num;
|
|
{
|
|
unsigned int x, y, a, size;
|
|
char **line;
|
|
|
|
size = 0;
|
|
if(num == 0)
|
|
return(0); /* ok? */
|
|
for (x = 0; x < num; x++, ext++) {
|
|
/* 11 = 10 (for ',\n"XPMEXT ') + 1 (for '"') */
|
|
size += strlen(ext->name) + 11;
|
|
a = ext->nlines; /* how can we trust ext->nlines to be not out-of-bounds? */
|
|
for (y = 0, line = ext->lines; y < a; y++, line++)
|
|
/* 4 = 3 (for ',\n"') + 1 (for '"') */
|
|
size += strlen(*line) + 4;
|
|
}
|
|
/* 13 is for ',\n"XPMENDEXT"' */
|
|
if(size > UINT_MAX - 13) /* unlikely */
|
|
return(0);
|
|
return size + 13;
|
|
}
|
|
|
|
static void
|
|
WriteExtensions(dataptr, data_size, used_size, ext, num)
|
|
char *dataptr;
|
|
unsigned int data_size;
|
|
unsigned int *used_size;
|
|
XpmExtension *ext;
|
|
unsigned int num;
|
|
{
|
|
unsigned int x, y, a;
|
|
char **line;
|
|
char *s = dataptr;
|
|
|
|
for (x = 0; x < num; x++, ext++) {
|
|
#ifndef VOID_SPRINTF
|
|
s +=
|
|
#endif
|
|
snprintf(s, data_size - (s-dataptr), ",\n\"XPMEXT %s\"", ext->name);
|
|
#ifdef VOID_SPRINTF
|
|
s += strlen(ext->name) + 11;
|
|
#endif
|
|
a = ext->nlines;
|
|
for (y = 0, line = ext->lines; y < a; y++, line++) {
|
|
#ifndef VOID_SPRINTF
|
|
s +=
|
|
#endif
|
|
snprintf(s, data_size - (s-dataptr), ",\n\"%s\"", *line);
|
|
#ifdef VOID_SPRINTF
|
|
s += strlen(*line) + 4;
|
|
#endif
|
|
}
|
|
}
|
|
strncpy(s, ",\n\"XPMENDEXT\"", data_size - (s-dataptr)-1);
|
|
*used_size += s - dataptr + 13;
|
|
}
|
|
|
|
static int
|
|
CommentsSize(info)
|
|
XpmInfo *info;
|
|
{
|
|
int size = 0;
|
|
|
|
/* 5 = 2 (for "/_*") + 3 (for "*_/\n") */
|
|
/* wrap possible but *very* unlikely */
|
|
if (info->hints_cmt)
|
|
size += 5 + strlen(info->hints_cmt);
|
|
|
|
if (info->colors_cmt)
|
|
size += 5 + strlen(info->colors_cmt);
|
|
|
|
if (info->pixels_cmt)
|
|
size += 5 + strlen(info->pixels_cmt);
|
|
|
|
return size;
|
|
}
|