Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

917 lines
19 KiB

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
softfont.c
Abstract:
Functions to support soft fonts (i.e. PostScript Type1 fonts
installed onto the NT system).
[Environment:]
Win32 subsystem, PostScript driver
Revision History:
08/22/95 -davidx-
Created it.
mm/dd/yy -author-
description
--*/
#include "pscript.h"
PSOFTNODE pCachedSoftNodes = NULL;
extern HSEMAPHORE hSoftListSemaphore;
PSOFTNODE CreateSoftNode(TYPE1_FONT*, DWORD, LARGE_INTEGER*);
VOID DeleteSoftNode(PSOFTNODE);
BOOL WritePfbToOutput(PDEVDATA, PBYTE);
INT GetSoftFontEncoding(HANDLE);
INT ExtractEncoding(PSTR, DWORD);
VOID CleanupSoftNodeList(VOID);
VOID
FlushSoftFontCache(
VOID
)
/*++
Routine Description:
Flush out all cached soft font information. This is called
when the driver is unloaded from the system.
Arguments:
NONE
Return Value:
NONE
--*/
{
PSOFTNODE pCurrentNode, pNextNode;
//
// Protect shared global data with a semaphore
//
ACQUIRESEMAPHORE(hSoftListSemaphore);
if ((pCurrentNode = pCachedSoftNodes) != NULL) {
//
// Delete the entire linked-list of soft nodes
//
do {
pNextNode = pCurrentNode->pNext;
DeleteSoftNode(pCurrentNode);
} while ((pCurrentNode = pNextNode) != NULL);
}
pCachedSoftNodes = NULL;
RELEASESEMAPHORE(hSoftListSemaphore);
}
VOID
EnumSoftFonts(
PDEVDATA pdev,
HDEV hdev
)
/*++
Routine Description:
Enumerate the list of soft fonts available to a PDEV.
This includes not only the soft fonts locally on the system
but also the soft fonts from a remote system when EMF
printing is involved.
Arguments:
pdev - Pointer to our DEVDATA structure
hdev - Handle passed to GDI for getting soft font information
Return Value:
NONE
--*/
{
ULONG cLocalFonts, cRemoteFonts;
LARGE_INTEGER lastModified;
TYPE1_FONT *pType1Fonts;
ULONG bufferSize;
PSOFTNODE pSoftNode;
//
// Assume no soft fonts by default
//
pdev->cSoftFonts = pdev->cLocalSoftFonts = 0;
pdev->pLocalSoftNode = pdev->pRemoteSoftNode = NULL;
//
// Ask GDI to find out how many soft fonts there are;
// and allocate memory to hold soft fonts info
//
if (! EngGetType1FontList(hdev, NULL, 0, &cLocalFonts, &cRemoteFonts, &lastModified))
return;
bufferSize = (cLocalFonts + cRemoteFonts) * sizeof(TYPE1_FONT);
if ((pType1Fonts = MEMALLOC(bufferSize)) == NULL)
return;
//
// Ask GDI to retrieve the soft font info
//
if (! EngGetType1FontList(hdev,
pType1Fonts,
bufferSize,
&cLocalFonts,
&cRemoteFonts,
&lastModified))
{
MEMFREE(pType1Fonts);
return;
}
//
// Create a soft node for local soft fonts if necessary
//
if (cLocalFonts > 0) {
ACQUIRESEMAPHORE(hSoftListSemaphore);
//
// If the list of cached soft nodes is empty, then create the first node.
//
if (pCachedSoftNodes == NULL) {
pCachedSoftNodes = CreateSoftNode(pType1Fonts, cLocalFonts, &lastModified);
if (pCachedSoftNodes == NULL) {
MEMFREE(pType1Fonts);
RELEASESEMAPHORE(hSoftListSemaphore);
return;
}
}
//
// Find out if the cached soft nodes are out-of-date.
// We assume the lastModified variable is non-decreasing.
//
if (memcmp(&pCachedSoftNodes->timeStamp,
&lastModified,
sizeof(LARGE_INTEGER)) != EQUAL_STRING)
{
//
// If the cached soft nodes are out-of-date, then we'll create
// a new soft node, insert it at the head of the list, and mark
// existing nodes as out-of-date.
//
pSoftNode = CreateSoftNode(pType1Fonts, cLocalFonts, &lastModified);
if (pSoftNode == NULL) {
MEMFREE(pType1Fonts);
RELEASESEMAPHORE(hSoftListSemaphore);
return;
}
pCachedSoftNodes->flags |= SOFTNODE_OUTOFDATE;
pSoftNode->pNext = pCachedSoftNodes;
pCachedSoftNodes = pSoftNode;
//
// Clean up any stale soft nodes
//
CleanupSoftNodeList();
}
// Remember local soft font information in DEVDATA structure
pdev->cSoftFonts = pdev->cLocalSoftFonts = pCachedSoftNodes->cSoftFonts;
pdev->pLocalSoftNode = pCachedSoftNodes;
pCachedSoftNodes->cPDEV++;
RELEASESEMAPHORE(hSoftListSemaphore);
}
if (cRemoteFonts > 0) {
//
// Create a soft node for remote soft fonts and
// remember remote soft font information in DEVDATA structure
//
pSoftNode = CreateSoftNode(pType1Fonts + cLocalFonts, cRemoteFonts, &lastModified);
if (pSoftNode != NULL) {
pdev->cSoftFonts += pSoftNode->cSoftFonts;
pdev->pRemoteSoftNode = pSoftNode;
}
}
MEMFREE(pType1Fonts);
}
VOID
FreeSoftFontInfo(
PDEVDATA pdev
)
/*++
Routine Description:
Delete, if necessary, the soft nodes associated with a PDEV.
The soft node associated with remote soft fonts is always
deleted. But the soft font associated it with local soft fonts
is cached and may be used later by other PDEVs.
Arguments:
pdev Pointer to our DEVDATA structure
Return Value:
NONE
--*/
{
PSOFTNODE pCurrentNode, pNode;
//
// Always delete the soft node associated with remote soft fonts
//
if (pdev->pRemoteSoftNode != NULL)
DeleteSoftNode(pdev->pRemoteSoftNode);
//
// Delete the soft node associated with the local fonts
// if it's out of date and no other PDEV is accessing it.
//
if ((pCurrentNode = pdev->pLocalSoftNode) != NULL) {
ASSERT(pCurrentNode->cPDEV > 0);
ACQUIRESEMAPHORE(hSoftListSemaphore);
if ((--pCurrentNode->cPDEV == 0) &&
(pCurrentNode->flags & SOFTNODE_OUTOFDATE))
{
ASSERT(! (pCachedSoftNodes->flags & SOFTNODE_OUTOFDATE));
//
// Find the current soft node on the linked-list.
// Update the link pointers and delete the node.
//
for (pNode = pCachedSoftNodes;
pNode != NULL && pNode->pNext != pCurrentNode;
pNode = pNode->pNext)
{
}
ASSERT(pNode != NULL);
pNode->pNext = pCurrentNode->pNext;
DeleteSoftNode(pCurrentNode);
}
RELEASESEMAPHORE(hSoftListSemaphore);
}
}
PSOFTNODE
CreateSoftNode(
TYPE1_FONT *pType1Fonts,
DWORD cSoftFonts,
LARGE_INTEGER *pTimeStamp
)
/*++
Routine Description:
Create a soft node to maintained relevant information
(PFB handle and NTM structure) about a set of soft fonts.
Arguments:
pType1Fonts Pointer to an array of TYPE1_FONT structures from GDI
cSoftFonts Number of soft fonts
pTimeStamp Pointer to soft font timestamp
Return Value:
Pointer to a soft node if successful. NULL otherwise.
--*/
{
PSOFTNODE pSoftNode;
DWORD softNodeSize;
PSOFTFONTENTRY pSoftFontEntry;
//
// Allocate memory for the soft node itself
//
softNodeSize = offsetof(SOFTNODE, softFontEntries) + cSoftFonts*sizeof(SOFTFONTENTRY);
if ((pSoftNode = MEMALLOC(softNodeSize)) == NULL)
return NULL;
memset(pSoftNode, 0, softNodeSize);
pSoftNode->timeStamp = *pTimeStamp;
//
// Process each soft font in turn
//
for (pSoftFontEntry = pSoftNode->softFontEntries; cSoftFonts-- > 0; pType1Fonts++) {
PBYTE pPFM;
ULONG fileSize;
PNTFM pntfm = NULL;
//
// Read font metrics information from the PFM file and convert it to NTM format
//
if (!pType1Fonts->hPFB ||
!pType1Fonts->hPFM ||
!EngMapFontFile((ULONG) pType1Fonts->hPFM, (PULONG*) &pPFM, &fileSize))
{
continue;
}
__try {
pntfm = pntfmConvertPfmToNtm(pPFM, TRUE);
} __finally {
EngUnmapFontFile((ULONG) pType1Fonts->hPFM);
}
if (pntfm != NULL) {
PIFIMETRICS pifi;
INT encoding;
//
// Determine if the font uses standard or custom encoding
//
if ((encoding = GetSoftFontEncoding(pType1Fonts->hPFB)) == ENCODING_ERROR) {
MEMFREE(pntfm);
continue;
}
if (encoding == ENCODING_CUSTOM)
pntfm->flNTFM |= FL_NTFM_NO_TRANSLATE_CHARSET;
//
// Stick the soft font identifier into a field of IFIMETRICS.
//
pifi = (PIFIMETRICS) ((PBYTE) pntfm + pntfm->ntfmsz.loIFIMETRICS);
if (pifi->cjIfiExtra > offsetof(IFIEXTRA, ulIdentifier))
((IFIEXTRA *)(pifi+1))->ulIdentifier = pType1Fonts->ulIdentifier;
//
// Remember NTM and PFB information
//
pSoftFontEntry->pntfm = pntfm;
pSoftFontEntry->hPFB = pType1Fonts->hPFB;
pSoftFontEntry++;
pSoftNode->cSoftFonts++;
}
}
if (pSoftNode->cSoftFonts == 0) {
MEMFREE(pSoftNode);
pSoftNode = NULL;
}
return pSoftNode;
}
VOID
DeleteSoftNode(
PSOFTNODE pSoftNode
)
/*++
Routine Description:
Delete a soft node from memory:
(1) memory occupied by the soft node itself
(2) for each soft font associated with the soft node:
(a) memory occupied by the NTFM structure
Arguments:
pSoftNode Pointer to a soft node
Return Value:
NONE
--*/
{
DWORD iFont;
for (iFont = 0; iFont < pSoftNode->cSoftFonts; iFont++) {
if (pSoftNode->softFontEntries[iFont].pntfm != NULL) {
MEMFREE(pSoftNode->softFontEntries[iFont].pntfm);
}
}
MEMFREE(pSoftNode);
}
VOID
CleanupSoftNodeList(
VOID
)
/*++
Routine Description:
Delete any out-of-date soft nodes on the soft node list
Arguments:
NONE
Return Value:
NONE
--*/
{
PSOFTNODE pCurrentNode, pPreviousNode;
if (pCachedSoftNodes != NULL) {
//
// The head of the soft node list must not be out of date
//
ASSERT(! (pCachedSoftNodes->flags & SOFTNODE_OUTOFDATE));
pCurrentNode = pCachedSoftNodes;
pPreviousNode = NULL;
//
// Scan thru the list and delete any out-of-date soft nodes
//
while (pCurrentNode != NULL) {
if ((pCurrentNode->cPDEV == 0) &&
(pCurrentNode->flags & SOFTNODE_OUTOFDATE))
{
pPreviousNode->pNext = pCurrentNode->pNext;
DeleteSoftNode(pCurrentNode);
} else
pPreviousNode = pCurrentNode;
pCurrentNode = pPreviousNode->pNext;
}
}
}
PSOFTFONTENTRY
GetSoftFontEntry(
PDEVDATA pdev,
DWORD iSoftFont
)
/*++
Routine Description:
Retrieve the SOFTFONTENTRY structure corresponding to a soft font
Arguments:
pdev Pointer to our DEVDATA structure
iSoftFont Zero-based soft font index
Return Value:
Pointer to the SOFTFONTENTRY structure corresponding to a soft font
--*/
{
//
// We need to differentiate remote softs from local ones.
//
if (iSoftFont >= pdev->cLocalSoftFonts) {
ASSERT((iSoftFont < pdev->cSoftFonts) && pdev->pRemoteSoftNode);
iSoftFont -= pdev->cLocalSoftFonts;
return & pdev->pRemoteSoftNode->softFontEntries[iSoftFont];
} else
return & pdev->pLocalSoftNode->softFontEntries[iSoftFont];
}
BOOL
DownloadSoftFont(
PDEVDATA pdev,
DWORD iSoftFace
)
/*++
Routine Description:
Download a soft font to the printer.
Arguments:
pdev Pointer to DEVDATA structure
iSoftFace Index of the soft font to be downloaded
Return Value:
TRUE if successful, FALSE otherwise
--*/
{
HANDLE hPFB;
PBYTE pPFB;
ULONG fileSize;
BOOL bResult = FALSE;
//
// Map PFB file into memory and write it to output stream
//
hPFB = GetSoftFontEntry(pdev, iSoftFace)->hPFB;
if (EngMapFontFile((ULONG) hPFB, (PULONG*) &pPFB, &fileSize)) {
__try {
bResult = WritePfbToOutput(pdev, pPFB);
} __finally {
EngUnmapFontFile((ULONG) hPFB);
}
}
return bResult;
}
INT
GetSoftFontEncoding(
HANDLE hPFB
)
/*++
Routine Description:
Extract encoding information from a PFB file.
Arguments:
hPFB Handle to the soft font PFB file
Return Value:
ENCODING_STANDARD, ENCODING_CUSTOM, or ENCODING_ERROR
--*/
{
PSTR pPFB;
ULONG fileSize;
INT iResult = ENCODING_ERROR;
//
// Map the PFB file into memory and extract encoding information
//
if (EngMapFontFile((ULONG) hPFB, (PULONG*) &pPFB, &fileSize)) {
__try {
iResult = ExtractEncoding(pPFB, fileSize);
} __finally {
EngUnmapFontFile((ULONG) hPFB);
}
}
return iResult;
}
BOOL
WritePfbToOutput(
PDEVDATA pdev,
PBYTE pPFB
)
/*++
Routine Description:
Download soft font data to printer
Arguments:
pdev Pointer to DEVDATA structure
pPFB Starting address of memory-mapped PFB file
Return Value:
TRUE if successful, FALSE otherwise
--*/
{
DWORD i, cbSegment;
PBYTE pSrc, pDest, pSave;
BYTE segmentType;
// The PFB file format is a sequence of segments, each of which has a
// header part and a data part. The header format, defined in the
// struct PFBHEADER below, consists of a one byte sanity check number
// (128) then a one byte segment type and finally a four byte length
// field for the data following data. The length field is stored in
// the file with the least significant byte first. Read in each
// PFBHEADER, then process the data following it until we are done.
while (TRUE) {
// Make sure we're getting a valid PFBHEADER
if (! ValidPfbHeader(pPFB)) {
SETLASTERROR(ERROR_INVALID_DATA);
return FALSE;
}
// If we have hit the end of the .PFB file, then we are done
segmentType = PfbSegmentType(pPFB);
if (segmentType == EOF_TYPE)
break;
// Get the length of the data in this segment
cbSegment = PfbSegmentLength(pPFB);
// Get a pointer to the data itself for this segment
pSrc = pPFB + PFBHEADER_SIZE;
// Create a buffer to do the conversion into
pSave = pDest = MEMALLOC(cbSegment * 3);
if (pDest == NULL)
return FALSE;
if (segmentType == ASCII_TYPE) {
// Read in an ASCII block, convert CR's to CR/LF's and
// write it out
for (i=0; i < cbSegment; i++) {
if ((*pDest++ = *pSrc++) == '\r')
*pDest++ = '\n';
}
} else if (segmentType == BINARY_TYPE) {
// Read in a BINARY block, convert it to HEX and write it out
for (i = 1; i <= cbSegment; i++) {
*pDest++ = HexDigit(*pSrc >> 4);
*pDest++ = HexDigit(*pSrc);
pSrc++;
// Output a CR/LF every 64 bytes for readability.
if (i%32 == 0 || i == cbSegment) {
*pDest++ = '\r';
*pDest++ = '\n';
}
}
} else {
SETLASTERROR(ERROR_INVALID_DATA);
MEMFREE(pSave);
return FALSE;
}
// Output the converted PFB data to printer
if (! pswrite(pdev, pSave, pDest - pSave)) {
MEMFREE(pSave);
return FALSE;
}
// Free up memory
MEMFREE(pSave);
// Move on to the next segment
pPFB += cbSegment + PFBHEADER_SIZE;
}
return TRUE;
}
PSTR
LocateKeyword(
PSTR pBuffer,
DWORD bufferSize,
PSTR pKeyword
)
/*++
Routine Description:
Find the first occurrence of a keyword string in a buffer.
Arguments:
pBuffer Pointer to memory buffer
bufferSize Size of the buffer in bytes
pKeyword Pointer to keyword string
Return Value:
Pointer to the first occurrence of the keyword string in the
memory buffer. NULL if the keyword doesn't appear in the buffer.
[Note:]
There are definitely faster ways to accomplish this. But since
/Encoding always appears quite early in the PFB file, the brute
force approach used here works well enough.
--*/
{
DWORD keylen = strlen(pKeyword);
if (bufferSize >= keylen) {
bufferSize -= keylen;
while(bufferSize-- > 0) {
// Search through the buffer until we find the keyword
// starting character (slash). Stop if we found the keyword.
if (*pBuffer == '/' && memcmp(pKeyword, pBuffer, keylen) == EQUAL_STRING)
return pBuffer;
pBuffer ++;
}
}
// We did not find the keyword
return NULL;
}
INT
ExtractEncoding(
PSTR pBuffer,
DWORD fileSize
)
/*++
Routine Description:
Peek into a PFB file and find out if a soft font has
standard or custom encoding.
Arguments:
pBuffer Starting address of memory-mapped PFB file
fileSize Size of the file in bytes
Return Value:
ENCODING_STANDARD, ENCODING_CUSTOM, or ENCODING_ERROR
--*/
{
static CHAR encodingKeyword[] = "/Encoding";
static CHAR standardEncodingKeyword[] = "StandardEncoding";
if ((pBuffer = LocateKeyword(pBuffer, fileSize, encodingKeyword)) == NULL) {
SETLASTERROR(ERROR_INVALID_DATA);
return ENCODING_ERROR;
}
// If we got to this point, pBuffer will be pointing to
// "/Encoding ....", skip the keyword "/Encoding"
pBuffer += strlen(encodingKeyword);
// Skip any white space.
while (*pBuffer == ' ')
pBuffer++;
// pBuffer is now pointing to the first letter of the string
// describing encoding vector. The font will have standard
// encoding if and only if this string is StandardEncoding.
if (strncmp(pBuffer, standardEncodingKeyword, strlen(standardEncodingKeyword)) == EQUAL_STRING)
return ENCODING_STANDARD;
else
return ENCODING_CUSTOM;
}