/* HaktarExt for Haktar V1.6
   by
   Guido Wegener
°ª°
   Extern/expansion functions including now :
     showilbm
*/
#define LI (long int)
#include <functions.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <exec/types.h>
#include <libraries/dos.h>
#include <intuition/intuition.h>
#include <graphics/gfx.h>
#include <graphics/gfxbase.h>
#define XMPBYTERUN1 1
#define mskHasMask 1
#define BADFLAGS (SPRITES|VP_HIDE|GENLOCK_AUDIO|GENLOCK_VIDEO)
#define FLAGMASK (~BADFLAGS)
#define CAMGMASK (FLAGMASK & (long)(0x0000FFFF))
#define SHOWPIC 0
#define SHOWSUB 1
#define SHOWFACE 2

extern void warn(char *text);
extern void style(void);
extern void clos(char *text);

extern struct DosBase *DosBase;
extern struct IntuitionBase *IntuitionBase;
extern struct GfxBase *GfxBase;
extern struct Screen *subscreen;
extern struct Window *subwindow;
extern struct Screen *MyScreen;
extern struct NewScreen MyNewScreen;
extern struct Window *MyWindow;
extern struct NewWindow MyNewWindow;

struct BitMapHeader
 {
  UWORD w,h;
  WORD x,y;
  UBYTE nPlanes;
  UBYTE masking;
  UBYTE compression;
  UBYTE pad1;
  UWORD transparentColor;
  UBYTE xAspect,yAspect;
  WORD pageWidth,pageHeight;
 };
struct CMap
 {
  UBYTE red,green,blue;
 };

struct Screen *MyIFFScreen=0;
struct Window *iMyWindow=0;
struct NewScreen MyNewIFFScreen=
 {
  0,0,320,STDSCREENHEIGHT,
  1,
  0,1,
  NULL,
  CUSTOMSCREEN/* | SCREENBEHIND*/,
  NULL,
  (UBYTE *)"Haktar by Guido Wegener",
  NULL,
  NULL
 };
struct NewWindow iMyNewWindow=
 {
  0,0,100,100,
  -1,-1,
  ACTIVEWINDOW,
  NOCAREREFRESH | SMART_REFRESH | BORDERLESS,
  NULL,NULL,
  NULL,
  NULL,
  NULL,
  0,0,0,0,
  CUSTOMSCREEN
 };

char nam[5]={0,0,0,0,0};
ULONG leng,pos,realpos,size;
struct BitMapHeader *bmh;
struct CMap *cmap;
UBYTE *cr;
char *mem,*realmem;
char mode;
UBYTE p[]={1,2,4,8,16,32,32,32};
BOOL beensub=FALSE;

void clo(char *text);
void search(char *what);

void showilbm(char *mpoint,ULONG limit,int timelimit,char lmode)
 {
  UBYTE first=0;
  register int i,col,x,y,count,line,plane,anz,xbytes;
  UBYTE *planes[6];
  char *point;
  BYTE lastbyte;
  long control;
  struct RastPort *rp;
  struct Message *msg;

  mode=lmode;
  if(mode==SHOWSUB) beensub=TRUE;
  if(!mpoint) return;
  size=limit;
  pos=1;
  mem=mpoint;
  if(strncmp(mem,"FORM",(size_t)4)) {clo("No IFF file !");return;}
  pos+=4+sizeof(ULONG);
  if(pos>size) {clo("Too short !");return;}
  mem+=4+sizeof(ULONG);
  if(strncmp(mem,"ILBM",(size_t)4)) {clo("No ILBM file !");return;}
  pos+=4;
  if(pos>size) {clo("Too short !");return;}
  mem+=4;
  realmem=mem;
  realpos=pos;
  search("BMHD");
  bmh=(struct BitMapHeader *)mem;
  pos+=sizeof(struct BitMapHeader);
  if(pos>size) {clo("End of File !");return;}
  mem+=sizeof(struct BitMapHeader);
  if(!bmh) {clo("No BitMapHeader !");return;}
  search("CMAP");
  cmap=(struct CMap *)mem;
  if(!cmap) {clo("No ColorMap !");return;}
  mem-=4+sizeof(ULONG);
  pos-=4+sizeof(ULONG);
  if(mode==SHOWFACE && (bmh->w!=640 || bmh->h!=200))
   {
    clo("Wrong format of pic!");
    return;
   }
  bmh->w=(bmh->w+15) & 0xfffffff0;
  if(mode!=SHOWFACE)
   {
    MyNewIFFScreen.Width=bmh->w;
    MyNewIFFScreen.Depth=bmh->nPlanes;
    MyNewIFFScreen.Height=bmh->h;
   }
  if(mode==SHOWFACE)
   {
    RemoveGList(MyWindow,MyWindow->FirstGadget,-1L);
    ClearMenuStrip(MyWindow);
    while(msg=GetMsg(MyWindow->UserPort)) ReplyMsg(msg);
    CloseWindow(MyWindow);
    CloseScreen(MyScreen);
    MyNewScreen.Depth=bmh->nPlanes;
    MyScreen=OpenScreen(&MyNewScreen);
    if(!MyScreen) clos("Can't reopen screen!");
    MyIFFScreen=MyScreen;
/*    MyWindow=OpenWindow(&MyNewWindow);
    if(!MyWindow) clos("Can't reopen window!");
*/    style();
    iMyWindow=MyWindow;
   }
  iMyNewWindow.Width=bmh->w;
  iMyNewWindow.Height=bmh->h;
  search("CAMG");
  if(mode!=SHOWFACE)
   {
    if(mem)
     {
      MyNewIFFScreen.ViewModes=(*((ULONG *)mem)) & CAMGMASK;
     }
    else
     {
      if(bmh->w>320) MyNewIFFScreen.ViewModes|=HIRES;
      if(bmh->h>250) MyNewIFFScreen.ViewModes|=LACE;
      if(bmh->nPlanes==6) MyNewIFFScreen.ViewModes|=HAM;
     }
    if(mode==SHOWSUB)
     {
      MyNewIFFScreen.TopEdge=256-bmh->h;
      if(timelimit) mode=SHOWPIC;
     }
    MyIFFScreen=OpenScreen(&MyNewIFFScreen);
    if(mode==SHOWSUB) subscreen=MyIFFScreen;
    if(!MyIFFScreen) {clo("Can't open screen !");return;}
    iMyNewWindow.Screen=MyIFFScreen;
    iMyWindow=OpenWindow(&iMyNewWindow);
    if(mode==SHOWSUB) subwindow=iMyWindow;
    if(!iMyWindow) {clo("Can't open window !");return;}
   }
  cr=(UBYTE *)cmap;
  for(i=0;i<p[bmh->nPlanes];i++)
   {
    SetRGB4(&(MyIFFScreen->ViewPort),LI(i),LI(*cr/16),LI(*(cr+1)/16),LI(*(cr+2)/16));
    cr+=3;
   }
  rp=(mode==SHOWFACE) ? &(MyIFFScreen->RastPort) : iMyWindow->RPort;
  search("BODY");
  if(!mem) {clo("No Body found !");return;}
  for(i=0;i<bmh->nPlanes;i++)
    planes[i]=(UBYTE *)rp->BitMap->Planes[(bmh->nPlanes-1)-i];
  xbytes=bmh->w/8;
  if(bmh->w%8)xbytes++;
  for(line=0;line<bmh->h;line++)
   {
    for(plane=0;plane<bmh->nPlanes;plane++)
     {
      point=(char *)planes[(bmh->nPlanes)-plane-1]+line*xbytes;
      if(bmh->compression)
       {
        count=0;
        while(count<xbytes)
         {
          pos++;
          if(pos>size) {clo("End in Body !");return;}
          lastbyte=*(mem++);
          if(lastbyte>=0)
           {
            lastbyte++;
            for(i=0;i<lastbyte;i++)
             {
              pos++;
              if(pos>size) {clo("End in Body !!");return;}
              *(point++)=*(mem++);
             }
            count+=lastbyte;
           }
          else
           {
            if(lastbyte!=-128)
             {
              anz=-lastbyte+1;
              pos++;
              if(pos>size) {clo("End in Body !!!");return;}
              lastbyte=*(mem++);
              for(i=0;i<anz;i++)
               {
                *point=lastbyte;
                point++;
               }
              count+=anz;
             }
           }
         }
       }
      else
       {
        for(i=0;i<xbytes;i++)
         {
          pos++;
          if(pos>size) {clo("End in Body !!!!");return;}
          *(point++)=*(mem++);
         }
       }
     }
    if(bmh->masking==mskHasMask)
     {
      if(bmh->compression)
       {
        count=0;
        while(count<xbytes)
         {
          pos++;
          if(pos>size) {clo("End in Mask !");return;}
          lastbyte=*(mem++);
          if(lastbyte>=0)
           {
            lastbyte++;
            pos+=lastbyte;
            if(pos>size) {clo("End in Mask !");return;}
            mem+=lastbyte;
            count+=lastbyte;
           }
          else
           {
            if(lastbyte!=-128)
             {
              anz=-lastbyte+1;
              pos++;
              if(pos>size) {clo("End in Mask !");return;}
              mem++;
              count+=anz;
             }
           }
         }
       }
      else
       {
        pos+=xbytes;
        if(pos>size) {clo("End in Mask !");return;}
        mem+=xbytes;
       }
     }
   }
  if(mode==SHOWPIC || (mode!=SHOWSUB && timelimit))
   {
    ScreenToFront(MyIFFScreen);
    if(!timelimit)
     {
      Wait(1L<<iMyWindow->UserPort->mp_SigBit);
      ReplyMsg(GetMsg(iMyWindow->UserPort));
     }
    else
     {
      for(i=0;i<timelimit;i++)
       {
        msg=GetMsg(iMyWindow->UserPort);
        if(msg)
         {
          ReplyMsg(msg);
          i=timelimit;
         }
        WaitTOF();
       }
     }
   }
  clo (NULL);
 }

void clo(char *text)
 {
  if(text) warn(text);
  if(mode==SHOWPIC)
   {
    CloseWindow(iMyWindow);
    iMyWindow=NULL;
    CloseScreen(MyIFFScreen);
    MyIFFScreen=NULL;
    if(beensub)
     {
      subscreen=NULL;
      subwindow=NULL;
     }
   }
 }

void search(char *what)
 {
  ULONG len;
  int i;

  mem=realmem;
  pos=realpos;
  while(TRUE)
   {
    if(!strncmp(mem,what,(size_t)4))
     {
      pos+=4+sizeof(ULONG);
      if(pos>size) {clo("End in File !");mem=NULL;}
      mem+=sizeof(ULONG)+4;
      return;
     }
    pos+=4;
    if(pos>size) {clo("End in File !!");mem=NULL;return;}
    mem+=4;
    len=*((ULONG *)mem);
    if(pos>size) {clo("End in File !!!");mem=NULL;return;}
    if(len%2) len++;
    pos+=sizeof(ULONG)+len;
    if(pos>size) {clo("End in File !!!!");mem=NULL;return;}
    mem+=sizeof(ULONG)+len;
   }
 }

