/*	pktopkd : Utility for long PK files used by dviout/dviprt
 *          Ver 1.1, 1991 written by SHIMA
 *
 *			Usage: pktopkd file_name
 */

#include	<stdio.h>
#include	<io.h>
#include	<dir.h>

#define PK_PRE		247
#define PK_POST		245
#define PK_ID		89
#define PK_POST		245
#define	LPK_ID		('p'+'k'+'d')
#define	MAX_CHAR	256
#define	get_ubyte(x)	((unsigned int)getc(x))

void usage(void);

read_flag_byte(FILE *);

char pass[MAXPATH];
char drive[MAXDRIVE];
char dir[MAXDIR];
char name[MAXFILE];
char ext[MAXEXT];
char *null = '\0';

char lpk_name[14];
char f_name[MAXPATH];
char address[MAX_CHAR * 3];

union POS {
	long l;
	char b[4];
}

pos;

unsigned int get_int(FILE * pk)
{
	unsigned int num;

	num = (get_ubyte(pk)) << 8;
	return (num + get_ubyte(pk));
}

long get_long(FILE * pk)
{
	unsigned long num;

	num = get_ubyte(pk);
	num = (num << 8) + get_ubyte(pk);
	num = (num << 8) + get_ubyte(pk);
	num = (num << 8) + get_ubyte(pk);
	return (num);
}

void move_ptr(FILE * fd, unsigned int x)
{
	pos.l += x;
	while (x--) {
		if (getc(fd) < 0) {
			printf("Error: Reading PK file\n");
			exit(1);
		}
	}
}

void main(int argc, char **argv)
{
	FILE *pk, *lpk;
	unsigned int char_code;
	int flag_byte, tmp, i, num, len, min_code, max_code;
	long packet_length, id;
	struct ftime ftimep;

	if (argc != 2)
		usage();

	fnsplit(argv[1], drive, dir, name, ext);
	fnmerge(f_name, null, dir, name, ext);
	fnmerge(lpk_name, null, null, name, ".pkd");

	if ((pk = fopen(argv[1], "rb")) == NULL) {
		printf("Error: Cannot open PK file %s\n", argv[1]);
		exit(1);
	}
	if (get_ubyte(pk) != PK_PRE || get_ubyte(pk) != PK_ID) {
		printf("Error: %s is not PK format font file.\n", argv[1]);
		exit(1);
	}
	if ((lpk = fopen(lpk_name, "wb")) == NULL) {
		printf("Error: Cannot create %s\n", f_name);
		exit(1);
	}
	num = 0;
	tmp = get_ubyte(pk);
	move_ptr(pk, tmp);

	putc(PK_PRE, lpk);
	putc(LPK_ID, lpk);
	len = strlen(f_name);
	putc(len + 5, lpk);
	putw(0, lpk);
	putw(0, lpk);

	for (i = 0; i <= len; i++)
		putc(f_name[i], lpk);
	for (i = 0; i < 16; i++)
		putc(get_ubyte(pk), lpk);
	/* design size, check sum, hppp and vppp */

	for (;;) {
		if ((flag_byte = read_flag_byte(pk)) == PK_POST)
			goto end;
		pos.l = ftell(pk) - 1;
		num++;

		switch (flag_byte & 7) {
		  case 7:
			  /* long-preamble */
			  packet_length = get_long(pk);
			  char_code = get_long(pk);
			  break;
		  case 4:
		  case 5:
		  case 6:
			  /* ex-short-preamble */
			  packet_length = (((long)flag_byte & 3) << 16) +
				  get_int(pk);
			  char_code = get_ubyte(pk);
			  break;
		  default:
			  /* short preamble */
			  packet_length = ((flag_byte & 7) << 8) +
				  get_ubyte(pk);
			  char_code = get_ubyte(pk);
			  break;
		}
		if (char_code >= 0x100) {
			printf("\nError: Large character code %d!\n", char_code);
			exit(1);
		}
		printf("%8d", char_code);
		char_code *= 3;

		address[char_code] = pos.b[2];
		address[char_code + 1] = pos.b[1];
		address[char_code + 2] = pos.b[0];
		move_ptr(pk, packet_length);
	}
  end:							/* */
	min_code = max_code = -1;
	for (i = 0; i < MAX_CHAR * 3; i += 3) {
		if (address[i] != 0 || address[i + 1] != 0 || address[i + 2] != 0) {
			min_code = i / 3;
			break;
		}
	}
	for (i = (MAX_CHAR - 1) * 3; i >= 0; i -= 3) {
		if (address[i] != 0 || address[i + 1] != 0 || address[i + 2] != 0) {
			max_code = i / 3;
			break;
		}
	}
	if (min_code == -1) {
		printf("\nEroor: No character in %s", f_name);
		exit(1);
	}
	if (fwrite(address + min_code * 3, max_code - min_code + 1, 3, lpk) < 3)
		goto w_err;
	putc(PK_POST, lpk);
	fflush(lpk);
	fseek(lpk, 4, SEEK_SET);
	if (putc(min_code, lpk) < 0
		|| putc(0, lpk) < 0
		|| putc(max_code, lpk) < 0) {
		printf("\nError: Cannot write in %s", f_name);
	}
	fflush(lpk);
	getftime(fileno(pk), &ftimep);
	setftime(fileno(lpk), &ftimep);
	if (fcloseall() == 2) {
		printf("\nCreate %s (%d characters: %d - %d) for %s\n",
			   lpk_name, num, min_code, max_code, f_name);
		exit(0);
	}
	else
	  w_err:
		fseek(lpk, 0, SEEK_SET);
	putw(0, lpk);
	fcloseall();
	printf("\nError int creating %s\n", f_name);
	exit(1);
}

int read_flag_byte(FILE * pk)
	/*  flag byte を読み出す．specialsのときはスキップする．
     */
{
	int flag_byte;
	long tmp;

	flag_byte = get_ubyte(pk);
	while (flag_byte >= 240 && flag_byte != PK_POST) {

		/* Skip Specials
         */
		switch (flag_byte) {
		  case 240:
		  case 241:
		  case 242:
		  case 243:
			  for (tmp = 0; flag_byte >= 240; flag_byte--)
				  tmp = (tmp << 8) + get_ubyte(pk);
			  move_ptr(pk, tmp);
			  break;
		  case 244:
			  move_ptr(pk, 4);
			  break;
		  case 245:
		  case 246:
			  break;
		  default:
			  printf("Error: Unexpected code %d!", flag_byte);
		}
		flag_byte = get_ubyte(pk);
	};
	return (flag_byte);
}

void usage(void)
{
	printf(
	  "\t<<< pktopkd: Utility for long PK files used by dviout/dviprt >>>\n"
			  "\t\t\t\t\tVer 1.1, 1991 written by SHIMA\n"
			  "Usage: pktopkd file_name\n");
	exit(1);
}
