home *** CD-ROM | disk | FTP | other *** search
- /* wasp - Copyright 1991 by Steven Reiz
- * see COPYING and wasp.c for further info
- * readgif.c, 9/12/90 - 30/1/91,
- * 30/4/91 - 2/6/91, 23/6/91, 30/6/91,
- * 8/7/91, 8/12/91, 27/12/91 - 29/12/91
- */
-
- static char *sourcefile=__FILE__;
-
- #include "wasp.h"
-
- static u_short width, height;
- static short bitsperpixel, interlaced, codesize;
- static u_short *cm=NULL;
- static u_short *rgboverflowrow=NULL;
- static u_short *gpp;
-
-
- read_gif(void)
- {
- char signature[6], separator;
- short y;
-
- cread(signature, 6);
- if (strncmp(signature, "GIF87a", 6)) {
- cseek_in(0L, 0);
- return 0;
- }
- if (readscreendescriptor())
- readcolormap();
- cread(&separator, 1);
- if (separator!=',')
- error1(E0_FATAL, E1_GIF, E2_FORMAT, E3_MISS_SEP, ',');
- if (readimagedescriptor())
- readcolormap();
- cread(&separator, 1); codesize=separator;
- printe("GIF input; %d x %d, %d bits/pixel", (int)width, (int)height,
- (int)bitsperpixel);
- if (interlaced)
- printe(", interlaced");
- if (codesize!=bitsperpixel)
- printe(", codesize: %d", (int)codesize);
- pute('\n');
- if (!outfilename)
- exit(0);
- xsz=width;
- ysz=height;
- rgb=Malloc(ysz*sizeof(u_short *));
- for (y=0; y<ysz; ++y)
- rgb[y]=Calloc(xsz*sizeof(u_short));
- readbody();
- return 1;
- }
-
-
- readscreendescriptor(void)
- {
- struct sd_t {
- u_char widthlo, widthhi;
- u_char heightlo, heighthi;
- u_char misc, bgindex, reserved;
- } sd;
-
- cread(&sd, 7);
- bitsperpixel=(sd.misc&7)+1;
- return sd.misc&0x80;
- }
-
-
- readimagedescriptor(void)
- {
- struct id_t {
- u_char xoffsetlo, xoffsethi;
- u_char yoffsetlo, yoffsethi;
- u_char widthlo, widthhi;
- u_char heightlo, heighthi;
- u_char misc;
- } id;
-
- cread(&id, 9);
- width=(id.widthhi<<8)|id.widthlo;
- height=(id.heighthi<<8)|id.heightlo;
- interlaced=(id.misc&0x40 ? 1 : 0);
- if (id.misc&0x80) {
- bitsperpixel=(id.misc&7)+1;
- return 1;
- } else
- return 0;
- }
-
-
- void
- readcolormap(void)
- {
- char *rgbin, *rgbp;
- int r, g, b, roundin;
- short i, nentries;
-
- roundin=(gifmaptrunc ? 0 : 8);
- nentries=1<<bitsperpixel;
- rgbin=Malloc(nentries*3);
- if (cm)
- free(cm);
- cread(rgbin, (int)(nentries*3));
- cm=Malloc(nentries*2);
- for (i=0, rgbp=rgbin; i<nentries; ++i) {
- r= *rgbp++ & 0xff;
- g= *rgbp++ & 0xff;
- b= *rgbp++ & 0xff;
- r=(r+roundin)>>4; if (r>15) r=15;
- g=(g+roundin)>>4; if (g>15) g=15;
- b=(b+roundin)>>4; if (b>15) b=15;
- cm[i]=(r<<8)|(g<<4)|b;
- }
- free(rgbin);
- }
-
-
- #define NCODES 6144
- static u_short *codes;
- static u_short *prefix;
- static u_char *suffix;
- static u_char *stack;
- static u_char *stack_end;
- #define NUBYTES 4096
- static u_short *ubytes;
- #define NBUF 16384
- static u_char *buf;
- #define NTRANSCHARS 256
- static u_char *transchars;
- #define NMASKS 64
- static u_short *masks;
-
-
- void
- readbody(void)
- {
- codes=Malloc(NCODES*sizeof(u_short));
- ubytes=Malloc(NUBYTES);
- buf=Malloc(NBUF);
- transchars=Malloc(NTRANSCHARS);
- masks=Malloc(NMASKS*sizeof(u_short));
- prefix=Malloc(NCODES*sizeof(u_short));
- suffix=Malloc(NCODES);
- stack=Malloc(NCODES);
- stack_end=stack+NCODES;
- fill_transchars();
- decompress();
- free(codes);
- free(ubytes);
- free(buf);
- free(transchars);
- free(masks);
- free(prefix);
- free(suffix);
- free(stack);
- }
-
-
- short
- nextrow(int mode)
- {
- static int rowsdone= -1;
- static int phase= -1;
- static int currow;
-
- ++rowsdone;
- counter();
- if (mode) {
- erase_counter(NULL);
- if (rowsdone!=ysz)
- error2(E0_ERROR, E1_GIF, E2_FORMAT, E3_WRONG_NR_ROWS, rowsdone, (int)ysz);
- } else {
- switch (phase) {
- case -1:
- currow=0;
- if (interlaced)
- phase=1;
- else
- phase=0;
- break;
- case 0:
- ++currow;
- break;
- case 1:
- currow+=8;
- if (currow>=ysz) {
- phase=2;
- currow=4;
- }
- break;
- case 2:
- currow+=8;
- if (currow>=ysz) {
- phase=3;
- currow=2;
- }
- break;
- case 3:
- currow+=4;
- if (currow>=ysz) {
- phase=4;
- currow=1;
- }
- break;
- case 4:
- currow+=2;
- break;
- }
- if (currow>=ysz) {
- if (!rgboverflowrow)
- rgboverflowrow=Malloc(xsz*sizeof(u_short));
- gpp=rgboverflowrow;
- } else
- gpp=rgb[currow];
- return xsz-1;
- }
- }
-
-
- void
- decompress(void)
- {
- u_short *cp; /* code pointer, into codes */
- u_char *sp; /* stack pointer, into stack */
- u_short *pp; /* pixel pointer, into rgb */
- u_short lastnormal;
- short ncodes;
- short curfree;
- u_char finchar;
- u_short oldcode, curcode, incode;
- short npix;
-
- init_counter(0, (int)ysz, 10, "reading GIF");
- npix=0;
- lastnormal=(1<<bitsperpixel)-1;
- ncodes=nextcodes();
- if (!ncodes)
- ncodes=nextcodes();
- while (ncodes>0) {
- curfree=(1<<codesize)+2;
- cp=codes;
- sp=stack;
- finchar=oldcode= *cp++;
- if (--npix<0) {
- npix=nextrow(0);
- pp=gpp;
- }
- *pp++ =cm[finchar];
- ncodes-=2;
- do {
- incode= *cp++;
- if (incode>=curfree) {
- curcode=oldcode;
- *sp++ =finchar;
- } else
- curcode=incode;
- while (curcode>lastnormal) {
- if (sp>=stack_end) {
- error0(E0_ERROR, E1_GIF, E2_FORMAT, E3_INVALID_CODE_TABLE);
- (void)nextrow(1);
- return;
- }
- *sp++ =suffix[curcode];
- curcode=prefix[curcode];
- }
- finchar=curcode;
- if (--npix<0) {
- npix=nextrow(0);
- pp=gpp;
- }
- *pp++ =cm[finchar];
- while (sp!=stack) {
- if (--npix<0) {
- npix=nextrow(0);
- pp=gpp;
- }
- *pp++ =cm[*--sp];
- }
- prefix[curfree]=oldcode;
- suffix[curfree]=finchar;
- oldcode=incode;
- ++curfree;
- } while (--ncodes>=0);
- ncodes=nextcodes();
- }
- gpp=pp;
- (void)nextrow(1);
- }
-
-
- short
- fill_masks(short startbit, short nbits)
- {
- u_short *m, *m2;
- short start, length, n, loopc;
- u_long mask;
-
- m=masks;
- start=startbit;
- length=nbits;
- n=0;
- do {
- if (start+length>16) { /* in two parts */
- mask=1<<(15-start);
- loopc=14-start;
- if (loopc>=0) {
- do {
- mask|=mask>>1;
- } while (--loopc>=0);
- }
- *m++ = -start;
- *m++ =mask;
- mask=1<<15;
- loopc=length+start-18;
- if (loopc>=0) {
- do {
- mask|=mask>>1;
- } while (--loopc>=0);
- }
- *m++ =16-start;
- *m++ =mask;
- n+=2;
- } else { /* in one part */
- mask=1<<(15-start);
- loopc=length-2;
- if (loopc>=0) {
- do {
- mask|=mask>>1;
- } while (--loopc>=0);
- }
- *m++ = -start;
- *m++ =mask;
- ++n;
- }
- start=(start+length)&15;
- } while (start!=startbit);
- for (start=NMASKS/2/n-2; start>=0; --start) {
- m2=masks;
- loopc=n-1;
- do {
- *m++ = *m2++;
- *m++ = *m2++;
- } while (--loopc>=0);
- }
- n=NMASKS/2/n*n;
- return n;
- }
-
-
- short
- nextcodes(void)
- {
- #define NC_EC_INIT 0
- #define NC_EC_CLEAR 1
- #define NC_EC_EOF 2
- static int endcode=NC_EC_INIT;
- u_short *ip; static u_short *sip;
- short nushorts; static short snushorts=0;
- static short bitpos=0, csz;
- short tonextcsz;
- static int ok=1;
- short nmasks, inmasks; u_short *m;
- u_short eofcode, clearcode;
- short ncodes; u_short *cp;
- u_short input, output; static u_short sinput;
- short shift;
- u_char *tc;
-
- if (!ok)
- return 0;
- if (endcode==NC_EC_EOF) {
- ok=0;
- return 0;
- }
- ip=sip;
- nushorts=snushorts;
- input=sinput;
- csz=codesize+1;
- clearcode=1<<codesize;
- eofcode=clearcode+1;
- tonextcsz=(1<<csz)-eofcode-1;
- ncodes=NCODES;
- cp=codes;
- tc=transchars;
- inmasks=fill_masks(bitpos, csz);
- do {
- nc_restart:
- m=masks;
- nmasks=inmasks-2;
- shift= *m++;
- if (shift>=0) {
- if (--nushorts<0) {
- nushorts=nextubytes();
- if (nushorts==0) {
- ok=0;
- return 0;
- }
- ip=(u_short *)ubytes;
- nushorts=(nushorts+1)/2-1;
- }
- input= *ip++;
- output=(u_long)(input & *m++)>>(u_short)shift;
- } else
- output=(u_long)(input & *m++)<<(u_short)(-shift);
- do {
- shift= *m++;
- if (shift<=0) {
- /* put output into the output stream, this code is repeated below */
- output=(tc[output&0xff]<<8)|tc[((u_long)output>>8)&0xff];
- if (output==eofcode) {
- endcode=NC_EC_EOF;
- bitpos= -shift;
- goto nc_end;
- }
- if (output==clearcode) {
- endcode=NC_EC_CLEAR;
- bitpos= -shift;
- goto nc_end;
- }
- if (--tonextcsz<0) {
- if (csz<12)
- ++csz;
- tonextcsz= (1<<(csz-1))-1;
- if (ncodes<tonextcsz)
- error0(E0_WARNING, E1_GIF, E2_FORMAT, E3_POT_CODE_OVERFLOW);
- bitpos= -shift;
- inmasks=fill_masks(bitpos, csz);
- *cp++ =output;
- --ncodes;
- goto nc_restart;
- }
- *cp++ =output;
- --ncodes;
- /* end of output code */
- }
- if (shift>=0) {
- if (--nushorts<0) {
- nushorts=nextubytes();
- if (nushorts==0) {
- ok=0;
- return 0;
- }
- ip=(u_short *)ubytes;
- nushorts=(nushorts+1)/2-1;
- }
- input= *ip++;
- }
- if (shift<=0)
- output=(u_long)(input & *m++)<<(u_short)(-shift);
- else
- output|=(u_long)(input & *m++)>>(u_short)shift;
- } while (--nmasks>=0);
- /* put output into the output stream, this code is repeated above */
- output=(tc[output&0xff]<<8)|tc[((u_long)output>>8)&0xff];
- if (output==eofcode) {
- endcode=NC_EC_EOF;
- goto nc_end;
- }
- if (output==clearcode) {
- endcode=NC_EC_CLEAR;
- goto nc_end;
- }
- if (--tonextcsz<0) {
- if (csz<12)
- ++csz;
- tonextcsz= (1<<(csz-1))-1;
- if (ncodes<tonextcsz)
- error0(E0_WARNING, E1_GIF, E2_FORMAT, E3_POT_CODE_OVERFLOW);
- inmasks=fill_masks(bitpos, csz);
- }
- *cp++ =output;
- --ncodes;
- /* end of output code */
- } while (1);
- nc_end:
- sip=ip;
- snushorts=nushorts;
- sinput=input;
- return NCODES-ncodes;
- }
-
-
- short
- nextubytes(void)
- {
- static int ok=1;
- short dec;
- u_char *bp; static u_char *sbp=NULL;
- u_char *up, *tc;
- short inbuf; static short sinbuf;
- short inblock; static short sinblock;
- short inubytes;
-
- if (!ok)
- return 0;
- bp=sbp;
- up=(u_char *)ubytes;
- tc=transchars;
- inbuf=sinbuf;
- inblock=sinblock;
- inubytes=NUBYTES;
- if (!sbp) {
- dec=0;
- inblock=0;
- inbuf=0;
- } else {
- if (inblock<inbuf)
- dec=inblock;
- else
- dec=inbuf;
- if (inubytes<dec)
- dec=inubytes;
- inblock-=dec;
- inbuf-=dec;
- inubytes-=dec;
- }
- do {
- if (--dec>=0) {
- do {
- *up++ = tc[*bp++];
- } while (--dec>=0);
- }
- if (inblock==0 && inbuf>0) {
- inblock= *bp++;
- --inbuf;
- if (!inblock) { /* zero bytecount encountered, repeated below */
- ok=0;
- break;
- }
- }
- if (inbuf==0) {
- cread_type=CREAD_VARLEN;
- cread(buf, NBUF);
- cread_type=CREAD_STRICT;
- inbuf=cread_result;
- if (inbuf<=0) {
- ok=0;
- return 0;
- }
- bp=buf;
- }
- if (inblock==0) {
- inblock= *bp++;
- --inbuf;
- assert(inbuf>0);
- if (!inblock) { /* zero bytecount encountered, repeated above */
- ok=0;
- break;
- }
- }
- if (inubytes==0) {
- break;
- }
- if (inblock<inbuf)
- dec=inblock;
- else
- dec=inbuf;
- if (inubytes<dec)
- dec=inubytes;
- inblock-=dec;
- inbuf-=dec;
- inubytes-=dec;
- } while (1);
- sbp=bp;
- sinbuf=inbuf;
- sinblock=inblock;
- return NUBYTES-inubytes;
- }
-
-
- void
- fill_transchars(void)
- {
- u_char *tc;
- u_char c, maskout;
- short i, maskin;
-
- tc=transchars;
- for (i=0; i<NTRANSCHARS; ++i) {
- c=0;
- for (maskout=0x80, maskin=1; maskout; maskin<<=1, maskout=(u_long)maskout>>1) {
- if (i&maskin)
- c|=maskout;
- }
- *tc++ =c;
- }
- }
-