home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magazyn Amiga Shareware Floppies
/
ma01.dms
/
ma01.adf
/
wasp
/
src
/
readgif.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-12-28
|
14KB
|
589 lines
/* 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;
}
}