/*
 * xvxpm.c - load routine for X11 XPM v2 & v3 format pictures
 *
 * LoadXPM(fname,pinfo)
 * WriteXPM(fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle,comment)
 */

/*
 * LoadXPM written by Mike Bretz & Thomas Woerner
 * (bretz@zdv.uni-tuebingen.de)
 * (twoerner@gris.informatik.uni-tuebingen.de)
 *
 * Supporting only XPM v2 and v3 format.
 *
 *
 * Algorithm for saving in WriteXPM written by Sam Yates 
 * (syates@spam.maths.adelaide.edu.au)
 * to support xpm v3 format. Modified by Thomas Woerner.
 */


#include "xv.h"

static int xpmError();

int 
LoadXPM(fname, pinfo)
     char *fname;
     PICINFO * pinfo;
{
  FILE   *fp;
  char   *pic, *pic8, *col, *clist, *cptr, *ptr, line[256], pixel[3], c, c1,
         c2, *col2, *ptr2, *bname;
  XColor col1, col3;
  int    width, height, cpp, numcols, i, j, k, l , found;
  long   color, filesize;

  pinfo->pic     = (byte *) NULL;
  pinfo->comment = (char *) NULL;

  bname = BaseName(fname);
  fp = fopen(fname, "r");
  if (!fp) return (xpmError(bname, "couldn't open file"));

  SetDirRButt(F_FORMAT, F_XPM);
  SetISTR(ISTR_FORMAT,"XPM");

  /* find the size of the file */
  fseek(fp, 0L, 2);
  filesize = ftell(fp);
  fseek(fp, 0L, 0);

  /* get width, height, numcols, cpp */
  i = 0;  
  while ((line[i] = getc(fp)) != '"') ;
  while ((line[++i] = getc(fp)) != '"') ;
  line[++i] = '\0';
  sscanf(line,"\"%d %d %d %d\"", &width, &height, &numcols, &cpp);

  /* cpp (characters per pixel) in [1..3] ? */
  if (cpp < 1 || cpp > 3)
    return (xpmError("no supported format"));
  
  pinfo->w = width;
  pinfo->h = height;
  
  /* allocating memory for color pattern list */
  clist = (char *) malloc (numcols * cpp);
  cptr = clist;
  col2 = (char *) malloc (255);

  /* getting colormap data */
  for (j=0; j<numcols; j++) {
    i = 0;
    while ((line[i] = getc(fp)) != '"') ;
    while ((line[i++] = getc(fp)) != '"') ;
    line[i] = '\0';
    k = i;
    /* inserting color pattern in list and overwriting pattern in line */
    for (i=0; i<cpp; i++) {
      *cptr = line[i];
      line[i] = 'x';
      cptr++;
    }
    for (i=0; i<k; i++) line[i] = tolower(line[i]);

    /* if color unnamed, insert none */
    if (((ptr = strstr(line, " c ")) == NULL) &&
	((ptr = strstr(line, "\tc ")) == NULL)) {
      strcpy(line,"\tc none\0");
      ptr = line;
    }
    ptr +=3;
    /* scan for "c color" in *ptr */
    if (ptr2 = (strstr(ptr, " m "))) *ptr2 = '\0';
    if (ptr2 = (strstr(ptr,"\tm "))) *ptr2 = '\0';
    if (ptr2 = (strstr(ptr, " g "))) *ptr2 = '\0';
    if (ptr2 = (strstr(ptr,"\tg "))) *ptr2 = '\0';
    if (ptr2 = (strstr(ptr, " s "))) *ptr2 = '\0';
    if (ptr2 = (strstr(ptr,"\ts "))) *ptr2 = '\0';
    if (ptr2 = (strstr(ptr,"\"")))   *ptr2 = '\0';

    /* erasing spaces or tabs at the end */
    while (ptr[strlen(ptr)-1] == ' ' || ptr[strlen(ptr)-1] == '\t')
      ptr[strlen(ptr)-1] = '\0';
    
    /* rgb color entry ? */
    if (*ptr == '#') {
      
      /* color entry for more than 24 bit ? */
      if (strlen(ptr) > 7) {
	/* cut the second byte of each entry */
	*(ptr+3) = *(ptr+5);
	*(ptr+4) = *(ptr+6);
	*(ptr+5) = *(ptr+9);
	*(ptr+6) = *(ptr+10);
	*(ptr+7) = '\0';
      }
      /* build rgb palette entry */
      sprintf(col2, "0%s\0", ptr);
      *(col2+1) = 'x';
      color = strtol(col2, (char **) NULL, 16);
      pinfo->r[j] = color >> 16;
      pinfo->g[j] = color >> 8;
      pinfo->b[j] = color;
    }
    else {
      /* color = none ? */
      if (!strncmp(ptr, "none", 4)) {
	strcpy(ptr, "white\0");
	xpmError("allocated white for none");
      }
      /* look for color */
      if (XLookupColor(theDisp,theCmap,ptr,&col1,&col3)) {
	pinfo->r[j] = col1.red >> 8;
	pinfo->g[j] = col1.green >> 8;
	pinfo->b[j] = col1.blue >> 8;	  
      }
      else
	return (xpmError("error in colormap"));
    }
  }
  free(col2);
  pic8 = (char *) malloc(width * height);
  pic = pic8;
  
  /* now getting picture data */
  for (i=0; i<height; i++) {
    while ((c = getc(fp)) != '"') ;
    if (feof(fp))
      xpmError("premature end of file");

    for (j=0; j<width; j++) {
      /* getting cpp characters. If feof(fp) then fill in 0 */
      for (k=0; k<cpp; k++) {
	if (!feof(fp))
	  pixel[k] = getc(fp);
	else {
	  pixel[k] = 0;
	  xpmError("premature end of file");
	}
      }
      /* searching for color pattern in clist */
      cptr = clist;
      found = False;
      for (k=0; k<numcols && !found; k++) {
	found = True;
	for (l=0; l<cpp && found; l++) {
	  if (pixel[l] != *(cptr+l))
	    found = False;
	}
	cptr += cpp;
      }
      if (!found) {
	*pic++ = 0;
	xpmError("error in colormap");
      }
      /* found pattern entry -> pixel has color k-1 */
      else
	*pic++ = k-1;
    }
    while ((c = getc(fp)) != '"') ;
  }

  free(clist);

  pinfo->pic     = pic8;
  pinfo->type    = PIC8;
  pinfo->frmType = F_XPM;
  pinfo->colType = F_FULLCOLOR;

  sprintf(pinfo->fullInfo, "PIXMAP,  %d characters per pixel. (%ld bytes)",
	  cpp, filesize);
  sprintf(pinfo->shrtInfo, "%dx%d PIXMAP.", width, height);

  if (fp != stdin)
    fclose(fp);
  return 1;
}


static int xpmError(st)
char *st;
{
  SetISTR(ISTR_WARNING,st);
  return 1;
}

/*
 * Algorithm for saving in WriteXPM written by Sam Yates 
 * (syates@spam.maths.adelaide.edu.au)
 * to support xpm v3 format.
 */

WriteXPM(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols, colorstyle, comment)
     FILE *fp;
     byte *pic;
     int   ptype, w,h;
     byte *rmap, *gmap, *bmap;
     int   numcols, colorstyle;
     char *comment;
{

  int i,j;
  byte c,*pix=pic, *pic8;
  char name[256];

  strncpy(name, comment, 255);
  name[255]=0;
  i = strspn(name,
	   "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
  if (!i || '9'>=*name) strcpy(name, "xpm");
  else name[i] = 0;

  if (ptype == PIC24) {  /* have to quantize down to 8 bits */
    byte rtemp[256], gtemp[256], btemp[256];
    char *pic8;

    pic8 = Conv24to8(pic, w, h, 256, rtemp, gtemp, btemp);
    if (!pic8)
      FatalError("Unable to malloc in WriteXPM()");
    rmap = rtemp;  gmap = gtemp;  bmap = btemp;  numcols=256;
    pix = pic8;
  }

  fprintf(fp,"/* XPM */\nstatic char* %s = {\n\"%d %d %d 2\",\n",
	  name, w, h, numcols);

  if (colorstyle != F_GREYSCALE)
    for (i=0; i<numcols; i++)
      fprintf(fp, "\"%c%c c #%02x%02x%02x\",\n",'_'+(i>>5),'_'+(i%32),
	      rmap[i], gmap[i], bmap[i]);
  else
    for (i=0; i<numcols; i++) {
      c = MONO(rmap[i], gmap[i], bmap[i]);
      fprintf(fp, "\"%c%c c #%02x%02x%02x\",\n", '_'+(i>>5), '_'+(i%32),
	      c, c, c);
    }
  for (i=0; i++<h; ) {
    fputc('"', fp);
    for (j=0; j++<w; pix++)
      fputc('_'+(*pix>>5), fp), fputc('_'+(*pix%32), fp);
    fputs("\", \n", fp);
  }
  
  if (fputs("} ;\n", fp) == EOF) return 1;
  else return 0;
}
