/* hpcdtoppm (Hadmut's pcdtoppm) v0.6
*  Copyright (c) 1992, 1993, 1994 by Hadmut Danisch (danisch@ira.uka.de).
*  Permission to use and distribute this software and its
*  documentation for noncommercial use and without fee is hereby granted,
*  provided that the above copyright notice appear in all copies and that
*  both that copyright notice and this permission notice appear in
*  supporting documentation. It is not allowed to sell this software in 
*  any way. This software is not public domain.
*/


/* NOTE: don't use this file for compiling hpcdtoppm, it is heavily */
/* modified by me (Günther Röhrich)                                 */

#include "hpcdtoppm.h"



#define cro(p,d) {if(p) {p->im+=d*p->mwidth; p->iheight-=d;}}
#define cru(p,d) {if(p) {p->iheight-=d;}}
#define crl(p,d) {if(p) {p->im+=d; p->iwidth-=d;}}
#define crr(p,d) {if(p) {p->iwidth-=d;}}


void cropit(sizeinfo *si,implane *l,implane *c1,implane *c2)
 {dim x,y,s,w,h;
  sINT nl,nr,no,nu;

  uBYTE *ptr;

  melde("crop\n");

  if(si->imvlen || si->imhlen) error(E_INTERN);
  w=si->rdhlen;
  h=si->rdvlen;

  if((!l) || (l->iwidth != w) || (l->iheight != h)) error(E_INTERN);
  
  if(!monochrome)
   {if((!c1) || (c1->iwidth != w) || (c1->iheight != h)) error(E_INTERN);
    if((!c2) || (c2->iwidth != w) || (c2->iheight != h)) error(E_INTERN);
   }


  for(y=0,no=0;y<h;y++,no++)
   {for(x=0,ptr=(l->im)+y*(l->mwidth); x<w && (*ptr)<MAX_BLACK ;x++,ptr++);
    if(x<w) break;
   }
  cro(l ,no);
  cro(c1,no);
  cro(c2,no);
  h-=no;


  for(y=h-1,nu=0;y;y--,nu++)
   {for(x=0,ptr=(l->im)+y*(l->mwidth); x<w && (*ptr)<MAX_BLACK ;x++,ptr++);
    if(x<w) break;
   }
  cru(l ,nu);
  cru(c1,nu);
  cru(c2,nu);
  h-=nu;


  s=l->mwidth;

  for(x=0,nl=0;x<w;x++,nl++)
   {for(y=0,ptr=(l->im)+x; y<h && (*ptr)<MAX_BLACK ; y++, ptr+=s);
    if(y<h) break;
   }
  crl(l ,nl);
  crl(c1,nl);
  crl(c2,nl);
  w-=nl;
  

  for(x=w-1,nr=0;x;x--,nr++)
   {for(y=0,ptr=(l->im)+x; y<h && (*ptr)<MAX_BLACK ; y++, ptr+=s);
    if(y<h) break;
   }
  crr(l ,nr);
  crr(c1,nr);
  crr(c2,nr);
  w-=nr;
  
  if (do_melde) 
   {
    if (no || nu || nr || nl )
      fprintf(stderr,"Cut off %d top, %d bottom, %d left, %d right,  new size is %dx%d\n",
              no,nu,nl,nr,w,h);
    else
      fprintf(stderr,"Nothing cut off\n");
   }

  si->imvlen=h;
  si->imhlen=w;
 }


void shrink(sizeinfo *si,implane *l,implane *c1,implane *c2)
 {dim w,h;

  melde("shrink\n");

  w=si->rdhlen;
  h=si->rdvlen;

  if((!l) || (l->iwidth != w) || (l->iheight != h)) error(E_INTERN);
  
  if(!monochrome)
   {if((!c1) || (c1->iwidth != w) || (c1->iheight != h)) error(E_INTERN);
    if((!c2) || (c2->iwidth != w) || (c2->iheight != h)) error(E_INTERN);
   }

  if((!si->imvlen) && (!si->imhlen))  /* no subrectangle given */
   {si->imvlen=si->rdvlen;
    si->imhlen=si->rdhlen;
    return;
   }

  if (si->imvlen>h || si->imvlen<1 )       error(E_INTERN);
  if (si->imvoff> si->rdvlen - si->imvlen) error(E_INTERN);

  if (si->imhlen>w || si->imhlen<1 ) error(E_INTERN);
  if (si->imhoff> si->rdhlen - si->imhlen) error(E_INTERN);

  cro(l ,si->imvoff);
  cro(c1,si->imvoff);
  cro(c2,si->imvoff);

  cru(l ,si->rdvlen - si->imvoff - si->imvlen);
  cru(c1,si->rdvlen - si->imvoff - si->imvlen);
  cru(c2,si->rdvlen - si->imvoff - si->imvlen);
  
  crl(l ,si->imhoff);
  crl(c1,si->imhoff);
  crl(c2,si->imhoff);

  crr(l ,si->rdhlen - si->imhoff - si->imhlen);
  crr(c1,si->rdhlen - si->imhoff - si->imhlen);
  crr(c2,si->rdhlen - si->imhoff - si->imhlen);
  

 }



void halve(implane *p)
 {dim w,h,x,y;
  uBYTE *optr,*nptr;

  melde("halve\n");
  if ((!p) || (!p->im)) error(E_INTERN);

  w=p->iwidth/=2;      
  h=p->iheight/=2;     


  for(y=0;y<h;y++)
   {
    nptr=(p->im) +   y*(p->mwidth);
    optr=(p->im) + 2*y*(p->mwidth);

    for(x=0;x<w;x++,nptr++,optr+=2)
     { *nptr = *optr;
     }

   }

 }




void planealloc(implane *p, dim width, dim height)
{
  melde("planealloc\n");
 
  p->iwidth=p->iheight=0;
  p->mwidth=width;
  p->mheight=height;

  p->mp = ( p->im = ( uBYTE * ) malloc  (width*height*sizeof(uBYTE)) );
  if(!(p->im)) error(E_MEM);
}
 

enum ERRORS readplain(sizeinfo *si,int fak,implane *l,implane *c1,implane *c2)
 {dim i,w,h,hoff,hlen,voff,vlen;
  uBYTE *pl=0,*pc1=0,*pc2=0;

  melde("readplain\n");

#ifdef DEBUG
  fprintf(stderr,"readplain %d %d %d %d %d %d %d\n",fak,si->w,si->h,si->rdhoff,si->rdhlen,si->rdvoff,si->rdvlen);
#endif

  if(fak >= 0)
   {w   =si->w     *fak;
    h   =si->h     *fak;
    hoff=si->rdhoff*fak;  if(hoff & 1 ) error(E_INTERN);  /* Must be all even */
    hlen=si->rdhlen*fak;  if(hlen & 1 ) error(E_INTERN);
    voff=si->rdvoff*fak;  if(voff & 1 ) error(E_INTERN);
    vlen=si->rdvlen*fak;  if(vlen & 1 ) error(E_INTERN);
   }
  else
   {fak = -fak;
    w   =si->w     /fak;
    h   =si->h     /fak;
    hoff=si->rdhoff/fak;  if(hoff & 1 ) error(E_INTERN);  /* Must be all even */
    hlen=si->rdhlen/fak;  if(hlen & 1 ) error(E_INTERN);
    voff=si->rdvoff/fak;  if(voff & 1 ) error(E_INTERN);
    vlen=si->rdvlen/fak;  if(vlen & 1 ) error(E_INTERN);
   }


    
  if(l)
   { if ((l->mwidth<hlen) || (l->mheight<vlen) || (!l->im)) error(E_INTERN);
     l->iwidth=hlen;
     l->iheight=vlen;
     pl=l->im;
   }

  if(c1)
   { if ((c1->mwidth<(hlen>>1)) || (c1->mheight<(vlen>>1)) || (!c1->im)) error(E_INTERN);
     c1->iwidth=hlen>>1;
     c1->iheight=vlen>>1;
     pc1=c1->im;
   }

  if(c2)
   { if ((c2->mwidth<(hlen>>1)) || (c2->mheight<(vlen>>1)) || (!c2->im)) error(E_INTERN);
     c2->iwidth=hlen>>1;
     c2->iheight=vlen>>1;
     pc2=c2->im;
   }

  if(voff) SKIPr(w*3*(voff>>1));

  for(i=0;i<vlen>>1;i++)
   {
    if(pl)
     { if(hlen==w)
        {if(READ(pl,w)<1) return(E_READ);
         pl+= l->mwidth;

         if(READ(pl,w)<1) return(E_READ);
         pl+= l->mwidth;
        }
       else
        {SKIPr(hoff);

         if(READ(pl,hlen)<1) return(E_READ);
         pl+= l->mwidth;
         
         SKIPr(w-hlen);    /* w - hlen - hoff + hoff */ 

         if(READ(pl,hlen)<1) return(E_READ);
         pl+= l->mwidth;

         SKIPr(w-hoff-hlen);         
        }
     }
    else SKIPr(2*w);
     
    if(pc1)
     {
       if(hlen==w)
        {
         if(READ(pc1,w>>1)<1) return(E_READ);
         pc1+= c1->mwidth;
        }
       else
        {SKIPr((hoff)>>1);
         if(READ(pc1,hlen>>1)<1) return(E_READ);
         pc1+= c1->mwidth;
         SKIPr((w-hoff-hlen)>>1);
        }
     }
    else SKIPr(w>>1);
     
    if(pc2)
     {
       if(hlen==w)
        {
         if(READ(pc2,w>>1)<1) return(E_READ);
         pc2+= c2->mwidth;
        }
       else
        {SKIPr((hoff)>>1);
         if(READ(pc2,hlen>>1)<1) return(E_READ);
         pc2+= c2->mwidth;
         SKIPr((w-hoff-hlen)>>1);
        }
     }
    else SKIPr(w>>1);


   }
  RPRINT;
  return E_NONE;
 }

void interpolate(implane *p)
 {dim w,h,x,y,yi;
  uBYTE *optr,*nptr,*uptr;

  melde("interpolate\n");
  if ((!p) || (!p->im)) error(E_INTERN);

  w=p->iwidth;
  h=p->iheight;

  if(p->mwidth  < 2*w ) error(E_INTERN);
  if(p->mheight < 2*h ) error(E_INTERN);


  p->iwidth=2*w;
  p->iheight=2*h;


  for(y=0;y<h;y++)
   {yi=h-1-y;
    optr=p->im+  yi*p->mwidth + (w-1);
    nptr=p->im+2*yi*p->mwidth + (2*w - 2);

    nptr[0]=nptr[1]=optr[0];

    for(x=1;x<w;x++)
     { optr--; nptr-=2;
       nptr[0]=optr[0];
       nptr[1]=(((sINT)optr[0])+((sINT)optr[1])+1)>>1;
     }
    }

  for(y=0;y<h-1;y++)
   {optr=p->im + 2*y*p->mwidth;
    nptr=optr+p->mwidth;
    uptr=nptr+p->mwidth;

    for(x=0;x<w-1;x++)
     {
      nptr[0]=(((sINT)optr[0])+((sINT)uptr[0])+1)>>1;
      nptr[1]=(((sINT)optr[0])+((sINT)optr[2])+((sINT)uptr[0])+((sINT)uptr[2])+2)>>2;
      nptr+=2; optr+=2; uptr+=2;
     }
    *(nptr++)=(((sINT)*(optr++))+((sINT)*(uptr++))+1)>>1;
    *(nptr++)=(((sINT)*(optr++))+((sINT)*(uptr++))+1)>>1;
   }


  optr=p->im + (2*h-2)*p->mwidth;
  nptr=p->im + (2*h-1)*p->mwidth;
  for(x=0;x<w;x++)
   { *(nptr++) = *(optr++);  *(nptr++) = *(optr++); }

 }


void eerror(enum ERRORS e,char *file,int line)
 {
  
  switch(e)
   {case E_NONE:   return;
    case E_IMP:    fprintf(stderr,"Sorry, Not yet implemented. [%s:%d]\n",file,line); break;
    case E_READ:   fprintf(stderr,"Error while reading.\n"); break;
    case E_WRITE:  fprintf(stderr,"Error while writing.\n"); break;
    case E_INTERN: fprintf(stderr,"Internal error. [%s:%d]\n",file,line); break; 
    case E_MEM:    fprintf(stderr,"Not enough memory !\n"); break;
    case E_DISPLAY: fprintf(stderr, "Could not open display!\n"); break;
    case E_MAPFILE: fprintf(stderr, "Error while reading mapfile.\n"); break;
    case E_ABORT:  close_all();
                   exit(0);

    case E_ARG:    fprintf(stderr,"Usage: PhotoCDAGA PhotoCD-file [ppm-file] switches\n"
           "switches: -b name  search for mapfile with basename\n" 
           "          -x       overskip mode (tries to improve color quality)\n"
           "          -s       apply simple sharpness-operator on the Luma-channel\n"
           "          -c       try to cut off the black frame\n"
           "          -n       don't rotate\n"
           "          -r       rotate clockwise for portraits\n"
           "          -l       rotate counter-clockwise for portraits\n"
           "          -h       rotate twice, turn on head\n"
           "          -m       show decoding steps\n"
           "          -c-      correct darker\n"
           "          -c+      correct brighter\n"
           "          -pgm     create grayscale pgm output\n"
           "          -ppm     create ppm output\n"
           "          -gray    use grayscale display\n"
           "          -vga     use VGA screenmode\n"
           "          -1       extract 128x192 (Base/16)\n"
           "          -2       extract 256x384 (Base/4)\n"
           "          -3       extract 512x768 (Base), default\n"); break;
   }
  close_all();
  exit(10);
}




static void flip_corr(dim w,dim h,uBYTE **ptr,sdim *ystep,sdim *xstep)
{
 if(flvert) 
 {
   (*ptr) += (h-1)* (*ystep);
   (*ystep) = -(*ystep);
 }

 if(flhori)
 {
   (*ptr) += (w-1)* (*xstep);
   (*xstep) = -(*xstep);
 }
}




static void call_1plane(OUT1PL proc, FILE *fout,
                        dim w,    dim h,uBYTE * ptr,
                        sdim zeil, sdim pix) 
 {
  flip_corr(w,h,&ptr,&zeil,&pix);
  (*proc)(fout,w,h,ptr,zeil,pix);
 }



static void do_1plane(OUT1PL proc, FILE *fout,
                      dim w,dim h,implane *g,enum TURNS t)
 {
   switch(t)
    {case T_NONE: call_1plane(proc,fout,w,h,g->im,g->mwidth,1);
                  break;
     case T_RIGHT:call_1plane(proc,fout,h,w,g->im + g->mwidth * ( g->iheight - 1) , 1 , -(g->mwidth));
                  break;
     case T_LEFT: call_1plane(proc,fout,h,w,g->im + g->iwidth - 1 , -1 , (g->mwidth));
                  break; 
     case T_HEAD: call_1plane(proc,fout,w,h,g->im + g->iwidth - 1 + g->mwidth * ( g->iheight - 1)  , -(g->mwidth) , -1);
                  break;     
     default:error(E_INTERN);
    }

 }







static void call_3plane(OUT3PL proc, FILE *fout,  dim w,dim h, 
                        uBYTE *rptr,sdim rzeil,sdim rpix,  
                        uBYTE *gptr,sdim gzeil,sdim gpix,  
                        uBYTE *bptr,sdim bzeil,sdim bpix) 
 {
  flip_corr(w,h,&rptr,&rzeil,&rpix);
  flip_corr(w,h,&gptr,&gzeil,&gpix);
  flip_corr(w,h,&bptr,&bzeil,&bpix);

  (*proc)(fout,w,h,rptr,rzeil,rpix,gptr,gzeil,gpix,bptr,bzeil,bpix );
 }


static void do_3plane(OUT3PL proc,FILE *fout,dim w,dim h,
                      implane *r,implane *g,implane *b,
                      enum TURNS t)
 {
   switch(t)
    {case T_NONE: call_3plane(proc,fout,w,h,r->im,r->mwidth,1,
                                            g->im,g->mwidth,1,
                                            b->im,b->mwidth,1);
                  break;     
     case T_RIGHT:call_3plane(proc,fout,h,w,r->im + r->mwidth * ( r->iheight - 1) , 1 , -(r->mwidth),
                                            g->im + g->mwidth * ( g->iheight - 1) , 1 , -(g->mwidth),
                                            b->im + b->mwidth * ( b->iheight - 1) , 1 , -(b->mwidth));
                  break;     
     case T_LEFT: call_3plane(proc,fout,h,w,r->im + r->iwidth - 1 , -1 , (r->mwidth),
                                            g->im + g->iwidth - 1 , -1 , (g->mwidth),
                                            b->im + b->iwidth - 1 , -1 , (b->mwidth));
                  break;           
     case T_HEAD: call_3plane(proc,fout,w,h,r->im + r->iwidth - 1 + r->mwidth * ( r->iheight - 1)  , -(r->mwidth) , -1,
                                            g->im + g->iwidth - 1 + g->mwidth * ( g->iheight - 1)  , -(g->mwidth) , -1,
                                            b->im + b->iwidth - 1 + b->mwidth * ( b->iheight - 1)  , -(b->mwidth) , -1);
                  break;     
     default:error(E_INTERN);
    }

 }



static sINT testbegin(void)
 {sINT i,j;
  for(i=j=0;i<32;i++)
    if(sbuffer[i]==0xff) j++;

  return (j>30);
  
 }


sINT Skip4Base(void)
 {sINT cd_offset,cd_offhelp;
  
  cd_offset = L_Head + L_Base16 + L_Base4 + L_Base ;
  SEEK(cd_offset+3);          
  EREADBUF;    
  cd_offhelp=((((sINT)sbuffer[510])<<8)|sbuffer[511]) + 1;

  cd_offset+=cd_offhelp;

  SEEK(cd_offset);
  EREADBUF;
  while(!testbegin())
   {cd_offset++;
    EREADBUF;
   }
  return cd_offset;
 }



void writepicture(FILE *fout, sizeinfo *si, 
                  implane *r,implane *g,implane *b,
                  enum TURNS t)
 {dim w,h;

  w=si->imhlen;
  h=si->imvlen;

  melde("writepicture\n");
     if((!r) || (r->iwidth != w ) || (r->iheight != h) || (!r->im)) error(E_INTERN);
  
  if(!monochrome)
   {
     if((!g) || (g->iwidth != w ) || (g->iheight != h) || (!g->im)) error(E_INTERN);
     if((!b) || (b->iwidth != w ) || (b->iheight != h) || (!b->im)) error(E_INTERN);
   }

  switch(outfor)
   {
    case O_PPM:    do_3plane(write_ppm     ,fout,w,h,r,g,b,t); break;
    case O_DCOLOR: do_3plane(write_dcolor  ,fout,w,h,r,g,b,t); break;

    case O_PGM:   do_1plane(write_pgm     ,fout,w,h,r,t);     break;
    case O_DGRAY: do_1plane(write_dgray     ,fout,w,h,r,t);     break;

    default: error(E_INTERN);
   }


 }



struct ph1 
 {char  id1[8];
  uBYTE ww1[14];
  char  id2[20];
  char  id3[4*16+4];
  short ww2;
  char  id4[20];
  uBYTE ww3[2*16+1];
  char  id5[4*16];
  uBYTE idx[11*16];
 } ;


void druckeid(void)
{struct ph1 *d;
 char ss[100];

 d=(struct ph1 *)sbuffer;

#define dr(feld,kennung)   \
     strncpy(ss,feld,sizeof(feld));\
     ss[sizeof(feld)]=0;\
     fprintf(stderr,"%s: %s \n",kennung,ss);


dr(d->id1,"Id1")
dr(d->id2,"Id2")
dr(d->id3,"Id3")
dr(d->id4,"Id4")
dr(d->id5,"Id5")

#undef dr 

}

struct pcdquad { uBYTE len,highseq,lowseq,key;};
struct pcdhqt  { uBYTE entries; struct pcdquad entry[256];};
struct myhqt   { uINT seq,mask,len; uBYTE key; };

static struct myhqt myhuff0[256],myhuff1[256],myhuff2[256];
static sINT          myhufflen0=0,myhufflen1=0,myhufflen2=0;



static void readhqtsub(struct pcdhqt *quelle,struct myhqt *ziel,sINT *anzahl)
#define E ((uINT) 1)
 {sINT i;
  struct pcdquad *sub;
  struct myhqt *help;
  *anzahl=(quelle->entries)+1;

  for(i=0;i<*anzahl;i++)
   {sub = (struct pcdquad *)(((uBYTE *)quelle)+1+i*sizeof(*sub));
    help=ziel+i;

    help->seq = (((uINT) sub->highseq) << 24) |(((uINT) sub->lowseq) << 16);
    help->len = ((uINT) sub->len) +1;
    help->key = sub->key;

#ifdef DEBUGhuff
   fprintf(stderr," Anz: %d A1: %08x  A2: %08x X:%02x %02x %02x %02x Seq:  %08x   Laenge:  %d %d\n",
          *anzahl,(uINT)sbuffer,(uINT)sub,
          ((uBYTE *)sub)[0],((uBYTE *)sub)[1],((uBYTE *)sub)[2],((uBYTE *)sub)[3],
          help->seq,help->len,sizeof(uBYTE));
#endif

    if(help->len > 16) error(E_HUFF);

    help->mask = ~ ( (E << (32-help->len)) -1); 

  }
#ifdef DEBUG
  for(i=0;i<*anzahl;i++)
   {help=ziel+i;
    fprintf(stderr,"H: %3d  %08lx & %08lx (%2d) = %02x = %5d  %8x\n",
        i, help->seq,help->mask,help->len,help->key,(sBYTE)help->key,
        help->seq & (~help->mask));
   }
#endif

#undef E
}




void readhqt(sINT n)
 {
  uBYTE *ptr;

  melde("readhqt\n");
  EREADBUF;
  ptr = sbuffer;

  readhqtsub((struct pcdhqt *)ptr,myhuff0,&myhufflen0);

  if(n<2) return;
  ptr+= 1 + 4* myhufflen0;
  readhqtsub((struct pcdhqt *)ptr,myhuff1,&myhufflen1);

  if(n<3) return;
  ptr+= 1 + 4* myhufflen1;
  readhqtsub((struct pcdhqt *)ptr,myhuff2,&myhufflen2);

}



#ifdef FASTHUFF

static struct myhqt *HTAB0[0x10000],*HTAB1[0x10000],*HTAB2[0x10000];

static void inithuff(sINT hlen,struct myhqt *ptr,struct myhqt *TAB[])
 {sINT i,n;
  sINT seq,len;
  struct myhqt *help;

  for(i=0;i<0x10000;i++) TAB[i]=0;

  for(n=0;n<hlen;n++)
   {help=ptr+n;
    seq=(help->seq)>>16;
    len=help->len;

    for(i=0;i<(1<<(16-len));i++)
      TAB[seq | i] = help;
   }
 }
#endif



static char *pn[]={"Luma Channel","Chroma1 Channel","Chroma2 Channel"};


void decode(sizeinfo *si,int fak,implane *f,implane *f1,implane *f2,sINT autosync)
 {dim w,h,hoff,hlen,hende,voff,vlen,vende,anfang,ende;
  sINT htlen,sum,do_inform,part;
  uINT sreg,maxwidth;
  uINT inh,n,zeile,segment,ident;
  struct myhqt *hp;

  uBYTE *nptr;
  uBYTE *lptr;

#define nextbuf  {  nptr=sbuffer; if(READBUF<1) { if(!do_rep) error(E_READ); \
                                                  fprintf(stderr,"Read error\n"); \
                                                  return; } }
#define checkbuf { if (nptr >= sbuffer + sizeof(sbuffer)) nextbuf; }

#ifdef U_TOO_LONG
#define shiftreg(n) sreg = (sreg<< n ) & 0xffffffff;
#else
#define shiftreg(n) sreg<<=n;
#endif

#define shiftout(n){ shiftreg(n); inh-=n; \
                     while (inh<=24) \
                      {checkbuf; \
                       sreg |= ((uINT)(*(nptr++)))<<(24-inh);\
                       inh+=8;\
                      }\
                    }  
#define issync     ((sreg & 0xffffff00) == 0xfffffe00) 
#define brutesync  ((sreg & 0x00fff000) == 0x00fff000) 
#define seeksync { while (!brutesync) shiftout(8); while (!issync) shiftout(1);}

#ifdef FASTHUFF
  struct myhqt **HTAB;
  HTAB=0;
  inithuff(myhufflen0,myhuff0,HTAB0);
  inithuff(myhufflen1,myhuff1,HTAB1);
  inithuff(myhufflen2,myhuff2,HTAB2);
#define SETHUFF0 HTAB=HTAB0;
#define SETHUFF1 HTAB=HTAB1;
#define SETHUFF2 HTAB=HTAB2;
#define FINDHUFF(x) {x=HTAB[sreg>>16];}

#else

  sINT i;
  struct myhqt *htptr;
  htptr=0;
#define SETHUFF0 { htlen=myhufflen0 ; htptr = myhuff0 ; }
#define SETHUFF1 { htlen=myhufflen1 ; htptr = myhuff1 ; }
#define SETHUFF2 { htlen=myhufflen2 ; htptr = myhuff2 ; }
#define FINDHUFF(x)  {for(i=0, x=htptr;(i<htlen) && ((sreg & x ->mask)!= x->seq); i++,x++); \
                      if(i>=htlen) x=0;}
#endif

  melde("decode\n");
  anfang=ende=0;

  if(fak >= 0)
   {w   =si->w     *fak;
    h   =si->h     *fak;
    hoff=si->rdhoff*fak;  if(hoff & 1 ) error(E_INTERN);  /* Must be all even */
    hlen=si->rdhlen*fak;  if(hlen & 1 ) error(E_INTERN); hende=hlen+hoff;
    voff=si->rdvoff*fak;  if(voff & 1 ) error(E_INTERN);
    vlen=si->rdvlen*fak;  if(vlen & 1 ) error(E_INTERN); vende=vlen+voff;
   }
  else
   {fak = -fak;
    w   =si->w     /fak;
    h   =si->h     /fak;
    hoff=si->rdhoff/fak;  if(hoff & 1 ) error(E_INTERN);  /* Must be all even */
    hlen=si->rdhlen/fak;  if(hlen & 1 ) error(E_INTERN); hende=hlen+hoff; 
    voff=si->rdvoff/fak;  if(voff & 1 ) error(E_INTERN);
    vlen=si->rdvlen/fak;  if(vlen & 1 ) error(E_INTERN); vende=vlen+voff;
   }


  if( f  && ((! f->im) || ( f->iheight != vlen  ) ||  (f->iwidth != hlen  ))) error(E_INTERN);
  if( f1 && ((!f1->im) || (f1->iheight != vlen/2) || (f1->iwidth != hlen/2))) error(E_INTERN);
  if( f2 && ((!f2->im) || (f2->iheight != vlen/2) || (f2->iwidth != hlen/2))) error(E_INTERN);

  htlen=sreg=maxwidth=0;
  zeile=0;
  nextbuf;
  inh=32;
  lptr=0;
  part=do_inform=0;
  shiftout(16);
  shiftout(16);

  if(autosync) seeksync;
  
  if(!issync)
   { if(!do_rep) error(E_SEQ6);
     else 
      {fprintf(stderr,"Image does not start with synchron mark, seeking...\n");
       seeksync;
       do_inform=1;
      }
   }

  n=0;

  for(;;)
   {
    if (issync)
     {shiftout(24);
      ident=sreg>>16;
      shiftout(16);

      zeile=(ident>>1) & 0x1fff;
      segment=ident>>14;
      if(do_inform) {fprintf(stderr,"Synchron mark found Line %d\n",zeile);do_inform=0;}
#ifdef DEBUG
      fprintf(stderr,"Id %4x Zeile: %6d Seg %3d Pix bisher: %5d  Position: %8lx+%5lx=%8x\n",
          ident,zeile,segment,n,bufpos,nptr-sbuffer,bufpos+nptr-sbuffer);
#endif


      if(lptr && (n!=maxwidth)) 
       {if(!do_rep)error(E_SEQ1);
        else fprintf(stderr,"Line %d in %s : wrong length of last line (%d)\n",zeile,pn[part],n);
       }
      n=0;

      if(zeile==h) {RPRINT; return; }
      if(zeile >h) 
       { if(!do_rep) error(E_SEQ2);
         else 
          {fprintf(stderr,"Wrong line number %d, ignoring line\n",zeile);
           seeksync;
           n=maxwidth;
           do_inform=1;
          }
       }    
      else switch(segment)
       {
        case 1: if(!do_rep) error(E_SEQ3);
                fprintf(stderr,"Abnormal line tag in %d, interpreting as Luma tag\n",zeile);
        case 0: maxwidth=w;
                if((!f) && autosync) {seeksync; n=maxwidth; break;}
                if(!f) error(E_SEQ7);
                if((zeile<voff) || (zeile >= vende)) {seeksync; n=maxwidth; break;}
                anfang=hoff; ende=hende;
                lptr=f->im + (zeile-voff)*f->mwidth;
                SETHUFF0;
                part=0;
                break;

        case 2: maxwidth=w>>1;
                if(!f1) return;
                /*if((!f1) && autosync) {seeksync; break;}*/
                if((zeile<voff) || (zeile >= vende)) {seeksync; n=maxwidth; break;}
                anfang=hoff>>1; ende=hende>>1;
                lptr=f1->im + ((zeile-voff)>>1)*f1->mwidth;
                SETHUFF1;
                part=1;
                break;
 
        case 3: maxwidth=w>>1;
                if(!f2) return;
                /*if((!f2) && autosync) {seeksync; break;}*/
                if((zeile<voff) || (zeile >= vende)) {seeksync; n=maxwidth; break;}
                anfang=hoff>>1; ende=hende>>1;
                lptr=f2->im + ((zeile-voff)>>1)*f2->mwidth;
                SETHUFF2;
                part=2;
                break;

        default:error(E_SEQ3);
	}
     }
    else
     {
      if(!lptr)      error(E_SEQ6);

      if(n>maxwidth) 
        {
#ifdef DEBUG
         fprintf(stderr,"Register: %08lx Pos: %08lx\n",sreg,bufpos+nptr-sbuffer);
#endif
         if (!do_rep) error(E_SEQ4);
         else { fprintf(stderr,"Missing synchron mark in %s line %d\n",pn[part],zeile);
                seeksync;
                do_inform=1;
                n=maxwidth;
              }
       }
      else
       {FINDHUFF(hp);
        if(!hp)
         { if(!do_rep) error(E_SEQ5);
           fprintf(stderr,"Unable to decode, ignoring rest of line\n");
           seeksync;
           n=maxwidth;
           do_inform=1;
         }
        else
         {if((n>= anfang) && (n<ende))
           {sum=((sINT)(*lptr)) + ((sBYTE)hp->key);
            NORM(sum);
            *(lptr++) = sum;
           }

          n++; 
          shiftout(hp->len);
         }
       }
     }

   }


#undef nextbuf  
#undef checkbuf 
#undef shiftout
#undef issync
#undef seeksync

 }