LCOV - code coverage report
Current view: top level - gutils - gimagereadxpm.c (source / functions) Hit Total Coverage
Test: FontForge coverage report 2017-08-04 01:21:11+02:00 (commit d35f7e4107a9e1db65cce47c468fcc914cecb8fd) Lines: 0 181 0.0 %
Date: 2017-08-04 Functions: 0 9 0.0 %

          Line data    Source code
       1             : /* Copyright (C) 2000-2012 by George Williams */
       2             : /* 2013apr11, additional fixes and error checks done, Jose Da Silva */
       3             : /*
       4             :  * Redistribution and use in source and binary forms, with or without
       5             :  * modification, are permitted provided that the following conditions are met:
       6             : 
       7             :  * Redistributions of source code must retain the above copyright notice, this
       8             :  * list of conditions and the following disclaimer.
       9             : 
      10             :  * Redistributions in binary form must reproduce the above copyright notice,
      11             :  * this list of conditions and the following disclaimer in the documentation
      12             :  * and/or other materials provided with the distribution.
      13             : 
      14             :  * The name of the author may not be used to endorse or promote products
      15             :  * derived from this software without specific prior written permission.
      16             : 
      17             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
      18             :  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
      19             :  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
      20             :  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      21             :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      22             :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
      23             :  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
      24             :  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      25             :  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
      26             :  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      27             :  */
      28             : #include "gimage.h"
      29             : /*#include "gxdrawP.h"*/
      30             : #include "string.h"
      31             : #include "utype.h"
      32             : 
      33             : /* X Pixmap format
      34             : These are c files, all the significant data resides in strings, everything
      35             : else may be ignored (well, the first line must be the comment / * XPM * /)
      36             : 
      37             :     / * XPM * /
      38             :     static char * plaid[] =
      39             :     {
      40             :     / * plaid pixmap * /
      41             :     / * width height ncolors chars_per_pixel * /
      42             :     "22 22 4 2 0 0 XPMEXT",
      43             :     / * colors * /
      44             :     "   c red       m white  s light_color",
      45             :     "Y  c green     m black  s ines_in_mix",
      46             :     "+  c yellow    m white  s lines_in_dark ",
      47             :     "x              m black  s dark_color ",
      48             :     / * pixels * /
      49             :     "x   x   x x x   x   x x x x x x + x x x x x ",
      50             :     "  x   x   x   x   x   x x x x x x x x x x x ",
      51             :     "x   x   x x x   x   x x x x x x + x x x x x ",
      52             : 
      53             : The first string has 4 interesting numbers in it: width, height, ncolors,
      54             : characters per pixel, these may be followed by the hot spot location (2 nums)
      55             : or the text XPMEXT which means there are extensions later.
      56             : 
      57             : The next few strings (there will be ncolors of them) provide a mapping between
      58             : character(s) and colors.  Above the "  " combination maps to red on a color
      59             : display, white on monochrome and is called light_color.
      60             : 
      61             : After that come lines of pixels.  Each line is width*chars_per_pixel long and
      62             : there are height of them.
      63             : 
      64             : color names may be: a name in the x database (ie sky blue), #xxxxxx (hex rgb),
      65             : %xxxxxx (hex hsb), None==transparent, "a symbolic name" and I don't know what
      66             : good they are.
      67             : */
      68             : /* There seems to be another, similar format XPM2 which is the same except
      69             :     nothing is in a string.  Example:
      70             : ! XPM2
      71             : 64 64 2 1
      72             : . c #FFFFFFFFFFFF
      73             : + c #000000000000
      74             : .....................++.......+...+.............................
      75             : .+....................................+..++.....................
      76             : ..+.............................................................
      77             : .....+.................+........................................
      78             : ........++..................................+...................
      79             : ................................................................
      80             : ................................................................
      81             : ................................................+...............
      82             : ............................+...................................
      83             : */
      84             : 
      85           0 : static int getstring(unsigned char *buf,int sz,FILE *fp) {
      86             : /* get a string of text within "" marks and skip */
      87             : /* backslash sequences, or concatenated strings. */
      88           0 :     int ch, incomment=0;
      89             : 
      90           0 :     while ( (ch=getc(fp))>=0 ) {
      91           0 :         if ( ch=='"' && !incomment )
      92           0 :             break;
      93           0 :         if ( !incomment && ch=='/' ) {
      94           0 :             if ( (ch=getc(fp))<0 ) break;
      95           0 :             if ( ch=='*' ) incomment=true;
      96           0 :             else ungetc(ch,fp);
      97           0 :         } else if ( incomment && ch=='*' ) {
      98           0 :             if ( (ch=getc(fp))<0 ) break;
      99           0 :             if ( ch=='/' ) incomment=false;
     100           0 :             else ungetc(ch,fp);
     101             :         }
     102             :     }
     103           0 :     if ( ch<0 )
     104           0 :         return( 0 );
     105             : 
     106             :     /* Get data within quote marks */
     107           0 :     while ( --sz>0 && (ch=getc(fp))>=0 && ch!='"' )
     108           0 :         *buf++ = ch;
     109           0 :     if ( ch!='"' )
     110           0 :         return( 0 );
     111           0 :     *buf = '\0';
     112           0 :     return( 1 );
     113             : }
     114             : 
     115           0 : static int gww_getline(unsigned char *buf,int sz,FILE *fp) {
     116             : /* get a single line of text (leave-out the '\n') */
     117           0 :     int ch=0;
     118           0 :     unsigned char *pt=buf;
     119             : 
     120           0 :     while ( --sz>0 && (ch=getc(fp))>=0 && ch!='\n' && ch!='\r' )
     121           0 :         *pt++ = ch;
     122           0 :     if ( ch=='\r' && (ch=getc(fp))!='\n' )
     123           0 :         ungetc(ch,fp);
     124           0 :     *pt = '\0';
     125           0 :     if ( ch<0 && pt==buf )
     126           0 :         return( 0 );
     127           0 :     return( 1 );
     128             : }
     129             : 
     130             : #define TRANS 0x1000000
     131             : union hash {
     132             :     long color;
     133             :     union hash *table;
     134             : };
     135             : 
     136           0 : static void freetab(union hash *tab, int nchars) {
     137             :     int i;
     138             : 
     139           0 :     if ( tab && nchars>1 ) {
     140           0 :         for ( i=0; i<256; ++i )
     141           0 :             if ( tab[i].table!=NULL )
     142           0 :                 freetab(tab[i].table,nchars-1);
     143             :     }
     144           0 :     free(tab);
     145           0 : }
     146             : 
     147           0 : static int fillupclut(Color *clut, union hash *tab,int index,int nchars) {
     148             :     int i;
     149             : 
     150           0 :     if ( nchars==1 ) {
     151           0 :         for ( i=0; i<256; ++i )
     152           0 :             if ( tab[i].color!=-1 ) {
     153           0 :                 if ( tab[i].color == TRANS ) {
     154           0 :                     clut[256] = index;
     155           0 :                     tab[i].color = 0;
     156             :                 }
     157           0 :                 clut[index] = tab[i].color;
     158           0 :                 tab[i].color = index++;
     159             :             }
     160             :     } else {
     161           0 :         for ( i=0; i<256; ++i )
     162           0 :             if ( tab[i].table!=NULL )
     163           0 :                 index = fillupclut(clut,tab[i].table,index,nchars-1);
     164             :     }
     165           0 : return( index );
     166             : }
     167             : 
     168           0 : static long parsecol(char *start, char *end) {
     169           0 :     long ret = -1;
     170             :     int ch;
     171             : 
     172           0 :     while ( !isspace(*start) && *start!='\0' ) ++start;
     173           0 :     while ( isspace(*start) ) ++start;
     174           0 :     while ( end>start && isspace(end[-1]) ) --end;
     175           0 :     ch = *end; *end = '\0';
     176             : 
     177           0 :     if ( strcmp(start,"None")==0 )
     178           0 :         ret = TRANS; /* no_color==transparent */
     179           0 :     else if ( *start=='#' || *start=='%' ) {
     180           0 :         if ( end-start==4 ) {
     181           0 :             sscanf(start+1,"%lx",&ret);
     182           0 :             ret = ((ret&0xf00)<<12) | ((ret&0xf0)<<8) | ((ret&0xf)<<4);
     183           0 :         } else if ( end-start==7 )
     184           0 :             sscanf(start+1,"%lx",&ret);
     185           0 :         else if ( end-start==13 ) {
     186             :             int r,g,b;
     187           0 :             sscanf(start+1,"%4x%4x%4x",&r,&g,&b);
     188           0 :             ret = ((r>>8)<<16) | ((g>>8)<<8) | (b>>8);
     189             :         }
     190           0 :         if ( *start=='%' ) {
     191             :             /* TODO! */
     192             :             /* How do I translate from HSB to RGB???? */
     193             :             ;
     194             :         }
     195           0 :     } else if ( strcmp(start,"white")==0 ) {
     196           0 :         ret = COLOR_CREATE(255,255,255);
     197             :     } else {
     198           0 :         ret = 0;
     199             :     }
     200             : 
     201           0 :     *end = ch;
     202           0 : return ret;
     203             : }
     204             : 
     205           0 : static char *findnextkey(char *str) {
     206           0 :     int oktostart=1;
     207             : 
     208           0 :     while ( *str ) {
     209           0 :         if ( isspace(*str)) oktostart=true;
     210           0 :         else if ( oktostart ) {
     211           0 :             if (( *str=='c' && isspace(str[1])) ||
     212           0 :                     (*str=='m' && isspace(str[1])) ||
     213           0 :                     (*str=='g' && isspace(str[1])) ||
     214           0 :                     (*str=='g' && str[1]=='4' && isspace(str[2])) ||
     215           0 :                     (*str=='s' && isspace(str[1])) )
     216           0 :                 return( str );
     217           0 :             oktostart = false;
     218             :         }
     219           0 :         ++str;
     220             :     }
     221           0 :     return( str );
     222             : }
     223             : 
     224           0 : static long findcol(char *str) {
     225             :     char *pt, *end;
     226           0 :     const char *try_order = "cgm"; /* Try in this order to find something */
     227             : 
     228           0 :     while ( *try_order ) {
     229           0 :         pt = findnextkey(str);
     230           0 :         while ( *pt ) {
     231           0 :             end = findnextkey(pt+2);
     232           0 :             if ( *pt==*try_order )
     233           0 :                 return( parsecol(pt,end) );
     234           0 :             pt = end;
     235             :         }
     236           0 :         ++try_order;
     237             :     }
     238           0 :     return( 0 );
     239             : }
     240             : 
     241           0 : static union hash *parse_colors(FILE *fp,unsigned char *line, int lsiz, int ncols, int nchars,
     242             :         int (*getdata)(unsigned char *,int,FILE *)) {
     243             :     union hash *tab;
     244             :     union hash *sub;
     245             :     int i, j;
     246             : 
     247           0 :     if ( (tab=(union hash *)malloc(256*sizeof(union hash)))==NULL ) {
     248           0 :         NoMoreMemMessage();
     249           0 :         return( NULL );
     250             :     }
     251             : 
     252           0 :     if ( nchars==1 )
     253           0 :         memset(tab,-1,256*sizeof(union hash));
     254           0 :     for ( i=0; i<ncols; ++i ) {
     255           0 :         if ( !getdata(line,lsiz,fp) ) {
     256           0 :             freetab(tab,nchars);
     257           0 :             return( NULL );
     258             :         }
     259           0 :         sub = tab;
     260           0 :         for ( j=0; j<nchars-1; ++j ) {
     261           0 :             if ( sub[line[j]].table==NULL ) {
     262           0 :                 if ( (sub[line[j]].table=(union hash *)malloc(256*sizeof(union hash)))==NULL ) {
     263           0 :                     NoMoreMemMessage();
     264           0 :                     freetab(tab,nchars);
     265           0 :                     return( NULL );
     266             :                 }
     267           0 :                 if ( j==nchars-2 )
     268           0 :                     memset(sub[line[j]].table,-1,256*sizeof(union hash));
     269             :             }
     270           0 :             sub = sub[line[j]].table;
     271             :         }
     272           0 :         sub[line[j]].color = findcol((char *) line+j+1);
     273             :     }
     274           0 :     return( tab );
     275             : }
     276             : 
     277           0 : GImage *GImageReadXpm(char * filename) {
     278             : /* Import an *.xpm image, else cleanup and return NULL if error */
     279             : /* TODO: There is an XPM3 library that takes care of all cases. */
     280             :    FILE *fp;
     281           0 :    GImage *ret=NULL;
     282             :    struct _GImage *base;
     283             :    int width, height, cols, nchar;
     284             :    unsigned char buf[80];
     285             :    unsigned char *line, *lpt;
     286             :    int y,j, lsiz;
     287             :    union hash *tab, *sub;
     288             :    unsigned char *pt, *end; unsigned long *ipt;
     289           0 :    int (*getdata)(unsigned char *,int,FILE *) = NULL;
     290             : 
     291           0 :     if ( (fp=fopen(filename,"r"))==NULL ) {
     292           0 :         fprintf(stderr,"Can't open \"%s\"\n", filename);
     293           0 :         return( NULL );
     294             :     }
     295             : 
     296           0 :     line=NULL; tab=NULL; nchar=0;
     297             :     /* If file begins with XPM then read lines using getstring;() */
     298             :     /* otherwise for XPM2 read lines using function gww_getline() */
     299           0 :     if ( (fgets((char *)buf,sizeof(buf),fp))==NULL )
     300           0 :         goto errorGImageReadXpm;
     301           0 :     if ( strstr((char *) buf,"XPM2")!=NULL )
     302           0 :         getdata = gww_getline;
     303           0 :     else if ( strstr((char *)buf,"/*")!=NULL && strstr((char *)buf,"XPM")!=NULL && strstr((char *)buf,"*/")!=NULL )
     304           0 :         getdata = getstring;
     305             : 
     306             :     /* If no errors yet then go get width, height, colors, nchars */
     307           0 :     if ( getdata==NULL ||
     308           0 :             !getdata(buf,sizeof(buf),fp) ||
     309           0 :             sscanf((char *)buf,"%d %d %d %d",&width,&height,&cols,&nchar)!=4 )
     310             :         goto errorGImageReadXpm;
     311             : 
     312             :     /* Prepare to fetch one graphic line at a time for conversion */
     313           0 :     if ( (line=(unsigned char *)malloc((lsiz=nchar*width+20)*sizeof(unsigned char)))==NULL ) {
     314           0 :         NoMoreMemMessage();
     315           0 :         goto errorGImageReadXpmMem;
     316             :     }
     317             : 
     318             :     /* Fetch color table */
     319           0 :     if ( (tab=parse_colors(fp,line,lsiz,cols,nchar,getdata))==NULL )
     320           0 :         goto errorGImageReadXpmMem;
     321             : 
     322           0 :     if ( cols<=256 ) {
     323             :         Color clut[257];
     324           0 :         clut[256] = COLOR_UNKNOWN;
     325           0 :         fillupclut(clut,tab,0,nchar);
     326           0 :         if ( (ret=GImageCreate(it_index,width,height))==NULL )
     327           0 :             goto errorGImageReadXpmMem;
     328           0 :         ret->u.image->clut->clut_len = cols;
     329           0 :         memcpy(ret->u.image->clut->clut,clut,cols*sizeof(Color));
     330           0 :         ret->u.image->trans = clut[256];
     331           0 :         ret->u.image->clut->trans_index = clut[256];
     332             :     } else {
     333           0 :         if ( (ret=GImageCreate(it_true,width,height))==NULL )
     334           0 :             goto errorGImageReadXpmMem;
     335           0 :         ret->u.image->trans = TRANS;              /* TRANS isn't a valid Color, but it fits in our 32 bit pixels */
     336             :     }
     337             : 
     338             :     /* Get image */
     339           0 :     base = ret->u.image;
     340           0 :     for ( y=0; y<height; ++y ) {
     341           0 :         if ( !getdata(line,lsiz,fp))
     342           0 :             goto errorGImageReadXpm;
     343           0 :         pt = (uint8 *) (base->data+y*base->bytes_per_line); ipt = NULL; end = pt+width;
     344           0 :         if ( cols>256 )
     345           0 :             ipt = (unsigned long *) pt;
     346           0 :         for ( lpt=line; *line && pt<end; ) {
     347           0 :             sub = tab;
     348           0 :             for ( j=0; *lpt && j<nchar-1; ++j, ++lpt )
     349           0 :                 if ( sub!=NULL )
     350           0 :                     sub = sub[*lpt].table;
     351           0 :             if ( sub!=NULL ) {
     352           0 :                 if ( cols<=256 )
     353           0 :                     *pt = sub[*lpt].color;
     354             :                 else
     355           0 :                     *ipt = sub[*lpt].color;
     356             :             }
     357           0 :             ++pt; ++ipt; ++lpt;
     358             :         }
     359             :     }
     360           0 :     free(line);
     361           0 :     freetab(tab,nchar);
     362           0 :     fclose(fp);
     363           0 :     return( ret );
     364             : 
     365             : errorGImageReadXpm:
     366           0 :     fprintf(stderr,"Bad input file \"%s\"\n",filename );
     367             : errorGImageReadXpmMem:
     368           0 :     GImageDestroy(ret);
     369           0 :     free(line); freetab(tab,nchar);
     370           0 :     fclose(fp);
     371           0 :     return( NULL );
     372             : }

Generated by: LCOV version 1.10