xref: /inferno-os/libdraw/readimage.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsyth #include "lib9.h"
2*37da2899SCharles.Forsyth #include "kernel.h"
3*37da2899SCharles.Forsyth #include "draw.h"
4*37da2899SCharles.Forsyth 
5*37da2899SCharles.Forsyth Image*
readimage(Display * d,int fd,int dolock)6*37da2899SCharles.Forsyth readimage(Display *d, int fd, int dolock)
7*37da2899SCharles.Forsyth {
8*37da2899SCharles.Forsyth 	char hdr[5*12+1];
9*37da2899SCharles.Forsyth 	int dy;
10*37da2899SCharles.Forsyth 	int new;
11*37da2899SCharles.Forsyth 	uint l, n;
12*37da2899SCharles.Forsyth 	int m, j, chunk;
13*37da2899SCharles.Forsyth 	int miny, maxy;
14*37da2899SCharles.Forsyth 	Rectangle r;
15*37da2899SCharles.Forsyth 	int ldepth;
16*37da2899SCharles.Forsyth 	ulong chan;
17*37da2899SCharles.Forsyth 	uchar *tmp;
18*37da2899SCharles.Forsyth 	Image *i;
19*37da2899SCharles.Forsyth 
20*37da2899SCharles.Forsyth 	if(libreadn(fd, hdr, 11) != 11) {
21*37da2899SCharles.Forsyth 		kwerrstr("readimage: short header");
22*37da2899SCharles.Forsyth 		return nil;
23*37da2899SCharles.Forsyth 	}
24*37da2899SCharles.Forsyth 	if(memcmp(hdr, "compressed\n", 11) == 0)
25*37da2899SCharles.Forsyth 		return creadimage(d, fd, dolock);
26*37da2899SCharles.Forsyth 	dolock &= 1;
27*37da2899SCharles.Forsyth 	if(libreadn(fd, hdr+11, 5*12-11) != 5*12-11) {
28*37da2899SCharles.Forsyth 		kwerrstr("readimage: short header");
29*37da2899SCharles.Forsyth 		return nil;
30*37da2899SCharles.Forsyth 	}
31*37da2899SCharles.Forsyth 	chunk = d->bufsize - 32;	/* a little room for header */
32*37da2899SCharles.Forsyth 
33*37da2899SCharles.Forsyth 	/*
34*37da2899SCharles.Forsyth 	 * distinguish new channel descriptor from old ldepth.
35*37da2899SCharles.Forsyth 	 * channel descriptors have letters as well as numbers,
36*37da2899SCharles.Forsyth 	 * while ldepths are a single digit formatted as %-11d.
37*37da2899SCharles.Forsyth 	 */
38*37da2899SCharles.Forsyth 	new = 0;
39*37da2899SCharles.Forsyth 	for(m=0; m<10; m++){
40*37da2899SCharles.Forsyth 		if(hdr[m] != ' '){
41*37da2899SCharles.Forsyth 			new = 1;
42*37da2899SCharles.Forsyth 			break;
43*37da2899SCharles.Forsyth 		}
44*37da2899SCharles.Forsyth 	}
45*37da2899SCharles.Forsyth 	if(hdr[11] != ' '){
46*37da2899SCharles.Forsyth 		kwerrstr("readimage: bad format");
47*37da2899SCharles.Forsyth 		return nil;
48*37da2899SCharles.Forsyth 	}
49*37da2899SCharles.Forsyth 	if(new){
50*37da2899SCharles.Forsyth 		hdr[11] = '\0';
51*37da2899SCharles.Forsyth 		if((chan = strtochan(hdr)) == 0){
52*37da2899SCharles.Forsyth 			kwerrstr("readimage: bad channel string %s", hdr);
53*37da2899SCharles.Forsyth 			return nil;
54*37da2899SCharles.Forsyth 		}
55*37da2899SCharles.Forsyth 	}else{
56*37da2899SCharles.Forsyth 		ldepth = ((int)hdr[10])-'0';
57*37da2899SCharles.Forsyth 		if(ldepth<0 || ldepth>3){
58*37da2899SCharles.Forsyth 			kwerrstr("readimage: bad ldepth %d", ldepth);
59*37da2899SCharles.Forsyth 			return nil;
60*37da2899SCharles.Forsyth 		}
61*37da2899SCharles.Forsyth 		chan = drawld2chan[ldepth];
62*37da2899SCharles.Forsyth 	}
63*37da2899SCharles.Forsyth 
64*37da2899SCharles.Forsyth 	r.min.x = atoi(hdr+1*12);
65*37da2899SCharles.Forsyth 	r.min.y = atoi(hdr+2*12);
66*37da2899SCharles.Forsyth 	r.max.x = atoi(hdr+3*12);
67*37da2899SCharles.Forsyth 	r.max.y = atoi(hdr+4*12);
68*37da2899SCharles.Forsyth 	if(r.min.x>r.max.x || r.min.y>r.max.y){
69*37da2899SCharles.Forsyth 		kwerrstr("readimage: bad rectangle");
70*37da2899SCharles.Forsyth 		return nil;
71*37da2899SCharles.Forsyth 	}
72*37da2899SCharles.Forsyth 
73*37da2899SCharles.Forsyth 	miny = r.min.y;
74*37da2899SCharles.Forsyth 	maxy = r.max.y;
75*37da2899SCharles.Forsyth 
76*37da2899SCharles.Forsyth 	l = bytesperline(r, chantodepth(chan));
77*37da2899SCharles.Forsyth 	if(dolock)
78*37da2899SCharles.Forsyth 		dolock = lockdisplay(d);
79*37da2899SCharles.Forsyth 	i = allocimage(d, r, chan, 0, -1);
80*37da2899SCharles.Forsyth 	if(dolock)
81*37da2899SCharles.Forsyth 		unlockdisplay(d);
82*37da2899SCharles.Forsyth 	if(i == nil)
83*37da2899SCharles.Forsyth 		return nil;
84*37da2899SCharles.Forsyth 	tmp = malloc(chunk);
85*37da2899SCharles.Forsyth 	if(tmp == nil)
86*37da2899SCharles.Forsyth 		goto Err;
87*37da2899SCharles.Forsyth 	while(maxy > miny){
88*37da2899SCharles.Forsyth 		dy = maxy - miny;
89*37da2899SCharles.Forsyth 		if(dy*l > chunk)
90*37da2899SCharles.Forsyth 			dy = chunk/l;
91*37da2899SCharles.Forsyth 		if(dy <= 0){
92*37da2899SCharles.Forsyth 			kwerrstr("readimage: image too wide for buffer");
93*37da2899SCharles.Forsyth 			goto Err;
94*37da2899SCharles.Forsyth 		}
95*37da2899SCharles.Forsyth 		n = dy*l;
96*37da2899SCharles.Forsyth 		m = libreadn(fd, tmp, n);
97*37da2899SCharles.Forsyth 		if(m != n){
98*37da2899SCharles.Forsyth 			kwerrstr("readimage: read count %d not %d: %r", m, n);
99*37da2899SCharles.Forsyth    Err:
100*37da2899SCharles.Forsyth 			if(dolock)
101*37da2899SCharles.Forsyth 				lockdisplay(d);
102*37da2899SCharles.Forsyth    Err1:
103*37da2899SCharles.Forsyth  			freeimage(i);
104*37da2899SCharles.Forsyth 			if(dolock)
105*37da2899SCharles.Forsyth 				unlockdisplay(d);
106*37da2899SCharles.Forsyth 			free(tmp);
107*37da2899SCharles.Forsyth 			return nil;
108*37da2899SCharles.Forsyth 		}
109*37da2899SCharles.Forsyth 		if(!new)	/* an old image: must flip all the bits */
110*37da2899SCharles.Forsyth 			for(j=0; j<chunk; j++)
111*37da2899SCharles.Forsyth 				tmp[j] ^= 0xFF;
112*37da2899SCharles.Forsyth 
113*37da2899SCharles.Forsyth 		if(dolock)
114*37da2899SCharles.Forsyth 			lockdisplay(d);
115*37da2899SCharles.Forsyth 		if(loadimage(i, Rect(r.min.x, miny, r.max.x, miny+dy), tmp, chunk) <= 0)
116*37da2899SCharles.Forsyth 			goto Err1;
117*37da2899SCharles.Forsyth 		if(dolock)
118*37da2899SCharles.Forsyth 			unlockdisplay(d);
119*37da2899SCharles.Forsyth 		miny += dy;
120*37da2899SCharles.Forsyth 	}
121*37da2899SCharles.Forsyth 	free(tmp);
122*37da2899SCharles.Forsyth 	return i;
123*37da2899SCharles.Forsyth }
124