/*
 * Type1 format
 */
#include	"defs.h"
#include	"global.h"
#include	"emit.h"
#include	"ps.h"
#include	"cscommands.h"
#define	MAX_CHAR_CODE	255

char *std_char_names[] = {
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
"space", "exclam", "quotedbl", "numbersign",
  "dollar", "percent", "ampersand", "quoteright",
"parenleft", "parenright", "asterisk", "plus",
  "comma", "hyphen", "period", "slash",
"zero", "one", "two", "three", "four", "five", "six", "seven",
"eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question",
"at", "A", "B", "C", "D", "E", "F", "G",
"H", "I", "J", "K", "L", "M", "N", "O",
"P", "Q", "R", "S", "T", "U", "V", "W",
"X", "Y", "Z", "bracketleft",
  "backslash", "bracketright", "asciicircum", "underscore",
"quoteleft", "a", "b", "c", "d", "e", "f", "g",
"h", "i", "j", "k", "l", "m", "n", "o",
"p", "q", "r", "s", "t", "u", "v", "w",
"x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, "exclamdown", "cent", "sterling", "fraction", "yen", "florin", "section",
"currency", "quotesingle", "quotedblleft", "guillemotleft",
  "guilsinglleft", "guilsinglright", "fi", "fl",
NULL, "endash", "dagger", "daggerdbl",
  "periodcentered", NULL, "paragraph", "bullet",
"quotesinglbase", "quotedblbase", "quotedblright", "guillemotright",
  "ellipsis", "perthousand", NULL, "questiondown",
NULL, "grave", "acute", "circumflex", "tilde", "macron", "breve", "dotaccent",
"dieresis", NULL, "ring", "cedilla", NULL, "hungarumlaut", "ogonek", "caron",
"emdash", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, "AE", NULL, "ordfeminine", NULL, NULL, NULL, NULL,
"Lslash", "Oslash", "OE", "ordmasculine", NULL, NULL, NULL, NULL,
NULL, "ae", NULL, NULL, NULL, "dotlessi", NULL, NULL,
"lslash", "oslash", "oe", "germandbls", NULL, NULL, NULL, NULL,
};

char *extra_char_names[] = {
"c00", "c01", "c02", "c03", "c04", "c05", "c06", "c07",
"c08", "c09", "c0A", "c0B", "c0C", "c0D", "c0E", "c0F",
"c10", "c11", "c12", "c13", "c14", "c15", "c16", "c17",
"c18", "c19", "c1A", "c1B", "c1C", "c1D", "c1E", "c1F",
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, "c7F",
"c80", "c81", "c82", "c83", "c84", "c85", "c86", "c87",
"c88", "c89", "c8A", "c8B", "c8C", "c8D", "c8E", "c8F",
"c90", "c91", "c92", "c93", "c94", "c95", "c96", "c97",
"c98", "c99", "c9A", "c9B", "c9C", "c9D", "c9E", "c9F",
"cA0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
"cB0", NULL, NULL, NULL, NULL, "cB5", NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, "cBE", NULL,
"cC0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, "cC9", NULL, NULL, "cCC", NULL, NULL, NULL,
NULL, "cD1", "cD2", "cD3", "cD4", "cD5", "cD6", "cD7",
"cD8", "cD9", "cDA", "cDB", "cDC", "cDD", "cDE", "cDF",
"cE0", NULL, "cE2", NULL, "cE4", "cE5", "cE6", "cE7",
NULL, NULL, NULL, NULL, "cEC", "cED", "cEE", "cEF",
"cF0", NULL, "cF2", "cF3", "cF4", NULL, "cF6", "cF7",
NULL, NULL, NULL, NULL, "cFC", "cFD", "cFE", "cFF",
};

char *
stdex_type1_charname(c)
int c;
{
    if (std_char_names[c] != NULL)
	return std_char_names[c];
    return extra_char_names[c];
}

stdex_type1_reencoding(mark, maxc, remap)
Boolean *mark;
int maxc;
unsigned char *remap;
{
    int i;

    EMIT(outfp, "/Encoding %d array\n", maxc+1);
    for (i = 0; i <= maxc; i++)
	if (mark[i])
	    EMIT(outfp, "dup %d /%s put\n", i, stdex_type1_charname(remap[i]));
    EMIT(outfp, "readonly def\n");
}

stdex_type1_encoding(mark, maxc, remap)
Boolean *mark;
int maxc;
unsigned char *remap;
{
    int i;

    for (i = 0; i <= maxc; i++)
	if (mark[i] && std_char_names[remap[i]] == NULL) {
	    stdex_type1_reencoding(mark, maxc, remap);
	    return;
	}
    EMIT(outfp, "/Encoding StandardEncoding def\n");
}

char *
cnum_type1_charname(c)
int c;
{
    static char cname[4];

    sprintf(cname, "c%02X", c);
    return cname;
}

cnum_type1_encoding(nc)
int nc;
{
    int n, i, j;

    n = nc > NPACKPSCHARS-FIRSTPACKPSCHAR ? NPACKPSCHARS : FIRSTPACKPSCHAR+nc;
    EMIT(outfp, "/Encoding %d array\n", n);
    for (i = FIRSTPACKPSCHAR, j = 0; i < n; i++, j++) {
	EMIT(outfp, "dup %d /c%02X put", i, i);
	if (j%4 == 3)
	    EMITC('\n');
	else
	    EMITC(' ');
    }
    for (i = 0; i < nc-(NPACKPSCHARS-FIRSTPACKPSCHAR); i++, j++) {
	EMIT(outfp, "dup %d /c%02X put", i, i);
	if (j%4 == 3)
	    EMITC('\n');
	else
	    EMITC(' ');
    }
    if ((j-1)%4 != 3)
	    EMITC('\n');
    EMIT(outfp, "readonly def\n");
}

reencode(glyphs, mark, maxc, remap)
char *glyphs[];
Boolean mark[];
int maxc;
unsigned char remap[];
{
    int i, j;

    for (i = 0; i <= maxc; i++)
	if (mark[i]) {
	    remap[i] = i;
	    for (j = 0; j <= MAX_CHAR_CODE; j++)
		if (strcmp(glyphs[i], stdex_type1_charname(j)) == 0) {
		    remap[i] = j;
		    break;
		}
	}
}


static int ecol;
#define	ELEN	64

begin_eexec()
{
    init_encrypt();
    ecol = 0;
    e_putchar(0);
    e_putchar(0);
    e_putchar(0);
    e_putchar(0);
}

end_eexec()
{
    int i, j;

    EMITC('\n');
    for (i = 0; i < 512/ELEN; i++) {
	for (j = 0; j < ELEN; j++)
	    EMITC('0');
	EMITC('\n');
    }
}


/*
 * The following functions
 *	charstring_start, charstring_byte, charstring_end, charstring_int
 * are taken from `t1asm' which has the copyright notice below.
 */

/* t1asm
**
** This program `assembles' Adobe Type-1 font programs in pseudo-PostScript
** form into either PFB or PFA format.  The human readable/editable input is
** charstring- and eexec-encrypted as specified in the `Adobe Type 1 Font
** Format' version 1.1 (the `black book').  There is a companion program,
** t1disasm, which `disassembles' PFB and PFA files into a pseudo-PostScript
** file.
**
** Copyright (c) 1992 by I. Lee Hetherington, all rights reserved.
**
** Permission is hereby granted to use, modify, and distribute this program
** for any purpose provided this copyright notice and the one below remain
** intact. 
**
** author: I. Lee Hetherington (ilh@lcs.mit.edu)
*/

/* lenIV and charstring start command */
static int lenIV = 4;
static char cs_start[10] = "-|";

/* for charstring buffering */
static byte charstring_buf[65535];
static byte *charstring_bp;

/* This function initializes charstring encryption.  Note that this is called
   at the beginning of every charstring. */

void charstring_start()
{
  int i;

  charstring_bp = charstring_buf;
  init_cencrypt();
  for (i = 0; i < lenIV; i++)
    *charstring_bp++ = cencrypt_char((byte) 0);
}

/* This function encrypts and buffers a single byte of charstring data. */

static void charstring_byte(v)
  int v;
{
  byte b = ((unsigned int)v) & 0xff;

  if (charstring_bp - charstring_buf > sizeof(charstring_buf)) {
    fprintf(stderr, "error: charstring_buf full (%d bytes)\n",
	    sizeof(charstring_buf));
    exit(1);
  }
  *charstring_bp++ = cencrypt_char(b);
}

/* This function outputs buffered, encrypted charstring data through possible
   eexec encryption. */

void charstring_end()
{
  byte *bp;
  char line[256];

  sprintf(line, "%d %s ", charstring_bp - charstring_buf, cs_start);
  e_printf(line);
  for (bp = charstring_buf; bp < charstring_bp; bp++)
    e_putchar(*bp);
}

/* This function generates the charstring representation of an integer. */

void charstring_int(int num)
{
  int x;

  if (num >= -107 && num <= 107) {
    charstring_byte(num + 139);
  } else if (num >= 108 && num <= 1131) {
    x = num - 108;
    charstring_byte(x / 256 + 247);
    charstring_byte(x % 256);
  } else if (num >= -1131 && num <= -108) {
    x = abs(num) - 108;
    charstring_byte(x / 256 + 251);
    charstring_byte(x % 256);
  } else if (num >= (-2147483647-1) && num <= 2147483647) {
    charstring_byte(255);
    charstring_byte(num >> 24);
    charstring_byte(num >> 16);
    charstring_byte(num >> 8);
    charstring_byte(num);
  } else {
    fprintf(stderr,
	    "error: cannot format the integer %d, too large\n", num);
    exit(1);
  }
}

struct cs {
  int one, two;
} cscom_table[] = {
  /* callothersubr */	{12, 16},
  /* callsubr */	{10, -1},
  /* closepath */	{9, -1},
  /* div */	{12, 12},
  /* dotsection */	{12, 0},
  /* endchar */	{14, -1},
  /* escape */	{12, -1},
  /* hlineto */	{6, -1},
  /* hmoveto */	{22, -1},
  /* hsbw */	{13, -1},
  /* hstem */	{1, -1},
  /* hstem3 */	{12, 2},
  /* hvcurveto */	{31, -1},
  /* pop */	{12, 17},
  /* return */	{11, -1},
  /* rlineto */	{5, -1},
  /* rmoveto */	{21, -1},
  /* rrcurveto */	{8, -1},
  /* sbw */	{12, 7},
  /* seac */	{12, 6},
  /* setcurrentpoint */	{12, 33},
  /* vhcurveto */	{30, -1},
  /* vlineto */	{7, -1},
  /* vmoveto */	{4, -1},
  /* vstem */	{3, -1},
  /* vstem3 */	{12, 1},
};

charstring_com(com)
cscommand com;
{
    charstring_byte(cscom_table[com].one);
    if (cscom_table[com].two >= 0)
	charstring_byte(cscom_table[com].two);
}


/* VARARGS1 */
e_printf(form, i0, i1, i2, i3, i4, i5, i6, i7, i8, i9)
char *form;
{
    int len, i;
    char buf[4096];

    (void)sprintf(buf, form, i0, i1, i2, i3, i4, i5, i6, i7, i8, i9);
    len = strlen(buf);
    for (i = 0; i < len; i++)
	e_putchar((unsigned)buf[i]);
}

e_putchar(plain)
unsigned char plain;
{
    EMIT(outfp, "%02X", encrypt_char(plain));
    ecol += 2;
    if (ecol == ELEN) {
	EMITC('\n');
	ecol = 0;
    }
}

#define	EKEY	55665	/* initial key for eexec encryption */
#define	CEKEY	4330	/* initial key for charstring encryption */
static unsigned short int r, cr;
static unsigned short int c1 = 52845, c2 = 22719;

init_encrypt()
{
    r = EKEY;
}

init_cencrypt()
{
    cr = CEKEY;
}

encrypt_char(plain)
unsigned char plain;
{
    unsigned char cipher;

    cipher = (plain ^ (r>>8));
    r = (cipher+r)*c1+c2;
    return cipher;
}

cencrypt_char(plain)
unsigned char plain;
{
    unsigned char cipher;

    cipher = (plain ^ (cr>>8));
    cr = (cipher+cr)*c1+c2;
    return cipher;
}
