#include "image.h" #include #include /* write to b the result of decompressing c with the algorithm described in image(6), using w as scratch space with sliding window size NMEM */ int _decompress(Biobuf *b, uchar *c, int clen) { uchar w[2*NMEM]; uchar *u, *we, *ce, *p, *pe; int n, o; u = w; we = w + 2*NMEM; ce = c + clen; while(c < ce) { if(*c & 0x80) { n = (*c & 0x7F) + 1; if(c + n > ce) { werrstr("truncated cdata"); return -1; } /* flush and slide the window if necessary */ if(u + n > we) { if(Bwrite(b, w, NMEM) < NMEM) sysfatal("write: %r"); memmove(w, w+NMEM, u - (w+NMEM)); u -= NMEM; } memmove(u, c+1, n); u += n; c += 1 + n; } else { if(c + 1 > ce) { werrstr("truncated code word"); return -1; } n = ((*c & 0x7C) >> 2) + 3; o = ((*c & 0x3) << 8 | *(c+1)) + 1; if(u - o < w) { werrstr("invalid offset"); return -1; } /* flush and slide the window if necessary */ if(u + n > we) { if(Bwrite(b, w, NMEM) < NMEM) sysfatal("write: %r"); memmove(w, w+NMEM, u - (w+NMEM)); u -= NMEM; } p = u-o; pe = p + n; while(p < pe) *u++ = *p++; c += 2; } } if(Bwrite(b, w, u-w) != u-w) sysfatal("write: %r"); return 0; } int decompress(ImgHdr h, int fd) { int p[2]; Biobuf bin, bout; int ncblock; uchar *cbuf; int y, n, nexty, csz; if(pipe(p) < 0) { werrstr("pipe: %r"); return -1; } if(Binit(&bin, fd, OREAD) < 0 || Binit(&bout, p[1], OWRITE) < 0) { werrstr("Binit: %r"); return -1; } switch(rfork(RFPROC|RFREND|RFFDG|RFNAMEG|RFNOWAIT)) { case -1: close(p[0]); close(p[1]); werrstr("fork: %r"); return -1; case 0: close(p[0]); if((argv0 = smprint("%s: decompress", argv0)) == nil) sysfatal("smprint: %r"); ncblock = _compblocksize(h.r, chantodepth(h.chan)); if((cbuf = malloc(ncblock)) == nil) sysfatal("alloc buf: %r"); for(y = h.r.min.y; y < h.r.max.y; y = nexty) { if((n = Bread(&bin, cbuf, 24)) != 24) { if(n < 0) sysfatal("line %d: cblock header: %r", y); sysfatal("line %d: cblock header: short read: %d/24", y, n); } if(cbuf[11] != ' ' || cbuf[23] != ' ') sysfatal("line %d: invalid cblock header", y); nexty = atoi((char *)cbuf); if(nexty < y || nexty > h.r.max.y) sysfatal("line %d: out of sequence: %d", y, nexty); csz = atoi((char *)cbuf + 12); if(csz > ncblock || csz < 0) sysfatal("line %d: unusual cblock size: %d/%d", y, csz, ncblock); if((n = Bread(&bin, cbuf, csz)) != csz) { if(n < 0) sysfatal("line %d: cblock: %r", y); sysfatal("line %d: cblock: short read: %d/%d", y, n, csz); } if(_decompress(&bout, cbuf, csz) < 0) sysfatal("line %d: %r", y); } Bflush(&bout); exits(nil); } close(p[1]); return p[0]; } int linesz(ImgHdr h) { return bytesperline(h.r, chantodepth(h.chan)); } void usage(void) { fprint(2, "usage: %s -u [-c chanstr] linesz(hsrc) ? linesz(hdst) : linesz(hsrc))) == nil) sysfatal("alloc buf: %r"); if(Binit(&bsrc, 0, OREAD) < 0 || Binit(&bdst, 1, OWRITE) < 0) sysfatal("Binit"); Bprint(&bdst, "%H", hdst); for(y = 0; y < Dy(hsrc.r); y++) { if((n = Bread(&bsrc, buf, linesz(hsrc))) != linesz(hsrc)) { if(n == 0) werrstr("eof"); sysfatal("read src: line %d/%d: %d/%d: %r", y, Dy(hsrc.r), n, linesz(hsrc)); } if(loadmemimage(srcline, srcline->r, buf, linesz(hsrc)) < 0) sysfatal("load src"); memimagedraw(dstline, dstline->r, srcline, ZP, nil, ZP, S); if(unloadmemimage(dstline, dstline->r, buf, linesz(hdst)) < 0) sysfatal("unload dst"); if(Bwrite(&bdst, buf, linesz(hdst)) != linesz(hdst)) sysfatal("write dst: %r"); } Bflush(&bdst); exits(nil); } /* image(6) /sys/src/libmemdraw/cread.c /sys/src/libmemdraw/write.c /sys/src/libdraw/computil.c /sys/src/libmemdraw/cload.c */