#define FARBE screen->ViewPort.ColorMap,i

struct IffHeader
  {
  ULONG   FormChunk;
   ULONG  FormLen;
  ULONG   ChunkType;
  ULONG   BmhdChunk;
   ULONG  BmhdLen;
   UWORD  Width;
   UWORD  Height;
   WORD   XPos;
   WORD   YPos;
   UBYTE  NumberOfBitPlanes;
   UBYTE  Masking;
   UBYTE  Compression;
   UBYTE  NullByte;
   UWORD  TransparentColor;
   UBYTE  XAspect;
   UBYTE  YAspect;
   WORD   PWidth;
   WORD   PHeight;
  ULONG   CamgChunk;
   ULONG  CamgLen;
   ULONG  ViewModes;
  ULONG   CmapChunk;
   ULONG  CmapLen;
   UBYTE  Colors[95];     /*  32 * 3 */
  ULONG   BodyChunk;
   ULONG  BodyLen;
  };

#define DUMP   0
#define RUN   1

#define MinRun 3
#define MaxRun 128
#define MaxDat 128

LONG putSize;
#define GetByte()   (*source++)
#define PutByte(c)   { *dest++ = (c);   ++putSize; }

char superiffbuffer[256];   /* [TBD] should be 128?  on stack?*/

BYTE *PutDump(dest, nn)  register BYTE *dest;  register int nn; {
   register int i;

   PutByte(nn-1);
   for(i = 0;  i < nn;  i++)   PutByte(superiffbuffer[i]);
   return(dest);
   }

BYTE *PutRun(dest, nn, cc)   register BYTE *dest;  register int nn, cc; {
   PutByte(-(nn-1));
   PutByte(cc);
   return(dest);
   }

#define OutDump(nn)   dest = PutDump(dest, nn)
#define OutRun(nn,cc) dest = PutRun(dest, nn, cc)

/*----------- PackRow --------------------------------------------------*/
/* Given POINTERS TO POINTERS, packs one row, updating the source and
   destination pointers.  RETURNs count of packed bytes.*/
LONG PackRow(pSource, pDest, rowSize)
    register BYTE **pSource, **pDest;   LONG rowSize; {
    register BYTE *source, *dest;
    char c,lastc = '\0';
    BOOL mode = DUMP;
    short nbuf = 0;      /* number of chars in buffer */
    short rstart = 0;      /* buffer index current run starts */

    source = *pSource;
    dest = *pDest;
    putSize = 0;
    superiffbuffer[0] = lastc = c = GetByte();  /* so have valid lastc */
    nbuf = 1;   rowSize--;   /* since one byte eaten.*/


    for (;  rowSize;  --rowSize) {
   superiffbuffer[nbuf++] = c = GetByte();
   switch (mode) {
      case DUMP:
         /* If the buffer is full, write the length byte,
            then the data */
         if (nbuf>MaxDat) {
            OutDump(nbuf-1);
            superiffbuffer[0] = c;
            nbuf = 1;   rstart = 0;
            break;
            }

         if (c == lastc) {
             if (nbuf-rstart >= MinRun) {
            if (rstart > 0) OutDump(rstart);
            mode = RUN;
            }
             else if (rstart == 0)
            mode = RUN;   /* no dump in progress,
            so can't lose by making these 2 a run.*/
             }
         else  rstart = nbuf-1;      /* first of run */
         break;

      case RUN: if ( (c != lastc)|| ( nbuf-rstart > MaxRun)) {
             /* output run */
            OutRun(nbuf-1-rstart,lastc);
             superiffbuffer[0] = c;
             nbuf = 1; rstart = 0;
             mode = DUMP;
             }
         break;
      }

   lastc = c;
   }

    switch (mode) {
   case DUMP: OutDump(nbuf); break;
   case RUN: OutRun(nbuf-rstart,lastc); break;
   }
    *pSource = source;
    *pDest = dest;
    return(putSize);
    }

SaveIff(screen,name)
struct Screen *screen;
char *name;
  {
   ULONG PackeZeile();
   struct IffHeader SaveHeader;
   struct FileHandle *savedatei;
   ULONG *DosBase;
   struct GfxBase *GfxBase;
   BYTE *picdata;
   BYTE *hilfsptr;
   register ULONG i,j,k;
   ULONG puffer;
   ULONG bpr;
   BOOL  erfolg;
   PLANEPTR myplanes[6];

   if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0L)))
     {
      return(FALSE);
     }

   if(!(DosBase = OpenLibrary("dos.library",0L)))
     {
       CloseLibrary(GfxBase);
       return(FALSE);
     }

   SaveHeader.FormChunk = 0x464f524d; /* FORM */
   SaveHeader.ChunkType = 0x494c424d; /* ILBM */
   SaveHeader.BmhdChunk = 0x424d4844; /* BMHD */
   SaveHeader.BmhdLen   = 20;       /* vorausgesetzt */
   SaveHeader.Width = SaveHeader.PWidth  = screen->Width;
   SaveHeader.Height= SaveHeader.PHeight = screen->Height;
   SaveHeader.XPos      = screen->LeftEdge;
   SaveHeader.YPos      = screen->TopEdge;
   SaveHeader.NumberOfBitPlanes = screen->BitMap.Depth;
   SaveHeader.Masking   = 0;
   SaveHeader.Compression = 1;
   SaveHeader.NullByte  = 0;         /*    Komplett  */
   SaveHeader.TransparentColor = 0;
   if(screen->Height > 300) SaveHeader.XAspect = 20;
   else                     SaveHeader.XAspect = 10;
   SaveHeader.YAspect   = 11;
   SaveHeader.CamgChunk = 0x43414d47; /* CAMG */
   SaveHeader.CamgLen   = 4;         /* Setz ich einfach mal voraus */
   SaveHeader.ViewModes = (ULONG)screen->ViewPort.Modes;
   SaveHeader.CmapChunk = 0x434d4150; /* CMAP */
   SaveHeader.CmapLen   = 96;        /* 32 *3 */
   SaveHeader.BodyChunk = 0x424f4459; /* BODY */

   k = 1 << SaveHeader.NumberOfBitPlanes;
   j = 0;
   for(i=0;i<96;i++) SaveHeader.Colors[i]= 0;

   for(i=0;i<k;i++)
       {
     SaveHeader.Colors[j++] = (UBYTE)(((GetRGB4(FARBE) >> 8) & 0x0f)*0x10);
     SaveHeader.Colors[j++] = (UBYTE)(((GetRGB4(FARBE) >> 4) & 0x0f)*0x10);
     SaveHeader.Colors[j++] = (UBYTE)((GetRGB4(FARBE) & 0x0f)*0x10);
       }
   i = (ULONG)SaveHeader.Width;
   j = (ULONG)SaveHeader.Height;
   k =  (ULONG)SaveHeader.NumberOfBitPlanes;
   puffer = (i*j*k)/8L;  /* Pufferspeicher für Packer */

   if(!(picdata = (BYTE *)AllocMem(puffer,MEMF_PUBLIC|MEMF_CLEAR)))
      {
       CloseLibrary(GfxBase);
       CloseLibrary(DosBase);
       return(FALSE);
      }
   j=0;
   hilfsptr = picdata;
 for(i=0;i<SaveHeader.NumberOfBitPlanes;i++)
       myplanes[i] = screen->BitMap.Planes[i];

 bpr = (ULONG)screen->BitMap.BytesPerRow;

   for(i=0;i<screen->Height;i++)
      {
       k=0;
       while(k<SaveHeader.NumberOfBitPlanes)
          {
           j = j + PackRow(&myplanes[k],&picdata,bpr);
           k++;
          }
      }
        SaveHeader.BodyLen = j;
        SaveHeader.FormLen = j+sizeof(struct IffHeader)-8L;
        if(j & 1) {
                   j++;
                   SaveHeader.FormLen = SaveHeader.FormLen + 1;
                  }

      savedatei = (struct FileHandle *)Open(name,MODE_NEWFILE);
      if(!savedatei)
          {
           goto weg;
          }
   erfolg = Write(savedatei,&SaveHeader,(ULONG)sizeof(struct IffHeader));
       if(erfolg == FALSE)
            {
             goto ganzweg;
            }
   erfolg = Write(savedatei,hilfsptr,j);

ganzweg: Close(savedatei);
weg:  CloseLibrary(GfxBase);
      CloseLibrary(DosBase);
      FreeMem(hilfsptr,puffer);
      if(erfolg == FALSE) return(FALSE);

      else return(TRUE);
}

