xenocara/lib/libXpm/src/CrBufFrI.c
2006-11-25 17:32:04 +00:00

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;
}