/*
 * Copyright 1990 by Baylor College of Medicine ALL RIGHTS RESERVED. 
 *
 * This program is subject to a license agreement between 
 * Baylor College of Medicine and MIT. Any use inconsistent with
 * said license and any use by persons other than the faculty, 
 * students and staff at MIT or any use on a computer not operated 
 * as part of the Athena Computing Environment (ACE) is expressly 
 * prohibited.
 */
/*
 *		Routines to read an write raster files to and from images.
 *		At present, images must be Z-Pixmap and only rasterfiles of depth
 *		less than that of the screen can be read in.
 */
#include <sys/types.h>
#include <sys/file.h>
#include <stdio.h>
#include <fcntl.h>
#include <malloc.h>
#include <rasterfile.h>

static int lbuf ;
static unsigned char buf[512] ;

/* Adds a char to buffer, flushing when necessary */
static
add_chr(fd,c)
	unsigned char c ;
{
	if (lbuf == sizeof buf)
	{
		write(fd,buf,lbuf) ;
		lbuf = 0 ;
	}
	buf[lbuf++] = c ;
}

/* Flushes run char */
static
int
flush_chrs(fd,chr,len)
	unsigned char chr ;
{
	if (len == 1)
	{
		if (chr == 128)
		{
			add_chr(fd,128) ;
			add_chr(fd,0) ;
			return 2 ;
		}
		else
		{
			add_chr(fd,chr) ;
			return 1 ;
		}
	}
	else if (len > 1)
	{
		add_chr(fd,128) ;
		add_chr(fd,len - 1) ;
		add_chr(fd,chr) ;
		return 3 ;
	}
	return 0 ;
}

/* Trasnfers a image read from a socket to a file */
write_rast_img_fd(fd,fd2)
{
	struct rasterfile rasterfile ;
	int size ;
	long width ;
	long height ;
	long depth ;
	long map_type ;
	if (read_f(fd2,"llll",&width,&height,&depth,&map_type) < 0)
	{
		return -1 ;
	}

	size = (((width * depth + 15) / 16) * 2) * height ;

	lseek(fd,sizeof rasterfile,L_SET) ;

	if (map_type == 1)
	{
		long map_size ;
		static unsigned char red[256] ;
		static unsigned char green[256] ;
		static unsigned char blue[256] ;
		static struct rgb {
			unsigned char r ;
			unsigned char g ;
			unsigned char b ;
		} map[256] ;
		int i ;
		if (read_f(fd2,"l",&map_size) < 0)
		{
			return -1 ;
		}
		if (map_size > 256)
		{
			return -1 ;
		}
		if (must_read(fd2,map,map_size * 3) != map_size * 3)
		{
			return -1 ;
		}
		for(i = 0; i < map_size; i++)
		{
			red[i] = map[i].r ;
			green[i] = map[i].g ;
			blue[i] = map[i].b ;
		}
		write(fd,red,map_size) ;
		write(fd,green,map_size) ;
		write(fd,blue,map_size) ;
		rasterfile.ras_maptype = RMT_EQUAL_RGB ;
		rasterfile.ras_maplength = map_size * 3 ;
	}
	else
	{
		rasterfile.ras_maptype = RMT_NONE ;
		rasterfile.ras_maplength = 0 ;
	}

	rasterfile.ras_magic =  RAS_MAGIC ;
	rasterfile.ras_width = width ;
	rasterfile.ras_height = height ;
	rasterfile.ras_depth = depth ;
	rasterfile.ras_type = RT_BYTE_ENCODED ;

	lbuf = 0 ;
	{
		int run_length = 0 ;
		unsigned char run_char ;
		int len = 0 ;
		int lrbuf = 0 ;
		static unsigned char rbuf[512] ;
		unsigned char *p = rbuf ;
		while(size)
		{
			unsigned char b ;
			if (lrbuf == 0)
			{
				lrbuf = (size > sizeof rbuf) ? sizeof rbuf : size ;
				if (must_read(fd2,rbuf,lrbuf) != lrbuf)
				{
					return -1 ;
				}
				p = rbuf ;
			}
			b = *p++ ;
			lrbuf-- ;
			if (!run_length)
			{
				run_char = b ;
				run_length = 1 ;
			}
			else if (b != run_char || run_length > 255)
			{
				len += flush_chrs(fd,run_char,run_length) ;
				run_char = b ;
				run_length = 1 ;
			}
			else
			{
				run_length++ ;
			}
			size-- ;
		}
		len += flush_chrs(fd,run_char,run_length) ;
		rasterfile.ras_length = len ;
	}
	if (lbuf > 0)
	{
		write(fd,buf,lbuf) ;
	}

	lseek(fd,0L,L_SET) ;

	/* Write out the header */
	/*
	(void)write(fd,(char *)&rasterfile,sizeof rasterfile,1) ;
	*/
	write_f(fd,"llllllll",
		rasterfile.ras_magic,
		rasterfile.ras_width,
		rasterfile.ras_height,
		rasterfile.ras_depth,
		rasterfile.ras_length,
		rasterfile.ras_type,
		rasterfile.ras_maptype,
		rasterfile.ras_maplength) ;

	return 0 ;
}
