#include "paint.h" #include /* -> p[1] -> p[0] -> image/conv -> q[1] -> q[0] */ static int conv(ImgHdr hdr, int fd, ulong outchan) { char chanstr[9]; int p[2], q[2]; uchar buf[8192]; int n; ImgHdr whocares; if(chantostr(chanstr, outchan) == 0) { werrstr("chantostr %#.8ulx", outchan); return -1; } if(pipe(p) < 0 || pipe(q) < 0) { /* this can leak */ werrstr("pipe: %r"); return -1; } switch(rfork(RFFDG|RFREND|RFPROC|RFNOWAIT)) { case -1: close(p[0]); close(p[1]); close(q[0]); close(q[1]); werrstr("fork: %r"); return -1; case 0: close(fd); close(p[1]); close(q[0]); dup(p[0], 0); dup(q[1], 1); execl("/bin/image/conv", "image/conv", "-u", "-c", chanstr, nil); execl("/bin/iconv", "iconv", "-u", "-c", chanstr, nil); fprint(2, "conv: exec: %r\n"); exits("exec"); } close(p[0]); close(q[1]); switch(rfork(RFFDG|RFREND|RFPROC|RFNOWAIT)) { case -1: close(p[1]); close(q[0]); werrstr("fork: %r"); return -1; case 0: close(q[0]); if(fprint(p[1], "%s", hdr.compressed ? "compressed\n" : "") < 0 || write(p[1], hdr.bytes, sizeof hdr.bytes) != sizeof hdr.bytes ) { fprint(2, "conv: write header: %r\n"); exits("write header"); } while((n = read(fd, buf, sizeof buf)) > 0) { if(write(p[1], buf, n) != n) { fprint(2, "conv: write: %r\n"); exits("write"); } } if(n < 0) { fprint(2, "conv: read: %r\n"); exits("read"); } exits(nil); } close(p[1]); if(readimghdr(q[0], &whocares) < 0) { werrstr("header: %r"); close(q[0]); return -1; } close(fd); return q[0]; } int readimghdr(int fd, ImgHdr *hdr) { char *b; int n, m; b = (char *)hdr->bytes; if((n = readn(fd, b, 11)) != 11) { if(n >= 0) werrstr("short read"); return -1; } if(hdr->compressed = memcmp(b, "compressed\n", 11) == 0) m = readn(fd, b, sizeof hdr->bytes); else m = readn(fd, b+11, sizeof(hdr->bytes)-11); if(m < 0) return -1; if((n += m) < sizeof b) { werrstr("short read"); return -1; } /* don't allow atoi to read beyond the end of the buffer */ if(b[5*12 - 1] != ' ') { werrstr("invalid"); return -1; } if((hdr->chan = strtochan(b)) == 0) { werrstr("bad chan: %.11s", b); return -1; } hdr->r = Rect(atoi(b + 1*12), atoi(b + 2*12), atoi(b + 3*12), atoi(b + 4*12)); return 0; } int loadmem(Memimage *dst, ImgHdr hdr, int fd) { int lsz; uchar *linebuf; Biobuf b; int y, n; if((fd = conv(hdr, fd, dst->chan)) < 0) { werrstr("conv: %r"); return -1; } lsz = bytesperline(hdr.r, chantodepth(dst->chan)); if((linebuf = malloc(lsz)) == nil) { werrstr("alloc linebuf: %r"); close(fd); return -1; } if(Binit(&b, fd, OREAD) < 0) { werrstr("Binits: %r"); free(linebuf); close(fd); return -1; } for(y = 0; y < Dy(hdr.r); y++) { if((n = Bread(&b, linebuf, lsz)) != lsz) { if(n < 0) werrstr("line %d: read: %r", y); else werrstr("line %d: short read: %d/%d", y, n, lsz); free(linebuf); close(fd); return -1; } if(loadmemimage(dst, Rect(0, y, Dx(hdr.r), y+1), linebuf, lsz) < 0) { werrstr("line %d: load", y); free(linebuf); close(fd); return -1; } } free(linebuf); close(fd); return 0; } int unloadmem(int fd, Memimage *src, Rectangle r) { char chanstr[9]; Biobuf b; int lsz; uchar *linebuf; Rectangle rr, line; int y; if(chantostr(chanstr, src->chan) == nil) { werrstr(Egreg); fprint(2, "unloadmem: bad chan: %.8ulx\n", src->chan); return -1; } if(!rectinrect(r, src->r)) { werrstr(Egreg); fprint(2, "unloadmem:\n"); fprint(2, " src->r: %R\n", src->r); fprint(2, " r: %R\n", r); return -1; } if(Binit(&b, fd, OWRITE) < 0) { werrstr("Binit: %r"); return -1; } lsz = bytesperline(r, chantodepth(src->chan)); if((linebuf = malloc(lsz)) == nil) { werrstr("alloc linebuf: %d: %r", lsz); return -1; } rr = rectsubpt(r, r.min); Bprint(&b, "%11s %11d %11d %11d %11d ", chanstr, rr.min.x, rr.min.y, rr.max.x, rr.max.y); for(y = r.min.y; y < r.max.y; y++) { line = Rect(r.min.x, y, r.max.x, y+1); if(unloadmemimage(src, line, linebuf, lsz) < 0) { werrstr("unload line %R", line); Bflush(&b); free(linebuf); return -1; } if(Bwrite(&b, linebuf, lsz) != lsz) { werrstr("write line %R: %r", line); Bflush(&b); free(linebuf); return -1; } } Bflush(&b); free(linebuf); return 0; }