
/*
 * DECODE IFF formatted files    V1.00
 *
 *	COMPILE W/ASTARTUP.OBJ and MY.LIB
 *
 * iffdump [-vV] file
 *
 * -v    :  display a little more information (only for forms and types
 *          the program knows about)
 * -V    :  display additional hex dump of all sections
 *
 *
 * NOTE:  The '-v' flag could use *a lot* of expansion... Since I haven't
 *        got the latest IFF documentation.
 *
 *
 * NOTE:  This program does almost no format checking (e.g. PROP's only
 *        within LIST's, etc...), it is meant to display the format of
 *        valid IFF files.
 */

#include "iff.h"
#include <graphics/view.h>


#define MODE_V1   0x01
#define MODE_V2   0x02

extern char *tabstr(), *ltos();

union {
   X_BMHD bmhd;
   X_CMAP cmap[64];
   X_GRAB grab;
   X_DEST dest;
   X_SPRT sprt;
   X_CAMG camg;
   X_CRNG crng;
} U;

int Modes;

main(ac, av)
char *av[];
{
   int i, j;
   char *str;
   long fi;
   long endpos;

   for (j = 0, i = 1; i < ac; ++i) {
      str = av[i];
      if (*str == '-') {
         while (*++str) {
            switch(*str) {
            case 'v':
               Modes |= MODE_V1;
               break;
            case 'V':
               Modes |= MODE_V2;
               break;
            default:
               printf ("'%lc' bad option\n", *str);
            }
         }
      } else {
         if (j) {
            puts("May specify only one file");
            exit(1);
         }
         j = i;
      }
   }
   if (j == 0) {
      puts ("IFFDUMP [-vV] file");
      puts ("(c)1986 Matthew Dillon.  Public Domain V1.00");
      puts ("");
      puts ("-v   show detail on things the prog. knows about");
      puts ("-V   show hex dump");
      exit(1);
   }
   fi = xopen(av[j], "r", 8192);
   if (fi == NULL) {
      puts ("could not open file");
      exit(1);
   }
   endpos = xseek(fi, 0, 1);
   xseek(fi, 0, -1);
   iffdecode(fi, 0, endpos);
   xclose(fi);
   if (checkbreak())
      puts ("*BREAK*");
}


iffdecode(fi, tab, endpos)
{
   long chunk[2];
   long curpos, bytes, curend;
   long data;
   char ok;
   char count = 0;

   for (;;) {
      curpos = xseek(fi, 0, 0);
      if (curpos == endpos)
         return(1);
      if (count++ && tab == 0) {
         puts ("Warning: Garbage after IFF-EOF");
         return (0);
      }
      if (curpos + 8 > endpos) {
         puts ("Error: Premature End Of File in header");
         return(0);
      }
      xread(fi, chunk, 8);
      curpos += 8;
      bytes = chunk[1];
      curend = curpos + bytes;
      printf ("%sCHUNK %s (%8ld)", tabstr(tab), ltos(chunk[0]), bytes);
      if (curend > endpos) {
         puts ("\nError: Premature End Of File within chunk");
         return(0);
      }

      ok = 0;
      switch(chunk[0]) {
      case IFF_FILLER:
         printf ("A filler chunk\n");
         if (Modes & MODE_V2)
            hexdump(fi, curpos, bytes, tab);
         break;
      case IFF_FORM:
      case IFF_LIST:
      case IFF_CAT:
      case IFF_PROP:
         xread(fi, &data, 4);
         curpos += 4;
         bytes  -= 4;
         printf ("TYPE %s\n", ltos(data));
         if (checkbreak())
            break;
         iffdecode(fi, tab + 4, curend);
         if (checkbreak())
            break;
         break;
      default:
         ok = 1;
         break;
      }
      if (ok) {
         puts ("");
         if (Modes & MODE_V1)
            decode_sub(fi, tab, chunk[0], bytes);
         if (Modes & MODE_V2)
            hexdump(fi, curpos, bytes, tab);
      }
      if (curend & 1) {
         printf ("%s(Filler Byte)\n", tabstr(tab));
         ++curend;
      }
      xseek(fi, curend, -1);
      if (checkbreak())
         break;
   }
}



decode_sub(fi, tab, name, bytes)
{
   int i, j;

   tab += 4;
   switch (name) {
   case ILBM_BMHD:
      cs(sizeof(U.bmhd), bytes);
      xread(fi, &U.bmhd, sizeof(U.bmhd));
      printf ("%s width= %-4ld\n", tabstr(tab), U.bmhd.w);
      printf ("%sheight= %-4ld\n", tabstr(tab), U.bmhd.h);
      printf ("%splanes= %-4ld\n", tabstr(tab), U.bmhd.planes);
      printf ("%s     x= %-4ld\n", tabstr(tab), U.bmhd.x);
      printf ("%s     y= %-4ld\n", tabstr(tab), U.bmhd.y);
      printf ("%s  mask= x%-2lx\n",tabstr(tab), U.bmhd.masking);
      printf ("%s  comp= x%-2lx\n",tabstr(tab), U.bmhd.compression);
      printf ("%stcolor= %-2ld\n", tabstr(tab), U.bmhd.transparent_color);
      printf ("%sxaspct= %-2ld\n", tabstr(tab), U.bmhd.xaspect);
      printf ("%syaspct= %-2ld\n", tabstr(tab), U.bmhd.yaspect);
      printf ("%s pagew= %-4ld\n", tabstr(tab), U.bmhd.pagewidth);
      printf ("%s pageh= %-4ld\n", tabstr(tab), U.bmhd.pageheight);
      break;
   case ILBM_CMAP:
      if (bytes % 3) {
         puts ("Expected multiples of 3 bytes for colormap");
         break;
      }
      if (bytes > 32*3) {
         puts ("Color map is larger than 32 entries");
         break;
      }
      xread(fi, &U.cmap, bytes);
      j = bytes/3;
      for (i = 0; i < j; ++i) {
         printf ("%scolor %2ld   %2lx %2lx %2lx\n",
            tabstr(tab), i, U.cmap[i][0], U.cmap[i][1], U.cmap[i][2]);
      }
      break;
   case ILBM_GRAB:
   case ILBM_DEST:
   case ILBM_SPRT:
      puts ("");
      break;
   case ILBM_CAMG:
      xread(fi, &U.camg, sizeof(U.camg));
      i = U.camg.vpmodes;
      printf ("%sVP MODES = %8lx (", tabstr(tab), i);
      if (i & HIRES)
         printf("HIRES ");
      if (i & SPRITES)
         printf("SPRITES ");
      if (i & VP_HIDE)
         printf("VP_HIDE ");
      if (i & HAM)
         printf ("HAM ");
      if (i & DUALPF)
         printf ("DUALPF ");
      if (i & GENLOCK_AUDIO)
         printf ("GENLOCK_AUDIO ");
      if (i & EXTRA_HALFBRITE)
         printf ("EXTRA_HALFBRITE ");
      if (i & PFBA)
         printf ("PFBA ");
      if (i & LACE)
         printf ("LACE ");
      if (i & GENLOCK_VIDEO)
         printf ("GENLOCK_VIDEO ");
      puts (")");
      break;
   case ILBM_CRNG:
   case ILBM_BODY:
      break;
   }
}



hexdump(fi, curpos, bytes, tab)
{
   long pos;
   UBYTE ch;

   pos = 0;
   xseek(fi, curpos, -1);
   while (bytes) {
      xread(fi, &ch, 1);
      if ((pos & 15) == 0) {
         if (checkbreak())
            break;
         printf("\n%s%5lx     ", tabstr(tab+4), pos);
      }
      printf ("%2lx ", ch);
      ++pos;
      --bytes;
   }
   puts("");
}



cs(shouldbe, actual)
{
   if (shouldbe != actual)
      printf ("Expected %ld bytes, got %ld\n", shouldbe, actual);
}


char *
tabstr(tab)
{
   static char space[128];
   static int lasttab;
   static int init = 1;

   if (init) {
      bset(space + 1, 127, ' ');
      init = 0;
   }
   if (tab != lasttab) {
      space[lasttab] = ' ';
      space[lasttab = tab] = '\0';
   }
   return (space);
}

char *
ltos(data)
unsigned long data;
{
   static char buf[5];

   buf[0] = (data >> 24) & 0xFF;
   buf[1] = (data >> 16) & 0xFF;
   buf[2] = (data >> 8 ) & 0xFF;
   buf[3] = data & 0xFF;
   return(buf);
}


