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