shithub: purgatorio

ref: fb7dd4b3a868cb8987049c95bb32e6425a73c8b9
dir: /appl/lib/readpicfile.b/

View raw version
implement RImagefile;

include "sys.m";
	sys: Sys;

include "draw.m";

include "bufio.m";
	bufio: Bufio;
	Iobuf: import bufio;

include "imagefile.m";

Header: adt
{
	fd:	ref Iobuf;
	ch:	chan of (ref Rawimage, string);
	# variables in i/o routines
	buf:	array of byte;
	bufi:	int;
	nbuf:	int;

	TYPE:	string;
	CHAN:	string;
	NCHAN:	string;
	CMAP:	int;

	dx:	int;
	dy:	int;
};

NBUF:	con 8*1024;

init(iomod: Bufio)
{
	if(sys == nil)
		sys = load Sys Sys->PATH;
	bufio = iomod;
}

read(fd: ref Iobuf): (ref Rawimage, string)
{
	# spawn a subprocess so I/O errors can clean up easily

	ch := chan of (ref Rawimage, string);
	spawn readslave(fd, ch);

	return <-ch;
}

readmulti(fd: ref Iobuf): (array of ref Rawimage, string)
{
	(i, err) := read(fd);
	if(i != nil){
		a := array[1] of { i };
		return (a, err);
	}
	return (nil, err);
}

readslave(fd: ref Iobuf, ch: chan of (ref Rawimage, string))
{
	(header, err) := header(fd, ch);
	if(header == nil){
		ch <-= (nil, err);
		exit;
	}

	ch <-= image(header);
}

readerror(): string
{
	return sys->sprint("ReadPIC: read error: %r");
}

header(fd: ref Iobuf, ch: chan of (ref Rawimage, string)): (ref Header, string)
{
	h := ref Header;

	h.fd = fd;
	h.ch = ch;
	h.CMAP = 0;
	h.dx = 0;
	h.dy = 0;
	cantparse := "ReadPIC: can't parse header";
	for(;;){
		s := fd.gets('\n');
		if(s==nil || s[len s-1]!='\n')
			return (nil, cantparse);
		if(s == "\n")
			break;
		addfield(h, s[0:len s-1]);
	}
	if(h.dx<=0 || h.dy<=0)
		return (nil, "ReadPIC: empty picture or WINDOW not set");
	return (h, nil);
}

addfield(h: ref Header, s: string)
{
	baddata := "ReadPIC: not a PIC header";
	for(i:=0; i<len s; i++){
		if(s[i] == '=')
			break;
		if(s[i]==0 || s[i]>16r7f){
			h.ch <-= (nil, baddata);
			exit;
		}
	}
	if(i == len s){
		h.ch <-= (nil, baddata);
		exit;
	}
	case s[0:i]{
	"TYPE" =>
		h.TYPE = s[i+1:];
	"CHAN" =>
		h.CHAN = s[i+1:];
	"NCHAN" =>
		h.NCHAN = s[i+1:];
	"CMAP" =>
		h.CMAP = 1;
	"WINDOW" =>
		(n, l) := sys->tokenize(s[i+1:], " ");
		if(n != 4){
			h.ch <-= (nil, "ReadPIC: bad WINDOW specification");
			exit;
		}
		x0 := int hd l;
		l = tl l;
		y0 := int hd l;
		l = tl l;
		h.dx = int hd l - x0;
		l = tl l;
		h.dy = int hd l - y0;
	}
}

image(h: ref Header): (ref Rawimage, string)
{
	if(h.TYPE!="dump" || h.CHAN!="rgb" || h.NCHAN!="3" || h.CMAP)
		return (nil, "ReadPIC: can't handle this type of picture");

	i := ref Rawimage;
	i.r = ((0,0), (h.dx, h.dy));
	i.cmap = nil;
	i.transp = 0;
	i.trindex = byte 0;
	i.nchans = int h.NCHAN;
	i.chans = array[i.nchans] of array of byte;
	for(j:=0; j<i.nchans; j++)
		i.chans[j] = array[h.dx*h.dy] of byte;
	i.chandesc = CRGB;
	n := h.dx*h.dy;
	b := array[i.nchans*n] of byte;
	if(h.fd.read(b, len b) != len b)
		return (nil, "ReadPIC: file too short");
	l := 0;
	for(j=0; j<n; j++)
		for(k:=0; k<i.nchans; k++)
			i.chans[k][j] = b[l++];
	return (i, nil);
}