Edit

IABSD.fr/xenocara/lib/libXpm/src/CrBufFrI.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2006-11-25 17:32:04
    Hash : d8e9d107
    Message : import from X.Org 7.1

  • lib/libXpm/src/CrBufFrI.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;
    }