aboutsummaryrefslogtreecommitdiff
path: root/src/libdraw/md-read.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libdraw/md-read.c')
-rw-r--r--src/libdraw/md-read.c111
1 files changed, 111 insertions, 0 deletions
diff --git a/src/libdraw/md-read.c b/src/libdraw/md-read.c
new file mode 100644
index 00000000..d7a535d7
--- /dev/null
+++ b/src/libdraw/md-read.c
@@ -0,0 +1,111 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <memdraw.h>
+
+Memimage*
+readmemimage(int fd)
+{
+ char hdr[5*12+1];
+ int dy;
+ u32int chan;
+ uint l, n;
+ int m, j;
+ int new, miny, maxy;
+ Rectangle r;
+ uchar *tmp;
+ int ldepth, chunk;
+ Memimage *i;
+
+ if(readn(fd, hdr, 11) != 11){
+ werrstr("readimage: short header");
+ return nil;
+ }
+ if(memcmp(hdr, "compressed\n", 11) == 0)
+ return creadmemimage(fd);
+ if(readn(fd, hdr+11, 5*12-11) != 5*12-11){
+ werrstr("readimage: short header (2)");
+ return nil;
+ }
+
+ /*
+ * distinguish new channel descriptor from old ldepth.
+ * channel descriptors have letters as well as numbers,
+ * while ldepths are a single digit formatted as %-11d.
+ */
+ new = 0;
+ for(m=0; m<10; m++){
+ if(hdr[m] != ' '){
+ new = 1;
+ break;
+ }
+ }
+ if(hdr[11] != ' '){
+ werrstr("readimage: bad format");
+ return nil;
+ }
+ if(new){
+ hdr[11] = '\0';
+ if((chan = strtochan(hdr)) == 0){
+ werrstr("readimage: bad channel string %s", hdr);
+ return nil;
+ }
+ }else{
+ ldepth = ((int)hdr[10])-'0';
+ if(ldepth<0 || ldepth>3){
+ werrstr("readimage: bad ldepth %d", ldepth);
+ return nil;
+ }
+ chan = drawld2chan[ldepth];
+ }
+
+ r.min.x = atoi(hdr+1*12);
+ r.min.y = atoi(hdr+2*12);
+ r.max.x = atoi(hdr+3*12);
+ r.max.y = atoi(hdr+4*12);
+ if(r.min.x>r.max.x || r.min.y>r.max.y){
+ werrstr("readimage: bad rectangle");
+ return nil;
+ }
+
+ miny = r.min.y;
+ maxy = r.max.y;
+
+ l = bytesperline(r, chantodepth(chan));
+ i = allocmemimage(r, chan);
+ if(i == nil)
+ return nil;
+ chunk = 32*1024;
+ if(chunk < l)
+ chunk = l;
+ tmp = malloc(chunk);
+ if(tmp == nil)
+ goto Err;
+ while(maxy > miny){
+ dy = maxy - miny;
+ if(dy*l > chunk)
+ dy = chunk/l;
+ if(dy <= 0){
+ werrstr("readmemimage: image too wide for buffer");
+ goto Err;
+ }
+ n = dy*l;
+ m = readn(fd, tmp, n);
+ if(m != n){
+ werrstr("readmemimage: read count %d not %d: %r", m, n);
+ Err:
+ freememimage(i);
+ free(tmp);
+ return nil;
+ }
+ if(!new) /* an old image: must flip all the bits */
+ for(j=0; j<chunk; j++)
+ tmp[j] ^= 0xFF;
+
+ if(loadmemimage(i, Rect(r.min.x, miny, r.max.x, miny+dy), tmp, chunk) <= 0)
+ goto Err;
+ miny += dy;
+ }
+ free(tmp);
+ return i;
+}