/* #ident	"@(#)x11:contrib/clients/xloadimage/faces.c 6.8 92/03/03 Labtam" */
/* faces.c:
 *
 * faces format image loader
 *
 * jim frost 07.06.89
 *
 * Copyright 1989 Jim Frost.
 * See included file "copyright.h" for complete copyright information.
 */

#include "copyright.h"
#include "xloadimage.h"

/* SUPPRESS 560 */

static short        HexTable[256];  /* conversion value */
static unsigned int Initialized= 0; /* easier to fill in at run time */

#define HEXIGNORE -1
#define HEXBAD    -2

/* build a hex digit value table with the bits inverted
 */

static void initHexTable()
{ int a;

  for (a= 0; a < 256; a++)
    HexTable[a]= HEXBAD;

  HexTable['0']= 0x0;
  HexTable['1']= 0x1;
  HexTable['2']= 0x2;
  HexTable['3']= 0x3;
  HexTable['4']= 0x4;
  HexTable['5']= 0x5;
  HexTable['6']= 0x6;
  HexTable['7']= 0x7;
  HexTable['8']= 0x8;
  HexTable['9']= 0x9;
  HexTable['A']= 0xa; HexTable['a']= HexTable['A'];
  HexTable['B']= 0xb; HexTable['b']= HexTable['B'];
  HexTable['C']= 0xc; HexTable['c']= HexTable['C'];
  HexTable['D']= 0xd; HexTable['d']= HexTable['D'];
  HexTable['E']= 0xe; HexTable['e']= HexTable['E'];
  HexTable['F']= 0xf; HexTable['f']= HexTable['F'];
  HexTable['\r']= HEXIGNORE;
  HexTable['\n']= HEXIGNORE;
  HexTable['\t']= HEXIGNORE;
  HexTable[' ']= HEXIGNORE;

  Initialized = 1;
}

/* read a hex value and return its value
 */

static int nextInt(zf, len)
     ZFILE        *zf;
     unsigned int  len;
{ int c;
  int value= 0;
  int count;

  len <<= 1;
  for (count= 0; count < len;) {
    c= zgetc(zf);
    if (c == EOF)
      return(-1);
    else {
      c= HexTable[c & 0xff];
      switch(c) {
      case HEXIGNORE:
	break;
      case HEXBAD:
	return(-1);
      default:
	value= (value << 4) + c;
	count++;
      }
    }
  }
  return(value);
}

boolean
isFaces(zf, name, fname, lname, wp, hp, dp)
     ZFILE        *zf;
     char         *name;
     char         *fname;
     char         *lname;
     unsigned int *wp, *hp, *dp;
{
  char          buf[BUFSIZ];
  unsigned int  w, h, d, iw, ih, id;

  w= h= d= 0;
  fname[0]= lname[0]= '\0';
  while (zgets((byte *)buf, BUFSIZ - 1, zf)) {
    if (! strcmp(buf, "\n"))
      break;
    if (!strncmp(buf, "FirstName:", 10))
      strcpy(fname, buf + 11);
    else if (!strncmp(buf, "LastName:", 9))
      strcpy(lname, buf + 10);
    else if (!strncmp(buf, "Image:", 6)) {
      if (sscanf(buf + 7, "%d%d%d", &iw, &ih, &id) != 3) {
	fprintf(stderr,"facesLoad: %s - Bad image\n", name);
	zclose(zf);
	return(NULL);
      }
    }
    else if (!strncmp(buf, "PicData:", 8)) {
      if (sscanf(buf + 9, "%d%d%d", &w, &h, &d) != 3) {
	fprintf(stderr,"facesLoad: %s - Bad image\n", name);
	zclose(zf);
	return(NULL);
      }
    }
  }
  if (!w || !h || !d)
    return FALSE;
  *wp = w;
  *hp = h;
  *dp = d;
  return TRUE;
}

Image *facesLoad(fullname, image_ops, verbose)
     ImageOptions *image_ops;
     char         *fullname;
     boolean       verbose;
{
  ZFILE        *zf;
  char         *name = image_ops->name;
  Image        *image;
  char          fname[BUFSIZ];
  char          lname[BUFSIZ];
  unsigned int  w, h, d;
  unsigned int  x, y;
  int           value;
  unsigned int  linelen;
  byte         *lineptr, *dataptr;

  if (! (zf= zopen(fullname))) {
    perror("facesLoad");
    return(NULL);
  }

  {
    unsigned int  tw, th, td;
    if (!isFaces(zf, name, fname, lname, &tw, &th, &td)) {
      zclose(zf);
      return NULL;
    }
    w = tw;
    h = th;
    d = td;
  }

  if (verbose)
    printf("%s is a  %dx%d %d-bit grayscale Faces Project image\n",
	   name, w, h, d);

  if (!Initialized)
    initHexTable();

  znocache(zf);
  image= newRGBImage(w, h, d);
  fname[strlen(fname) - 1]= ' ';
  strcat(fname, lname);
  fname[strlen(fname) - 1]= '\0';
  image->title= dupString(fname);

  /* image is greyscale; build RGB map accordingly
   */

  for (x= 0; x < image->rgb.size; x++)
    *(image->rgb.red + x)= *(image->rgb.green + x)= *(image->rgb.blue + x)=
      (65536 / image->rgb.size) * x;
  image->rgb.used= image->rgb.size;

  /* read in image data
   */

  linelen= w * image->pixlen;
  lineptr= image->data + (h * linelen);
  for (y= 0; y < h; y++) {
    lineptr -= linelen;
    dataptr= lineptr;
    for (x= 0; x < w; x++) {
      if ((value= nextInt(zf, image->pixlen)) < 0) {
	fprintf(stderr,"facesLoad: %s - Bad image data (returning partial image)\n", fullname);
	zclose(zf);
	return(image);
      }
      *(dataptr++)= value;
    }
  }
  zclose(zf);
  read_trail_opt(image_ops,zf,image,verbose);
  return(image);
}

int facesIdent(fullname, name)
     char *fullname, *name;
{
  ZFILE        *zf;
  char          fname[BUFSIZ];
  char          lname[BUFSIZ];
  unsigned int  w, h, d;

  if (! (zf= zopen(fullname))) {
    perror("facesIdent");
    return(NULL);
  }

  if (!isFaces(zf, name, fname, lname, &w, &h, &d)) {
    zclose(zf);
    return(0);
  }
  printf("%s is a  %dx%d %d-bit grayscale Faces Project image\n",
	 name, w, h, d);
  zclose(zf);
  return(1);
}
