|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <draw.h> | 
|  | #include <memdraw.h> | 
|  |  | 
|  | #define	CHUNK	16000 | 
|  |  | 
|  | #define	HSHIFT	3	/* HSHIFT==5 runs slightly faster, but hash table is 64x bigger */ | 
|  | #define	NHASH	(1<<(HSHIFT*NMATCH)) | 
|  | #define	HMASK	(NHASH-1) | 
|  | #define	hupdate(h, c)	((((h)<<HSHIFT)^(c))&HMASK) | 
|  | typedef struct Hlist Hlist; | 
|  | struct Hlist{ | 
|  | uchar *s; | 
|  | Hlist *next, *prev; | 
|  | }; | 
|  |  | 
|  | int | 
|  | writememimage(int fd, Memimage *i) | 
|  | { | 
|  | uchar *outbuf, *outp, *eout;		/* encoded data, pointer, end */ | 
|  | uchar *loutp;				/* start of encoded line */ | 
|  | Hlist *hash;				/* heads of hash chains of past strings */ | 
|  | Hlist *chain, *hp;			/* hash chain members, pointer */ | 
|  | Hlist *cp;				/* next Hlist to fall out of window */ | 
|  | int h;					/* hash value */ | 
|  | uchar *line, *eline;			/* input line, end pointer */ | 
|  | uchar *data, *edata;			/* input buffer, end pointer */ | 
|  | u32int n;				/* length of input buffer */ | 
|  | u32int nb;				/* # of bytes returned by unloadimage */ | 
|  | int bpl;				/* input line length */ | 
|  | int offs, runlen;			/* offset, length of consumed data */ | 
|  | uchar dumpbuf[NDUMP];			/* dump accumulator */ | 
|  | int ndump;				/* length of dump accumulator */ | 
|  | int miny, dy;				/* y values while unloading input */ | 
|  | int ncblock;				/* size of compressed blocks */ | 
|  | Rectangle r; | 
|  | uchar *p, *q, *s, *es, *t; | 
|  | char hdr[11+5*12+1]; | 
|  | char cbuf[20]; | 
|  |  | 
|  | r = i->r; | 
|  | bpl = bytesperline(r, i->depth); | 
|  | n = Dy(r)*bpl; | 
|  | data = malloc(n); | 
|  | ncblock = _compblocksize(r, i->depth); | 
|  | outbuf = malloc(ncblock); | 
|  | hash = malloc(NHASH*sizeof(Hlist)); | 
|  | chain = malloc(NMEM*sizeof(Hlist)); | 
|  | if(data == 0 || outbuf == 0 || hash == 0 || chain == 0){ | 
|  | ErrOut: | 
|  | free(data); | 
|  | free(outbuf); | 
|  | free(hash); | 
|  | free(chain); | 
|  | return -1; | 
|  | } | 
|  | for(miny = r.min.y; miny != r.max.y; miny += dy){ | 
|  | dy = r.max.y-miny; | 
|  | if(dy*bpl > CHUNK) | 
|  | dy = CHUNK/bpl; | 
|  | nb = unloadmemimage(i, Rect(r.min.x, miny, r.max.x, miny+dy), | 
|  | data+(miny-r.min.y)*bpl, dy*bpl); | 
|  | if(nb != dy*bpl) | 
|  | goto ErrOut; | 
|  | } | 
|  | sprint(hdr, "compressed\n%11s %11d %11d %11d %11d ", | 
|  | chantostr(cbuf, i->chan), r.min.x, r.min.y, r.max.x, r.max.y); | 
|  | if(write(fd, hdr, 11+5*12) != 11+5*12) | 
|  | goto ErrOut; | 
|  | edata = data+n; | 
|  | eout = outbuf+ncblock; | 
|  | line = data; | 
|  | r.max.y = r.min.y; | 
|  | while(line != edata){ | 
|  | memset(hash, 0, NHASH*sizeof(Hlist)); | 
|  | memset(chain, 0, NMEM*sizeof(Hlist)); | 
|  | cp = chain; | 
|  | h = 0; | 
|  | outp = outbuf; | 
|  | for(n = 0; n != NMATCH; n++) | 
|  | h = hupdate(h, line[n]); | 
|  | loutp = outbuf; | 
|  | while(line != edata){ | 
|  | ndump = 0; | 
|  | eline = line+bpl; | 
|  | for(p = line; p != eline; ){ | 
|  | if(eline-p < NRUN) | 
|  | es = eline; | 
|  | else | 
|  | es = p+NRUN; | 
|  | q = 0; | 
|  | runlen = 0; | 
|  | for(hp = hash[h].next; hp; hp = hp->next){ | 
|  | s = p + runlen; | 
|  | if(s >= es) | 
|  | continue; | 
|  | t = hp->s + runlen; | 
|  | for(; s >= p; s--) | 
|  | if(*s != *t--) | 
|  | goto matchloop; | 
|  | t += runlen+2; | 
|  | s += runlen+2; | 
|  | for(; s < es; s++) | 
|  | if(*s != *t++) | 
|  | break; | 
|  | n = s-p; | 
|  | if(n > runlen){ | 
|  | runlen = n; | 
|  | q = hp->s; | 
|  | if(n == NRUN) | 
|  | break; | 
|  | } | 
|  | matchloop: ; | 
|  | } | 
|  | if(runlen < NMATCH){ | 
|  | if(ndump == NDUMP){ | 
|  | if(eout-outp < ndump+1) | 
|  | goto Bfull; | 
|  | *outp++ = ndump-1+128; | 
|  | memmove(outp, dumpbuf, ndump); | 
|  | outp += ndump; | 
|  | ndump = 0; | 
|  | } | 
|  | dumpbuf[ndump++] = *p; | 
|  | runlen = 1; | 
|  | } | 
|  | else{ | 
|  | if(ndump != 0){ | 
|  | if(eout-outp < ndump+1) | 
|  | goto Bfull; | 
|  | *outp++ = ndump-1+128; | 
|  | memmove(outp, dumpbuf, ndump); | 
|  | outp += ndump; | 
|  | ndump = 0; | 
|  | } | 
|  | offs = p-q-1; | 
|  | if(eout-outp < 2) | 
|  | goto Bfull; | 
|  | *outp++ = ((runlen-NMATCH)<<2) + (offs>>8); | 
|  | *outp++ = offs&255; | 
|  | } | 
|  | for(q = p+runlen; p != q; p++){ | 
|  | if(cp->prev) | 
|  | cp->prev->next = 0; | 
|  | cp->next = hash[h].next; | 
|  | cp->prev = &hash[h]; | 
|  | if(cp->next) | 
|  | cp->next->prev = cp; | 
|  | cp->prev->next = cp; | 
|  | cp->s = p; | 
|  | if(++cp == &chain[NMEM]) | 
|  | cp = chain; | 
|  | if(edata-p > NMATCH) | 
|  | h = hupdate(h, p[NMATCH]); | 
|  | } | 
|  | } | 
|  | if(ndump != 0){ | 
|  | if(eout-outp < ndump+1) | 
|  | goto Bfull; | 
|  | *outp++ = ndump-1+128; | 
|  | memmove(outp, dumpbuf, ndump); | 
|  | outp += ndump; | 
|  | } | 
|  | line = eline; | 
|  | loutp = outp; | 
|  | r.max.y++; | 
|  | } | 
|  | Bfull: | 
|  | if(loutp == outbuf) | 
|  | goto ErrOut; | 
|  | n = loutp-outbuf; | 
|  | sprint(hdr, "%11d %11ld ", r.max.y, n); | 
|  | write(fd, hdr, 2*12); | 
|  | write(fd, outbuf, n); | 
|  | r.min.y = r.max.y; | 
|  | } | 
|  | free(data); | 
|  | free(outbuf); | 
|  | free(hash); | 
|  | free(chain); | 
|  | return 0; | 
|  | } |