ref: d180b70c6c69ffe8168cc8571772ad6e15ac6aba
dir: /load.myr/
use std use sys use "types" use "chan" use "image" use "pack" pkg draw = const load : (dpy : display#, buf : byte[:] -> std.result(image#, err)) const xload : (dpy : display#, buf : byte[:] -> std.result((image#, std.size), err)) ;; const load = {dpy, buf match xload(dpy, buf) | `std.Ok (img, n): if n != buf.len // freeimg(img) -> `std.Err `Efmt ;; -> `std.Ok img | `std.Err e: -> `std.Err e ;; } const xload = {dpy, buf var chan, rect, compressed var n, img if !parsehdr(buf, &chan, &rect, &compressed, &buf) -> `std.Err `Efmt ;; img = genallocimage(dpy, 0, Refnone, chan, DWhite, false, rect, rect) if compressed n = 5*12 + 11 n += loadcomp(dpy, img, buf) else n = 5*12 n += loadraw(dpy, img, buf) ;; if n > 0 -> `std.Ok (img, n) else // freeimg(img) -> `std.Err `Efmt ;; } const loadcomp = {dpy, img, buf var l, n, ymin, ymax, err l = 0 ymin = img.r.y0 while ymin != img.r.y1 if buf.len < 24 -> -1 ;; err = false ymax = getint(buf[:12], &err) n = getint(buf[12:24], &err) if err -> -1 ;; l += 24 buf = buf[24:] pack(dpy, "biiiiid", (n : std.size), \ ('Y' : byte), \ img.id, \ img.r.x0, \ ymin, \ img.r.x1, \ ymax, \ buf[:n]) buf = buf[n:] ymin = ymax l += n ;; -> (l : std.size) } const loadraw = {dpy, img, buf var chunk, btp, btl var l, n, r, dx, dy l = 0 r = img.r dx = r.x1 - r.x0 btp = (chandepth(img.chan) / 8 : int) btl = btp * dx chunk = dpy.buf.len - 64 while r.y0 != r.y1 dy = r.y1 - r.y0 /* FIXME: deal with images where btl > chunk */ if dy * btl > chunk dy = chunk / btl ;; n = dy * btl pack(dpy, "biiiiid", (n : std.size), \ ('y' : byte), \ img.id, \ r.x0, \ r.y0, \ r.x1, \ r.y0 + dy, \ buf[:n]) l += n buf = buf[n:] r.y0 += dy ;; -> (l : std.size) } const parsehdr = {buf, chanp, rectp, compressedp, bufp if buf.len < 5*12 -> false ;; if std.sleq(buf[:11], "compressed\n") && buf.len >= 5*12 + 11 compressedp# = true bufp# = buf[5*12 + 11:] -> parsefmt(buf[11:11+5*12], chanp, rectp) else compressedp# = false bufp# = buf[5*12:] -> parsefmt(buf[:5*12], chanp, rectp) ;; } const parsefmt = {buf, chanp, rectp var spbuf : byte[:][5] var sp, err sp = std.bstrtok(spbuf[:], buf) if sp.len == 0 -> false ;; match chanparse(sp[0]) | `std.Some c: chanp# = c | `std.None: std.fatal("bad chan\n"); -> false ;; err = false rectp.x0 = getint(sp[1], &err) rectp.y0 = getint(sp[2], &err) rectp.x1 = getint(sp[3], &err) rectp.y1 = getint(sp[4], &err) -> !err }