| #include <u.h> | 
 | #include <libc.h> | 
 | #include <bio.h> | 
 | #include <draw.h> | 
 | #include "imagefile.h" | 
 |  | 
 | /* | 
 |  * Hacked version for writing from Rawimage to file. | 
 |  * Assumes 8 bits per component. | 
 |  */ | 
 |  | 
 | #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 | 
 | writerawimage(int fd, Rawimage *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 */ | 
 | 	ulong n;				/* length of input buffer */ | 
 | 	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 ncblock;				/* size of buffer */ | 
 | 	Rectangle r; | 
 | 	uchar *p, *q, *s, *es, *t; | 
 | 	char hdr[11+5*12+1], buf[16]; | 
 | 	ulong desc; | 
 |  | 
 | 	r = i->r; | 
 | 	switch(i->chandesc){ | 
 | 	default: | 
 | 		werrstr("can't handle chandesc %d", i->chandesc); | 
 | 		return -1; | 
 | 	case CY: | 
 | 		bpl = Dx(r); | 
 | 		desc = GREY8; | 
 | 		break; | 
 | 	case CYA16: | 
 | 		bpl = 2*Dx(r); | 
 | 		desc = CHAN2(CGrey, 8, CAlpha, 8); | 
 | 		break; | 
 | 	case CRGBV: | 
 | 		bpl = Dx(r); | 
 | 		desc = CMAP8; | 
 | 		break; | 
 | 	case CRGBVA16: | 
 | 		bpl = 2*Dx(r); | 
 | 		desc = CHAN2(CMap, 8, CAlpha, 8); | 
 | 		break; | 
 | 	case CRGB24: | 
 | 		bpl = 3*Dx(r); | 
 | 		desc = RGB24; | 
 | 		break; | 
 | 	case CRGBA32: | 
 | 		bpl = 4*Dx(r); | 
 | 		desc = RGBA32; | 
 | 		break; | 
 | 	} | 
 | 	ncblock = _compblocksize(r, bpl/Dx(r)); | 
 | 	outbuf = malloc(ncblock); | 
 | 	hash = malloc(NHASH*sizeof(Hlist)); | 
 | 	chain = malloc(NMEM*sizeof(Hlist)); | 
 | 	if(outbuf == 0 || hash == 0 || chain == 0){ | 
 | 	ErrOut: | 
 | 		free(outbuf); | 
 | 		free(hash); | 
 | 		free(chain); | 
 | 		return -1; | 
 | 	} | 
 | 	n = Dy(r)*bpl; | 
 | 	data = i->chans[0]; | 
 | 	sprint(hdr, "compressed\n%11s %11d %11d %11d %11d ", | 
 | 		chantostr(buf, desc), r.min.x, r.min.y, r.max.x, r.max.y); | 
 | 	if(write(fd, hdr, 11+5*12) != 11+5*12){ | 
 | 		werrstr("i/o error writing header"); | 
 | 		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){ | 
 | 			werrstr("compressor out of sync"); | 
 | 			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(outbuf); | 
 | 	free(hash); | 
 | 	free(chain); | 
 | 	return 0; | 
 | } |