/* $XConsortium: scanfont.c,v 1.10 94/02/06 16:23:17 gildea Exp $ */
/* Copyright International Business Machines,Corp. 1991
 * All Rights Reserved
 *
 * License to use, copy, modify, and distribute this software
 * and its documentation for any purpose and without fee is
 * hereby granted, provided that the above copyright notice
 * appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation,
 * and that the name of IBM not be used in advertising or
 * publicity pertaining to distribution of the software without
 * specific, written prior permission.
 *
 * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
 * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
 * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
 * THIRD PARTY RIGHTS.  THE ENTIRE RISK AS TO THE QUALITY AND
 * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
 * OR MAINTAIN, BELONGS TO THE LICENSEE.  SHOULD ANY PORTION OF
 * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
 * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION.  IN
 * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */
/* Author: Katherine A. Hitchcock    IBM Almaden Research Laboratory */

#ifndef T1GST
#include "global.h"
#endif

#include "encodings.h"		// TetiSoft: Added several encodings
#include "glyphlist.h"		// TetiSoft: Adobe Glyph List (AGL)

//static int rc;		// TetiSoft: Now in T1GlyphEngine
//static boolean InPrivateDict;	// TetiSoft: Now auto
//static boolean WantFontInfo;	// TetiSoft: Now auto
//static boolean TwoSubrs;	// TetiSoft: Now auto & param
//static psobj inputFile;	// TetiSoft: Now auto
//static psobj filterFile;	// TetiSoft: Now auto
//static psobj *inputP;		// TetiSoft: Now param

static psobj *MakeEncodingArrayP(struct T1GlyphEngine *engine, const EncodingNumTable *encodingTableLow, const EncodingTable *encodingTableHigh);
static psobj *MakeEncodingNumArrayP(struct T1GlyphEngine *engine, const EncodingNumTable *encodingTableLow, const EncodingNumTable *encodingTableHigh);
static int getNextValue(struct T1GlyphEngine *engine, psobj *inputP, int valueType);
static int getInt(struct T1GlyphEngine *engine, psobj *inputP);
static int getEncoding(struct T1GlyphEngine *engine, psobj *inputP, psobj *arrayP);
static int getArray(struct T1GlyphEngine *engine, psobj *inputP, psobj *arrayP);
static int getName(struct T1GlyphEngine *engine, psobj *inputP, char *nameP);
static int getNbytes(struct T1GlyphEngine *engine, psobj *inputP, int N);
static int getLiteralName(struct T1GlyphEngine *engine, psobj *inputP, psobj *nameObjP);
static int BuildSubrs(struct T1GlyphEngine *engine, psobj *inputP, boolean *TwoSubrs, psfont *fontP);
static int BuildCharStrings(struct T1GlyphEngine *engine, psobj *inputP, boolean *TwoSubrs, psfont *fontP);
static int BuildFontInfo(struct T1GlyphEngine *engine, psfont *fontP);
static int BuildPrivate(struct T1GlyphEngine *engine, psfont *fontP);
static int GetType1Blues(struct T1GlyphEngine *engine, psfont *fontP);
static int FindDictValue(struct T1GlyphEngine *engine, psobj *inputP, psdict *dictP);


/**********************************************************************/
/*   Init_BuiltInEncoding()                                           */
/*                                                                    */
/*     Initializes the StandardEncoding and ISOLatin1Encoding vector. */
/*                                                                    */
/**********************************************************************/

// TetiSoft: Added several encodings, this func sets them. returns 0 on failure
int setencoding(struct T1GlyphEngine *engine, ULONG SymbolSet)
{
	int rc = 1;

	engine->fontencoding = engine->PSISOLatin1EncArrayP;

	switch (SymbolSet)
	{
		case PSISOLATIN1ENCODING:
			break;
		case STANDARDENCODING:
			engine->fontencoding = engine->StdEncArrayP;
			break;
		case CEENCODING:
			if (!engine->CEEncArrayP)
				engine->CEEncArrayP = MakeEncodingNumArrayP(engine, UniCodeLowEnc, CEEnc);
			if (engine->CEEncArrayP)
				engine->fontencoding = engine->CEEncArrayP;
			else
				rc = 0;
			break;
		case UNICODE:
		case ISOLATIN1ENCODING:
			if (!engine->ISO1Latin1EncArrayP)
				engine->ISO1Latin1EncArrayP = MakeEncodingNumArrayP(engine, UniCodeLowEnc, ISO8859_1Enc);
			if (engine->ISO1Latin1EncArrayP)
				engine->fontencoding = engine->ISO1Latin1EncArrayP;
			else
				rc = 0;
			break;
		case ISOLATIN2ENCODING:
			if (!engine->ISO2Latin2EncArrayP)
				engine->ISO2Latin2EncArrayP = MakeEncodingNumArrayP(engine, UniCodeLowEnc, ISO8859_2Enc);
			if (engine->ISO2Latin2EncArrayP)
				engine->fontencoding = engine->ISO2Latin2EncArrayP;
			else
				rc = 0;
			break;
		case ISOLATIN3ENCODING:
			if (!engine->ISO3Latin3EncArrayP)
				engine->ISO3Latin3EncArrayP = MakeEncodingNumArrayP(engine, UniCodeLowEnc, ISO8859_3Enc);
			if (engine->ISO3Latin3EncArrayP)
				engine->fontencoding = engine->ISO3Latin3EncArrayP;
			else
				rc = 0;
			break;
		case ISOLATIN4ENCODING:
			if (!engine->ISO4Latin4EncArrayP)
				engine->ISO4Latin4EncArrayP = MakeEncodingNumArrayP(engine, UniCodeLowEnc, ISO8859_4Enc);
			if (engine->ISO4Latin4EncArrayP)
				engine->fontencoding = engine->ISO4Latin4EncArrayP;
			else
				rc = 0;
			break;
		case ISOCYRILLICENCODING:
			if (!engine->ISO5CyrillicEncArrayP)
				engine->ISO5CyrillicEncArrayP = MakeEncodingNumArrayP(engine, UniCodeLowEnc, ISO8859_5Enc);
			if (engine->ISO5CyrillicEncArrayP)
				engine->fontencoding = engine->ISO5CyrillicEncArrayP;
			else
				rc = 0;
			break;
		case ISOARABICENCODING:
			if (!engine->ISO6ArabicEncArrayP)
				engine->ISO6ArabicEncArrayP = MakeEncodingNumArrayP(engine, UniCodeLowEnc, ISO8859_6Enc);
			if (engine->ISO6ArabicEncArrayP)
				engine->fontencoding = engine->ISO6ArabicEncArrayP;
			else
				rc = 0;
			break;
		case ISOGREEKENCODING:
			if (!engine->ISO7GreekEncArrayP)
				engine->ISO7GreekEncArrayP = MakeEncodingNumArrayP(engine, UniCodeLowEnc, ISO8859_7Enc);
			if (engine->ISO7GreekEncArrayP)
				engine->fontencoding = engine->ISO7GreekEncArrayP;
			else
				rc = 0;
			break;
		case ISOHEBREWENCODING:
			if (!engine->ISO8HebrewEncArrayP)
				engine->ISO8HebrewEncArrayP = MakeEncodingNumArrayP(engine, UniCodeLowEnc, ISO8859_8Enc);
			if (engine->ISO8HebrewEncArrayP)
				engine->fontencoding = engine->ISO8HebrewEncArrayP;
			else
				rc = 0;
			break;
		case ISOLATIN5ENCODING:
			if (!engine->ISO9Latin5EncArrayP)
				engine->ISO9Latin5EncArrayP = MakeEncodingNumArrayP(engine, UniCodeLowEnc, ISO8859_9Enc);
			if (engine->ISO9Latin5EncArrayP)
				engine->fontencoding = engine->ISO9Latin5EncArrayP;
			else
				rc = 0;
			break;
		case ISOLATIN6ENCODING:
			if (!engine->ISO10Latin6EncArrayP)
				engine->ISO10Latin6EncArrayP = MakeEncodingNumArrayP(engine, UniCodeLowEnc, ISO8859_10Enc);
			if (engine->ISO10Latin6EncArrayP)
				engine->fontencoding = engine->ISO10Latin6EncArrayP;
			else
				rc = 0;
			break;
		case ISOTHAIENCODING:
			if (!engine->ISO11ThaiEncArrayP)
				engine->ISO11ThaiEncArrayP = MakeEncodingArrayP(engine, UniCodeLowEnc, ISO8859_11Enc);
			if (engine->ISO11ThaiEncArrayP)
				engine->fontencoding = engine->ISO11ThaiEncArrayP;
			else
				rc = 0;
			break;
		case ISOLATIN7ENCODING:
			if (!engine->ISO13Latin7EncArrayP)
				engine->ISO13Latin7EncArrayP = MakeEncodingNumArrayP(engine, UniCodeLowEnc, ISO8859_13Enc);
			if (engine->ISO13Latin7EncArrayP)
				engine->fontencoding = engine->ISO13Latin7EncArrayP;
			else
				rc = 0;
			break;
		case ISOLATIN8ENCODING:
			if (!engine->ISO14Latin8EncArrayP)
				engine->ISO14Latin8EncArrayP = MakeEncodingArrayP(engine, UniCodeLowEnc, ISO8859_14Enc);
			if (engine->ISO14Latin8EncArrayP)
				engine->fontencoding = engine->ISO14Latin8EncArrayP;
			else
				rc = 0;
			break;
		case ISOLATIN9ENCODING:
			if (!engine->ISO15Latin9EncArrayP)
				engine->ISO15Latin9EncArrayP = MakeEncodingNumArrayP(engine, UniCodeLowEnc, ISO8859_15Enc);
			if (engine->ISO15Latin9EncArrayP)
				engine->fontencoding = engine->ISO15Latin9EncArrayP;
			else
				rc = 0;
			break;
		case WINLATIN1ENCODING:
			if (!engine->WinLatin1EncArrayP)
				engine->WinLatin1EncArrayP = MakeEncodingNumArrayP(engine, UniCodeLowEnc, Win1252Enc);
			if (engine->WinLatin1EncArrayP)
				engine->fontencoding = engine->WinLatin1EncArrayP;
			else
				rc = 0;
			break;
		case WINCYRILLICENCODING:
			if (!engine->WinCyrillicEncArrayP)
				engine->WinCyrillicEncArrayP = MakeEncodingNumArrayP(engine, UniCodeLowEnc, CP1251Enc);
			if (engine->WinCyrillicEncArrayP)
				engine->fontencoding = engine->WinCyrillicEncArrayP;
			else
				rc = 0;
			break;
		case KOI8RENCODING:
			if (!engine->koi8rEncArrayP)
				engine->koi8rEncArrayP = MakeEncodingNumArrayP(engine, UniCodeLowEnc, koi8rEnc);
			if (engine->koi8rEncArrayP)
				engine->fontencoding = engine->koi8rEncArrayP;
			else
				rc = 0;
			break;
		case E2ENCODING:
			if (!engine->E2EncArrayP)
				engine->E2EncArrayP = MakeEncodingNumArrayP(engine, UniCodeLowEnc, E2Enc);
			if (engine->E2EncArrayP)
				engine->fontencoding = engine->E2EncArrayP;
			else
				rc = 0;
			break;
		case 0:		// unset
		case BUILTINENCODING:
			engine->fontencoding = engine->FontP->fontInfoP[ENCODING].value.data.arrayP;
			break;
		default:
			rc = 0;
			break;
	}
	return rc;
}

// Version for names
static psobj *MakeEncodingArrayP(struct T1GlyphEngine *engine,
				 const EncodingNumTable *encodingTableLow,
				 const EncodingTable *encodingTableHigh)
{
	int i;
	psobj *encodingArrayP;

	encodingArrayP = (psobj *) vm_alloc(engine, ENCSIZE * (sizeof(psobj)));
	if (!encodingArrayP)
		return NULL;

	/* initialize everything to .notdef */
	for (i = 0; i < ENCSIZE; i++)
		objFormatName(&(encodingArrayP[i]), 7, ".notdef");

	for (i = 0; encodingTableLow[i].eindex; i++)
	{
		objFormatName(&(encodingArrayP[encodingTableLow[i].eindex]),
			      strlen(AGL[encodingTableLow[i].uindex].name),
			      AGL[encodingTableLow[i].uindex].name);
	}

	for (i = 0; encodingTableHigh[i].name; i++)
	{
		objFormatName(&(encodingArrayP[encodingTableHigh[i].index]),
			      strlen(encodingTableHigh[i].name),
			      encodingTableHigh[i].name);
	}

	return (encodingArrayP);
}

// Version for numbers
static psobj *MakeEncodingNumArrayP(struct T1GlyphEngine *engine,
				 const EncodingNumTable *encodingTableLow,
				 const EncodingNumTable *encodingTableHigh)
{
	int i;
	psobj *encodingArrayP;

	encodingArrayP = (psobj *) vm_alloc(engine, ENCSIZE * (sizeof(psobj)));
	if (!encodingArrayP)
		return NULL;

	/* initialize everything to .notdef */
	for (i = 0; i < ENCSIZE; i++)
		objFormatName(&(encodingArrayP[i]), 7, ".notdef");

	for (i = 0; encodingTableLow[i].eindex; i++)
	{
		objFormatName(&(encodingArrayP[encodingTableLow[i].eindex]),
			      strlen(AGL[encodingTableLow[i].uindex].name),
			      AGL[encodingTableLow[i].uindex].name);
	}

	for (i = 0; encodingTableHigh[i].eindex; i++)
	{
		objFormatName(&(encodingArrayP[encodingTableHigh[i].eindex]),
			      strlen(AGL[encodingTableHigh[i].uindex].name),
			      AGL[encodingTableHigh[i].uindex].name);
	}

	return (encodingArrayP);
}

boolean Init_BuiltInEncoding(struct T1GlyphEngine *engine)
{
	engine->StdEncArrayP = MakeEncodingNumArrayP(engine, StdLowEnc, StdEnc);
	engine->PSISOLatin1EncArrayP = MakeEncodingNumArrayP(engine, ISOLatin1LowEnc, ISO8859_1Enc);
	return (engine->StdEncArrayP && engine->PSISOLatin1EncArrayP);
}

/********************************************************************/
/***================================================================***/
static int getNextValue(struct T1GlyphEngine *engine, psobj *inputP, int valueType)
{
	scan_token(engine, inputP);
	if (engine->tokenType != valueType)
	{
		return (SCAN_ERROR);
	}
	return (SCAN_OK);

}
/***================================================================***/
/*  This routine will set the global rc if there is an error          */
/***================================================================***/
static int getInt(struct T1GlyphEngine *engine, psobj *inputP)
{
	scan_token(engine, inputP);
	if (engine->tokenType != TOKEN_INTEGER)
	{
		engine->scanfont_rc = SCAN_ERROR;
		return (0);
	}
	else
	{
		return (engine->tokenValue.integer);
	}

}
/***================================================================***/
/*
 * See Sec 10.3 of ``Adobe Type 1 Font Format'' v1.1,
 * for parsing Encoding.
 */
static int getEncoding(struct T1GlyphEngine *engine, psobj *inputP, psobj *arrayP)
{

	scan_token(engine, inputP);
	if ((engine->tokenType == TOKEN_NAME)
	    &&
	    (((engine->tokenLength == 16) && (!strncmp(engine->tokenStartP, "StandardEncoding", 16))) ||
	     (((engine->tokenLength == 17) && (!strncmp(engine->tokenStartP, "ISOLatin1Encoding", 17))))))
	{
		engine->Has_Builtin_Encoding = FALSE;	// TetiSoft

		/* Adobe Standard Encoding */
		if (engine->tokenLength == 16)
			arrayP->data.valueP = (char *)engine->StdEncArrayP;
		else
			arrayP->data.valueP = (char *)engine->PSISOLatin1EncArrayP;
/***
 *** Hack by Amish 2/12/95: Always use ISOLatin1 over of StdEncoding.
 *** Can still use the font's built in encoding however (for Symbol, etc)
 ***/
		arrayP->data.valueP = (char *)engine->PSISOLatin1EncArrayP;	// TetiSoft: Can be changed with OT_SymbolSet

		arrayP->len = ENCSIZE;
		return (SCAN_OK);
	}
	else if ((engine->tokenType == TOKEN_LEFT_BRACE) ||
		 (engine->tokenType == TOKEN_LEFT_BRACKET))
	{
		/* Array of literal names */

		psobj *objP;
		int i;

		engine->Has_Builtin_Encoding = TRUE;	// TetiSoft

		objP = (psobj *) vm_alloc(engine, ENCSIZE * (sizeof(psobj)));
		if (!(objP))
			return (SCAN_OUT_OF_MEMORY);

		arrayP->data.valueP = (char *)objP;
		arrayP->len = ENCSIZE;

		for (i = 0; i < ENCSIZE; i++, objP++)
		{
			scan_token(engine, inputP);

			if (engine->tokenType != TOKEN_LITERAL_NAME)
				return (SCAN_ERROR);

			if (!(vm_alloc(engine, engine->tokenLength)))
				return (SCAN_OUT_OF_MEMORY);

			objFormatName(objP, engine->tokenLength, engine->tokenStartP);
		}

		scan_token(engine, inputP);
		if ((engine->tokenType == TOKEN_RIGHT_BRACE) ||
		    (engine->tokenType == TOKEN_RIGHT_BRACKET))
			return (SCAN_OK);
	}
	else
	{
		/* Must be sequences of ``dup <index> <charactername> put" */

		psobj *objP;
		int i;

		engine->Has_Builtin_Encoding = TRUE;	// TetiSoft

		objP = (psobj *) vm_alloc(engine, ENCSIZE * (sizeof(psobj)));
		if (!(objP))
			return (SCAN_OUT_OF_MEMORY);

		arrayP->data.valueP = (char *)objP;
		arrayP->len = ENCSIZE;

		for (i = 0; i < ENCSIZE; i++)
			objFormatName(objP + i, 7, ".notdef");

		while (TRUE)
		{
			scan_token(engine, inputP);

			switch (engine->tokenType)
			{
			case TOKEN_NAME:
				if (engine->tokenLength == 3)
				{
					if (strncmp(engine->tokenStartP, "dup", 3) == 0)
					{
						/* get <index> */
						scan_token(engine, inputP);
						if (engine->tokenType != TOKEN_INTEGER ||
						    engine->tokenValue.integer < 0 ||
						    engine->tokenValue.integer >= ENCSIZE)
							return (SCAN_ERROR);
						i = engine->tokenValue.integer;

						/* get <characer_name> */
						scan_token(engine, inputP);
						if (engine->tokenType != TOKEN_LITERAL_NAME)
							return (SCAN_ERROR);

						if (!(vm_alloc(engine, engine->tokenLength)))
							return (SCAN_OUT_OF_MEMORY);
						objFormatName(objP + i, engine->tokenLength, engine->tokenStartP);

						/* get "put" */
						scan_token(engine, inputP);
						if (engine->tokenType != TOKEN_NAME)
							return (SCAN_ERROR);
					}
					else if (strncmp(engine->tokenStartP, "def", 3) == 0)
						return (SCAN_OK);
				}
				break;
			case TOKEN_EOF:
			case TOKEN_NONE:
			case TOKEN_INVALID:
				return (SCAN_ERROR);
			}
		}
	}

	return (SCAN_ERROR);
}


/***================================================================***/
static int getArray(struct T1GlyphEngine *engine, psobj *inputP, psobj *arrayP)
{
	int N;			/* count the items in the array */
	psobj *objP;


	scan_token(engine, inputP);
	if ((engine->tokenType != TOKEN_LEFT_BRACE) &&
	    (engine->tokenType != TOKEN_LEFT_BRACKET))
	{
		return (SCAN_ERROR);
	}
	/* format the array in memory, save pointer to the beginning */
	arrayP->data.valueP = engine->tokenStartP;
	/* loop, picking up next object, until right BRACE or BRACKET */
	N = 0;
	do
	{
		scan_token(engine, inputP);
		if ((engine->tokenType == TOKEN_RIGHT_BRACE) ||
		    (engine->tokenType == TOKEN_RIGHT_BRACKET))
		{
			/* save then number of items in the array */
			arrayP->len = N;
			return (SCAN_OK);
		}
		/* allocate the space for the object */
		objP = (psobj *) vm_alloc(engine, sizeof(psobj));
		if (!(objP))
			return (SCAN_OUT_OF_MEMORY);

		/* array is an array of numbers, (real or integer)  */
		if (engine->tokenType == TOKEN_REAL)
		{
			objFormatReal(objP, engine->tokenValue.real);
		}
		else if (engine->tokenType == TOKEN_INTEGER)
		{
			objFormatInteger(objP, engine->tokenValue.integer);
		}
		else
			return (SCAN_ERROR);
		N++;
	}
	while (1 > 0);
	/* NOTREACHED*/
}
/***================================================================***/
static int getName(struct T1GlyphEngine *engine, psobj *inputP, char *nameP)
{
	do
	{
		scan_token(engine, inputP);
		if (engine->tokenType <= TOKEN_NONE)
		{
			if (engine->tokenTooLong)
				return (SCAN_OUT_OF_MEMORY);
			return (SCAN_ERROR);
		}
	}
	while ((engine->tokenType != TOKEN_NAME) ||
	       (0 != strncmp(engine->tokenStartP, nameP, strlen(nameP))));
	/* found */
	return (SCAN_OK);
}
/***================================================================***/
static int getNbytes(struct T1GlyphEngine *engine, psobj *inputP, int N)
{
	int I;


	engine->tokenStartP = vm_next_byte(engine);
	engine->tokenMaxP = engine->tokenStartP + MIN(vm_free_bytes(engine), MAX_STRING_LEN);
	if (N > vm_free_bytes(engine))
	{
		return (SCAN_OUT_OF_MEMORY);
	}
	I = T1Read(engine->tokenStartP, 1, N, inputP->data.fileP);
	if (I != N)
		return (SCAN_FILE_EOF);
	return (SCAN_OK);
}

/***================================================================***/
/*  getLiteralName(nameObjP)                                          */
/*     scan for next literal.                                         */
/*  if we encounter the name 'end' then terminate and say ok.         */
/*    It means that the CharStrings does not have as many characters  */
/*    as the dictionary said it would and that is ok.                 */
/***================================================================***/
static int getLiteralName(struct T1GlyphEngine *engine, psobj *inputP, psobj *nameObjP)
{
	do
	{
		scan_token(engine, inputP);
		if (engine->tokenType <= TOKEN_NONE)
		{
			if (engine->tokenTooLong)
				return (SCAN_OUT_OF_MEMORY);
			return (SCAN_ERROR);
		}
		if (engine->tokenType == TOKEN_NAME)
		{
			if (0 == strncmp(engine->tokenStartP, "end", 3))
			{
				return (SCAN_END);
			}
		}
	}
	while (engine->tokenType != TOKEN_LITERAL_NAME);
	nameObjP->len = engine->tokenLength;
	/* allocate all the names in the CharStrings Structure */
	if (!(vm_alloc(engine, engine->tokenLength)))
		return (SCAN_OUT_OF_MEMORY);
	nameObjP->data.valueP = engine->tokenStartP;
	/* found */
	return (SCAN_OK);
}

/***================================================================***/
/*
 *   BuildSubrs routine
 */
/***================================================================***/

static int BuildSubrs(struct T1GlyphEngine *engine, psobj *inputP, boolean *TwoSubrs, psfont *fontP)
{
	int N;			/* number of values in Subrs */
	int I;			/* index into Subrs */
	int i;			/* loop thru  Subrs */
	int J;			/* length of Subrs entry */
	psobj *arrayP;

	/* next token should be a positive int */
	/* note: rc is set by getInt. */
	N = getInt(engine, inputP);
	if (engine->scanfont_rc)
		return (engine->scanfont_rc);
	if (N < 0)
		return (SCAN_ERROR);
	/* if we already have a Subrs, then skip the second one */
	/* The second one is for hiresolution devices.          */
	if (fontP->Subrs.data.arrayP != NULL)
	{
		*TwoSubrs = TRUE;
		/* process all the Subrs, but do not update anything */
		/* can not just skip them because of the binary data */
		for (i = 0; i < N; i++)
		{
			/* look for dup */
			engine->scanfont_rc = getName(engine, inputP, "dup");
			if (engine->scanfont_rc)
				return (engine->scanfont_rc);
			/* get 2 integers */
			I = getInt(engine, inputP);
			if (engine->scanfont_rc)
				return (engine->scanfont_rc);
			J = getInt(engine, inputP);
			if (engine->scanfont_rc)
				return (engine->scanfont_rc);
			if ((I < 0) || (J < 0))
				return (SCAN_ERROR);
			/* get the next token, it should be RD or -|, either is ok */
			engine->scanfont_rc = getNextValue(engine, inputP, TOKEN_NAME);
			if (engine->scanfont_rc != SCAN_OK)
				return (engine->scanfont_rc);
			engine->scanfont_rc = getNbytes(engine, inputP, J);
			if (engine->scanfont_rc)
				return (engine->scanfont_rc);
		}
		return (SCAN_OK);
	}

	arrayP = (psobj *) vm_alloc(engine, N * sizeof(psobj));
	if (!(arrayP))
		return (SCAN_OUT_OF_MEMORY);
	fontP->Subrs.len = N;
	fontP->Subrs.data.arrayP = arrayP;
	/* get N values for Subrs */
	for (i = 0; i < N; i++)
	{
		/* look for dup */
		engine->scanfont_rc = getName(engine, inputP, "dup");
		if (engine->scanfont_rc)
			return (engine->scanfont_rc);
		/* get 2 integers */
		I = getInt(engine, inputP);
		if (engine->scanfont_rc)
			return (engine->scanfont_rc);
		J = getInt(engine, inputP);
		if (engine->scanfont_rc)
			return (engine->scanfont_rc);
		if ((I < 0) || (J < 0))
			return (SCAN_ERROR);
		arrayP[I].len = J;
		/* get the next token, it should be RD or -|, either is ok */
		engine->scanfont_rc = getNextValue(engine, inputP, TOKEN_NAME);
		if (engine->scanfont_rc != SCAN_OK)
			return (engine->scanfont_rc);
		engine->scanfont_rc = getNbytes(engine, inputP, J);
		if (engine->scanfont_rc == SCAN_OK)
		{
			arrayP[I].data.valueP = engine->tokenStartP;
			if (!(vm_alloc(engine, J)))
				return (SCAN_OUT_OF_MEMORY);
		}
		else
			return (engine->scanfont_rc);
	}
	return (SCAN_OK);

}
/***================================================================***/
/***================================================================***/
/*
 *   BuildCharStrings routine
 */
/***================================================================***/

static int BuildCharStrings(struct T1GlyphEngine *engine, psobj *inputP, boolean *TwoSubrs, psfont *fontP)
{
	int N;			/* number of values in CharStrings */
	int i;			/* loop thru  Subrs */
	int J;			/* length of Subrs entry */
	psdict *dictP;

	/* next token should be a positive int */
	N = getInt(engine, inputP);
	if (engine->scanfont_rc)
	{
		/* check if file had TwoSubrs, hi resolution stuff is in file*/
		if (*TwoSubrs)
		{
			do
			{
				scan_token(engine, inputP);
				if (engine->tokenType <= TOKEN_NONE)
				{
					if (engine->tokenTooLong)
						return (SCAN_OUT_OF_MEMORY);
					return (SCAN_ERROR);
				}
			}
			while (engine->tokenType != TOKEN_INTEGER);
			N = engine->tokenValue.integer;
		}
		else
			return (engine->scanfont_rc);	/* if next token was not an Int */
	}
	if (N <= 0)
		return (SCAN_ERROR);
	/* save number of entries in the dictionary */

	dictP = (psdict *) vm_alloc(engine, (N + 1) * sizeof(psdict));
	if (!(dictP))
		return (SCAN_OUT_OF_MEMORY);
	fontP->CharStringsP = dictP;
	dictP[0].key.len = N;

/*
 * TetiSoft: If SCAN_END is reported, the remaining array elements
 * would be left uninitialized (vm_alloc() doesn't clear the memory),
 * so we initialize all entries now.
 */
	for (i = 1; i <= N; i++)
	{
		dictP[i].key.len = 0;
		dictP[i].key.data.valueP = NULL;
		dictP[i].value.len = 0;
		dictP[i].value.data.valueP = NULL;
	}

	/* get N values for CharStrings */
	for (i = 1; i <= N; i++)
	{
		/* look for next literal name  */
		engine->scanfont_rc = getLiteralName(engine, inputP, &(dictP[i].key));
		if (engine->scanfont_rc)
			return (engine->scanfont_rc);

		/* get 1 integer */
		J = getInt(engine, inputP);
		if (engine->scanfont_rc)
			return (engine->scanfont_rc);	/* if next token was not an Int */
		if (J < 0)
			return (SCAN_ERROR);
		dictP[i].value.len = J;
		/* get the next token, it should be RD or -|, either is ok */
		engine->scanfont_rc = getNextValue(engine, inputP, TOKEN_NAME);
		if (engine->scanfont_rc != SCAN_OK)
			return (engine->scanfont_rc);
		engine->scanfont_rc = getNbytes(engine, inputP, J);
		if (engine->scanfont_rc == SCAN_OK)
		{
			dictP[i].value.data.valueP = engine->tokenStartP;
			if (!(vm_alloc(engine, J)))
				return (SCAN_OUT_OF_MEMORY);
		}
		else
			return (engine->scanfont_rc);
	}
	return (SCAN_OK);

}
/***================================================================***/
/***================================================================***/
/*
 *   BuildFontInfo Dictionary
 */
/***================================================================***/
static int BuildFontInfo(struct T1GlyphEngine *engine, psfont *fontP)
{
	psdict *dictP;

	/* allocate the private dictionary */
	dictP = (psdict *) vm_alloc(engine, 20 * sizeof(psdict));
	if (!(dictP))
		return (SCAN_OUT_OF_MEMORY);

	fontP->fontInfoP = dictP;
	fontP->fontInfoP[0].key.len = 17;	/* number of actual entries */
	objFormatName(&(dictP[FONTNAME].key), 8, "FontName");
	objFormatName(&(dictP[FONTNAME].value), 0, NULL);
	objFormatName(&(dictP[PAINTTYPE].key), 9, "PaintType");
	objFormatInteger(&(dictP[PAINTTYPE].value), 0);
	objFormatName(&(dictP[FONTTYPENUM].key), 8, "FontType");
	objFormatInteger(&(dictP[FONTTYPENUM].value), 0);
	objFormatName(&(dictP[FONTMATRIX].key), 10, "FontMatrix");
	objFormatArray(&(dictP[FONTMATRIX].value), 0, NULL);
	objFormatName(&(dictP[FONTBBOX].key), 8, "FontBBox");
	objFormatArray(&(dictP[FONTBBOX].value), 0, NULL);
	objFormatName(&(dictP[ENCODING].key), 8, "Encoding");
	objFormatEncoding(&(dictP[ENCODING].value), 0, NULL);
	objFormatName(&(dictP[UNIQUEID].key), 8, "UniqueID");
	objFormatInteger(&(dictP[UNIQUEID].value), 0);
	objFormatName(&(dictP[STROKEWIDTH].key), 11, "StrokeWidth");
	objFormatReal(&(dictP[STROKEWIDTH].value), 0.0);
	objFormatName(&(dictP[VERSION].key), 7, "version");
	objFormatString(&(dictP[VERSION].value), 0, NULL);
	objFormatName(&(dictP[NOTICE].key), 6, "Notice");
	objFormatString(&(dictP[NOTICE].value), 0, NULL);
	objFormatName(&(dictP[FULLNAME].key), 8, "FullName");
	objFormatString(&(dictP[FULLNAME].value), 0, NULL);
	objFormatName(&(dictP[FAMILYNAME].key), 10, "FamilyName");
	objFormatString(&(dictP[FAMILYNAME].value), 0, NULL);
	objFormatName(&(dictP[WEIGHT].key), 6, "Weight");
	objFormatString(&(dictP[WEIGHT].value), 0, NULL);
	objFormatName(&(dictP[ITALICANGLE].key), 11, "ItalicAngle");
	objFormatReal(&(dictP[ITALICANGLE].value), 0.0);
	objFormatName(&(dictP[ISFIXEDPITCH].key), 12, "isFixedPitch");
	objFormatBoolean(&(dictP[ISFIXEDPITCH].value), FALSE);
	objFormatName(&(dictP[UNDERLINEPOSITION].key), 17, "UnderlinePosition");
	objFormatReal(&(dictP[UNDERLINEPOSITION].value), 0.0);
	objFormatName(&(dictP[UNDERLINETHICKNESS].key), 18, "UnderlineThickness");
	objFormatReal(&(dictP[UNDERLINETHICKNESS].value), 0.0);
	return (SCAN_OK);
}
/***================================================================***/
/*
 *   BuildPrivate Dictionary
 */
/***================================================================***/
static int BuildPrivate(struct T1GlyphEngine *engine, psfont *fontP)
{
	psdict *Private;

	/* allocate the private dictionary */
	Private = (psdict *) vm_alloc(engine, 20 * sizeof(psdict));

	if (!(Private))
		return (SCAN_OUT_OF_MEMORY);

	fontP->Private = Private;
	fontP->Private[0].key.len = 16;	/* number of actual entries */

	objFormatName(&(Private[BLUEVALUES].key), 10, "BlueValues");
	objFormatArray(&(Private[BLUEVALUES].value), 0, NULL);
	objFormatName(&(Private[OTHERBLUES].key), 10, "OtherBlues");
	objFormatArray(&(Private[OTHERBLUES].value), 0, NULL);
	objFormatName(&(Private[FAMILYBLUES].key), 11, "FamilyBlues");
	objFormatArray(&(Private[FAMILYBLUES].value), 0, NULL);
	objFormatName(&(Private[FAMILYOTHERBLUES].key), 16, "FamilyOtherBlues");
	objFormatArray(&(Private[FAMILYOTHERBLUES].value), 0, NULL);
	objFormatName(&(Private[BLUESCALE].key), 9, "BlueScale");
	objFormatReal(&(Private[BLUESCALE].value), DEFAULTBLUESCALE);
	objFormatName(&(Private[BLUESHIFT].key), 9, "BlueShift");
	objFormatInteger(&(Private[BLUESHIFT].value), DEFAULTBLUESHIFT);
	objFormatName(&(Private[BLUEFUZZ].key), 8, "BlueFuzz");
	objFormatInteger(&(Private[BLUEFUZZ].value), DEFAULTBLUEFUZZ);
	objFormatName(&(Private[STDHW].key), 5, "StdHW");
	objFormatArray(&(Private[STDHW].value), 0, NULL);
	objFormatName(&(Private[STDVW].key), 5, "StdVW");
	objFormatArray(&(Private[STDVW].value), 0, NULL);
	objFormatName(&(Private[STEMSNAPH].key), 9, "StemSnapH");
	objFormatArray(&(Private[STEMSNAPH].value), 0, NULL);
	objFormatName(&(Private[STEMSNAPV].key), 9, "StemSnapV");
	objFormatArray(&(Private[STEMSNAPV].value), 0, NULL);
	objFormatName(&(Private[FORCEBOLD].key), 9, "ForceBold");
	objFormatBoolean(&(Private[FORCEBOLD].value), DEFAULTFORCEBOLD);
	objFormatName(&(Private[LANGUAGEGROUP].key), 13, "LanguageGroup");
	objFormatInteger(&(Private[LANGUAGEGROUP].value), DEFAULTLANGUAGEGROUP);
	objFormatName(&(Private[LENIV].key), 5, "LenIV");
	objFormatInteger(&(Private[LENIV].value), DEFAULTLENIV);
	objFormatName(&(Private[RNDSTEMUP].key), 9, "RndStemUp");
	objFormatBoolean(&(Private[RNDSTEMUP].value), DEFAULTRNDSTEMUP);
	objFormatName(&(Private[EXPANSIONFACTOR].key), 9, "ExpansionFactor");
	objFormatReal(&(Private[EXPANSIONFACTOR].value),
		      DEFAULTEXPANSIONFACTOR);
	return (SCAN_OK);
}
/***================================================================***/
/**********************************************************************/
/*     GetType1Blues(fontP)                                           */
/*                                                                    */
/*   Routine to support font-level hints.                             */
/*                                                                    */
/*         Gets all the Blues information from the Private dictionary */
/*         for the font.                                              */
/*                                                                    */
/*                                                                    */
/**********************************************************************/
static int GetType1Blues(struct T1GlyphEngine *engine, psfont *fontP)
{
	psdict *PrivateDictP;	/* the Private dict relating to hints */
	struct blues_struct *blues;	/* ptr for the blues struct we will allocate */
	int i;
	psobj *HintEntryP;



	/* get the Private dictionary pointer */
	PrivateDictP = fontP->Private;

	/* allocate the memory for the blues structure */
	blues = (struct blues_struct *)vm_alloc(engine, sizeof(struct blues_struct));

	if (!blues)
		return (SCAN_OUT_OF_MEMORY);

	/* Make fontP's blues ptr point to this newly allocated structure. */
	fontP->BluesP = blues;

	/* fill in the BlueValues array */
	HintEntryP = &(PrivateDictP[BLUEVALUES].value);
	/* check to see if the entry exists and if it's an array */
	if (!objPIsArray(HintEntryP) || (HintEntryP->len == 0))
		blues->numBlueValues = 0;
	else
	{
		/* get the number of values in the array */
		if (HintEntryP->len > NUMBLUEVALUES)
		{
			blues->numBlueValues = NUMBLUEVALUES;
		}
		else
			blues->numBlueValues = HintEntryP->len;
		for (i = 0; i <= blues->numBlueValues - 1; ++i)
		{
			if (objPIsInteger(&HintEntryP->data.arrayP[i]))
				blues->BlueValues[i] =
				    HintEntryP->data.arrayP[i].data.integer;
			else if (objPIsReal(&HintEntryP->data.arrayP[i]))
				blues->BlueValues[i] =
				    HintEntryP->data.arrayP[i].data.real;
			else
				blues->BlueValues[i] = 0;
		}
	}

	/* fill in the OtherBlues array */
	HintEntryP = &(PrivateDictP[OTHERBLUES].value);
	/* check to see if the entry exists and if it's an array */
	if (!objPIsArray(HintEntryP) || (HintEntryP->len == 0))
		blues->numOtherBlues = 0;
	else
	{
		/* get the number of values in the array */
		if (HintEntryP->len > NUMOTHERBLUES)
		{
			blues->numOtherBlues = NUMOTHERBLUES;
		}
		else
			blues->numOtherBlues = HintEntryP->len;
		for (i = 0; i <= blues->numOtherBlues - 1; ++i)
		{
			if (objPIsInteger(&HintEntryP->data.arrayP[i]))
				blues->OtherBlues[i] =
				    HintEntryP->data.arrayP[i].data.integer;
			else if (objPIsReal(&HintEntryP->data.arrayP[i]))
				blues->OtherBlues[i] =
				    HintEntryP->data.arrayP[i].data.real;
			else
				blues->OtherBlues[i] = 0;
		}
	}

	/* fill in the FamilyBlues array */
	HintEntryP = &(PrivateDictP[FAMILYBLUES].value);
	/* check to see if the entry exists and if it's an array */
	if (!objPIsArray(HintEntryP) || (HintEntryP->len == 0))
		blues->numFamilyBlues = 0;
	else
	{
		/* get the number of values in the array */
		if (HintEntryP->len > NUMFAMILYBLUES)
		{
			blues->numFamilyBlues = NUMFAMILYBLUES;
		}
		else
			blues->numFamilyBlues = HintEntryP->len;
		for (i = 0; i <= blues->numFamilyBlues - 1; ++i)
		{
			if (objPIsInteger(&HintEntryP->data.arrayP[i]))
				blues->FamilyBlues[i] =
				    HintEntryP->data.arrayP[i].data.integer;
			else if (objPIsReal(&HintEntryP->data.arrayP[i]))
				blues->FamilyBlues[i] =
				    HintEntryP->data.arrayP[i].data.real;
			else
				blues->FamilyBlues[i] = 0;
		}
	}

	/* fill in the FamilyOtherBlues array */
	HintEntryP = &(PrivateDictP[FAMILYOTHERBLUES].value);
	/* check to see if the entry exists and if it's an array */
	if (!objPIsArray(HintEntryP) || (HintEntryP->len == 0))
		blues->numFamilyOtherBlues = 0;
	else
	{
		/* get the number of values in the array */
		if (HintEntryP->len > NUMFAMILYOTHERBLUES)
		{
			blues->numFamilyOtherBlues = NUMFAMILYOTHERBLUES;
		}
		else
			blues->numFamilyOtherBlues = HintEntryP->len;
		for (i = 0; i <= blues->numFamilyOtherBlues - 1; ++i)
		{
			if (objPIsInteger(&HintEntryP->data.arrayP[i]))
				blues->FamilyOtherBlues[i] =
				    HintEntryP->data.arrayP[i].data.integer;
			else if (objPIsReal(&HintEntryP->data.arrayP[i]))
				blues->FamilyOtherBlues[i] =
				    HintEntryP->data.arrayP[i].data.real;
			else
				blues->FamilyOtherBlues[i] = 0;
		}
	}

	/* fill in the StemSnapH array */
	HintEntryP = &(PrivateDictP[STEMSNAPH].value);
	/* check to see if the entry exists and if it's an array */
	if (!objPIsArray(HintEntryP) || (HintEntryP->len == 0))
		blues->numStemSnapH = 0;
	else
	{
		/* get the number of values in the array */
		if (HintEntryP->len > NUMSTEMSNAPH)
		{
			blues->numStemSnapH = NUMSTEMSNAPH;
		}
		else
			blues->numStemSnapH = HintEntryP->len;
		for (i = 0; i <= blues->numStemSnapH - 1; ++i)
		{
			if (objPIsInteger(&HintEntryP->data.arrayP[i]))
				blues->StemSnapH[i] =
				    HintEntryP->data.arrayP[i].data.integer;
			else if (objPIsReal(&HintEntryP->data.arrayP[i]))
				blues->StemSnapH[i] =
				    HintEntryP->data.arrayP[i].data.real;
			else
				blues->StemSnapH[i] = 0;
		}
	}

	/* fill in the StemSnapV array */
	HintEntryP = &(PrivateDictP[STEMSNAPV].value);
	/* check to see if the entry exists and if it's an array */
	if (!objPIsArray(HintEntryP) || (HintEntryP->len == 0))
		blues->numStemSnapV = 0;
	else
	{
		/* get the number of values in the array */
		if (HintEntryP->len > NUMSTEMSNAPV)
		{
			blues->numStemSnapV = NUMSTEMSNAPV;
		}
		else
			blues->numStemSnapV = HintEntryP->len;
		for (i = 0; i <= blues->numStemSnapV - 1; ++i)
		{
			if (objPIsInteger(&HintEntryP->data.arrayP[i]))
				blues->StemSnapV[i] =
				    HintEntryP->data.arrayP[i].data.integer;
			else if (objPIsReal(&HintEntryP->data.arrayP[i]))
				blues->StemSnapV[i] =
				    HintEntryP->data.arrayP[i].data.real;
			else
				blues->StemSnapV[i] = 0;
		}
	}

	/* fill in the StdVW array */
	HintEntryP = &(PrivateDictP[STDVW].value);
	/* check to see if the entry exists and if it's an array */
	if (!objPIsArray(HintEntryP) || (HintEntryP->len == 0))
		/* a value of zero signifies no entry */
		blues->StdVW = 0;
	else
	{
		if (HintEntryP->len > NUMSTDVW)
		{
		}
		if (objPIsInteger(&HintEntryP->data.arrayP[0]))
			blues->StdVW = HintEntryP->data.arrayP[0].data.integer;
		else if (objPIsReal(&HintEntryP->data.arrayP[0]))
			blues->StdVW = HintEntryP->data.arrayP[0].data.real;
		else
			blues->StdVW = 0;
	}

	/* fill in the StdHW array */
	HintEntryP = &(PrivateDictP[STDHW].value);
	/* check to see if the entry exists and if it's an array */
	if (!objPIsArray(HintEntryP) || (HintEntryP->len == 0))
		/* a value of zero signifies no entry */
		blues->StdHW = 0;
	else
	{
		if (HintEntryP->len > NUMSTDHW)
		{
		}
		if (objPIsInteger(&HintEntryP->data.arrayP[0]))
			blues->StdHW = HintEntryP->data.arrayP[0].data.integer;
		else if (objPIsReal(&HintEntryP->data.arrayP[0]))
			blues->StdHW = HintEntryP->data.arrayP[0].data.real;
		else
			blues->StdHW = 0;
	}


	/* get the ptr to the BlueScale entry */
	HintEntryP = &(PrivateDictP[BLUESCALE].value);
	/* put the BlueScale in the blues structure */
	if (objPIsInteger(HintEntryP))	/* Must be integer! */
		blues->BlueScale = HintEntryP->data.integer;
	else if (objPIsReal(HintEntryP))	/* Error? */
		blues->BlueScale = HintEntryP->data.real;
	else
		blues->BlueScale = DEFAULTBLUESCALE;

	/* get the ptr to the BlueShift entry */
	HintEntryP = &(PrivateDictP[BLUESHIFT].value);
	if (objPIsInteger(HintEntryP))	/* Must be integer! */
		blues->BlueShift = HintEntryP->data.integer;
	else if (objPIsReal(HintEntryP))	/* Error? */
		blues->BlueShift = HintEntryP->data.real;
	else
		blues->BlueShift = DEFAULTBLUESHIFT;

	/* get the ptr to the BlueFuzz entry */
	HintEntryP = &(PrivateDictP[BLUEFUZZ].value);
	if (objPIsInteger(HintEntryP))	/* Must be integer! */
		blues->BlueFuzz = HintEntryP->data.integer;
	else if (objPIsReal(HintEntryP))	/* Error? */
		blues->BlueFuzz = HintEntryP->data.real;
	else
		blues->BlueFuzz = DEFAULTBLUEFUZZ;

	/* get the ptr to the ForceBold entry */
	HintEntryP = &(PrivateDictP[FORCEBOLD].value);
	if (objPIsBoolean(HintEntryP))	/* Must be integer! */
		blues->ForceBold = HintEntryP->data.boolean;
	else
		blues->ForceBold = DEFAULTFORCEBOLD;

	/* get the ptr to the LanguageGroup entry */
	HintEntryP = &(PrivateDictP[LANGUAGEGROUP].value);
	if (objPIsInteger(HintEntryP))	/* Must be integer! */
		blues->LanguageGroup = HintEntryP->data.integer;
	else
		blues->LanguageGroup = DEFAULTLANGUAGEGROUP;

	/* get the ptr to the RndStemUp entry */
	HintEntryP = &(PrivateDictP[RNDSTEMUP].value);
	if (objPIsBoolean(HintEntryP))	/* Must be integer! */
		blues->RndStemUp = HintEntryP->data.boolean;
	else
		blues->RndStemUp = DEFAULTRNDSTEMUP;

	/* get the ptr to the lenIV entry */
	HintEntryP = &(PrivateDictP[LENIV].value);
	if (objPIsInteger(HintEntryP))	/* Must be integer! */
		blues->lenIV = HintEntryP->data.integer;
	else
		blues->lenIV = DEFAULTLENIV;

	/* get the ptr to the ExpansionFactor entry */
	HintEntryP = &(PrivateDictP[EXPANSIONFACTOR].value);
	if (objPIsInteger(HintEntryP))
		blues->ExpansionFactor = HintEntryP->data.integer;
	else if (objPIsReal(HintEntryP))
		blues->ExpansionFactor = HintEntryP->data.real;
	else
		blues->ExpansionFactor = DEFAULTEXPANSIONFACTOR;
	return (SCAN_OK);
}
/**********************************************************************/
/*   GetType1CharString(fontP,code)                                   */
/*                                                                    */
/*          Look up code in the standard encoding vector and return   */
/*          the charstring associated with the character name.        */
/*                                                                    */
/*   fontP  is the psfont structure.                                  */
/*                                                                    */
/*   Returns a psobj (string)                                         */
/**********************************************************************/
psobj *GetType1CharString(struct T1GlyphEngine *engine, psfont *fontP, unsigned char code)
{
	int N;			/* the 'Nth' entry in the CharStrings       */
	psobj *charnameP;	/* points to psobj that is name of character*/

	psdict *CharStringsDictP;	/* dictionary with char strings     */
	psobj *theStringP;	/* the definition for the code */



	if (engine->StdEncArrayP == NULL)
	{
		return (NULL);
	}
	/* use the code to index into the standard encoding vector  */
	charnameP = &(engine->StdEncArrayP[code]);

	/* test if the encoding array points to a name */
	if (!(objPIsName(charnameP)))
	{
		return (NULL);
	}

	/* Now that we have the character name out of the standardencoding */
	/* get the character definition out of the current font */
	CharStringsDictP = fontP->CharStringsP;

	/* search the chars string for this charname as key */
	N = SearchDictName(CharStringsDictP, charnameP);
	if (N <= 0)
	{
		return (NULL);
	}
	/* OK, the nth item is the psobj that is the string for this char */
	theStringP = &(CharStringsDictP[N].value);

	return (theStringP);
}

/***================================================================***/
/*
 *   FindDictValue
 */
/***================================================================***/

static int FindDictValue(struct T1GlyphEngine *engine, psobj *inputP, psdict *dictP)
{
	psobj LitName;
	int N;
	int V;

	/* we have just scanned a token and it is a literal name */
	/* need to check if that name is in Private dictionary */
	objFormatName(&LitName, engine->tokenLength, engine->tokenStartP);
	/* is it in the dictP */
	N = SearchDictName(dictP, &LitName);
	/* if found */
	if (N > 0)
	{
		/* what type */
		switch (dictP[N].value.type)
		{
		case OBJ_ENCODING:
			V = getEncoding(engine, inputP, &(dictP[N].value));
			if (V != SCAN_OK)
				return (V);
			break;
		case OBJ_ARRAY:
			V = getArray(engine, inputP, &(dictP[N].value));
			if (V != SCAN_OK)
				return (V);
			break;
		case OBJ_INTEGER:
			/* next value in integer */
			dictP[N].value.data.integer = getInt(engine, inputP);
			if (engine->scanfont_rc)
				return (engine->scanfont_rc);	/* if next token was not an Int */
			break;
		case OBJ_REAL:
			/* next value must be real or int, store as a real */
			scan_token(engine, inputP);
			if (engine->tokenType == TOKEN_REAL)
			{
				dictP[N].value.data.real = engine->tokenValue.real;
			}
			else if (engine->tokenType == TOKEN_INTEGER)
			{
				dictP[N].value.data.real = engine->tokenValue.integer;
			}
			else
				return (SCAN_ERROR);
			break;
		case OBJ_NAME:
			V = getNextValue(engine, inputP, TOKEN_LITERAL_NAME);
			if (V != SCAN_OK)
				return (V);
			if (!(vm_alloc(engine, engine->tokenLength+1)))
				return (SCAN_OUT_OF_MEMORY);
			objFormatName(&(dictP[N].value), engine->tokenLength, engine->tokenStartP);
			break;
		case OBJ_STRING:
			V = getNextValue(engine, inputP, TOKEN_STRING);
			if (V != SCAN_OK)
				return (V);

// TetiSoft: One byte more for '\0'-Termination of Strings (e.g. FamilyName of Font Dictionary)
//			if (!(vm_alloc(engine, engine->tokenLength)))
			if (!(vm_alloc(engine, engine->tokenLength+1)))

				return (SCAN_OUT_OF_MEMORY);
			objFormatString(&(dictP[N].value), engine->tokenLength, engine->tokenStartP);
			break;
		case OBJ_BOOLEAN:
			scan_token(engine, inputP);
			if (engine->tokenType != TOKEN_NAME)
			{
				return (SCAN_ERROR);
			}
			if (0 == strncmp(engine->tokenStartP, "true", 4))
			{
				dictP[N].value.data.boolean = TRUE;
			}
			else if (0 == strncmp(engine->tokenStartP, "false", 5))
			{
				dictP[N].value.data.boolean = FALSE;
			}
			else
				return (SCAN_ERROR);
			break;

		default:
			return (SCAN_ERROR);
			break;
		}
	}
	/* Name is not in dictionary.  That is ok. */
	return (SCAN_OK);

}
/***================================================================***/

/*
 * -------------------------------------------------------------------
 *  Scan the next token and convert it into an object
 *  Result is placed on the Operand Stack as next object
 * -------------------------------------------------------------------
 */
int scan_font(struct T1GlyphEngine *engine, psfont *fontP)
{
	char filename[MAXFONTPATH];
//	char filetype[3];
	F_FILE *fileP;
	const char *nameP;
	int namelen;
	int V;
	int i;
	boolean starthex80;
	boolean InPrivateDict;	// TetiSoft: Now auto
	boolean WantFontInfo;	// TetiSoft: Now auto
	boolean TwoSubrs;	// TetiSoft: Now auto & param
	psobj inputFile;	// TetiSoft: Now auto
	psobj filterFile;	// TetiSoft: Now auto
	psobj *inputP;		// TetiSoft: Now param

	starthex80 = FALSE;
//	filetype[0] = 'r';
////	filetype[1] = 'b';
////	filetype[2] = '\0';
//	filetype[1] = '\0';
	/* copy the filename and remove leading or trailing blanks */
	/* point to name and search for leading blanks */
	nameP = fontP->FontFileName.data.nameP;
	namelen = fontP->FontFileName.len;
	while (nameP[0] == ' ')
	{
		nameP++;
		namelen--;
	}
	/* now remove any trailing blanks */
	while ((namelen > 0) && (nameP[namelen - 1] == ' '))
	{
		namelen--;
	}
	strncpy(filename, nameP, namelen);
	filename[namelen] = '\0';
	/* file name is now constructed */
	inputFile.data.fileP = NULL;
	filterFile.data.fileP = NULL;

	inputP = &inputFile;
	if (fileP = T1Open(engine, filename))
	{
		/* get the first byte of file */
		V = T1Getc(fileP);
		/* if file starts with x'80' then skip next 5 bytes */
		if (V == 0X80)
		{
			for (i = 0; i < 5; i++)
				T1Getc(fileP);
//				V = T1Getc(fileP);
			starthex80 = TRUE;
		}
		else
			T1Ungetc(V, fileP);
		objFormatFile(inputP, fileP);
	}
	else
	{
		return (SCAN_FILE_OPEN_ERROR);
	};

	WantFontInfo = TRUE;
	InPrivateDict = FALSE;
	TwoSubrs = FALSE;
	engine->scanfont_rc = BuildFontInfo(engine, fontP);
	if (engine->scanfont_rc != 0)
		return (engine->scanfont_rc);

	/* Assume everything will be OK */
	engine->scanfont_rc = 0;

	/* Loop until complete font is read  */
	do
	{
		/* Scan the next token */
		scan_token(engine, inputP);

		/* ==> tokenLength, tokenTooLong, tokenType, and tokenValue are */
		/* now set */

		switch (engine->tokenType)
		{
		case TOKEN_EOF:
		case TOKEN_NONE:
		case TOKEN_INVALID:
			/* in this case we are done */
			if (engine->tokenTooLong)
				return (SCAN_OUT_OF_MEMORY);
			engine->scanfont_rc = SCAN_ERROR;
			break;
		case TOKEN_LITERAL_NAME:
			/* Look up the name */
			engine->tokenStartP[engine->tokenLength] = '\0';
			if (InPrivateDict)
			{
				if (0 == strncmp(engine->tokenStartP, "Subrs", 5))
				{
					engine->scanfont_rc = BuildSubrs(engine, inputP, &TwoSubrs, fontP);
					break;
				}
				if (0 == strncmp(engine->tokenStartP, "CharStrings", 11))
				{
					engine->scanfont_rc = BuildCharStrings(engine, inputP, &TwoSubrs, fontP);
					if ((engine->scanfont_rc == SCAN_OK) || (engine->scanfont_rc == SCAN_END))
					{
						T1Close(engine, inputP->data.fileP);
						/* Build the Blues Structure */
						engine->scanfont_rc = GetType1Blues(engine, fontP);
						/* whatever the return code, return it */
						/* all the work is done. This is the normal exit.*/
						return (engine->scanfont_rc);
					}
					break;
				}
//				engine->scanfont_rc = FindDictValue(engine, fontP->Private);
				FindDictValue(engine, inputP, fontP->Private);
				/* we are not going to report errors */
				/* Sometimes the font file may test a value such as */
				/* testing to see if the font is alreadly loaded with */
				/* same UniqueID.  We would faile on /UniqueID get  */
				/* because we are expecting a int to follow UniqueID*/
				/* If the correct object type does not follow a Name*/
				/* then we will skip over it without reporting error*/
				engine->scanfont_rc = SCAN_OK;
				break;
			}	/* end of reading Private dictionary */
			else if (0 == strncmp(engine->tokenStartP, "Private", 7))
			{
				InPrivateDict = TRUE;
				engine->scanfont_rc = BuildPrivate(engine, fontP);
				break;
			}
			else if (WantFontInfo)
			{
//				engine->scanfont_rc = FindDictValue(engine, fontP->fontInfoP);
				FindDictValue(engine, inputP, fontP->fontInfoP);
				/* we are not going to report errors */
				engine->scanfont_rc = SCAN_OK;
				break;
			}
			break;
		case TOKEN_NAME:
			if (0 == strncmp(engine->tokenStartP, "eexec", 5))
			{
				/* if file started with x'80', check next 5 bytes */
				if (starthex80)
				{
					V = T1Getc(fileP);
					if (V == 0X80)
					{
						for (i = 0; i < 5; i++)
							T1Getc(fileP);
//							V = T1Getc(fileP);
					}
					else
						T1Ungetc(V, fileP);
				}
				filterFile.data.fileP = inputP->data.fileP;

/* TetiSoft: Added ASCII decryption */
				T1eexecASCII(inputP->data.fileP);

				T1eexec(inputP->data.fileP);
#if 0
{
	BPTR file = Open("ram:test", MODE_NEWFILE);
	if (file)
	{
		Write(file, inputP->data.fileP->fbuf+inputP->data.fileP->curpos, inputP->data.fileP->fbuflen);
		Close(file);
	}
}
#endif
				if (filterFile.data.fileP == NULL)
				{
					T1Close(engine, inputFile.data.fileP);
					return (SCAN_FILE_OPEN_ERROR);
				}
				inputP = &filterFile;

				WantFontInfo = FALSE;
			}
			break;
		}

	} while (engine->scanfont_rc == 0);

	T1Close(engine, inputP->data.fileP);
	if (engine->tokenTooLong)
		return (SCAN_OUT_OF_MEMORY);
	return (engine->scanfont_rc);
}
