/* nomarch 1.4 - extract old `.arc' archives. * Copyright (C) 2001-2006 Russell Marks. See main.c for license details. * * readlzw.c - read (RLE+)LZW-compressed files. * * This is based on zgv's GIF reader. The LZW stuff is much the same, but * figuring out the details of the rather bizarre encoding involved much * wall therapy. %-( */ #include #include #include #include #include "readrle.h" #include "readlzw.h" /* now this is for the string table. * the st_ptr array stores which pos to back reference to, * each string is [...]+ end char, [...] is traced back through * the 'pointer' (index really), then back through the next, etc. * a 'null pointer' is = to UNUSED. * the st_chr array gives the end char for each. * an unoccupied slot is = to UNUSED. */ #define UNUSED (-1) #define REALMAXSTR 65536 static int st_ptr[REALMAXSTR],st_chr[REALMAXSTR],st_last; static int st_ptr1st[REALMAXSTR]; /* this is for the byte -> bits mangler: * dc_bitbox holds the bits, dc_bitsleft is number of bits left in dc_bitbox, */ static int dc_bitbox,dc_bitsleft; static unsigned char *data_in_point,*data_in_max; static unsigned char *data_out_point,*data_out_max; static int codeofs; static int global_use_rle,oldver; static int maxstr; static int st_oldverhashlinks[4096]; /* only used for 12-bit types */ /* prototypes */ void code_resync(int old); void inittable(int orgcsize); int addstring(int oldcode,int chr); int readcode(int *newcode,int numbits); void outputstring(int code); void outputchr(int chr); int findfirstchr(int code); unsigned char *convert_lzw_dynamic(unsigned char *data_in, int max_bits,int use_rle, unsigned long in_len, unsigned long orig_len) { unsigned char *data_out; int csize,orgcsize; int newcode,oldcode,k=0; int first=1,noadd; global_use_rle=use_rle; maxstr=(1<st_last+1) fprintf(stderr,"warning: bad LZW code\n"); #endif /* k=findfirstchr(oldcode);*/ /* don't think I actually need this */ outputstring(oldcode); outputchr(k); } if(st_last!=maxstr-1) { if(!noadd) { if(!addstring(oldcode,k)) { /* XXX I think this is meant to be non-fatal? * well, nothing for now, anyway... */ } if(st_last!=maxstr-1 && st_last==((1<>6)&0xfff); /* first, check link chain from there */ while(st_chr[hashval]!=UNUSED && st_oldverhashlinks[hashval]!=UNUSED) hashval=st_oldverhashlinks[hashval]; /* make sure we return early if possible to avoid adding link */ if(st_chr[hashval]==UNUSED) return(hashval); lasthash=hashval; /* slightly odd approach if it's not in that - first try skipping * 101 entries, then try them one-by-one. It should be impossible * for this to loop indefinitely, if the table isn't full. (And we * shouldn't have been called if it was full...) */ hashval+=101; hashval&=0xfff; if(st_chr[hashval]!=UNUSED) { for(f=0;f=maxstr) return(1); st_ptr[idx]=oldcode; if(st_ptr[oldcode]==UNUSED) /* if we're pointing to a root... */ st_ptr1st[idx]=oldcode; /* then that holds the first char */ else /* otherwise... */ st_ptr1st[idx]=st_ptr1st[oldcode]; /* use their pointer to first */ return(1); } /* read a code of bitlength numbits */ int readcode(int *newcode,int numbits) { int bitsfilled,got; bitsfilled=got=0; (*newcode)=0; while(bitsfilled=data_in_max) return(0); dc_bitbox=*data_in_point++; dc_bitsleft=8; } if(dc_bitsleft>8)<<(numbits-bitsfilled)); dc_bitsleft-=got; } else { (*newcode)|=((dc_bitbox&((1<>=got; dc_bitsleft-=got; bitsfilled+=got; } } if((*newcode)<0 || (*newcode)>maxstr-1) return(0); /* yuck... see code_resync() for explanation */ codeofs++; codeofs&=7; return(1); } void outputstring(int code) { static int buf[REALMAXSTR]; int *ptr=buf; while(st_ptr[code]!=UNUSED && ptrbuf) outputchr(*--ptr); } static void rawoutput(int byte) { if(data_out_point