xref: /inferno-os/appl/lib/readpicfile.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
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