/*
 *  TEX Device Driver  ver 2.02-
 *  copyright(c) 1988,89 by TSG, 1990-93 by SHIMA
 *
 *  decodepk.c :
 *  Oct.  6, 1988 : first edition
 *                     programed by K.Miyashita
 *  Apr. 15, 1989 : second edition
 *  Jul.  2, 1989 : third edition
 *                     programed by T.IWAI
 *  1991 changed by hideki
 *	very slightly modified against warnings by Oh-Yeah? 25 May 1992
 *  1992 changed by Yakumo
 */

#include <stdio.h>
#define _DEF_STDIO_H_
#include "dd.h"
#include "err.h"
#include "buffer.h"

#ifdef VFD
#ifdef MSVC
#include "msvcdir.h"
#else
#include <dir.h>
#endif
#include <dir.h>
#include <string.h>
#include "vfont.h"
#include "vraster.h"

BOOL tatevfd = FALSE;
extern V_JFM *vfd_top;
const int sl_ratio[3] =
{180, 372, 591};

#define VFD_FINE 40
#define VFD_XFAT 0
#define VFD_YFAT 0
#define VFD_THIN 100

int draw_character(VPARA_TBL *);
int draw_fine(VPARA_TBL *);
void decode_vfn(int, BUFFER *, PREAMBLE *, FONT_INFO *);
void raster_buf_realloc(PREAMBLE **);
static int vfn_remaining_bits;
static BUFFER *vfn_current_pos;
void TateKanji_type(unsigned int);

#endif

/*  temp-buf size */
#define MAX_DIV_8 1000
#define	IS_EXP2	0x40

/* static int power[8]=
{	0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80	}; */

static int gpower[9] =
{0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};

#if DEBUG & MEM_CHK
static void _rasterchk(void);
static void _pkptrchk(BUFFER *);

#define pixel_integer_8(n) (_rasterchk(),*raster++=(uchar)(n))
#else
#define pixel_integer_8(n) (*raster++=(uchar)(n))
#endif

/*  今扱っているビット( in function 'get_bit', 'get_nyb' ) */
static int bit_weight;

/*  dyn_f */
static int dyn_f;

/*  ドット幅，高さ，バイト幅 */
static int c_width, c_height, byte_width;

/*  used in function 'get_bit' and 'get_nyb' */
static int input_byte;

static long repeat_count;

static long lastrep;

static int iexpf;

static BUFFER *pk_data;

/*  pk-data pointer */
static BUFFER *raster;

/*  展開する場所
static uchar row[MAX_DIV_8];
 */
/*  raster-dataを送るまで保持 */

#define	row	common_work


/* getfont.c */
char *get_font_name(FONT_INFO *);

void decode_init(void);
void decode_pk(BUFFER *, PREAMBLE *, int, FONT_INFO *);
void decode_jxl(BUFFER *, PREAMBLE *, int, FONT_INFO *);

void too_big_font(void);

/* static int get_bit( void ); */
/* static int get_nyb( void ); */
static void raster_by_bits(void);
static BOOL normal_packed_raster(BOOL);
static BOOL jxl_packed_raster(void);
static long get_pknum(void);
static void send_row(void);

#define	get_nyb() ((bit_weight^=1)?((input_byte=get_ubyte(pk_data))>>4):(input_byte & 0x0f))

void decode_init(void)
{
}

void decode_pk(BUFFER *pk, PREAMBLE *preamble, int flag_byte, FONT_INFO *font)
	/*  pk-fontを展開．既にpreambleは設定されているとする．
	 *  さらに，raster-dataのバッファ領域は確保されているとする．
	 *  この事については，decode_pkはチェックしていない．
	 *  (section 37 and 46.)
	 */
{
	BOOL turn_on;

	/*  黒か白か？ */
	ENTER("decode_pk");

#if DEBUG & MEM_CHK
	_ptrchk = _pkptrchk;
#endif

	bit_weight = 0;
	dyn_f = flag_byte >> 4;
	turn_on = ((flag_byte & 8) != 0);
	pk_data = pk;
	if (font->f_goth & K_DBL) {
		c_width = preamble->width / 2;
		c_height = preamble->height / 2;
		byte_width = (preamble->byte_width + 1) / 2;
	}
	else {
		c_width = preamble->width;
		c_height = preamble->height;
		byte_width = preamble->byte_width;
	}
	raster = preamble->raster;

	if (dyn_f == 14)
		raster_by_bits();
	else if (normal_packed_raster(turn_on))
		error(UNPACK_ERROR, "More bits than required.\n"
			  "%5d: %s->%s", font->font_code, font->n, get_font_name(font));
	END();
}

#ifdef VFD
int get_ten_vfd()
{
	static union {
		uchar u[4];
		short s[2];
		long l;
	}
	d;

	if (vfn_remaining_bits < 10) {
		d.s[1] = d.s[0];
		d.u[0] = *vfn_current_pos++;
		d.u[1] = *vfn_current_pos++;
		vfn_remaining_bits += 16;
	}
	vfn_remaining_bits -= 10;
	return ((d.l >> vfn_remaining_bits) & MAX_VALUE);
}

void decode_vfn(int char_code, BUFFER *pk, PREAMBLE *preamble, FONT_INFO *font)
{
	int i, j, k, vfn_fine;
	int size_bytes, draw_sw;
	char *s;
	char vfd_name[9];
	unsigned short charcode = STD_CODE;
	V_JFM *vfd_tmp = NULL;
	VPARA_TBL tbl;

	ENTER("decode_vfn");
	tbl.v_code = 0;
	tbl.v_font_name = NULL;
	tbl.font_type = VFD_FONT;
	tbl.width = preamble->width;
	tbl.height = preamble->height;
	tbl.yoffset = 0;			/*yoffsetはとりあえず０(^_^;*/
	size_bytes = preamble->byte_width * tbl.height;

	if (vfd_top || tatevfd) {
		s = font->name;
		if (*s == '*')
			s += strlen(s + 9) + 10;
	}
	vfd_name[8] = NULL;
	for (vfd_tmp = vfd_top; vfd_tmp != NULL; vfd_tmp = vfd_tmp->next) {
		for (i = 0; i < 8 && (vfd_name[i] = vfd_tmp->name[i]) != NULL; ++i);
		if (strstr(s, vfd_name))
			break;
	}
	if (vfd_tmp) {
		tbl.thin = vfd_tmp->thin;
		tbl.xfat = vfd_tmp->_xfat;
		tbl.yfat = vfd_tmp->_yfat;
		tbl.rotation = vfd_tmp->rotation;
		tbl.slant = vfd_tmp->slant;
		vfn_fine = vfd_tmp->threshold;
		draw_sw = vfd_tmp->draw_sw;
		if ((int)'b' <= vfd_tmp->long_wide
			&& vfd_tmp->long_wide <= (int)'e') {
			tbl.height = (int)((long)tbl.width
							 * 10 / (10 - (vfd_tmp->long_wide - (int)'a')));
		}
		else if ((int)'g' <= vfd_tmp->long_wide
				 && vfd_tmp->long_wide <= (int)'j') {
			tbl.height = (int)((long)tbl.width
							 * (10 - (vfd_tmp->long_wide - (int)'f')) / 10);
		}
		if (vfd_tmp->slant != (int)'a') {
			i = (vfd_tmp->slant - (int)'b') % 3;
			if ((int)'b' <= vfd_tmp->slant && vfd_tmp->slant <= (int)'g') {
				tbl.max_width = MAX_VALUE + sl_ratio[i];
				tbl.width = (int)((long)tbl.width
								  * (long)tbl.max_width / (MAX_VALUE + 1));
				tbl.max_height = MAX_VALUE;
			}
			else if ((int)'h' <= vfd_tmp->slant && vfd_tmp->slant <= (int)'m') {
				tbl.max_height = MAX_VALUE + sl_ratio[i];
				tbl.height = (int)((long)tbl.height
								   * (long)tbl.max_height / (MAX_VALUE + 1));
				tbl.max_width = MAX_VALUE;
			}
			else {
				tbl.max_width = MAX_VALUE;
				tbl.max_height = MAX_VALUE;
			}
		}
		preamble->pitch_offset = (tbl.width - preamble->width) / 2;
		preamble->depth_offset = tbl.height * 4 / 5;
		preamble->width = tbl.width;
		preamble->height = tbl.height;
		preamble->byte_width = (tbl.width + 7) / 8;
		if (preamble->byte_width * tbl.height > size_bytes)
			raster_buf_realloc(&preamble);
		size_bytes = preamble->byte_width * tbl.height;
	}
	else {
		tbl.max_width = MAX_VALUE;
		tbl.max_height = MAX_VALUE;
		tbl.thin = VFD_THIN;
		tbl.xfat = VFD_XFAT;
		tbl.yfat = VFD_YFAT;
		tbl.rotation = 0;
		tbl.slant = (int)'a';
		vfn_fine = VFD_FINE;
		draw_sw = (int)'n';
	}

	if (tatevfd) {
		s = strchr(s, 'j') + 1;
		if (s != NULL) {
/* フォント名とchar_codeから shift-jis code への変換ルーチン */
			if (strstr(s, "an"))
				charcode = 0x843f + char_code;
			else if (strstr(s, "ra"))
				charcode = 0x829d + char_code;
			else if (strstr(s, "ta"))
				charcode = 0x833f + char_code;
/* とりあえず、疑似縦書き処理に関係無いコードの変換はコメントアウトしておく
			else if (strstr(s, "en"))
				charcode = 0x849d + char_code;
			else if (*s == 'k') {
				if (*(s + 1) < 'm') {
					k = char_code + ((*(s + 1) - 'a') << 8);
					j = k / 94 + 0xf;
				}
				else {
					k = char_code + ((*(s + 1) - 'm') << 8);
					j = k / 94 + 0x2f;
					if (j >= 0x3e)
						j += 0x80;
				}
				charcode = (k % 94) + ((j >> 1) << 8);
				charcode += (j & 1) ? 0x819e : 0x8140;
			}
			else if (strstr(s, "ma"))
				charcode = 0x821f + char_code;
			else if (strstr(s, "ek"))
				charcode = 0x839d + char_code;
*/
			else if (strstr(s, "sy")) {
				if (char_code >= 100)
					charcode = 0x8139 + char_code;
				else
					charcode = 0x813f + char_code;
			}
			if ((charcode & 0xff) >= 0x7f)
				++charcode;
		}
	}
	tbl.char_code = charcode;
	TateKanji_type((unsigned int)charcode);

	vfn_remaining_bits = 0;
	vfn_current_pos = pk;
	tbl.buffer = raster = preamble->raster;
	for (i = 0; i < size_bytes; i++)
		raster[i] = 0;

	if ((draw_sw == (int)'n' || draw_sw == (int)'f')
		&& tbl.width < vfn_fine) {
		if (draw_fine(&tbl) == FAILURE)
			for (i = 0; i < size_bytes; i++)
				raster[i] = 0xff;
	}
	else {
		if (draw_sw == (int)'o')
			tbl.dtype = VTRACE;
		else if (draw_sw == (int)'f')
			tbl.dtype = FILL;
		else
			tbl.dtype = BOTH;
		if (draw_character(&tbl) == FAILURE)
			for (i = 0; i < size_bytes; i++)
				raster[i] = 0xff;
	}
	END();
}

#endif

void decode_jxl(BUFFER *pk, PREAMBLE *preamble, int flag_byte, FONT_INFO *font)
{
	BOOL turn_on;

	ENTER("decode_jxl");
	bit_weight = 0;
	dyn_f = flag_byte & 0xf;
	turn_on = ((flag_byte & 0x80) != 0);
	pk_data = pk;
	c_width = preamble->width;
	c_height = preamble->height;
	byte_width = preamble->byte_width;
	raster = preamble->raster;

	if (dyn_f == 14)
		raster_by_bits();
	else if (((flag_byte & IS_EXP2) == 0) ?
			 normal_packed_raster(turn_on) : jxl_packed_raster())
		error(UNPACK_ERROR, "More bits than required.\n"
			  "%5d: %s->%s", font->font_code, font->n, get_font_name(font));
	END();

}

void raster_by_bits(void)
{
	unsigned int i;
	int j;
	int shift, mode;

	ENTER("raster_by_bits");

	if ((mode = (c_width & 0x7)) == 0) {
		for (i = (unsigned int)byte_width * (unsigned int)c_height;
		  i != 0; i--) {
			*raster++ = *pk_data++;
		}
		END();
	}
	shift = 0;
	for (i = 0; i < c_height; ++i) {
		for (j = byte_width - 1; j > 0; j--) {
			*raster = *pk_data << shift;
			*raster++ |= *(++pk_data) >> (8 - shift);
		}
		*raster = *pk_data << shift;
		if (mode + shift >= 8) {
			*raster |= *(++pk_data) >> (8 - shift);
		}
		*raster++ &= 0xff << (8 - mode);
		shift = ((shift + mode) & 0x7);
	}
	END();
}

/* int r_byte;
static int get_nyb( void )	*/
/* ニブル単位（４ビット）での読み出し．
	 * section 44
{
	if ( bit_weight == 0 ) {
		bit_weight = 4;
		return( ((input_byte = get_ubyte(pk_data)) >> 4 ) & 0x0f );
	}
	r_byte++;
	bit_weight = 0;
	return( input_byte & 0x0f );
}
*/

/* static int get_bit( void )	*/
/* ビット単位での読み出し．
	 * section 44
	 */
/* {
	if ( bit_weight == 0 ) {
		input_byte = get_ubyte(pk_data);
		bit_weight = 8;
	}
	return( ( input_byte & power[ --bit_weight ] ) != 0 );
}	*/

/* static void raster_by_bits( void )	*/
/*  全く圧縮されていないまま格納されているデータ．
	 *  (section 47.)
	 */
/* {
	int h, v, byte, byte_weight;
	ENTER( "raster_by_bits" );

	for ( v = 1; v <= c_height; v++ ) {
		byte = 0;
		byte_weight = 7;
		for ( h = 1; h <= c_width; h++ ) {
			if ( get_bit() ) byte |= power[byte_weight];
			byte_weight--;
			if ( byte_weight == -1 ) {
				pixel_integer_8( byte );
				byte = 0;
				byte_weight = 7;
			}
		}
		if ( byte_weight < 7 )
			pixel_integer_8( byte );
	}
	END();
} */

static BOOL jxl_packed_raster(void)
{
	int r_p,	/* 水平方向の現在位置（バイト単位） */
		h_bit,	/* １ラスター中で右側に残っているビット数 */
		rows_left,	/* 残りのrowの数 */
		byte_weight,	/* 現在位置 */
		i;

	long count;	/* 現在の色が後何ビット残っているか */

	ENTER("jxl_packed_raster");
	rows_left = c_height;
	h_bit = c_width + 1;
	r_p = repeat_count = 0;
	byte_weight = iexpf = 1;

	for (i = 1; i <= c_width; i++)
		row[i] = 0;
	for (;;) {
		count = get_pknum();
		while (count >= h_bit) {/* skip to next line */
			send_row();
			if (--rows_left <= 0)
				RETURN(0);
			count -= h_bit;
			r_p = 1;
			h_bit = c_width;
			byte_weight = 8;
		}
		while (count >= byte_weight) {	/* skip to next byte */
			count -= byte_weight;
			h_bit -= byte_weight;
			r_p++;
			byte_weight = 8;
		}						/* In this byte */

		byte_weight -= count;	/* should be positive */
		h_bit -= count;			/* should be positive */
		repeat_count++;
		while (repeat_count >= h_bit) {	/* next ptr is next row */

			if (byte_weight < h_bit) {	/* not the last byte */
				row[r_p++] ^= gpower[byte_weight];
				h_bit -= byte_weight;
				repeat_count -= byte_weight;

			}
			else {				/* last byte in the row */
				row[r_p] ^= (gpower[byte_weight] - gpower[byte_weight - h_bit]);
				send_row();
				if (--rows_left <= 0)
					RETURN(0);;
				r_p = 1;
				repeat_count -= h_bit;
				h_bit = c_width;
			}
			byte_weight = 8;
		}
		/* next ptr is in this row */
		while (repeat_count) {
			if (byte_weight > repeat_count) {	/* next ptr is in this byte */
				row[r_p] ^=
					(gpower[byte_weight] - gpower[byte_weight - repeat_count]);
				byte_weight -= repeat_count;
				h_bit -= repeat_count;
				repeat_count = 0;
				break;
			}
			else {				/* next ptr is not in this byte */
				row[r_p++] ^= gpower[byte_weight];
				h_bit -= byte_weight;
				repeat_count -= byte_weight;
				byte_weight = 8;
			}
		}
	}
}

static BOOL normal_packed_raster(BOOL turn_on)
	/*  圧縮データを展開する．
	 *  (section 51.)
	 */
{
	int	tmp,
		r_p,	/* 水平方向の現在位置（バイト単位） */
		h_bit,	/* １ラスター中で右側に残っているビット数 */
		rows_left,	/* 残りのrowの数 */
		byte,	/* raster-dataを一時的に入れる */
		byte_weight;	/* 現在位置 */

	long count;	/* 現在の色が後何ビット残っているか */

	ENTER("normal_packed_raster");
	rows_left = c_height;
	h_bit = c_width;
	byte = repeat_count = iexpf = 0;
	byte_weight = 8;
	r_p = 1;

	while (rows_left > 0) {
		count = get_pknum();
		while (count > 0) {
			if ((count < byte_weight) && (count < h_bit)) {
				if (turn_on)
					byte |= (gpower[byte_weight] -
							 gpower[byte_weight - count]);

				h_bit -= count;
				byte_weight -= count;
				break;
			}
			else if ((count >= h_bit) &&
					 (h_bit <= byte_weight)) {
				if (turn_on)
					byte |= (gpower[byte_weight] -
							 gpower[byte_weight - h_bit]);

				row[r_p] = byte;
				for (tmp = repeat_count; tmp-- >= 0; )
					send_row();
				rows_left = rows_left - repeat_count - 1;
				repeat_count = 0;
				r_p = 1;
				byte = 0;
				byte_weight = 8;
				count -= h_bit;
				h_bit = c_width;
			}
			else {
				if (turn_on)
					byte |= gpower[byte_weight];

				row[r_p++] = byte;
				byte = 0;
				count -= byte_weight;
				h_bit -= byte_weight;
				byte_weight = 8;
			}
		}
		turn_on = (!turn_on);
	}
	RETURN((rows_left != 0) || (h_bit != c_width));
}

static long get_pknum(void)
	/*  first editionでは，pk_packed_numという名前
	 *  (section 19.)
	 */
{
	uint i;
	long j;

	/*  long j; */
	ENTER("get_pknum");

	i = get_nyb();
	if (i == 0) {
		do {
			j = get_nyb();
			i++;
		} while (j == 0);
		while (i > 0) {
			j = (j << 4) + get_nyb();
			i--;
		}
		RETURN(j - 15 + ((uint)(13 - dyn_f) << 4) + dyn_f);
	}
	else if (i <= dyn_f) {
		RETURN(i);
	}
	else if (i < 14) {
		RETURN(((i - dyn_f - 1) << 4) + get_nyb() + dyn_f + 1);
	}
	else {
		if (i == 14)
			lastrep = repeat_count = get_pknum();
		else
			repeat_count = (iexpf == 0) ? 1 : lastrep;
		RETURN(get_pknum());
	}
}

static void send_row(void)
{
	int h;

	ENTER("send_row");

	for (h = 1; h <= byte_width; h++)
		pixel_integer_8(row[h]);

	END();
}

#if DEBUG & MEM_CHK

static void _rasterchk(void)
	/* Buffer-accessをcheck
	 */
{
	if ((HUGE_BUF *)raster < (HUGE_BUF *)(raster_buf_pointer->start)
		|| (HUGE_BUF *)raster >= (HUGE_BUF *)(raster_buf_pointer->end))
		error(MEMORY_FAULT, "raster_buf");
}

static void _pkptrchk(BUFFER *ptr)
{
	if ((HUGE_BUF *)ptr < (HUGE_BUF *)(pk_buf_pointer->start)
		|| (HUGE_BUF *)ptr >= (HUGE_BUF *)(pk_buf_pointer->end))
		error(MEMORY_FAULT, "pk-buffer");
}

#endif

/* end of file : decodepk.c */
