xref: /plan9-contrib/sys/src/cmd/unix/drawterm/libmemdraw/cread.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1 #include "../lib9.h"
2 
3 #include "../libdraw/draw.h"
4 #include "../libmemdraw/memdraw.h"
5 
6 /*
7  * compressed data are sequences of byte codes.
8  * if the first byte b has the 0x80 bit set, the next (b^0x80)+1 bytes
9  * are data.  otherwise, it's two bytes specifying a previous string to repeat.
10  */
11 static void
12 twiddlecompressed(uchar *buf, int n)
13 {
14 	uchar *ebuf;
15 	int j, k, c;
16 
17 	ebuf = buf+n;
18 	while(buf < ebuf){
19 		c = *buf++;
20 		if(c >= 128){
21 			k = c-128+1;
22 			for(j=0; j<k; j++, buf++)
23 				*buf ^= 0xFF;
24 		}else
25 			buf++;
26 	}
27 }
28 
29 Memimage*
30 creadmemimage(int fd)
31 {
32 	char hdr[5*12+1];
33 	Rectangle r;
34 	int m, nb, miny, maxy, new, ldepth;
35 	uchar *buf;
36 	Memimage *i;
37 	ulong chan;
38 
39 	if(readn(fd, hdr, 5*12) != 5*12)
40 		return nil;
41 
42 	/*
43 	 * distinguish new channel descriptor from old ldepth.
44 	 * channel descriptors have letters as well as numbers,
45 	 * while ldepths are a single digit formatted as %-11d.
46 	 */
47 	new = 0;
48 	for(m=0; m<10; m++){
49 		if(hdr[m] != ' '){
50 			new = 1;
51 			break;
52 		}
53 	}
54 	if(hdr[11] != ' '){
55 		werrstr("creadimage: bad format");
56 		return nil;
57 	}
58 	if(new){
59 		hdr[11] = '\0';
60 		if((chan = strtochan(hdr)) == 0){
61 			werrstr("creadimage: bad channel string %s", hdr);
62 			return nil;
63 		}
64 	}else{
65 		ldepth = ((int)hdr[10])-'0';
66 		if(ldepth<0 || ldepth>3){
67 			werrstr("creadimage: bad ldepth %d", ldepth);
68 			return nil;
69 		}
70 		chan = drawld2chan[ldepth];
71 	}
72 	r.min.x=atoi(hdr+1*12);
73 	r.min.y=atoi(hdr+2*12);
74 	r.max.x=atoi(hdr+3*12);
75 	r.max.y=atoi(hdr+4*12);
76 	if(r.min.x>r.max.x || r.min.y>r.max.y){
77 		werrstr("creadimage: bad rectangle");
78 		return nil;
79 	}
80 
81 	i = allocmemimage(r, chan);
82 	if(i == nil)
83 		return nil;
84 	buf = malloc(NCBLOCK);
85 	if(buf == nil)
86 		goto Errout;
87 	miny = r.min.y;
88 	while(miny != r.max.y){
89 		if(readn(fd, hdr, 2*12) != 2*12){
90 		Errout:
91 			freememimage(i);
92 			free(buf);
93 			return nil;
94 		}
95 		maxy = atoi(hdr+0*12);
96 		nb = atoi(hdr+1*12);
97 		if(maxy<=miny || r.max.y<maxy){
98 			werrstr("readimage: bad maxy %d", maxy);
99 			goto Errout;
100 		}
101 		if(nb<=0 || NCBLOCK<nb){
102 			werrstr("readimage: bad count %d", nb);
103 			goto Errout;
104 		}
105 		if(readn(fd, buf, nb)!=nb)
106 			goto Errout;
107 		if(!new)	/* old image: flip the data bits */
108 			twiddlecompressed(buf, nb);
109 		cloadmemimage(i, Rect(r.min.x, miny, r.max.x, maxy), buf, nb);
110 		miny = maxy;
111 	}
112 	free(buf);
113 	return i;
114 }
115