1implement RImagefile; 2 3include "sys.m"; 4 sys: Sys; 5 6include "draw.m"; 7 8include "bufio.m"; 9 bufio: Bufio; 10 Iobuf: import bufio; 11 12include "imagefile.m"; 13 14Header: adt 15{ 16 fd: ref Iobuf; 17 ch: chan of (ref Rawimage, string); 18 # variables in i/o routines 19 buf: array of byte; 20 bufi: int; 21 nbuf: int; 22 23 TYPE: string; 24 CHAN: string; 25 NCHAN: string; 26 CMAP: int; 27 28 dx: int; 29 dy: int; 30}; 31 32NBUF: con 8*1024; 33 34init(iomod: Bufio) 35{ 36 if(sys == nil) 37 sys = load Sys Sys->PATH; 38 bufio = iomod; 39} 40 41read(fd: ref Iobuf): (ref Rawimage, string) 42{ 43 # spawn a subprocess so I/O errors can clean up easily 44 45 ch := chan of (ref Rawimage, string); 46 spawn readslave(fd, ch); 47 48 return <-ch; 49} 50 51readmulti(fd: ref Iobuf): (array of ref Rawimage, string) 52{ 53 (i, err) := read(fd); 54 if(i != nil){ 55 a := array[1] of { i }; 56 return (a, err); 57 } 58 return (nil, err); 59} 60 61readslave(fd: ref Iobuf, ch: chan of (ref Rawimage, string)) 62{ 63 (header, err) := header(fd, ch); 64 if(header == nil){ 65 ch <-= (nil, err); 66 exit; 67 } 68 69 ch <-= image(header); 70} 71 72readerror(): string 73{ 74 return sys->sprint("ReadPIC: read error: %r"); 75} 76 77header(fd: ref Iobuf, ch: chan of (ref Rawimage, string)): (ref Header, string) 78{ 79 h := ref Header; 80 81 h.fd = fd; 82 h.ch = ch; 83 h.CMAP = 0; 84 h.dx = 0; 85 h.dy = 0; 86 cantparse := "ReadPIC: can't parse header"; 87 for(;;){ 88 s := fd.gets('\n'); 89 if(s==nil || s[len s-1]!='\n') 90 return (nil, cantparse); 91 if(s == "\n") 92 break; 93 addfield(h, s[0:len s-1]); 94 } 95 if(h.dx<=0 || h.dy<=0) 96 return (nil, "ReadPIC: empty picture or WINDOW not set"); 97 return (h, nil); 98} 99 100addfield(h: ref Header, s: string) 101{ 102 baddata := "ReadPIC: not a PIC header"; 103 for(i:=0; i<len s; i++){ 104 if(s[i] == '=') 105 break; 106 if(s[i]==0 || s[i]>16r7f){ 107 h.ch <-= (nil, baddata); 108 exit; 109 } 110 } 111 if(i == len s){ 112 h.ch <-= (nil, baddata); 113 exit; 114 } 115 case s[0:i]{ 116 "TYPE" => 117 h.TYPE = s[i+1:]; 118 "CHAN" => 119 h.CHAN = s[i+1:]; 120 "NCHAN" => 121 h.NCHAN = s[i+1:]; 122 "CMAP" => 123 h.CMAP = 1; 124 "WINDOW" => 125 (n, l) := sys->tokenize(s[i+1:], " "); 126 if(n != 4){ 127 h.ch <-= (nil, "ReadPIC: bad WINDOW specification"); 128 exit; 129 } 130 x0 := int hd l; 131 l = tl l; 132 y0 := int hd l; 133 l = tl l; 134 h.dx = int hd l - x0; 135 l = tl l; 136 h.dy = int hd l - y0; 137 } 138} 139 140image(h: ref Header): (ref Rawimage, string) 141{ 142 if(h.TYPE!="dump" || h.CHAN!="rgb" || h.NCHAN!="3" || h.CMAP) 143 return (nil, "ReadPIC: can't handle this type of picture"); 144 145 i := ref Rawimage; 146 i.r = ((0,0), (h.dx, h.dy)); 147 i.cmap = nil; 148 i.transp = 0; 149 i.trindex = byte 0; 150 i.nchans = int h.NCHAN; 151 i.chans = array[i.nchans] of array of byte; 152 for(j:=0; j<i.nchans; j++) 153 i.chans[j] = array[h.dx*h.dy] of byte; 154 i.chandesc = CRGB; 155 n := h.dx*h.dy; 156 b := array[i.nchans*n] of byte; 157 if(h.fd.read(b, len b) != len b) 158 return (nil, "ReadPIC: file too short"); 159 l := 0; 160 for(j=0; j<n; j++) 161 for(k:=0; k<i.nchans; k++) 162 i.chans[k][j] = b[l++]; 163 return (i, nil); 164} 165