/* $XConsortium: scanfont.c,v 1.9 92/07/07 17:14:56 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 */ #include #include "types.h" #include "t1stdio.h" #include "util.h" #include "token.h" #include "fontfcn.h" #include "blues.h" extern void objFormatInteger(psobj *,int); extern void objFormatReal(psobj *, float); extern void objFormatBoolean(psobj *, boolean); extern void objFormatEncoding(psobj *, int, psobj *); extern void objFormatArray(psobj *, int, psobj *); extern void objFormatString(psobj *, int, char *); extern void objFormatName(psobj *, int, char *); extern void objFormatFile(psobj *, FILE *); extern int SearchDictName(psdict *, psobj *); extern int T1Getc(struct F_FILE *f); extern int T1Ungetc(int c,struct F_FILE *f); static int rc; static boolean InPrivateDict; static boolean WantFontInfo; static boolean TwoSubrs; static psobj inputFile; static psobj filterFile; static psobj *inputP; /**********************************************************************/ /* Init_BuiltInEncoding() */ /* */ /* Initializes the StandardEncoding and ISOLatin1Encoding vector. */ /* */ /**********************************************************************/ typedef struct /* Builtin Standard Encoding */ { int index; char *name; } EncodingTable; static EncodingTable StdEnc[] = { 040 , "space", 041 , "exclam", 042 , "quotedbl", 043 , "numbersign", 044 , "dollar", 045 , "percent", 046 , "ampersand", 047 , "quoteright", 050 , "parenleft", 051 , "parenright", 052 , "asterisk", 053 , "plus", 054 , "comma", 055 , "hyphen", 056 , "period", 057 , "slash", 060 , "zero", 061 , "one", 062 , "two", 063 , "three", 064 , "four", 065 , "five", 066 , "six", 067 , "seven", 070 , "eight", 071 , "nine", 072 , "colon", 073 , "semicolon", 074 , "less", 075 , "equal", 076 , "greater", 077 , "question", 0100 , "at", 0101 , "A", 0102 , "B", 0103 , "C", 0104 , "D", 0105 , "E", 0106 , "F", 0107 , "G", 0110 , "H", 0111 , "I", 0112 , "J", 0113 , "K", 0114 , "L", 0115 , "M", 0116 , "N", 0117 , "O", 0120 , "P", 0121 , "Q", 0122 , "R", 0123 , "S", 0124 , "T", 0125 , "U", 0126 , "V", 0127 , "W", 0130 , "X", 0131 , "Y", 0132 , "Z", 0133 , "bracketleft", 0134 , "backslash", 0135 , "bracketright", 0136 , "asciicircum", 0137 , "underscore", 0140 , "quoteleft", 0141 , "a", 0142 , "b", 0143 , "c", 0144 , "d", 0145 , "e", 0146 , "f", 0147 , "g", 0150 , "h", 0151 , "i", 0152 , "j", 0153 , "k", 0154 , "l", 0155 , "m", 0156 , "n", 0157 , "o", 0160 , "p", 0161 , "q", 0162 , "r", 0163 , "s", 0164 , "t", 0165 , "u", 0166 , "v", 0167 , "w", 0170 , "x", 0171 , "y", 0172 , "z", 0173 , "braceleft", 0174 , "bar", 0175 , "braceright", 0176 , "asciitilde", 0241 , "exclamdown", 0242 , "cent", 0243 , "sterling", 0244 , "fraction", 0245 , "yen", 0246 , "florin", 0247 , "section", 0250 , "currency", 0251 , "quotesingle", 0252 , "quotedblleft", 0253 , "guillemotleft", 0254 , "guilsinglleft", 0255 , "guilsinglright", 0256 , "fi", 0257 , "fl", 0261 , "endash", 0262 , "dagger", 0263 , "daggerdbl", 0264 , "periodcentered", 0266 , "paragraph", 0267 , "bullet", 0270 , "quotesinglbase", 0271 , "quotedblbase", 0272 , "quotedblright", 0273 , "guillemotright", 0274 , "ellipsis", 0275 , "perthousand", 0277 , "questiondown", 0301 , "grave", 0302 , "acute", 0303 , "circumflex", 0304 , "tilde", 0305 , "macron", 0306 , "breve", 0307 , "dotaccent", 0310 , "dieresis", 0312 , "ring", 0313 , "cedilla", 0315 , "hungarumlaut", 0316 , "ogonek", 0317 , "caron", 0320 , "emdash", 0341 , "AE", 0343 , "ordfeminine", 0350 , "Lslash", 0351 , "Oslash", 0352 , "OE", 0353 , "ordmasculine", 0361 , "ae", 0365 , "dotlessi", 0370 , "lslash", 0371 , "oslash", 0372 , "oe", 0373 , "germandbls", 0, 0 }; static EncodingTable ISO8859Enc[] = { 32, "space", 33, "exclam", 34, "quotedbl", 35, "numbersign", 36, "dollar", 37, "percent", 38, "ampersand", 39, "quoteright", 40, "parenleft", 41, "parenright", 42, "asterisk", 43, "plus", 44, "comma", 45, "minus", 46, "period", 47, "slash", 48, "zero", 49, "one", 50, "two", 51, "three", 52, "four", 53, "five", 54, "six", 55, "seven", 56, "eight", 57, "nine", 58, "colon", 59, "semicolon", 60, "less", 61, "equal", 62, "greater", 63, "question", 64, "at", 65, "A", 66, "B", 67, "C", 68, "D", 69, "E", 70, "F", 71, "G", 72, "H", 73, "I", 74, "J", 75, "K", 76, "L", 77, "M", 78, "N", 79, "O", 80, "P", 81, "Q", 82, "R", 83, "S", 84, "T", 85, "U", 86, "V", 87, "W", 88, "X", 89, "Y", 90, "Z", 91, "bracketleft", 92, "backslash", 93, "bracketright", 94, "asciicircum", 95, "underscore", 96, "quoteleft", 97, "a", 98, "b", 99, "c", 100, "d", 101, "e", 102, "f", 103, "g", 104, "h", 105, "i", 106, "j", 107, "k", 108, "l", 109, "m", 110, "n", 111, "o", 112, "p", 113, "q", 114, "r", 115, "s", 116, "t", 117, "u", 118, "v", 119, "w", 120, "x", 121, "y", 122, "z", 123, "braceleft", 124, "bar", 125, "braceright", 126, "asciitilde", 161, "exclamdown", 162, "cent", 163, "sterling", 164, "currency", 165, "yen", 166, "brokenbar", 167, "section", 168, "dieresis", 169, "copyright", 170, "ordfeminine", 171, "guillemotleft", 172, "logicalnot", 173, "hyphen", 174, "registered", 175, "macron", 176, "degree", 177, "plusminus", 178, "twosuperior", 179, "threesuperior", 180, "acute", 181, "mu", 182, "paragraph", 183, "periodcentered", 184, "cedilla", 185, "onesuperior", 186, "ordmasculine", 187, "guillemotright", 188, "onequarter", 189, "onehalf", 190, "threequarters", 191, "questiondown", 192, "Agrave", 193, "Aacute", 194, "Acircumflex", 195, "Atilde", 196, "Adieresis", 197, "Aring", 198, "AE", 199, "Ccedilla", 200, "Egrave", 201, "Eacute", 202, "Ecircumflex", 203, "Edieresis", 204, "Igrave", 205, "Iacute", 206, "Icircumflex", 207, "Idieresis", 208, "Eth", 209, "Ntilde", 210, "Ograve", 211, "Oacute", 212, "Ocircumflex", 213, "Otilde", 214, "Odieresis", 215, "multiply", 216, "Oslash", 217, "Ugrave", 218, "Uacute", 219, "Ucircumflex", 220, "Udieresis", 221, "Yacute", 222, "Thorn", 223, "germandbls", 224, "agrave", 225, "aacute", 226, "acircumflex", 227, "atilde", 228, "adieresis", 229, "aring", 230, "ae", 231, "ccedilla", 232, "egrave", 233, "eacute", 234, "ecircumflex", 235, "edieresis", 236, "igrave", 237, "iacute", 238, "icircumflex", 239, "idieresis", 240, "eth", 241, "ntilde", 242, "ograve", 243, "oacute", 244, "ocircumflex", 245, "otilde", 246, "odieresis", 247, "divide", 248, "oslash", 249, "ugrave", 250, "uacute", 251, "ucircumflex", 252, "udieresis", 253, "yacute", 254, "thorn", 255, "ydieresis", 0, 0 }; static psobj *StdEncArrayP = NULL; psobj *ISOLatin1EncArrayP = NULL; static psobj *MakeEncodingArrayP(encodingTable) EncodingTable *encodingTable; { int i; psobj *encodingArrayP; encodingArrayP = (psobj *)vm_alloc(256*(sizeof(psobj))); if (!encodingArrayP) return NULL; /* initialize everything to .notdef */ for (i=0; i<256;i++) objFormatName(&(encodingArrayP[i]),7, ".notdef"); for (i=0; encodingTable[i].name; i++) { objFormatName(&(encodingArrayP[encodingTable[i].index]), strlen(encodingTable[i].name), encodingTable[i].name); } return(encodingArrayP); } boolean Init_BuiltInEncoding() { StdEncArrayP = MakeEncodingArrayP(StdEnc); ISOLatin1EncArrayP = MakeEncodingArrayP(ISO8859Enc); return (StdEncArrayP && ISOLatin1EncArrayP); } /********************************************************************/ /***================================================================***/ static int getNextValue(valueType) int valueType; { scan_token(inputP); if (tokenType != valueType) { return(SCAN_ERROR); } return(SCAN_OK); } /***================================================================***/ /* This routine will set the global rc if there is an error */ /***================================================================***/ static int getInt() { scan_token(inputP); if (tokenType != TOKEN_INTEGER) { rc = SCAN_ERROR; return(0); } else { return( tokenValue.integer); } } /***================================================================***/ /* * See Sec 10.3 of ``Adobe Type 1 Font Format'' v1.1, * for parsing Encoding. */ static int getEncoding(arrayP) psobj *arrayP; { scan_token(inputP); if ((tokenType == TOKEN_NAME) && (((tokenLength==16) && (!strncmp(tokenStartP,"StandardEncoding",16))) || (((tokenLength==17) && (!strncmp(tokenStartP,"ISOLatin1Encoding",17)))))) { /* Adobe Standard Encoding */ if (tokenLength == 16) arrayP->data.valueP = (char *) StdEncArrayP; else arrayP->data.valueP = (char *) ISOLatin1EncArrayP; arrayP->len = 256; return(SCAN_OK); } else if ( (tokenType == TOKEN_LEFT_BRACE) || (tokenType == TOKEN_LEFT_BRACKET) ) { /* Array of literal names */ psobj *objP; int i; objP = (psobj *)vm_alloc(256*(sizeof(psobj))); if (!(objP)) return(SCAN_OUT_OF_MEMORY); arrayP->data.valueP = (char *) objP; arrayP->len = 256; for (i=0; i<256; i++, objP++) { scan_token(inputP); if (tokenType != TOKEN_LITERAL_NAME) return(SCAN_ERROR); if (!(vm_alloc(tokenLength)) ) return(SCAN_OUT_OF_MEMORY); objFormatName(objP,tokenLength,tokenStartP); } scan_token(inputP); if ( (tokenType == TOKEN_RIGHT_BRACE) || (tokenType == TOKEN_RIGHT_BRACKET) ) return(SCAN_OK); } else { /* Must be sequences of ``dup put" */ psobj *objP; int i; objP = (psobj *)vm_alloc(256*(sizeof(psobj))); if (!(objP)) return(SCAN_OUT_OF_MEMORY); arrayP->data.valueP = (char *) objP; arrayP->len = 256; for (i=0; i<256; i++) objFormatName(objP + i, 7, ".notdef"); while (TRUE) { scan_token(inputP); switch (tokenType) { case TOKEN_NAME: if (tokenLength == 3) { if (strncmp(tokenStartP,"dup",3) == 0) { /* get */ scan_token(inputP); if (tokenType != TOKEN_INTEGER || tokenValue.integer < 0 || tokenValue.integer > 255) return (SCAN_ERROR); i = tokenValue.integer; /* get */ scan_token(inputP); if (tokenType != TOKEN_LITERAL_NAME) return(SCAN_ERROR); if (!(vm_alloc(tokenLength)) ) return(SCAN_OUT_OF_MEMORY); objFormatName(objP + i,tokenLength,tokenStartP); /* get "put" */ scan_token(inputP); if (tokenType != TOKEN_NAME) return(SCAN_ERROR); } else if (strncmp(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(arrayP) psobj *arrayP; { int N; /* count the items in the array */ psobj *objP; scan_token(inputP); if ( (tokenType != TOKEN_LEFT_BRACE) && (tokenType != TOKEN_LEFT_BRACKET) ) { return(SCAN_ERROR); } /* format the array in memory, save pointer to the beginning */ arrayP->data.valueP = tokenStartP; /* loop, picking up next object, until right BRACE or BRACKET */ N = 0; do { scan_token(inputP); if ( (tokenType == TOKEN_RIGHT_BRACE) || (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(sizeof(psobj)); if (!(objP)) return(SCAN_OUT_OF_MEMORY); /* array is an array of numbers, (real or integer) */ if (tokenType == TOKEN_REAL) { objFormatReal(objP, tokenValue.real); } else if (tokenType == TOKEN_INTEGER) { objFormatInteger(objP, tokenValue.integer); } else return(SCAN_ERROR); N++; } while ( 1>0 ); /* NOTREACHED*/ } /***================================================================***/ static int getName(nameP) char *nameP; { do { scan_token(inputP); if (tokenType <= TOKEN_NONE) { if (tokenTooLong) return(SCAN_OUT_OF_MEMORY); return(SCAN_ERROR); } } while ((tokenType != TOKEN_NAME) || (0 != strncmp(tokenStartP,nameP,strlen(nameP))) ); /* found */ return(SCAN_OK); } /***================================================================***/ static int getNbytes(N) int N; { int I; if (N > vm_free_bytes()) { if (!vm_init()) return(SCAN_OUT_OF_MEMORY); } tokenStartP = vm_next_byte(); I = fread(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(nameObjP) psobj *nameObjP; { do { scan_token(inputP); if (tokenType <= TOKEN_NONE) { if (tokenTooLong) return(SCAN_OUT_OF_MEMORY); return(SCAN_ERROR); } if (tokenType == TOKEN_NAME) { if (0 == strncmp(tokenStartP,"end",3) ) { return(SCAN_END); } } } while (tokenType != TOKEN_LITERAL_NAME) ; nameObjP->len = tokenLength; /* allocate all the names in the CharStrings Structure */ if (!(vm_alloc(tokenLength)) ) return(SCAN_OUT_OF_MEMORY); nameObjP->data.valueP = tokenStartP; /* found */ return(SCAN_OK); } /***================================================================***/ /* * BuildSubrs routine */ /***================================================================***/ static int BuildSubrs(FontP) 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(); if (rc) return(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;iSubrs.len = N; FontP->Subrs.data.arrayP = arrayP; /* get N values for Subrs */ for (i=0;iCharStringsP = dictP; dictP[0].key.len = N; /* get N values for CharStrings */ for (i=1;i<=N;i++) { /* look for next literal name */ rc = getLiteralName(&(dictP[i].key)); if (rc) return(rc); /* get 1 integer */ J = getInt(); if (rc) return(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 */ rc = getNextValue(TOKEN_NAME); if ( rc != SCAN_OK ) return(rc); rc = getNbytes(J); if (rc == SCAN_OK) { dictP[i].value.data.valueP = tokenStartP; if ( !(vm_alloc(J)) ) return(SCAN_OUT_OF_MEMORY); } else return(rc); } return(SCAN_OK); } /***================================================================***/ /***================================================================***/ /* * BuildFontInfo Dictionary */ /***================================================================***/ static int BuildFontInfo(fontP) psfont *fontP; { psdict *dictP; /* allocate the private dictionary */ dictP = (psdict *)vm_alloc(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(fontP) psfont *fontP; { psdict *Private; /* allocate the private dictionary */ Private = (psdict *)vm_alloc(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(fontP) 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(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(fontP, code) 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 (StdEncArrayP == NULL) { return(NULL); } /* use the code to index into the standard encoding vector */ charnameP = &(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(dictP) 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,tokenLength,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(&(dictP[N].value)); if ( V != SCAN_OK ) return(V); break; case OBJ_ARRAY: V = getArray(&(dictP[N].value)); if ( V != SCAN_OK ) return(V); break; case OBJ_INTEGER: /* next value in integer */ dictP[N].value.data.integer = getInt(); if (rc) return(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(inputP); if (tokenType == TOKEN_REAL) { dictP[N].value.data.real = tokenValue.real; } else if (tokenType == TOKEN_INTEGER) { dictP[N].value.data.real = tokenValue.integer; } else return(SCAN_ERROR); break; case OBJ_NAME: V = getNextValue(TOKEN_LITERAL_NAME); if ( V != SCAN_OK ) return(V); if (!(vm_alloc(tokenLength)) ) return(SCAN_OUT_OF_MEMORY); objFormatName(&(dictP[N].value),tokenLength,tokenStartP); break; case OBJ_STRING: V = getNextValue(TOKEN_STRING); if ( V != SCAN_OK ) return(V); if (!(vm_alloc(tokenLength)) ) return(SCAN_OUT_OF_MEMORY); objFormatString(&(dictP[N].value),tokenLength,tokenStartP); break; case OBJ_BOOLEAN: scan_token(inputP); if (tokenType != TOKEN_NAME) { return(SCAN_ERROR); } if (0 == strncmp(tokenStartP,"true",4) ) { dictP[N].value.data.boolean =TRUE; } else if (0 == strncmp(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(FontP) psfont *FontP; { char filename[128]; char filetype[3]; FILE *fileP; char *nameP; int namelen; int V; int i; boolean starthex80; starthex80 = FALSE; filetype[0] = 'r'; filetype[1] = 'b'; filetype[2] = '\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 = fopen(filename,filetype)) { /* get the first byte of file */ V = getc(fileP); /* if file starts with x'80' then skip next 5 bytes */ if ( V == 0X80 ) { for (i=0;i<5;i++) V = getc(fileP); starthex80 = TRUE; } else ungetc(V,fileP); objFormatFile(inputP,fileP); } else { return(SCAN_FILE_OPEN_ERROR); }; WantFontInfo = TRUE; InPrivateDict = FALSE; TwoSubrs = FALSE; rc = BuildFontInfo(FontP); if (rc != 0) return(rc); /* Assume everything will be OK */ rc = 0; /* Loop until complete font is read */ do { /* Scan the next token */ scan_token(inputP); /* ==> tokenLength, tokenTooLong, tokenType, and tokenValue are */ /* now set */ switch (tokenType) { case TOKEN_EOF: case TOKEN_NONE: case TOKEN_INVALID: /* in this case we are done */ if (tokenTooLong) return(SCAN_OUT_OF_MEMORY); rc = SCAN_ERROR; break; case TOKEN_LITERAL_NAME: /* Look up the name */ tokenStartP[tokenLength] = '\0'; if (InPrivateDict ) { if (0== strncmp(tokenStartP,"Subrs",5) ) { rc = BuildSubrs(FontP); break; } if (0== strncmp(tokenStartP,"CharStrings",11) ) { rc = BuildCharStrings(FontP); if ( (rc == SCAN_OK) ||(rc == SCAN_END) ) { fclose(inputP->data.fileP); /* Build the Blues Structure */ rc = GetType1Blues(FontP); /* whatever the return code, return it */ /* all the work is done. This is the normal exit.*/ return(rc); } break; } rc = FindDictValue(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*/ rc = SCAN_OK; break; } /* end of reading Private dictionary */ else if (0== strncmp(tokenStartP,"Private",7) ) { InPrivateDict = TRUE; rc = BuildPrivate(FontP); break; } else if (WantFontInfo) { rc = FindDictValue(FontP->fontInfoP); /* we are not going to report errors */ rc = SCAN_OK; break; } break; case TOKEN_NAME: if (0 == strncmp(tokenStartP,"eexec",5) ) { /* if file started with x'80', check next 5 bytes */ if (starthex80) { V = getc(fileP); if ( V == 0X80 ) { for (i=0;i<5;i++) V = getc(fileP); } else ungetc(V,fileP); } filterFile.data.fileP = T1eexec(inputP->data.fileP); if (filterFile.data.fileP == NULL) { fclose(inputFile.data.fileP); return(SCAN_FILE_OPEN_ERROR); } inputP = &filterFile; WantFontInfo = FALSE; } break; } } while (rc ==0); fclose(inputP->data.fileP); if (tokenTooLong) return(SCAN_OUT_OF_MEMORY); return(rc); }