Untype1.c program -- a pipeline, more portable version
Kevin O'Gorman
kevin at kosman.UUCP
Tue Dec 4 10:59:16 AEST 1990
A little while ago, Chris Sears (sears at dungeon.enet.dec.com) posted a
set of programs to decode eexec-ed type 1 font programs. I had some
trouble with that version, especially on MSDOS, so I combined some stuff
and made this version, which compiles on MSC 5.1 and 6.00A, as well as
under gcc on my SYSV UNIX. It should be reasonably portable, since
the machines differ in word-size and endianness. There are some SYSV-isms,
but just in the names of include files, I think. Also, see NEED_STRSTR.
This routine also can be used in a pipeline. Specify - for the standard
input. Output is always on stdout.
I HAVE been having some trouble with it though -- the resulting
PostScript seems always to get a VMERROR on my LaserWriter Plus, on any
real font. Ideas? The result is informative anyway.
I tried sending this to Chris first, but email to the indicated address
does not work. Chris, thanks for the original.
This is a single source file, not in shar format. Beware the trailing
signature.
/*
* untype1.c -- decrypt an Adobe font file encrypted for eexec
*
* original by Chris B. Sears (sears at dungeon.enet.dec.com)
*
* Modified for portability by Kevin O'Gorman (kosman!kevin), because MSDOS
* had trouble with intermediate files that were mixed binary and text, and
* because it's really all one task. (3 Dec 1990)
*
* The original was distributed without a copyright notice, and no comment
* about the status. I take that to place it in the public domain. I
* (Kevin O'Gorman) specifically place my modifications in the public domain
* -- I assert no rights, and accept no responsibility.
*
* As a courtesy, I request that notices of authorship be kept honest and
* complete (and don't forget your own).
*
* usage:
* untype1 [-s] inputfile
*
* The optional -s switch causes the output to be truncated at the first line
* containing the token "definefont". This is useful in conjunction with the
* shell scripts distributed by Chris Sears.
*
* The font-related code assumes that the font is eexec encoded (they almost
* always are); the copying loop for stuff outside of eexec does not check
* for font-related things. Further, the RD and -| tokens are hardwired in.
*
* Inputfile may be specified as "-".
*
* The decoded result is placed on the standard output.
*
* Current status: the results get VMerrors on my LaserWriter Plus, even if
* I setpacking to true. The results are nevertheless very informative.
*
* Things to do:
* 1: directly turn a type1 into a type3 font.
* 2: draw the font characters large, with the hints and control points
* made visible.
* 3: decode printer internal fonts (type 5).
* 4: strip ^D (from some postscript files) and ^Z (from MSDOS) characters.
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define SEEK_SET 0
#define TRUE 1
#define FALSE 0
#define EEXEC_SKIP_BYTES 4
#define MAX_ESCAPE 33
int lenIV = 4; /* CharString salt length */
typedef struct {
char *command;
int value;
} Command;
#define BUFFERSIZE 4096
static int skip_salt = EEXEC_SKIP_BYTES + 1;
static FILE *in;
static char in_buff[BUFFERSIZE], out_buff[BUFFERSIZE];
static int in_size, in_ptr;
static int o, obase;
static unsigned short int
cr, cc1, cc2, er, ec1, ec2;
#define ER 55665
#define EC1 52845
#define EC2 22719
#define CR 4330
#define CC1 52845
#define CC2 22719
static int count, csalt;
Command commands[] = {
{ "notdefined_c0", 0 },
{ "hstem", 1 },
{ "notdefined_c2", 2 },
{ "vstem", 3 },
{ "vmoveto", 4 },
{ "chars_rlineto", 5 },
{ "hlineto", 6 },
{ "vlineto", 7 },
{ "rrcurveto", 8 },
{ "chars_closepath",9 },
{ "callsubr", 10 },
{ "return", 11 },
{ "escape", 12 },
{ "hsbw", 13 },
{ "endchar", 14 },
{ "notdefined_c15", 15 },
{ "notdefined_c16", 16 },
{ "notdefined_c17", 17 },
{ "notdefined_c18", 18 },
{ "notdefined_c19", 19 },
{ "notdefined_c20", 20 },
{ "chars_rmoveto", 21 },
{ "hmoveto", 22 },
{ "notdefined_c23", 23 },
{ "notdefined_c24", 24 },
{ "notdefined_c25", 25 },
{ "notdefined_c26", 26 },
{ "notdefined_c27", 27 },
{ "notdefined_c28", 28 },
{ "notdefined_c29", 29 },
{ "vhcurveto", 30 },
{ "hvcurveto", 31 }
};
Command escapes[] = {
{ "dotsection", 0 },
{ "vstem3", 1 },
{ "hstem3", 2 },
{ "notdefined_e3", 3 },
{ "notdefined_e4", 4 },
{ "notdefined_e5", 5 },
{ "seac", 6 },
{ "sbw", 7 },
{ "notdefined_e8", 8 },
{ "notdefined_e9", 9 },
{ "notdefined_e10", 10 },
{ "notdefined_e11", 11 },
{ "chars_div", 12 },
{ "notdefined_e13", 13 },
{ "notdefined_e14", 14 },
{ "notdefined_e15", 15 },
{ "callothersubr", 16 },
{ "chars_pop", 17 },
{ "notdefined_e18", 18 },
{ "notdefined_e19", 19 },
{ "notdefined_e20", 20 },
{ "notdefined_e21", 21 },
{ "notdefined_e22", 22 },
{ "notdefined_e23", 23 },
{ "notdefined_e24", 24 },
{ "notdefined_e25", 25 },
{ "notdefined_e26", 26 },
{ "notdefined_e27", 27 },
{ "notdefined_e28", 28 },
{ "notdefined_e29", 29 },
{ "notdefined_e30", 30 },
{ "notdefined_e31", 31 },
{ "notdefined_e32", 32 },
{ "setcurrentpoint",33 }
};
unsigned char GetPlain()
{
if (in_ptr >= in_size) {
if(fgets(in_buff, BUFSIZ, in) == NULL) {
fprintf(stderr,"Errror -- end of file.\n");
exit(1);
}
in_size = strlen(in_buff) - 1;
in_ptr = 0;
}
return in_buff[in_ptr++];
}
unsigned int GetHexChar()
{
unsigned int byte;
/* skip whitespace */
do {
byte = GetPlain();
} while ((byte == '\n') || (byte == ' ') || (byte == '\t')
|| (byte == '\r') || (byte == '\f'));
/* figure the digit */
if ( (byte >= '0') && (byte <= '9') ) return (byte - '0');
if ( (byte >= 'A') && (byte <= 'F') ) return (byte - 'A' + 10);
if ( (byte >= 'a') && (byte <= 'f') ) return (byte - 'a' + 10);
/* anything else is an error */
fprintf(stderr, "Illegal hex digit.\n");
exit (1);
}
unsigned char
EDeCrypt()
{
unsigned char ch1, ch2, plain, cipher;
/*
* Decode cipher.
*/
do {
ch1 = GetHexChar();
ch2 = GetHexChar();
cipher = (ch1 << 4) + ch2;
plain = (cipher ^ (er >> 8));
er = (cipher + er) * ec1 + ec2;
if (skip_salt) skip_salt--;
} while (skip_salt);
return plain;
}
unsigned char
CDeCrypt()
{
unsigned char plain, cypher;
if (count <= 0) {
fprintf(stderr,"Reading too many bytes of charstring data.\n");
exit(1);
}
do {
cypher = EDeCrypt();
count--;
plain = (cypher ^ (cr >> 8));
cr = (cypher + cr) * cc1 + cc2;
if (csalt) csalt--;
} while (csalt);
return plain;
}
#ifdef NEED_STRSTR
char *
strstr(char *string, char *target)
{
int slen, tlen, i;
tlen = strlen(target);
slen = strlen(string);
for (i=0; i+tlen <= slen; i++) {
if (!strncmp(target, &string[i],tlen)) return (&string[i]);
}
return NULL;
}
#endif
void
out_check()
{
out_buff[o] = '\0'; /* terminate the string */
/* mostly serves to help use CodeView */
if (o-obase > 78) {
int ptr;
unsigned char c;
for (ptr=obase+78; ptr>obase; ptr--) {
c = out_buff[ptr];
if(c==' ' || c=='\t') break;
}
if (ptr-obase < 10) return;
for (; ptr>obase; ptr--) {
c = out_buff[ptr];
if (isalpha(c)) break;
}
if (ptr-obase < 10) return;
for (;; ptr++) {
c = out_buff[ptr];
if(c==' ' || c=='\t') break;
}
out_buff[ptr] = '\0';
fputs(out_buff, stdout);
strcpy(out_buff,"\n\t");
strcat(out_buff,&out_buff[ptr+1]);
o = strlen(out_buff);
obase = -6;
}
}
void
main(argc, argv)
int argc;
char **argv;
{
unsigned char plainchar;
char *count_pos;
int i;
int line_pos;
long value;
#define DATA_STATE 0
#define CHAR_STATE 1
#define CINZ_STATE 2
int state = DATA_STATE;
unsigned char byte;
if ((argc != 2 && argc != 3)
|| (argc == 3 && strcmp(argv[1],"-s"))) {
fprintf(stderr, "Usage: %s [-s] input\n", argv[0]);
exit(0);
}
if (strcmp(argv[argc-1], "-")) {
if ((in = fopen(argv[argc-1], "r")) == NULL) {
fprintf(stderr,
"%s: can't open %s\n", argv[0], argv[argc-1]);
exit(0);
}
} else {in = stdin;}
/*
* Just copy to output until we see an eexec.
*/
COPYFILE:
while (1) {
if (fgets(in_buff, BUFSIZ, in) == NULL) goto fin;
if (strcmp(in_buff, "currentfile eexec\n") == 0)
break;
fprintf(stdout, "%s", in_buff);
}
skip_salt = EEXEC_SKIP_BYTES + 1;
er = ER;
ec1 = EC1;
ec2 = EC2;
for (in_ptr = 999, in_size = 0, o=0, obase=0;;) {
switch(state) {
case CINZ_STATE:
cr = CR;
cc1 = CC1;
cc2 = CC2;
csalt = lenIV + 1;
for (count_pos = &out_buff[o-5];
(count_pos >= out_buff) && (*count_pos != ' ');
count_pos--)
;
/* This can be at the beginning of a line */
if (*count_pos == ' ')
count_pos++;
count = atoi(count_pos);
/*
* Change "count RD" to "{"
*/
o = count_pos - out_buff;
out_buff[o++] = '{';
out_buff[o] = '\0';
state = CHAR_STATE;
case CHAR_STATE:
for ( ; count > 0; i += 2) {
/*
* Translate the buffer.
*/
byte = CDeCrypt();
if (byte == 11) { /* return */
o += sprintf(&out_buff[o], " %s",
commands[byte].command);
out_check();
break;
} else if (byte == 12) { /* escape */
byte = CDeCrypt();
if (byte > MAX_ESCAPE) {
o += sprintf(&out_buff[o],
" not_defined_e%d", byte);
out_check();
} else {
o += sprintf(&out_buff[o], " %s",
escapes[byte].command);
out_check();
}
continue;
} else if (byte < 32) {
o += sprintf(&out_buff[o], " %s",
commands[byte].command);
out_check();
}
if (byte >= 32) {
if (byte <= 246) {
o += sprintf(&out_buff[o], " %d",
byte - 139);
out_check();
} else if ((byte >= 247) && (byte <= 250)) {
o += sprintf(&out_buff[o], " %d",
(byte - 247) * 256
+ CDeCrypt() + 108);
out_check();
}
else if ((byte >= 251) && (byte <= 254)) {
o += sprintf(&out_buff[o], " %d",
-((int)byte - 251) * 256
- (int)CDeCrypt() - 108);
out_check();
}
else if (byte == 255) {
value = CDeCrypt();
value <<= 8;
value += CDeCrypt();
value <<= 8;
value += CDeCrypt();
value <<= 8;
value += CDeCrypt();
o +=sprintf(&out_buff[o],
/* NOTE: long value */ " %ld", value);
out_check();
}
}
}
o += sprintf(&out_buff[o], " }");
out_check();
state = DATA_STATE;
case DATA_STATE:
/*
* Decrypt a line of hex.
*/
plainchar = EDeCrypt();
out_buff[o++] = plainchar;
out_check();
if ((o >=4) && !strncmp(" RD ", &out_buff[o-4], 4)) {
state = CINZ_STATE;
break;
}
if ((o >=4) && !strncmp(" -| ", &out_buff[o-4], 4)) {
state = CINZ_STATE;
break;
}
if (plainchar == '\n') {
if (argc==3 && strstr(out_buff,"definefont")) goto fin;
if (strncmp("/lenIV", out_buff, 6) == 0)
lenIV = atoi(out_buff + 7);
if ((count_pos =
strstr(out_buff,"currentfile closefile"))
!= NULL){
strcpy(count_pos, "\n");
fputs(out_buff, stdout);
goto COPYFILE;
}
fputs(out_buff, stdout);
o = 0;
obase = 0;
}
} /* switch */
} /* for (reading file) */
fin: fclose(in);
exit(0);
}
--
Kevin O'Gorman ( kevin at kosman.UUCP, kevin%kosman.uucp at nrc.com )
voice: 805-984-8042 Vital Computer Systems, 5115 Beachcomber, Oxnard, CA 93035
Non-Disclaimer: my boss is me, and he stands behind everything I say.
More information about the Alt.sources
mailing list