/***************************************************************************/
/*                      IFF to chunky converter                            */
/* Compiler: SAS/C  V6.51                                           ORHAN  */
/***************************************************************************/
#define __USE_SYSBASE
#define NO_PROTOS
#define NO_SAS_PRAGMAS

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/nodes.h>
#include <dos/dos.h>
#include <dos/rdargs.h>
#include <iffp/iff.h>
#include <iffp/ilbm.h>
#include <libraries/iffparse.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/iffparse.h>


BOOL  unpkbody(BYTE *body, BYTE *dest, LONG lensrc, LONG lendest);
VOID  copybody(BYTE *body, BYTE *dest, LONG lensrc, LONG lendest);
ULONG readpixel(LONG x, LONG y);


struct  RDArgs       *rdargs=NULL;
struct  IFFHandle    *iff=NULL;
BitMapHeader         bmheader;
struct  ContextNode  *chunk=NULL;
ColorRegister        cmap;
enum    {ARG_IFFFILE,ARG_CHUNKYFILE,ARG_CHUNKYWIDTH,ARG_CHUNKYHEIGHT,ARGCOUNT};
LONG    myarray[ARGCOUNT];
BYTE    *planes=NULL;
BYTE    *body=NULL;
UWORD   *chunky=NULL,*memptr=NULL;
UWORD   palette[256];
LONG    chunkyw,chunkyh,colors,planesize,rowbytes;
LONG    parms[10];
BPTR    f1=NULL;
LONG    rc=NULL,rciff=NULL,rcparse=NULL;
UBYTE   version[]="$VER: ifftochunky 1.0 (12.01.95) © by OR\r\n";


LONG ifftochunky(void)
{
LONG  i,x,y;
  
      SysBase = (*((struct ExecBase **)0x4));
      DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",36);
      if ((IFFParseBase=OpenLibrary("iffparse.library",0))==NULL);
      if (DOSBase==NULL || IFFParseBase==NULL) goto cleanexit;

      rdargs = ReadArgs("IFFFILE/A,"
                        "CHUNKYFILE/A,"
                        "CHUNKYWIDTH/A/N,"
                        "CHUNKYHEIGHT/A/N",&myarray[0],NULL);

      if (!rdargs) {rc=IoErr(); goto cleanexit;}

      chunkyw=*(LONG *)myarray[ARG_CHUNKYWIDTH]; chunkyh=*(LONG *)myarray[ARG_CHUNKYHEIGHT];
      if (chunkyw<=0 || chunkyh<=0) {rciff=11; goto cleanexit;}

      if ((chunky=AllocVec(chunkyw*2,MEMF_PUBLIC))==NULL)
                            {rc=ERROR_NO_FREE_STORE; goto cleanexit;}

      if ((iff=AllocIFF())==NULL) {rciff=4; goto cleanexit;}
      if ((iff->iff_Stream=Open((UBYTE *)myarray[ARG_IFFFILE],MODE_OLDFILE))==NULL)
                        {rc=IoErr(); goto cleanexit;}

      InitIFFasDOS(iff);
      if (OpenIFF(iff,IFFF_READ)) {rc=IoErr(); goto cleanexit;}

      while(1) {
      rcparse = ParseIFF(iff,IFFPARSE_RAWSTEP);
      if (rcparse==IFFERR_EOC) continue; else if (rcparse) break;
      if ((chunk=CurrentChunk(iff))==NULL) {rciff=7; goto cleanexit;}
      if (chunk->cn_Type!=ID_ILBM) {rciff=8; goto cleanexit;}

      if (chunk->cn_ID==ID_CMAP) {
      colors=chunk->cn_Size/sizeof(cmap); if (colors>sizeof(palette)/2) {rciff=10; goto cleanexit;}
      for (i=0; i<colors; i++) {
      if ((ReadChunkBytes(iff,&cmap,sizeof(cmap)))<=0) {rciff=9; goto cleanexit;}
      palette[i] = ((cmap.red & 0xF0)<<4)+(cmap.green & 0xF0)+((cmap.blue>>4) & 0x0F);
                               }
                                 }

      if (chunk->cn_ID==ID_BMHD) {
      if ((ReadChunkBytes(iff,&bmheader,sizeof(bmheader)))<=0) {rciff=9; goto cleanexit;}
      if (bmheader.w<chunkyw || bmheader.h<chunkyh) {rciff=11; goto cleanexit;}
                                 }

      if (chunk->cn_ID==ID_BODY) {
      if ((body=AllocVec(chunk->cn_Size,MEMF_PUBLIC))==NULL)
                            {rc=ERROR_NO_FREE_STORE; goto cleanexit;}
      rowbytes=BytesPerRow(bmheader.w); planesize=rowbytes*bmheader.h;
      if ((planes=AllocVec(planesize*bmheader.nPlanes,MEMF_PUBLIC))==NULL)
                            {rc=ERROR_NO_FREE_STORE; goto cleanexit;}
      if ((ReadChunkBytes(iff,body,chunk->cn_Size))<=0) {rciff=9; goto cleanexit;}
      if (bmheader.compression!=cmpByteRun1)
               copybody(body,planes,chunk->cn_Size,planesize*bmheader.nPlanes);
      else if (unpkbody(body,planes,chunk->cn_Size,planesize*bmheader.nPlanes)==FALSE) {rciff=13; goto cleanexit;}
                                 }
               }


      if (rcparse!=IFFERR_EOF) {rciff=12; goto cleanexit;}
      if ((f1=Open((UBYTE *)myarray[ARG_CHUNKYFILE],MODE_NEWFILE))==NULL)
                        {rc=IoErr(); goto cleanexit;}

      for (y=0; y<chunkyh; y++) {
      memptr=chunky;
      for (x=0; x<chunkyw; x++) *memptr++=palette[readpixel(x,y)];
      if (Write(f1,chunky,chunkyw*2)!=chunkyw*2) {rc=IoErr(); goto cleanexit;}
                                }

      if (Flush(f1)!=DOSTRUE) {rc=IoErr(); goto cleanexit;}

      parms[0]=bmheader.w;
      parms[1]=bmheader.h;
      parms[2]=bmheader.nPlanes;
      parms[3]=colors;
      parms[4]=chunkyw;
      parms[5]=chunkyh;
      parms[6]=16;
      rciff=1;


  cleanexit:
     if (iff) {CloseIFF(iff);
               if (iff->iff_Stream) Close(iff->iff_Stream);
               FreeIFF(iff);
              }

     if (f1) Close(f1);
     if (rdargs) FreeArgs(rdargs);
     if (planes) FreeVec(planes);
     if (chunky) FreeVec(chunky);
     if (body) FreeVec(body);
     if (rc) PrintFault(rc,NULL);

         switch(rciff) {
     case  1: VPrintf("Image size %ldx%ldx%ld, color registers %ld\n"
                      "Chunky size %ldx%ldx%ld, 4096 true colors\n",
                      &parms); break;
     case  4: PutStr("AllocIFF fail\n"); break;
     case  7: PutStr("CurrentChunk fail\n"); break;
     case  8: PutStr("Not an ILBM form\n"); break;
     case  9: PutStr("ReadChunkbytes fail\n"); break;
     case 10: PutStr("Too many colors\n"); break;
     case 11: PutStr("Chunky sizes invalid\n"); break;
     case 12: PutStr("ParseIFF fail\n"); break;
     case 13: PutStr("Unpack fail\n"); break;
                       }

     if (IFFParseBase) CloseLibrary(IFFParseBase);
     if (DOSBase) CloseLibrary((struct Library *)DOSBase);
     return(rc);
}


BOOL unpkbody(BYTE *body, BYTE *dest, LONG lensrc, LONG lendest)
{
WORD n;
BYTE c;
BOOL retcode=FALSE;

      while (lendest>0) {
         if ((lensrc -= 1)<0) goto errorexit;
         n=*body++; 
         if (n>=0) {n++;
                    if ((lensrc  -= n)<0) goto errorexit;
                    if ((lendest -= n)<0) goto errorexit;
                    do {*dest++=*body++;} while (--n>0);
                   }

         else if (n!=-128) {n=-n+1;
                            if ((lensrc  -= 1)<0) goto errorexit;
                            if ((lendest -= n)<0) goto errorexit;
                            c=*body++;
                            do {*dest++=c;} while (--n>0);
                           }
                        }

    retcode=TRUE;
  errorexit:
    return(retcode);
}


VOID copybody(BYTE *body, BYTE *dest, LONG lensrc, LONG lendest)
{
     while (lendest--) *body++=*dest++; 
}


ULONG readpixel(LONG x, LONG y)
{
UBYTE  *location;
UBYTE  c;
ULONG  colreg=NULL;
ULONG  i;

        location=planes+(y+1)*rowbytes*bmheader.nPlanes+x/8;
        x = 7-(x%8);

        for (i=0; i<bmheader.nPlanes; i++) {
        location -= rowbytes;
        c = *location; c = (c>>x) & 1;
        colreg = colreg*2+c;
                                           }

        return(colreg);
}
