/* -*-C-*- dvidjp.c */
/*-->dvidj500*/
/**********************************************************************/
/***************************** dvidj500 *******************************/
/**********************************************************************/

/* DVI Driver for HP DeskJet 500 printer
 *  by Joerg Bullmann (bullmann@fzi.de)
 *               20 February 1994
 *
 * modified from:
 *
 *  Beebe Laser Jet driver
 *   by  Paul Kirkaas (kirkaas@cs.ucla.edu)
 *               22 May 1990
 *  HP DeskJet Plus driver
 *   by  David Megginson (dmeggins@acadvm1.uottawa.ca)
 *               20 January 1993
 *   and Hagen Patzke (i31ahp@rz.unibw-muenchen.de, till 31.3.1993 only!)
 *               18 February 1993
 *
 * Employs 3 types of data compression to achieve minimal output file size:
 *
 *    1) Run length encodimng
 *    2) Tagged image file format encoding
 *    3) Delta row compression
 *
 * All described in "HP DeskJet Printer Family Technical Reference Guide"
 *
 * It should run straight with the Beebe driver set; you might
 * have to make some adjustments.  I have personally only run
 * it on a Linux system, Lib 4.5.8, GCC 2.5.7.
 *
 * TOPS20 (never heard of this) will probably not work because
 * it has only 7 bits in a byte.
 *
 * Please let me know if you make any improvements or repairs.
 * Thanks
 *
 * Good Luck.
 */

#include "dvihead.h"

/**********************************************************************/
/************************  Device Definitions  ************************/
/**********************************************************************/

/* All output-device-specific definitions go here.  This section must
be changed when modifying a dvi driver for use on a new device */
#define  MFMODE  "HPDeskJet"
#define  FONTDESTDIR  FONTPATH

#undef HPLASERJET
#define  HPLASERJET      1		/* conditional compilation flag */
#define  HPDESKJET       1		/* conditional compilation flag */

#define VERSION_NO	"2.10"		/* DVI driver version number */

#define  DEVICE_ID "Hewlett-Packard DeskJet500 compression methods 0 - 3"
				/* this string is printed at runtime */

#define OUTFILE_EXT	"dj5"
#define COMPRESSED_EXT  "dj5.Z"

#define  DEFAULT_RESOLUTION 300		/* default dots/inch on HP Desk Jet */

/* =============================================== */
/* Look out: this will not run on TOPS20, I think! */
/* =============================================== */
                    /* ======= */
                    /* ======= */
                    /* ======= */
#define  BYTE_SIZE        8		/* output file byte size */
                    /* ======= */
                    /* ======= */
                    /* ======= */

#undef STDRES
#define STDRES  1			/* 0 for low-resolution devices */

#define  XDPI		300		/* HP Laser Jet horizontal dots/inch */
#define  XPSIZE		8		/* horizontal paper size in inches */

#define  XBYTES         300             /* Number of bytes to store a line. */

#define  XSIZE		(((XDPI*XPSIZE+2*HOST_WORD_SIZE-1)/\
				(2*HOST_WORD_SIZE))*(2*HOST_WORD_SIZE))
					/* number of horizontal dots; */
					/* MUST BE multiple of */
					/* 2*HOST_WORD_SIZE */
#define  XWORDS		((XSIZE + HOST_WORD_SIZE - 1)/HOST_WORD_SIZE)
					/* number of words in rows  */
					/* of bitmap array */

#define  YDPI		300		/* HP Laser Jet vertical dots/inch */

#define  YPSIZE		11		/* vertical paper size in inches */
#define  YSIZE		(YDPI*YPSIZE)	/* number of vertical dots */

/* The printer bit map (must have an even number of columns). */

#define XBIT ((1+2*XWORDS)/2)
#define YBIT YSIZE
#if    (IBM_PC_LATTICE | IBM_PC_MICROSOFT | IBM_PC_WIZARD)
#undef SEGMEM
#define SEGMEM 1 /* ( ((long)XBIT * (long)YBIT) > 65536L ) */
#endif

#include "bitmap.h"

#include "main.h"
#undef STDMAG
#undef RESOLUTION
#define STDMAG 1500
#define	RESOLUTION	(((float)STDMAG)/5.0)	/* dots per inch */
#include "abortrun.h"
#include "actfact.h"
#include "alldone.h"
#include "chargf.h"
#include "charpk.h"
#include "charpxl.h"
#include "clrbmap.h"
#include "clrrow.h"
#include "dbgopen.h"

/*-->devinit*/
/**********************************************************************/
/****************************** devinit *******************************/
/**********************************************************************/

void
devinit(argc,argv)		/* initialize device */
int argc;
char *argv[];
{
    (void)getbmap();
    OUTS("\033*rbC");	    /* End graphics */
    OUTS("\033E");	    /* printer reset */
    OUTS("\033&l0o0L");	    /* Portrait orient. and disable perf. skip */
    OUTS("\033*t300r300S"); /* printer resolution and raster width */
    OUTS("\033*p2N");	    /* prining direction */
    OUTS("\033*r0A");	    /* Start graphics, at leftmost position */
}

/*-->devterm*/
/**********************************************************************/
/****************************** devterm *******************************/
/**********************************************************************/

void
devterm()			/* terminate device */
{
    OUTS("\033E");	/* printer reset*/
}

#include "dvifile.h"
#include "dviinit.h"
#include "dviterm.h"
#include "dispchar.h"
#if 0
#include "f20open.h"
#endif
#include "fatal.h"
#include "fillrect.h"
#include "findpost.h"
#include "fixpos.h"
#include "fontfile.h"
#include "fontsub.h"
#include "getbmap.h"
#include "getbytes.h"
#include "getfntdf.h"
#include "getpgtab.h"
#include "initglob.h"
#include "inch.h"
#include "loadchar.h"
#include "movedown.h"
#include "moveover.h"
#include "moveto.h"
#include "nosignex.h"
#include "openfont.h"
#include "option.h"

/* ================================================== */
/* ================================================== */
/* ===== Compression routines for HP DeskJet500 ===== */
/* ================================================== */
/* ================================================== */

/* Run Length Encoding:
   control byte c, databyte d: (c + 1) times repetition of data byte d
*/
int encode_rl(source, sourcelen, dest, destlen)
char source[];
int sourcelen;
char dest[];
int destlen;
{
  int
    readp     = 0,
    runlength = 0,
    usedlen   = 0;

  while(readp < sourcelen) {
    while(readp + runlength + 1 < sourcelen &&
	  runlength < 255 &&
	  source[readp] == source[readp + runlength + 1])
      runlength++;

    if(usedlen > destlen - 3)
       return destlen + 1;

    dest[usedlen++] = runlength;
    dest[usedlen++] = source[readp];
    readp           += runlength + 1;
    runlength       = 0;
  }

  return usedlen;  
}

/* Tagged Image File Format */
int encode_tiff(source, sourcelen, dest, destlen)
char source[];
int sourcelen;
char dest[];
int destlen;
{
  int
    i,
    identical,
    readp     = 0,
    runlength = 0,
    usedlen   = 0;

  while(readp < sourcelen) {
    identical = 1;
    while(readp + runlength + 1 < sourcelen &&
	  runlength < 127 &&
	  source[readp] == source[readp + runlength + 1])
      runlength++;

    if(!runlength) {
      identical = 0;
      while(readp + runlength + 1 < sourcelen &&
	    runlength < 127 &&
	    (source[readp + runlength] != source[readp + runlength + 1] ||
	     (readp + runlength + 2 < sourcelen &&
	      source[readp + runlength] != source[readp + runlength + 2])))
	runlength++;
    }

    if(identical) {
      if(usedlen > destlen - 3)
	return destlen + 1;
      dest[usedlen++] = -runlength;
      dest[usedlen++] = source[readp];
    }
    else {
      if(usedlen > destlen - 2)
	return destlen + 1;
      dest[usedlen++] = runlength;
      for(i = 0; i <= runlength; i++)
	if(usedlen < destlen)
	  dest[usedlen++] = source[readp + i];
	else
	  return destlen + 1;
    }

    readp     += runlength + 1;
    runlength = 0;
  }

  return usedlen;  
}

/* Delta row Compression */
int encode_dr(prev_src, source, sourcelen, dest, destlen)
char prev_src[];
char source[];
int sourcelen;
char dest[];
int destlen;
{

  unsigned int
    start = 0,
    offs,
    length,
    outlen = 0,
    i,
    control;

  if(destlen <= 2)
    return 3;

  while(start < sourcelen) {
    for(offs = 0;
	start + offs < sourcelen && prev_src[start + offs] == source[start + offs];
	offs++);
  
    if(start + offs == sourcelen) {
      if(!start)
	return destlen + 1;
      return outlen;
    }

    /* length : replacement length - 1 */
    for(length = 0;
	length < 7 &&                             /* max replacment length = 8 */
	start + offs + length + 1 < sourcelen &&  /* end of data */
	prev_src[start + offs + length + 1] != source[start + offs + length + 1];
	length++);

    if(offs > 30)
      control = 31;
    else
      control = offs;
  
    control |= length << 5;
    
    if(outlen < destlen)
      dest[outlen++] = control;
    else
      return destlen + 1;
    
    if(offs > 30) {
      control = offs - 31;

      while(control >= 255) {
	if(outlen < destlen)
	  dest[outlen++] = 255;
	else
	  return destlen + 1;
	control -= 255;
      }

      if(outlen < destlen)
	dest[outlen++] = control;
      else
	return destlen + 1;
    }

    for(i = 0; i <= length; i++)
      if(outlen < destlen)
	dest[outlen++] = source[start + offs + i];
      else
	return destlen + 1;

    start += offs + length + 1;
  }
  
  return outlen;
}

/*-->outline*/
/**********************************************************************/
/***************** get_line_from_raster *******************************/
/**********************************************************************/

int
get_line_from_raster(pbit, line, length)
UNSIGN32 *pbit;	 /* pointer to raster line */
char line[];     /* put the byte-wise line here */
int *length;     /* length of returned data */

/*************************************************************************
Use machine-specific coding here for efficiency.  For TOPS-20, we encode
9 bytes from every pair  of 36-bit words.

For each raster line on the paper, the Laser Jet expects a binary  8-bit
byte stream of the form

    <ESC>*bnnnWxxxxxxx ... xxxxxxx
               <--- nnn bytes --->

where each byte contains, in order from high to low bit, a left-to-right
bit pattern.  No  end-of-line marker  is required.
*************************************************************************/

{
    register UNSIGN32 w_even,w_odd;
    register UNSIGN32 *p;
    char *pbuf;
    register INT16 i;

    p    = pbit;
    pbuf = line;

    for (i = 0; i < XBIT; i += 2) { /* loop over trimmed raster */
      w_even = (*p++);
      w_odd = (*p++);

#if    (HOST_WORD_SIZE == 36)
      *pbuf++ = (BYTE)( (w_even >> 28) & 0xff);
      *pbuf++ = (BYTE)( (w_even >> 20) & 0xff);
      *pbuf++ = (BYTE)( (w_even >> 12) & 0xff);
      *pbuf++ = (BYTE)( (w_even >>  4) & 0xff);
      *pbuf++ = (BYTE)( ((w_even <<  4) | (w_odd >> 32)) & 0xff);
      *pbuf++ = (BYTE)( (w_odd  >> 24) & 0xff);
      *pbuf++ = (BYTE)( (w_odd  >> 16) & 0xff);
      *pbuf++ = (BYTE)( (w_odd  >>  8) & 0xff);
      *pbuf++ = (BYTE)( (w_odd       ) & 0xff);
#else /* HOST_WORD_SIZE == 32 */
      /* encode 8 bytes at a time on 32-bit machines */
      *pbuf++ = (BYTE)( (w_even >> 24) & 0xff);
      *pbuf++ = (BYTE)( (w_even >> 16) & 0xff);
      *pbuf++ = (BYTE)( (w_even >>  8) & 0xff);
      *pbuf++ = (BYTE)( (w_even      ) & 0xff);
      *pbuf++ = (BYTE)( (w_odd  >> 24) & 0xff);
      *pbuf++ = (BYTE)( (w_odd  >> 16) & 0xff);
      *pbuf++ = (BYTE)( (w_odd  >>  8) & 0xff);
      *pbuf++ = (BYTE)( (w_odd       ) & 0xff);
#endif
    }
    
    for(pbuf-- ;pbuf > line && *pbuf == 0; pbuf--);
    
    if(pbuf == line && *pbuf == 0) {
      *length = 0;
      return 0;
    }
  
    *length = (pbuf - line) + 1;

    return 1;
}

/*-->prtbmap*/
/**********************************************************************/
/****************************** prtbmap *******************************/
/**********************************************************************/

char
  data1[XBYTES],
  data2[XBYTES],
  data3[XBYTES],
  data4[XBYTES],
  *data[4] = {data1, data2, data3, data4};

void
prtbmap()
{
  register UNSIGN32 *p;
  int ycnt = 0;

  char
    *lastline,
    *line,
    *bestline;
  
  int
    i, j, k,
    useline,
    usegetline,
    len,
    lastlen,
    st,
    thislen,
    bestlen,
    laststrategy,
    strategy;
  
  if (DBGOPT(DBG_PAGE_DUMP)) {
    INT16 k1,k2,k3;

    for (k3 = 0; k3 < XBIT; (k3 += 7, ++p)) {
      /*  print bitmap 7 words at a pass */
      k1 = k3;
      k2 = MIN(XBIT,k1+7);
      (void)printf("prtbmap()...bitmap words %d..%d",k1,k2-1);
      NEWLINE(stdout);
      (void)printf("     ");
      for (k = k1; k < k2; ++k)
	(void)printf("%10d",k*HOST_WORD_SIZE);
      NEWLINE(stdout);
      for (j = YBIT-1; j >= 0; --j) {
	p = BITMAP(j,0);
	for (k = 0; k < XBIT; (++k,++p)) {
	  if (*p) {	/* print non-blank raster line */
	    p = BITMAP(j,k1);
	    (void)printf("%5d:",j);
	    for (k = k1; k < k2; (++k,++p))
	      (void)printf(" %09lx",*p);
	    NEWLINE(stdout);
	    break;	/* exit loop over k */
	  }
	}
      }
    }
  }

  (void)clearerr(plotfp);

  OUTS("\033*r0A");	/* Start graphics, at leftmost position */
  
  usegetline   = 0;
  lastline     = 0;
  laststrategy = -1;
  ycnt         = 0;
  
  for (j = YBIT - 1; j >= 0 ; --j) {	/* loop over raster lines */
    line       = data[usegetline];
    usegetline = usegetline == 0 ? 1 : 0;
    
    if(!get_line_from_raster(BITMAP(j,0), line, &len))
      ycnt ++;
    else {	
      thislen  = len;
      bestlen  = len;
      bestline = line;
      strategy = 0;
      useline  = 2;
      
      for(st = 3; st > 0; st--) {
	if(st == 1)
	  thislen = encode_rl(line, len, data[useline], bestlen);
	else if(st == 2)
	  thislen = encode_tiff(line, len, data[useline], bestlen);
	else if(st == 3 && lastline) {
	  if(len < lastlen)
	    thislen = encode_dr(lastline, line, lastlen, data[useline],
				ycnt > 0 ? bestlen - 4 : bestlen);
	  else
	    thislen = encode_dr(lastline, line, len, data[useline],
				ycnt > 0 ? bestlen - 4 : bestlen);
	}
	
	if(thislen < bestlen) {
	  strategy = st;
	  bestlen  = thislen;
	  bestline = data[useline];
	  useline  = useline == 3 ? 2 : 3;
	}
      }
      
      if(ycnt > 0) {
	if(strategy == 3) {
	  if(ycnt > 1)
	    OUTF("\033*b%dy0m0w", ycnt - 1);
	  else
	    OUTS("\033*b0m0w");
	}
	else
	  OUTF("\033*b%dy", ycnt);
	
	laststrategy = 0;
	ycnt         = 0;
      }
      else
	OUTS("\033*b");
      
      if(strategy == laststrategy)
	OUTF("%dW", bestlen);
      else {
	OUTF2("%dm%dW", strategy, bestlen);
	laststrategy = strategy;
      }
      
      for(i = 0; i < bestlen; i++)
	OUTC(bestline[i]);
    }
    
    lastlen  = len;
    lastline = line;
  }
  
  OUTS("\033*rB\f"); /* end raster graphics, eject page */
  
  (void)fflush(plotfp);
  
  if (DISKFULL(plotfp))
    (void)fatal("Output error -- disk full.");
}


#include "outrow.h"
#include "prtpage.h"
#include "readfont.h"
#include "readgf.h"
#include "readpk.h"
#include "readpost.h"
#include "readpxl.h"
#include "reldfont.h"
#include "rulepxl.h"
#include "setchar.h"
#include "setfntnm.h"
#include "setrule.h"
#include "signex.h"
#include "skgfspec.h"
#include "skipfont.h"
#include "skpkspec.h"
#include "special.h"
#include "strchr.h"
#include "strcm2.h"
#include "strid2.h"
#include "strrchr.h"
#include "tctos.h"
#include "usage.h"
#include "warning.h"
