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