/* This was originally pktopx in C by Tomas Rokicki */

/* 
   This version converted for DVItoVDU and ported to BSD and System V UNIX by
   some chaps at Kernel Technology up to September 1989.  Contact
   mjh@uk.co.kernel (Mark J. Hewitt) with bug fixes etc.

   Involved were:	Mark J. Hewitt
   			Dave Dixon
			Marc Hadley
*/

#include "def.h"

static char *sccsid[] = "@(#)pktopx.c	1.1";

#ifdef USG
# include <sys/types.h>
# include <sys/stat.h>			/* definitions needed for chmod(2) */
#endif /* USG */

#define NAMELENGTH 80 
#define TERMINALLINELENGTH 132 
#define MAXDIV32 100 
#define ONEFOURTH 1073741824 

#define INCR(a) (a++)
#define DECR(a) (a--)
#define ROUND(a) ((int)(a+0.5))

/* values for access(2) `amode' argument */
#define FILE_EXISTS   00
#define FILE_READABLE 04

/* values returned by openpxlfile() */
#define PXL_FILE_EXISTS  1
#define PXL_FILE_CREATED 0

typedef int integer;
typedef unsigned char quarterword;
typedef char  boolean;
typedef quarterword eightbits;
typedef FILE * bytefile;
bytefile pxlfile;
bytefile pkfile;
char  pxlname[81], pkname[81];
integer pxlloc, pkloc;
integer magnification;
integer designsize;
integer checksum;
integer hppp, vppp;
/* integer i, j; */
integer endofpacket;
integer rasterpointer[128];
integer sizes[128];
integer offsets[128];
integer tfmwidth[128];
integer dynf;
integer car;
integer cheight, cwidth;
integer wordwidth;
integer horesc;
integer packetlength;
eightbits inputbyte;
eightbits bitweight;
integer row[101];
integer word;
integer wordweight;
integer power[32];
integer gpower[33];
integer repeatcount;
integer rowsleft;
boolean turnon;
integer hbit;
integer count;
integer rp;
integer dirptr;
integer flagbyte;
integer haveext;
integer lastext;
int   gargc;
char **gargv;

initialize ()
{
  integer i;
  power[0] = 1;
  for (i = 1; i <= 30; i++)
    power[i] = power[i - 1] * 2;
  power[31] = -ONEFOURTH - ONEFOURTH;
  gpower[0] = 0;
  for (i = 1; i <= 32; i++)
    gpower[i] = gpower[i - 1] + power[
	i - 1];
  for (i = 0; i <= 127; i++)
    rasterpointer[i] = 0;
}

jumpout ()
{
  exit (1);
}

openpxlfile ()
{
  if(access(pxlname, FILE_EXISTS) == 0 &&
     access(pxlname, FILE_READABLE) == 0)
      return PXL_FILE_EXISTS;
  else if((pxlfile = fopen (pxlname, "w")) == NULL)
  {
      fprintf(stderr, "can't write PXL file %s\n", pxlname);
      fflush(stderr);
      exitprog(1);
  }
  pxlloc = 0;
  return PXL_FILE_CREATED;
}

void openpkfile ()
{
    if((pkfile = fopen (pkname, "r")) == NULL)
    {
	fprintf(stderr, "can't read PK file %s\n", pkname);
	fflush(stderr);
	exitprog(1);
    }
  pkloc = 0;
}

pixelinteger (i)
integer i;
{
  (void) putc ((char) ((i >> 24) & 255), pxlfile);
  (void) putc ((char) ((i >> 16) & 255), pxlfile);
  (void) putc ((char) ((i >> 8) & 255), pxlfile);
  (void) putc ((char) (i & 255), pxlfile);
  INCR (pxlloc);
}

eightbits pkbyte ()
{
  INCR (pkloc);
  return (getc (pkfile));
}

integer get16 ()
{
  integer a;
  a = pkbyte ();
  return (a * 256 + pkbyte ());
}

integer get32 ()
{
  integer a;
  a = get16 ();
  if (a > 32767)
    a = a - 65536;
  return (a * 65536 + get16 ());
}

integer getnyb ()
{
  eightbits temp;
  if (bitweight == 0)
  {
    inputbyte = pkbyte ();
    bitweight = 16;
  }
  temp = inputbyte / bitweight;
  inputbyte = inputbyte - temp * bitweight;
  bitweight = bitweight / 16;
  return (temp);
}

boolean getbit ()
{
  boolean temp;
  bitweight = bitweight / 2;
  if (bitweight == 0)
  {
    inputbyte = pkbyte ();
    bitweight = 128;
  }
  temp = inputbyte >= bitweight;
  if (temp)
    inputbyte = inputbyte - bitweight;
  return (temp);
}

integer pkpackednum ()
{
  integer i, j;
  i = getnyb ();
  if (i == 0)
  {
    do
    {
      j = getnyb ();
      INCR (i);
    } while (!(j != 0));
    while (i > 0)
    {
      j = j * 16 + getnyb ();
      DECR (i);
    }
    return (j - 15 + (13 - dynf) * 16 + dynf);
  }
  else
    if (i <= dynf)
      return (i);
    else
      if (i < 14)
	return ((i - dynf - 1) * 16 + getnyb () + dynf + 1
	  );
      else
      {
	if (i == 14)
	  repeatcount = pkpackednum ();
	else
	  repeatcount = 1;
	return (pkpackednum ());
      }
}

skipspecials ()
{
  integer i, j;
  do
  {
    flagbyte = pkbyte ();
    if (flagbyte >= 240)
      switch (flagbyte)
      {
	case 240: 
	case 241: 
	case 242: 
	case 243: 

	  {
	    i = 0;
	    for (j = 240; j <= flagbyte; j++)
	      i = 256 * i + pkbyte ();
	    for (j = 1; j <= i; j++)
	      (void) pkbyte ();
	  }
	  break;
	case 244: 
	  i = get32 ();
	  break;
	case 245: 

	  {;
	  }
	  break;
	case 246: 

	  {;
	  }
	  break;
	case 247: 
	case 248: 
	case 249: 
	case 250: 
	case 251: 
	case 252: 
	case 253: 
	case 254: 
	case 255: 

	  {
	    (void) printf (" Unexpected %d!\n", flagbyte);
	    jumpout ();
	  }
	  break;
      }
  } while (!((flagbyte < 240) || (flagbyte == 245)));
}

dialog ()
{
  integer i;
  if ((gargc < 2) || (gargc > 3))
  {
    (void) printf (" Usage: pktopx pkfile[.pk] [pxlfile[.nnnnpxl]]\n")
      ;
    jumpout ();
  }
  (void) strcpy (pkname, gargv[1]);
  lastext = -1;
  i = 0;
  while (pkname[i] != 0)
  {
    if (pkname[i] == '.')
      lastext = i;
    else
      if (pkname[i] == '/')
	lastext = -1;
    INCR (i);
  }
  if (lastext == -1)
  {
    (void) strcpy (pkname + i, ".pk");
    lastext = i;
  }
  if (gargc == 3)
  {
    (void) strcpy (pxlname, gargv[2]);
    haveext = TRUE;
  }
  else
  {
    (void) strcpy (pxlname, pkname);
    haveext = FALSE;
  }
}

int   pktopx (argc, argv)
int   argc;
char *argv[];
{
  integer i, j;
    
  gargc = argc;
  gargv = argv;
  initialize ();
  dialog ();
  openpkfile ();
  if (pkbyte () != 247)
  {
    (void) printf (" Bad pk file!  pre command missing.\n");
    jumpout ();
  }
  if (pkbyte () != 89)
  {
    (void) printf (" Wrong version of packed file!.\n");
    jumpout ();
  }
  j = pkbyte ();
  for (i = 1; i <= j; i++)
    hppp = pkbyte ();
  designsize = get32 ();
  checksum = get32 ();
  hppp = get32 ();
  vppp = get32 ();
  if (hppp != vppp)
    (void) printf ("Warning:  aspect ratio not 1:1!\n");
  magnification = ROUND (hppp * 72.27 * 5 / 65536);
  if (!haveext)
  {
    i = ROUND (hppp * 72.27 * 5 / 65536);
    (void) sprintf (pxlname + lastext, ".%dpxl", i);
  }
  if(openpxlfile () == PXL_FILE_EXISTS)
  {
      (void) fclose(pkfile);
      return;
  }
  pixelinteger (1001);
  skipspecials ();
  while (flagbyte != 245)
  {
    dynf = flagbyte / 16;
    flagbyte = flagbyte % 16;
    turnon = flagbyte >= 8;
    if (turnon)
      flagbyte = flagbyte - 8;
    if (flagbyte == 7)
    {
      packetlength = get32 ();
      car = get32 ();
      endofpacket = packetlength + pkloc;
      if ((car > 127) || (car < 0))
	goto lab9997;
      tfmwidth[car] = get32 ();
      horesc = get32 ();
      i = get32 ();
      cwidth = get32 ();
      cheight = get32 ();
      if ((cwidth < 0) || (cheight < 0) || (cwidth > 65535) || (
	    cheight > 65535))
	goto lab9997;
      wordwidth = (cwidth + 31) / 32;
      sizes[car] = cwidth * 65536 + cheight;
      i = get32 ();
      j = get32 ();
      if (j < 0)
	j = j + 65536;
      offsets[car] = i * 65536 + j;
    }
    else
      if (flagbyte > 3)
      {
	packetlength = (flagbyte - 4) * 65536 + get16 ();
	car = pkbyte ();
	endofpacket = packetlength + pkloc;
	if (car > 127)
	  goto lab9997;
	i = pkbyte ();
	tfmwidth[car] = i * 65536 + get16 ();
	horesc = get16 ();
	cwidth = get16 ();
	cheight = get16 ();
	wordwidth = (cwidth + 31) / 32;
	sizes[car] = cwidth * 65536 + cheight;
	i = get16 ();
	j = get16 ();
	if (i > 32767)
	  i = i - 65536;
	offsets[car] = i * 65536 + j;
      }
      else
      {
	packetlength = flagbyte * 256 + pkbyte ();
	car = pkbyte ();
	endofpacket = packetlength + pkloc;
	if (car > 127)
	  goto lab9997;
	i = pkbyte ();
	tfmwidth[car] = i * 65536 + get16 ();
	horesc = pkbyte ();
	cwidth = pkbyte ();
	cheight = pkbyte ();
	wordwidth = (cwidth + 31) / 32;
	sizes[car] = cwidth * 65536 + cheight;
	i = pkbyte ();
	j = pkbyte ();
	if (i > 127)
	  i = i - 256;
	if (j > 127)
	  j = j + 255 * 256;
	offsets[car] = i * 65536 + j;
      }
    if (rasterpointer[car] != 0)
    {
      (void) printf (" Second time this character used!\n");
      jumpout ();
    }
    rasterpointer[car] = pxlloc;
    bitweight = 0;
    if (dynf == 14)
    {
      bitweight = 0;
      for (i = 1; i <= cheight; i++)
      {
	word = 0;
	wordweight = 31;
	for (j = 1; j <= cwidth; j++)
	{
	  if (getbit ())
	    word = word + power[wordweight];
	  wordweight = wordweight - 1;
	  if (wordweight == -1)
	  {
	    pixelinteger (word);
	    word = 0;
	    wordweight = 31;
	  }
	}
	if (wordweight < 31)
	  pixelinteger (word);
      }
    }
    else
    {
      rowsleft = cheight;
      hbit = cwidth;
      repeatcount = 0;
      wordweight = 32;
      word = 0;
      rp = 1;
      while (rowsleft > 0)
      {
	count = pkpackednum ();
	while (count > 0)
	{
	  if ((count < wordweight) && (count < hbit))
	  {
	    if (turnon)
	      word = word + gpower[wordweight] - gpower
		[wordweight - count];
	    hbit = hbit - count;
	    wordweight = wordweight - count;
	    count = 0;
	  }
	  else
	    if ((count >= hbit) && (hbit <= wordweight))
	    {
	      if (turnon)
		word = word + gpower[wordweight] - gpower
		  [wordweight - hbit];
	      row[rp] = word;
	      for (i = 0; i <= repeatcount; i++)
		for (j = 1; j <=
		    wordwidth; j++)
		  pixelinteger (row[j]);
	      rowsleft = rowsleft - repeatcount - 1;
	      repeatcount = 0;
	      rp = 1;
	      word = 0;
	      wordweight = 32;
	      count = count - hbit;
	      hbit = cwidth;
	    }
	    else
	    {
	      if (turnon)
		word = word + gpower[wordweight];
	      row[rp] = word;
	      rp = rp + 1;
	      word = 0;
	      count = count - wordweight;
	      hbit = hbit - wordweight;
	      wordweight = 32;
	    }
	}
	turnon = !turnon;
      }
      if ((rowsleft != 0) || (hbit != cwidth))
      {
	(void) printf (" Bad pk file---more bits than required!\n");
	jumpout ();
      }
    }
    if (endofpacket != pkloc)
    {
      (void) printf (" Bad pk file!  Bad packet length.\n");
      jumpout ();
    }
    goto lab9998;
lab9997: while (pkloc != endofpacket)
      i = pkbyte ();
    (void) printf ("Character %d out of range!\n", car);
lab9998: skipspecials ();
  }
  while (!feof (pkfile))
    i = pkbyte ();
  DECR (pkloc);
  dirptr = pxlloc;
  for (car = 0; car <= 127; car++)
  {
    pixelinteger (sizes[car]);
    pixelinteger (offsets[car]);
    pixelinteger (rasterpointer[car]);
    pixelinteger (tfmwidth[car]);
  }
  pixelinteger (checksum);
  pixelinteger (magnification);
  pixelinteger (designsize);
  pixelinteger (dirptr);
  pixelinteger (1001);
  (void) fclose (pxlfile);
  (void) fclose (pkfile);
}
