/* 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 "image.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
#define MAXFACESNAME 256 /* to avoid buffer overflow */

/* 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);
}

Image *facesLoad(fullname, name, verbose)
     char *fullname, *name;
{ ZFILE        *zf;
  Image        *image;
  char          fname[BUFSIZ];
  char          lname[BUFSIZ];
  char          buf[BUFSIZ];
  unsigned int  w, h, d, iw, ih, id;
  unsigned int  x, y;
  int           value;
  unsigned int  linelen;
  byte         *lineptr, *dataptr;

  if (!Initialized)
    initHexTable();

  if (! (zf= zopen(fullname)))
    return(NULL);

  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)){
      strncpy(fname, buf + 11, MAXFACESNAME);
	}
    else if (!strncmp(buf, "LastName:", 9))
      strncpy(lname, buf + 10, MAXFACESNAME);
    else if (!strncmp(buf, "Image:", 6)) {
      if (sscanf(buf + 7, "%d%d%d", &iw, &ih, &id) != 3) {
	fprintf(stderr, "%s: Bad Faces Project image\n", fullname);
	cleanup(-1);
      }
    }
    else if (!strncmp(buf, "PicData:", 8)) {
      if (sscanf(buf + 9, "%d%d%d", &w, &h, &d) != 3) {
	fprintf(stderr, "%s: Bad Faces Project image\n", fullname);
	cleanup(-1);
      }
    }
  }
  if (!w || !h || !d) {
    zclose(zf);
    return(NULL);
  }
  znocache(zf);

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

  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, "%s: Bad Faces Project image data\n", fullname);
	cleanup(-1);
      }
      *(dataptr++)= value;
    }
  }
  zclose(zf);
  return(image);
}

int facesIdent(fullname, name)
     char *fullname, *name;
{ Image *image;

  if ((image = facesLoad(fullname, name, 1))) {
    freeImage(image);
    return(1);
  }
  return(0);
}
