/*
 * timtoppm.c - read a tim file and produce a ppm file
 */

#include <stdio.h>
#include <varargs.h>

#define MAX_INDEX	256

unsigned char r[MAX_INDEX];
unsigned char g[MAX_INDEX];
unsigned char b[MAX_INDEX];


main (argc, argv)
int argc;
char **argv;
{
  FILE *fp;
  int ch;
  char *fname;

  if (argc <= 1) {
    fp = stdin;
  } else {
    fname = argv[argc-1];
    if ((fp = fopen(fname, "r")) == NULL) {
      FatalError("Can't open input file %s.", fname);
    }
  }

  if ((ch = getint(fp)) != 0x10) {
    FatalError("Unknown format %d.", ch);
  }

  switch (ch = getint(fp)) {
    case 0x02: load15rgb(fp);  break;
    case 0x03: load24rgb(fp);  break;
    case 0x08: load16idx(fp);  break;
    case 0x09: load256idx(fp); break;
    default:   FatalError("Unknown format %d.", ch); break;
  }
}  


/*******************************************/
static int load15rgb(fp)
FILE *fp;
{
  int   i, j, w, h, c;

  (void)getint(fp);
  (void)getint(fp);
  w = getshort(fp);
  h = getshort(fp);

  printf("P6\n%d %d\n255\n", w, h);
  for (i = 0; i < h; i++) {
    for (j = 0; j < w; j++) {
      c = getshort(fp);
      putchar(255*(c & 0x1F)/31);
      putchar(255*((c >> 5) & 0x1F)/31);
      putchar(255*((c >> 10) & 0x1F)/31);
    }
  }
}


/*******************************************/
static int load24rgb(fp)
FILE *fp;
{
  int   i, j, w, h, c;
  long  pad;

  (void)getint(fp);
  (void)getint(fp);
  c = getshort(fp);
  w = c*2/3;
  h = getshort(fp);
  pad = c*2 % 3;

  printf("P6\n%d %d\n255\n", w, h);
  for (i = 0; i < h; i++) {
    for (j = 0; j < w; j++) {
      putchar(getc(fp)); putchar(getc(fp)); putchar(getc(fp));
    }
    for (j = 0; j < pad; j++) {
      (void)getc(fp);
    }
  }
}


/*******************************************/
static int load16idx(fp)
FILE *fp;
{
  int   i, j, w, h;
  int   c1, c2;
  long	offset;

  offset = getint(fp)+16;
  (void)getint(fp);
  (void)getint(fp);

  for (i = 0; i < 16; i++) {
    c1 = getshort(fp);
    r[i] = 255*(c1 & 0x1F)/31;
    g[i] = 255*((c1 >> 5) & 0x1F)/31;
    b[i] = 255*((c1 >> 10) & 0x1F)/31;
  }

  for (i = offset-52; i > 0; i--) {
    (void)getc(fp);
  }
  w = getshort(fp)*4;
  h = getshort(fp);

  printf("P6\n%d %d\n255\n", w, h);
  for (i = 0; i < h; i++) {
    for (j = 0; j < w; j += 2) {
      c1 = getc(fp);
      c2 = (c1 >> 4) & 0x0F;
      c1 = c1 & 0x0F;
      putchar(r[c1]); putchar(g[c1]); putchar(b[c1]);
      putchar(r[c2]); putchar(g[c2]); putchar(b[c2]);
    }
  }
}


/*******************************************/
static int load256idx(fp)
FILE *fp;
{
  int   i, j, w, h, c;
  long	offset;

  offset = getint(fp)+16;
  (void)getint(fp);
  (void)getint(fp);

  for (i = 0; i < 256; i++) {
    c = getshort(fp);
    r[i] = 255*(c & 0x1F)/31;
    g[i] = 255*((c >> 5) & 0x1F)/31;
    b[i] = 255*((c >> 10) & 0x1F)/31;
  }

  for (i = offset-532; i > 0; i--) {
    (void)getc(fp);
  }
  w = getshort(fp)*2;
  h = getshort(fp);

  printf("P6\n%d %d\n255\n", w, h);
  for (i = 0; i < h; i++) {
    for (j = 0; j < w; j++) {
      c = getc(fp);
      putchar(r[c]); putchar(g[c]); putchar(b[c]);
    }
  }
}


/*******************************************/
static int getint(fp)
FILE *fp;
{
  int c1, c2, c3, c4;

  c1 = getc(fp);
  if (c1 == EOF) return 0;
  c2 = getc(fp);
  if (c2 == EOF) return 0;
  c3 = getc(fp);
  if (c3 == EOF) return 0;
  c4 = getc(fp);
  if (c4 == EOF) return 0;

  return (c4 << 24) | (c3 << 16) | (c2 << 8) | c1;
}


/*******************************************/
static int getshort(fp)
FILE *fp;
{
  int c1, c2;

  c1 = getc(fp);
  if (c1 == EOF) return 0;
  c2 = getc(fp);
  if (c2 == EOF) return 0;

  return (c2 << 8) | c1;
}


FatalError(va_alist)
va_dcl
{
  va_list ap;
  char *format;

  va_start(ap);
  format = va_arg(ap, char *);
  vfprintf(stderr, format, ap);
  va_end(ap);
  fprintf(stderr, "\n");
  fflush(stderr);
  exit(1);
}
