windows-nt/Source/XPSP1/NT/shell/osshell/control/t1instal/t1instal.c
2020-09-26 16:20:57 +08:00

1724 lines
39 KiB
C

/***
**
** Module: T1Instal
**
** Description:
** This is the Win32 DLL (t1instal.dll) interface to the
** font converter. All window specific code is located in
** this module and the error hadler module (errors.c).
**
** Author: Michael Jansson
** Created: 12/18/93
**
***/
/***** INCLUDES */
#include "windows.h"
#include <string.h>
#include <time.h>
#include <limits.h>
#include <ctype.h>
#undef IN
#include "titott.h"
#include "types.h"
#include "t1local.h"
#include "t1instal.h"
#include "fileio.h"
#include "safemem.h"
#include "t1msg.h"
#undef UNICODE
/* The CopyrightCheck/MAYBEOK case always succeeds for now. */
#define MAYBEOK SUCCESS
/***** LOCAL TYPES */
struct callFrame {
const void (STDCALL *Progress)(short, void*);
void *arg;
int last;
int done;
};
static short lastCP = FALSE;
static char lastVendor[256] = "Unknown.";
/***** CONSTANTS */
#define MIN_PROGRESS 3
#define DELIMITERS " ,"
#define COPYSIGN 169
#define TRUE 1
#define FALSE 0
#define DFFACE 139
#define DFDRIVERINFO 101
#define VERSTR "Converter: Windows Type 1 Installer V1.0d.\n" \
"Font: V"
const char version[] = "\n$VER: 1.0d\n";
#ifndef NOANSIWINMAC
const char *winmac[] = {
"A",
"AE",
"Aacute",
"Acircumflex",
"Adieresis",
"Agrave",
"Aring",
"Atilde",
"B",
"C",
"Cacute",
"Ccaron",
"Ccedilla",
"D",
"Delta",
"E",
"Eacute",
"Ecircumflex",
"Edieresis",
"Egrave",
"Eth",
"F",
"G",
"Gbreve",
"H",
"I",
"Iacute",
"Icircumflex",
"Idieresis",
"Idot",
"Igrave",
"J",
"K",
"L",
"Lslash",
"M",
"N",
"Ntilde",
"O",
"OE",
"Oacute",
"Ocircumflex",
"Odieresis",
"Ograve",
"Oslash",
"Otilde",
"P",
"Q",
"R",
"S",
"Scaron",
"Scedilla",
"T",
"Thorn",
"U",
"Uacute",
"Ucircumflex",
"Udieresis",
"Ugrave",
"V",
"W",
"X",
"Y",
"Yacute",
"Ydieresis",
"Z",
"a",
"aacute",
"acircumflex",
"acute",
"adieresis",
"ae",
"agrave",
"ampersand",
"approxequal",
"aring",
"asciicircum",
"asciitilde",
"asterisk",
"at",
"atilde",
"b",
"backslash",
"bar",
"braceleft",
"braceright",
"bracketleft",
"bracketright",
"breve",
"brokenbar",
"bullet",
"c",
"cacute",
"caron",
"ccaron",
"ccedilla",
"cedilla",
"cent",
"circumflex",
"colon",
"comma",
"copyright",
"currency",
"d",
"dagger",
"daggerdbl",
"degree",
"dieresis",
"divide",
"dmacron",
"dollar",
"dotaccent",
"dotlessi",
"e",
"eacute",
"ecircumflex",
"edieresis",
"egrave",
"eight",
"ellipsis",
"emdash",
"endash",
"equal",
"eth",
"exclam",
"exclamdown",
"f",
"fi",
"five",
"fl",
"florin",
"four",
"fraction",
"franc",
"g",
"gbreve",
"germandbls",
"grave",
"greater",
"greaterequal",
"guillemotleft",
"guillemotright",
"guilsinglleft",
"guilsinglright",
"h",
"hungerumlaut",
"hyphen",
"i",
"iacute",
"icircumflex",
"idieresis",
"igrave",
"infinity",
"integral",
"j",
"k",
"l",
"less",
"lessequal",
"logicalnot",
"lozenge",
"lslash",
"m",
"macron",
"middot",
"minus",
"mu",
"multiply",
"n",
"nbspace",
"nine",
"notequal",
"ntilde",
"numbersign",
"o",
"oacute",
"ocircumflex",
"odieresis",
"oe",
"ogonek",
"ograve",
"ohm",
"one",
"onehalf",
"onequarter",
"onesuperior",
"ordfeminine",
"ordmasculine",
"oslash",
"otilde",
"overscore",
"p",
"paragraph",
"parenleft",
"parenright",
"partialdiff",
"percent",
"period",
"periodcentered",
"perthousand",
"pi",
"plus",
"plusminus",
"product",
"q",
"question",
"questiondown",
"quotedbl",
"quotedblbase",
"quotedblleft",
"quotedblright",
"quoteleft",
"quoteright",
"quotesinglbase",
"quotesingle",
"r",
"radical",
"registered",
"ring",
"s",
"scaron",
"scedilla",
"section",
"semicolon",
"seven",
"sfthyphen",
"six",
"slash",
"space",
"sterling",
"summation",
"t",
"thorn",
"three",
"threequarters",
"threesuperior",
"tilde",
"trademark",
"two",
"twosuperior",
"u",
"uacute",
"ucircumflex",
"udieresis",
"ugrave",
"underscore",
"v",
"w",
"x",
"y",
"yacute",
"ydieresis",
"yen",
"z",
"zero"
};
#define GLYPHFILTER &win
const struct GlyphFilter win = {
sizeof(winmac) / sizeof(winmac[0]),
winmac
};
#else
#define GLYPHFILER (struct GlyphFilter *)0
#endif /* NOANSIWINMAC */
/***** PROTOTYPES */
extern int __cdecl sprintf(char *, const char *, ...);
/***** MACROS */
#define ReadLittleEndianDword(file,dw) { \
dw = (DWORD)io_ReadOneByte(file) ; \
dw |= (DWORD)io_ReadOneByte(file) << 8; \
dw |= (DWORD)io_ReadOneByte(file) << 16; \
dw |= (DWORD)io_ReadOneByte(file) << 24; \
}
#ifndef try
#define try __try
#define except __except
#endif
/***** GLOBALS */
HANDLE hInst;
/***** STATIC FUNCTIONS */
/***
** Function: Decrypt
**
** Description:
** Decrypt a byte.
***/
static DWORD CSum(char *str)
{
DWORD sum = 0;
while (*str)
sum += *str++;
return sum;
}
/***
** Function: Decrypt
**
** Description:
** Decrypt a byte.
***/
static char *Encrypt(char *str, char *out)
{
const USHORT c1 = 52845;
const USHORT c2 = 22719;
UBYTE cipher;
USHORT r = 8366;
int i;
for (i=0; i<(int)strlen(str); i++) {
cipher = (UBYTE)(str[i] ^ (r>>8));
r = (USHORT)((cipher + r) * c1 + c2);
out[i] = (char)((cipher & 0x3f) + ' ');
/* Unmap 'bad' characters, that the Registry DB doesn't like. */
if (out[i]=='=' || out[i]==' ' || out[i]=='@' || out[i]=='"')
out[i] = 'M';
}
out[i] = '\0';
return out;
}
static char *stristr(char *src, char *word)
{
int len = strlen(word);
char *tmp = src;
while (*src) {
if (!_strnicmp(src, word, len))
break;
src++;
}
return src;
}
/***
** Function: GetCompany
**
** Description:
** Extract the company name out of a copyright string.
***/
char *GetCompany(char *buf)
{
char *company = NULL;
int done = FALSE;
UBYTE *token;
UBYTE *tmp1;
UBYTE *tmp2;
UBYTE *tmp3;
UBYTE *tmp4;
int i;
token = buf;
while (token && !done) {
/* Locate the start of the copyright string. */
tmp1 = stristr(token, "copyright");
tmp2 = stristr(token, "(c)");
tmp3 = stristr(token, " c ");
if ((tmp4 = strchr(token, COPYSIGN))==NULL)
tmp4 = &token[strlen(token)];
if (*tmp1==0 && *tmp2==0 && *tmp3==0 && *tmp4==0) {
token = NULL;
break;
} else if (tmp1<tmp2 && tmp1<tmp3 && tmp1<tmp4)
token = tmp1;
else if (tmp2<tmp3 && tmp2<tmp4)
token = tmp2;
else if (tmp3<tmp4)
token = tmp3;
else
token = tmp4;
/* Skip the leading copyright strings/character. */
if (token[0]==COPYSIGN && token[1]!='\0') {
token += 2;
} else if (!_strnicmp(token, "copyright", strlen("copyright"))) {
token += strlen("copyright");
} else {
token += strlen("(c)");
}
/* Skip blanks. */
while(*token && isspace(*token) || *token==',')
token++;
/* Another copyright word? */
if (!_strnicmp((char*)token, "(c)", strlen("(c)")) ||
!_strnicmp((char*)token, "copyright", strlen("copyright")) ||
token[0]==COPYSIGN)
continue;
/* Skip the years. */
company = token;
if (isdigit(token[0])) {
while (isdigit(*company) || isspace(*company) ||
ispunct(*company) || (*company)=='-')
company++;
if (*company=='\0')
break;
/* Skip strings like "by", up to the beginning of a name that */
/* starts with an upper case letter. */
while (*company && (company[0]<'A' || company[0]>'Z'))
company++;
done = TRUE;
} else {
continue;
}
}
/* Did we find it? */
if (company) {
while (*company && isspace(*company))
company++;
if (*company=='\0') {
company=NULL;
} else {
/* Terminate the company name. */
if ((token = (UBYTE*)strchr(company, '.'))!=NULL) {
/* Period as an initial delimiter, e.g. James, A. B. ?*/
if (token[-1]>='A' && token[-1]<='Z') {
if (strchr((char*)&token[1], '.'))
token = (UBYTE*)strchr((char*)&token[1], '.');
/* Check for "James A. Bently, " */
else if (strchr((char*)&token[1], ',')) {
token = (UBYTE*)strchr((char*)&token[1], ',');
token[0] = '.';
}
}
token[1] = '\0';
} else {
/* Name ending with a ';'? */
if ((token = (UBYTE*)strrchr(company, ';'))) {
*token = '\0';
}
}
/* Truncate some common strings. */
tmp1 = stristr(company, "all rights reserved");
*tmp1 = '\0';
/* Remove trailing punctuation character. */
for (i=strlen(company)-1; i>0 &&
(ispunct(company[i]) || isspace(company[i])); i--) {
company[i] = 0;
}
}
}
return company;
}
/**** FUNCTIONS */
/***
** Function: ConvertAnyway
**
** Description:
** Ask the user if it is ok to convert.
***/
static errcode ConvertAnyway(const char *vendor, const char *facename)
{
char tmp[256];
char msg[1024];
errcode answer;
if (vendor==NULL || strlen(vendor)==0) {
LoadString(hInst, IDS_RECOGNIZE1, tmp, sizeof(tmp));
sprintf(msg, tmp, facename);
} else {
LoadString(hInst, IDS_RECOGNIZE2, tmp, sizeof(tmp));
sprintf(msg, tmp, facename, vendor);
}
LoadString(hInst, IDS_MAINMSG, tmp, sizeof(tmp));
strcat(msg, tmp);
LoadString(hInst, IDS_CAPTION, tmp, sizeof(tmp));
answer = (errcode)MessageBox(NULL, msg, tmp, QUERY);
SetLastError(0);
return answer;
}
/***
** Function: CheckCopyright
**
** Description:
** This is the callback function that verifies that
** the converted font is copyrighted by a company who
** has agreed to having their fonts converted by
** this software. These companies are registered in the
** registry data base.
***/
static errcode CheckCopyright(const char *facename,
const char *copyright,
const char *notice)
{
#ifdef NOCOPYRIGHTS
return SKIP;
#else
HKEY key;
char tmp[256];
char *company = NULL;
char buf[1024];
int done = FALSE;
short result = FAILURE;
/* Access the REG data base. */
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, SUBKEY_TYPE1COPYRIGHTS, 0,
KEY_QUERY_VALUE, &key)==ERROR_SUCCESS) {
/* Look for the company name in the /notice string. */
if (notice && notice[0]) {
strcpy(buf, notice);
company = GetCompany(buf);
}
/* Look in the /copyright string if the company name was not found. */
if (company==NULL && copyright && copyright[0]) {
strcpy(buf, copyright);
company = GetCompany(buf);
}
#ifdef SHOWCOPYRIGHTS
LogError(MSG_INFO, MSG_Copyright, company);
Encrypt(company, tmp);
sprintf(&tmp[strlen(tmp)], "(%d)\n", CSum(tmp));
LogError(MSG_INFO, MSG_Encoding, tmp);
#else
/* Did not find a company name? */
if (company==NULL &&
((notice==NULL || notice[0]=='\0'||
strstr(notice, "Copyright")==NULL) &&
(copyright==NULL || copyright[0]=='\0' ||
strstr(copyright, "Copyright")==NULL))) {
/* No known copyright. */
LogError(MSG_WARNING, MSG_NOCOPYRIGHT, NULL);
result = MAYBEOK;
/* Strange copyright format? */
} else if (company==NULL || company[0]=='\0') {
if (notice || notice[0])
LogError(MSG_WARNING, MSG_BADFORMAT, notice);
else
LogError(MSG_WARNING, MSG_BADFORMAT, copyright);
result = MAYBEOK;
/* Found copyright! */
} else {
DWORD size;
DWORD csum;
size = 4;
if (RegQueryValueEx(key, Encrypt(company, tmp), NULL, NULL,
(LPBYTE)&csum, &size)==ERROR_SUCCESS) {
/* A positive match -> ok to convert. */
if (CSum(tmp)==csum) {
LogError(MSG_INFO, MSG_COPYRIGHT, company);
result = SUCCESS;
} else {
LogError(MSG_ERROR, MSG_BADCOPYRIGHT, company);
result = SKIP;
}
} else {
LogError(MSG_WARNING, MSG_BADCOPYRIGHT, company);
result = MAYBEOK;
}
}
#endif
RegCloseKey(key);
/* Give the user the final word. */
if (result==FAILURE) {
if (ConvertAnyway(company, facename)==TRUE)
result = SUCCESS;
}
/* No copyright key in the registry? */
} else {
LogError(MSG_ERROR, MSG_NODB, NULL);
result = FAILURE;
}
return result;
#endif
}
/***
** Function: NTCheckCopyright
**
** Description:
** This is the callback function that verifies that
** the converted font is copyrighted by a company who
** has agreed to having their fonts converted by
** this software. These companies are registered in the
** registry data base.
***/
static errcode NTCheckCopyright(const char *facename,
const char *copyright,
const char *notice)
{
HKEY key;
char tmp[256];
char *company = NULL;
char buf[1024];
int done = FALSE;
short result = FAILURE;
/* Access the REG data base. */
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, SUBKEY_TYPE1COPYRIGHTS, 0,
KEY_QUERY_VALUE, &key)==ERROR_SUCCESS) {
/* Look for the company name in the /notice string. */
if (notice && notice[0]) {
strcpy(buf, notice);
company = GetCompany(buf);
}
/* Look in the /copyright string if the company name was not found. */
if (company==NULL && copyright && copyright[0]) {
strcpy(buf, copyright);
company = GetCompany(buf);
}
/* Did not find a company name? */
if (company==NULL &&
((notice==NULL || notice[0]=='\0'||
strstr(notice, "Copyright")==NULL) &&
(copyright==NULL || copyright[0]=='\0' ||
strstr(copyright, "Copyright")==NULL))) {
/* No known copyright. */
result = MAYBE;
/* Strange copyright format? */
} else if (company==NULL || company[0]=='\0') {
result = MAYBE;
/* Found copyright! */
} else {
DWORD size;
DWORD csum;
/* remember for future use. */
strncpy(lastVendor, company, 256);
lastVendor[MIN(255, strlen(company))] = '\0';
size = 4;
if (RegQueryValueEx(key, Encrypt(company, tmp), NULL, NULL,
(LPBYTE)&csum, &size)==ERROR_SUCCESS) {
/* A positive match -> ok to convert. */
if (CSum(tmp)==csum) {
result = SUCCESS;
} else {
result = FAILURE;
}
} else {
result = MAYBE;
}
}
RegCloseKey(key);
/* No copyright key in the registry? */
} else {
result = FAILURE;
}
lastCP = result;
return FAILURE;
}
/***
** Function: _Progress
**
** Description:
** This is the internal progress callback function that
** computes an percentage-done number, based on the
** number of converted glyphs.
***/
static void _Progress(short type, void *generic, void *arg)
{
struct callFrame *f = arg;
/* Processing glyphs or wrapping up? */
if (type==0 || type==1)
f->done++;
else
f->done = MIN(sizeof(winmac)/sizeof(winmac[0]), f->done+10);
if ((f->done-f->last)>MIN_PROGRESS) {
f->Progress((short)(f->done*100/(sizeof(winmac)/sizeof(winmac[0]))),
f->arg);
f->last = f->done;
}
UNREFERENCED_PARAMETER(type);
UNREFERENCED_PARAMETER(generic);
SetLastError(0L);
}
static BOOL ReadStringFromOffset(struct ioFile *file,
const DWORD dwOffset,
char *pszString,
int cLen,
BOOL bStrip)
{
BOOL result = TRUE;
DWORD offset;
/* Get offset to string. */
io_FileSeek(file, dwOffset);
/* Read the offset. */
ReadLittleEndianDword(file, offset);
/* Get the string. */
(void)io_FileSeek(file, offset);
if (io_FileError(file) != SUCCESS) {
result = FALSE;
} else {
int i;
i=0;
while (io_FileError(file)==SUCCESS && i<cLen) {
pszString[i] = (UBYTE)io_ReadOneByte(file);
if (pszString[i]=='\0')
break;
/* Replace all dashes with spaces. */
if (bStrip && pszString[i]=='-')
pszString[i]=' ';
i++;
}
}
return TRUE;
}
/**** FUNCTIONS */
/***
** Function: ConvertTypeFaceA
**
** Description:
** Convert a T1 font into a TT font file. This is the
** simplified interface used by the Win32 DLL, with the
** ANSI interface.
***/
short STDCALL ConvertTypefaceAInternal(const char *type1,
const char *metrics,
const char *truetype,
const void (STDCALL *Progress)(short, void*),
void *arg)
{
struct callFrame f;
struct callProgress p;
struct T1Arg t1Arg;
struct TTArg ttArg;
short status;
/* Check parameters. */
if (type1==NULL || metrics==NULL)
return FAILURE;
/* Set up arguments to ConvertTypefaceA() */
t1Arg.filter = GLYPHFILTER;
t1Arg.upem = (short)2048;
t1Arg.name = (char *)type1;
t1Arg.metrics = (char *)metrics;
ttArg.precision = (short)50;
ttArg.name = (char *)truetype;
ttArg.tag = VERSTR;
/* Use progress gauge */
if (Progress) {
LogError(MSG_INFO, MSG_STARTING, type1);
f.Progress = Progress;
f.done = 0;
f.last = 0;
f.arg = arg;
p.arg = &f;
p.cb = _Progress;
status = ConvertT1toTT(&ttArg, &t1Arg, CheckCopyright, &p);
Progress(100, arg);
} else {
status = ConvertT1toTT(&ttArg, &t1Arg, CheckCopyright, NULL);
}
return status;
}
short STDCALL ConvertTypefaceA(const char *type1,
const char *metrics,
const char *truetype,
const void (STDCALL *Progress)(short, void*),
void *arg)
{
short bRet;
try
{
bRet = ConvertTypefaceAInternal(type1,
metrics,
truetype,
Progress,
arg);
}
except (EXCEPTION_EXECUTE_HANDLER)
{
#if 0
ASSERTGDI(
GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR,
"ttfd!ttfdSemLoadFontFile, strange exception code\n"
);
#endif
bRet = BADINPUTFILE;
}
return bRet;
}
short STDCALL FindPfb (
char *pszPFM,
char *achPFB
);
/***
** Function: CheckPfmA
**
** Description:
** This function determines if there is a pfm/pfb pair of
** files that makes up an Adobe Type 1 font, and determins
** the descriptive face name of it.
**
** Returns: 16-bit encoded value indicating error and type of file where
** error occurred. (see fvscodes.h) for definitions.
** The following table lists the "status" portion of the codes
** returned.
**
** FVS_SUCCESS
** FVS_INVALID_FONTFILE
** FVS_FILE_OPEN_ERR
** FVS_INVALID_ARG
** FVS_FILE_IO_ERR
** FVS_BAD_VERSION
***/
short STDCALL CheckPfmA(
char *pszPFM,
DWORD cjDesc,
char *pszDesc,
DWORD cjPFB,
char *pszPFB
)
{
struct ioFile *file;
char szDriver[MAX_PATH];
short result = FVS_MAKE_CODE(FVS_SUCCESS, FVS_FILE_UNK);
short ver;
char achPFB[MAX_PATH];
char *psz_PFB;
DWORD cjPFB1;
if (pszPFB)
{
psz_PFB = pszPFB;
cjPFB1 = cjPFB;
}
else
{
psz_PFB = (char *)achPFB;
cjPFB1 = MAX_PATH;
}
/* Check parameter. */
if (pszPFM==NULL || ((strlen(pszPFM)+3) >= cjPFB1))
return FVS_MAKE_CODE(FVS_INVALID_ARG, FVS_FILE_UNK);
// check if pfb file exists and find the path to it:
result = FindPfb(pszPFM, psz_PFB);
if (FVS_STATUS(result) != FVS_SUCCESS)
return result;
/****
* Locate the pszDescriptive name of the font.
*/
if ((file = io_OpenFile(pszPFM, READONLY))==NULL)
return FVS_MAKE_CODE(FVS_FILE_OPEN_ERR, FVS_FILE_PFM);
(void)io_ReadOneByte(file); /* Skip the revision number. */
ver = (short)io_ReadOneByte(file);
if (ver > 3) {
/* ERROR - unsupported format */
result = FVS_MAKE_CODE(FVS_BAD_VERSION, FVS_FILE_PFM);
} else {
/* Read the driver name. */
if (!ReadStringFromOffset(file, DFDRIVERINFO, szDriver,
sizeof(szDriver), FALSE))
{
result = FVS_MAKE_CODE(FVS_FILE_IO_ERR, FVS_FILE_PFM);
}
/* Is it "PostScript" ? */
else if (_stricmp(szDriver, "PostScript"))
{
result = FVS_MAKE_CODE(FVS_INVALID_FONTFILE, FVS_FILE_PFM);
}
/* Only get description if asked to do so. */
else if (pszDesc && !ReadStringFromOffset(file, DFFACE, pszDesc, cjDesc, TRUE))
{
result = FVS_MAKE_CODE(FVS_FILE_IO_ERR, FVS_FILE_PFM);
}
}
(void)io_CloseFile(file);
return result;
}
/***
** Function: DllMain
**
** Description:
** Main function of the DLL. Use to cache the module handle,
** which is needed to pop-up messages and peek in the registry.
***/
BOOL WINAPI DllMain(PVOID hmod,
ULONG ulReason,
PCONTEXT pctx OPTIONAL)
{
if (ulReason == DLL_PROCESS_ATTACH) {
hInst = hmod;
DisableThreadLibraryCalls(hInst);
}
UNREFERENCED_PARAMETER(pctx);
return TRUE;
}
/***
** Function: CheckCopyrightsA
**
** Description:
** This function verifies that it is ok to convert the font. This is
** done by faking an installation.
***/
short STDCALL CheckCopyrightAInternal(const char *szPFB,
const DWORD wSize,
char *szVendor)
{
struct T1Arg t1Arg;
struct TTArg ttArg;
/* Set up arguments to ConvertTypefaceA() */
t1Arg.metrics = NULL;
t1Arg.upem = (short)2048;
t1Arg.filter = GLYPHFILTER;
t1Arg.name = szPFB;
ttArg.precision = (short)200;
ttArg.tag = NULL;
ttArg.name = "NIL:";
lastCP = FAILURE;
strcpy(lastVendor, "");
(void)ConvertT1toTT(&ttArg, &t1Arg, NTCheckCopyright, NULL);
strncpy(szVendor, lastVendor, wSize);
szVendor[MIN(wSize, strlen(lastVendor))] = '\0';
return lastCP;
}
short STDCALL CheckCopyrightA(const char *szPFB,
const DWORD wSize,
char *szVendor)
{
short iRet;
try
{
iRet = CheckCopyrightAInternal(szPFB,wSize,szVendor);
}
except (EXCEPTION_EXECUTE_HANDLER)
{
iRet = BADINPUTFILE;
}
return iRet;
}
/******************************Public*Routine******************************\
*
* short STDCALL CheckInfA (
*
* If pfm and inf files are in the same directory only pfm is recognized
* and inf file is ignored.
*
* History:
* 27-Apr-1994 -by- Bodin Dresevic [BodinD]
* Wrote it.
*
* Returns: 16-bit encoded value indicating error and type of file where
* error occurred. (see fvscodes.h) for definitions.
* The following table lists the "status" portion of the codes
* returned.
*
* FVS_SUCCESS
* FVS_INVALID_FONTFILE
* FVS_FILE_OPEN_ERR
* FVS_FILE_BUILD_ERR
* FVS_FILE_EXISTS
* FVS_INSUFFICIENT_BUF
*
\**************************************************************************/
short CreatePFM(char *pszINF, char *pszAFM, char *pszPFM);
BOOL bGetDescFromInf(char * pszINF, DWORD cjDesc, char *pszDesc);
BOOL bFileExists(char *pszFile)
{
HFILE hf;
if ((hf = _lopen(pszFile, OF_READ)) != -1)
{
_lclose(hf);
return TRUE;
}
return FALSE;
}
short STDCALL CheckInfA (
char *pszINF,
DWORD cjDesc,
char *pszDesc,
DWORD cjPFM,
char *pszPFM,
DWORD cjPFB,
char *pszPFB,
BOOL *pbCreatedPFM,
char *pszFontPath
)
{
char achPFM[MAX_PATH];
char achPFB[MAX_PATH];
char achAFM[MAX_PATH];
DWORD cjKey;
char *pszParent = NULL; // points to the where parent dir of the inf file is
char *pszBare = NULL; // "bare" .inf name, initialization essential
short result = FVS_MAKE_CODE(FVS_SUCCESS, FVS_FILE_UNK);
BOOL bAfmExists = FALSE;
BOOL bPfbExists = FALSE;
//
// This is a real hack use of pbCreatedPFM.
// It's the best solution with the time we have.
//
BOOL bCheckForExistingPFM = *pbCreatedPFM;
*pbCreatedPFM = FALSE;
// example:
// if pszINF -> "c:\psfonts\fontinfo\foo_____.inf"
// then pszParent -> "fontinfo\foo_____.inf"
cjKey = strlen(pszINF) + 1;
if (cjKey < 5) // 5 = strlen(".pfm") + 1;
return FVS_MAKE_CODE(FVS_INVALID_FONTFILE, FVS_FILE_INF);
// check if a pfm file exists in the SAME directory.
// Use the buffer on the stack to produce the path for the pfm file:
strcpy(achPFM, pszINF);
strcpy(&achPFM[cjKey - 5],".PFM");
// try to open pfm file to check if it exists:
if (bCheckForExistingPFM && bFileExists(achPFM))
{
// we found the pfm file, therefore we do not report this .inf file.
return FVS_MAKE_CODE(FVS_FILE_EXISTS, FVS_FILE_PFM);
}
// pfm file is NOT found, go on to check if .afm and .pfb files exists:
// We will first check if .afm and .pfb files exists in the same dir as .inf
strcpy(achAFM, pszINF);
strcpy(&achAFM[cjKey - 5],".AFM");
strcpy(achPFB, pszINF);
strcpy(&achPFB[cjKey - 5],".PFB");
bAfmExists = bFileExists(achAFM);
bPfbExists = bFileExists(achPFB);
if (!bAfmExists || !bPfbExists)
{
// we did not find the .afm and .pfb files in the same dir as .inf
// we will check two more directories for the .afm and .pfb files
// 1) the parent directory of the .inf file for .pfb file
// 2) the afm subdirectory of the .inf parent directory for .afm file
//
// This is meant to handle the standard configuration of files produced
// on user's hard drive by unlocking fonts from Adobe's CD or from a
// previous installation of atm manager on this machine.
// This configuration is as follows:
// c:\psfonts\ *.pfb files are here
// c:\psfonts\afm *.afm files are here
// c:\psfonts\fontinfo *.inf files are here
// c:\psfonts\pfm *.pfm files that are created on the fly
// are PUT here by atm.
// We will instead put the files in windows\system dir where all other
// fonts are, it may not be possible to write pmf files on the media
// from where we are installing fonts
pszBare = &pszINF[cjKey - 5];
for ( ; pszBare > pszINF; pszBare--)
{
if ((*pszBare == '\\') || (*pszBare == ':'))
{
pszBare++; // found it
break;
}
}
// check if full path to .inf file was passed in or a bare
// name itself was passed in to look for .inf file in the current dir
if ((pszBare > pszINF) && (pszBare[-1] == '\\'))
{
// skip '\\' and search backwards for another '\\':
for (pszParent = &pszBare[-2]; pszParent > pszINF; pszParent--)
{
if ((*pszParent == '\\') || (*pszParent == ':'))
{
pszParent++; // found it
break;
}
}
// create .pfb file name in the .inf parent directory:
strcpy(&achPFB[pszParent - pszINF], pszBare);
strcpy(&achPFB[strlen(achPFB) - 4], ".PFB");
// create .afm file name in the afm subdirectory of the .inf
// parent directory:
strcpy(&achAFM[pszParent - pszINF], "afm\\");
strcpy(&achAFM[pszParent - pszINF + 4], pszBare);
strcpy(&achAFM[strlen(achAFM) - 4], ".AFM");
}
else if (pszBare == pszINF)
{
// bare name was passed in, to check for the inf file in the "." dir:
strcpy(achPFB, "..\\");
strcpy(&achPFB[3], pszBare); // 3 == strlen("..\\")
strcpy(&achPFB[strlen(achPFB) - 4], ".PFB");
strcpy(achAFM, "..\\afm\\");
strcpy(&achAFM[7], pszBare); // 7 == strlen("..\\afm\\")
strcpy(&achAFM[strlen(achAFM) - 4], ".AFM");
}
else
{
return FVS_MAKE_CODE(FVS_INVALID_FONTFILE, FVS_FILE_UNK);
}
// check again if we can find the files, if not fail.
if (!bAfmExists && !bFileExists(achAFM))
return FVS_MAKE_CODE(FVS_FILE_OPEN_ERR, FVS_FILE_AFM);
if (!bPfbExists && !bFileExists(achPFB))
return FVS_MAKE_CODE(FVS_FILE_OPEN_ERR, FVS_FILE_PFB);
}
// now we have paths to .inf .afm and .pfb files. Now let us see
// what the caller wants from us:
if (pszDesc)
{
// we need to return description string in the buffer supplied
if (!bGetDescFromInf(pszINF, (DWORD)cjDesc, pszDesc))
return FVS_MAKE_CODE(FVS_INVALID_FONTFILE, FVS_FILE_INF);
}
// copy pfb file path out if requested
if (pszPFB)
{
if ((strlen(achPFB) + 1) < cjPFB)
strcpy(pszPFB,achPFB);
else
return FVS_MAKE_CODE(FVS_INSUFFICIENT_BUF, FVS_FILE_UNK);
}
// the caller wants a pfm file created from inf,afm files
// For now and probably for ever we will put this file in
// the %windir%\system, or %windir%\fonts for the secure system.
if (pszPFM)
{
UINT cjSystemDir;
char *pszAppendHere; // append "bare" name here
// copy the first directory of the font path into the buffer provided
// It is expected that this routine will get something like
// "c:\foo" pointing to font path
strcpy(achPFM,pszFontPath);
pszAppendHere = &achPFM[strlen(pszFontPath) - 1];
if (*pszAppendHere != '\\')
{
pszAppendHere++;
*pszAppendHere = '\\';
}
pszAppendHere++;
// find bare name of the .inf file if we do not have already:
if (!pszBare)
{
pszBare = &pszINF[cjKey - 5];
for ( ; pszBare > pszINF; pszBare--)
{
if ((*pszBare == '\\') || (*pszBare == ':'))
{
pszBare++; // found it
break;
}
}
}
// append Bare name to the %windir%system\ path
strcpy(pszAppendHere, pszBare);
// finally change .inf extension to .pfm extension
strcpy(&pszAppendHere[strlen(pszAppendHere) - 4], ".PFM");
// copy out:
strcpy(pszPFM, achPFM);
result = CreatePFM(pszINF, achAFM, pszPFM);
*pbCreatedPFM = (FVS_STATUS(result) == FVS_SUCCESS);
if (!(*pbCreatedPFM))
return result;
}
return FVS_MAKE_CODE(FVS_SUCCESS, FVS_FILE_UNK);
}
/******************************Public*Routine******************************\
*
* short STDCALL CheckType1AInternal
*
* Effects: See if we are going to report this as a valid type 1 font
*
* Warnings:
*
* History:
* 29-Apr-1994 -by- Bodin Dresevic [BodinD]
* Wrote it.
*
* Returns: 16-bit encoded value indicating error and type of file where
* error occurred. (see fvscodes.h) for definitions.
* The following table lists the "status" portion of the codes
* returned.
*
* FVS_SUCCESS
* FVS_INVALID_FONTFILE
* FVS_FILE_OPEN_ERR
* FVS_FILE_BUILD_ERR
* FVS_INVALID_ARG
* FVS_FILE_IO_ERR
* FVS_BAD_VERSION
* FVS_FILE_EXISTS
* FVS_INSUFFICIENT_BUF
*
\**************************************************************************/
short STDCALL CheckType1AInternal (
char *pszKeyFile,
DWORD cjDesc,
char *pszDesc,
DWORD cjPFM,
char *pszPFM,
DWORD cjPFB,
char *pszPFB,
BOOL *pbCreatedPFM,
char *pszFontPath
)
{
DWORD cjKey;
*pbCreatedPFM = FALSE; // initialization is essential.
cjKey = strlen(pszKeyFile) + 1;
if (cjKey < 5) // 5 = strlen(".pfm") + 1;
return FVS_MAKE_CODE(FVS_INVALID_FONTFILE, FVS_FILE_UNK);
if (!_strcmpi(&pszKeyFile[cjKey - 5], ".PFM"))
{
// copy out pfm string when asked to do so:
if (pszPFM && (cjKey < cjPFM))
{
if (cjKey < cjPFM)
strcpy(pszPFM, pszKeyFile);
else
return FVS_MAKE_CODE(FVS_INSUFFICIENT_BUF, FVS_FILE_UNK);
}
return CheckPfmA(
pszKeyFile,
cjDesc,
pszDesc,
cjPFB,
pszPFB
);
}
else if (!_strcmpi(&pszKeyFile[cjKey - 5], ".INF"))
{
return CheckInfA (
pszKeyFile,
cjDesc,
pszDesc,
cjPFM,
pszPFM,
cjPFB,
pszPFB,
pbCreatedPFM,
pszFontPath
);
}
else
{
// this font is not our friend
return FVS_MAKE_CODE(FVS_INVALID_FONTFILE, FVS_FILE_UNK);
}
}
/******************************Public*Routine******************************\
*
* CheckType1WithStatusA, try / except wrapper
*
* Effects:
*
* Warnings:
*
* History:
* 14-Jun-1994 -by- Bodin Dresevic [BodinD]
* Wrote it.
*
* Returns: 16-bit encoded value indicating error and type of file where
* error occurred. (see fvscodes.h) for definitions.
* The following table lists the "status" portion of the codes
* returned.
*
* FVS_SUCCESS
* FVS_INVALID_FONTFILE
* FVS_FILE_OPEN_ERR
* FVS_FILE_BUILD_ERR
* FVS_INVALID_ARG
* FVS_FILE_IO_ERR
* FVS_BAD_VERSION
* FVS_FILE_EXISTS
* FVS_INSUFFICIENT_BUF
* FVS_EXCEPTION
*
\**************************************************************************/
short STDCALL CheckType1WithStatusA (
char *pszKeyFile,
DWORD cjDesc,
char *pszDesc,
DWORD cjPFM,
char *pszPFM,
DWORD cjPFB,
char *pszPFB,
BOOL *pbCreatedPFM,
char *pszFontPath
)
{
short status;
try
{
status = CheckType1AInternal (
pszKeyFile,
cjDesc,
pszDesc,
cjPFM,
pszPFM,
cjPFB,
pszPFB,
pbCreatedPFM,
pszFontPath);
}
except (EXCEPTION_EXECUTE_HANDLER)
{
status = FVS_MAKE_CODE(FVS_EXCEPTION, FVS_FILE_UNK);
}
return status;
}
/******************************Public*Routine******************************\
*
* CheckType1A, try / except wrapper
*
* Effects:
*
* Warnings:
*
* History:
* 14-Jun-1994 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
BOOL STDCALL CheckType1A (
char *pszKeyFile,
DWORD cjDesc,
char *pszDesc,
DWORD cjPFM,
char *pszPFM,
DWORD cjPFB,
char *pszPFB,
BOOL *pbCreatedPFM,
char *pszFontPath
)
{
short status = CheckType1WithStatusA(pszKeyFile,
cjDesc,
pszDesc,
cjPFM,
pszPFM,
cjPFB,
pszPFB,
pbCreatedPFM,
pszFontPath);
return (FVS_STATUS(status) == FVS_SUCCESS);
}
/******************************Public*Routine******************************\
*
* FindPfb, given pfm file, see if pfb file exists in the same dir or in the
* parent directory of the pfm file
*
* History:
* 14-Jun-1994 -by- Bodin Dresevic [BodinD]
* Wrote it.
*
* Returns: 16-bit encoded value indicating error and type of file where
* error occurred. (see fvscodes.h) for definitions.
* The following table lists the "status" portion of the codes
* returned.
*
* FVS_SUCCESS
* FVS_INVALID_FONTFILE
* FVS_FILE_OPEN_ERR
*
\**************************************************************************/
short STDCALL FindPfb (
char *pszPFM,
char *achPFB
)
{
DWORD cjKey;
char *pszParent = NULL; // points to the where parent dir of the inf file is
char *pszBare = NULL; // "bare" .inf name, initialization essential
// example:
// if pszPFM -> "c:\psfonts\pfm\foo_____.pfm"
// then pszParent -> "pfm\foo_____.pfm"
cjKey = strlen(pszPFM) + 1;
if (cjKey < 5) // 5 = strlen(".pfm") + 1;
return FVS_MAKE_CODE(FVS_INVALID_FONTFILE, FVS_FILE_PFM);
// go on to check if .pfb file exists:
// We will first check .pfb file exists in the same dir as .pfm
strcpy(achPFB, pszPFM);
strcpy(&achPFB[cjKey - 5],".PFB");
if (!bFileExists(achPFB))
{
// we did not find the .pfb file in the same dir as .pfm
// Now check the parent directory of the .pfm file
pszBare = &pszPFM[cjKey - 5];
for ( ; pszBare > pszPFM; pszBare--)
{
if ((*pszBare == '\\') || (*pszBare == ':'))
{
pszBare++; // found it
break;
}
}
// check if full path to .pfm was passed in or a bare
// name itself was passed in to look for .pfm file in the current dir
if ((pszBare > pszPFM) && (pszBare[-1] == '\\'))
{
// skip '\\' and search backwards for another '\\':
for (pszParent = &pszBare[-2]; pszParent > pszPFM; pszParent--)
{
if ((*pszParent == '\\') || (*pszParent == ':'))
{
pszParent++; // found it
break;
}
}
// create .pfb file name in the .pfm parent directory:
strcpy(&achPFB[pszParent - pszPFM], pszBare);
strcpy(&achPFB[strlen(achPFB) - 4], ".PFB");
}
else if (pszBare == pszPFM)
{
// bare name was passed in, to check for the inf file in the "." dir:
strcpy(achPFB, "..\\");
strcpy(&achPFB[3], pszBare); // 3 == strlen("..\\")
strcpy(&achPFB[strlen(achPFB) - 4], ".PFB");
}
else
{
return FVS_MAKE_CODE(FVS_INVALID_FONTFILE, FVS_FILE_PFM); // We should never get here.
}
// check again if we can find the file, if not fail.
if (!bFileExists(achPFB))
{
return FVS_MAKE_CODE(FVS_FILE_OPEN_ERR, FVS_FILE_PFB);
}
}
// now we have paths to .pfb file in the buffer provided by the caller.
return FVS_MAKE_CODE(FVS_SUCCESS, FVS_FILE_UNK);
}