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