/****************************Module*Header******************************\ * Module Name: FIUTILS.C * * Module Descripton: * This file has utility functions that handle NT5 Unidrv font files. * * Warnings: * * Issues: * * Created: 11 November 1997 * Author: Srinivasan Chandrasekar [srinivac] * * Copyright (c) 1996, 1997 Microsoft Corporation \***********************************************************************/ #include "precomp.h" // // External functions // BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD); BOOL WINAPI GetPrinterW(HANDLE, DWORD, LPBYTE, DWORD, LPDWORD);; // // Internal data structures // // // Structure used to remember which glyph set data's have been written to file // typedef struct _FI_GLYPHDATA { SHORT sGlyphID; // unique glyph ID WORD wPadding; // set to zero DWORD gdPos; // position of glyph data inside file } FI_GLYPHDATA, *PFI_GLYPHDATA; // // The handle we pass out is a pointer to this structure // typedef struct tagFI_FILE { DWORD dwSignature; // Signature of data structure HANDLE hPrinter; // Handle of printer for using spooler funcs HANDLE hHeap; // Handle to heap to use WCHAR wchFileName[MAX_PATH]; // Name of font file HANDLE hFile; // Handle of open file PUFF_FILEHEADER pFileHdr; // Pointer to file header PUFF_FONTDIRECTORY pFontDir; // Pointer to font directory DWORD dwCurPos; // Current position of write in file DWORD dwFlags; // Miscellaneous flags // // The following are used only if read access is present // PBYTE pView; // Pointer to view of file // // The following are used only if write access is present // PFI_GLYPHDATA pGlyphData; // Pointer to glyphs that have been written DWORD nGlyphs; // Number of glyphs written } FI_FILE, *PFI_FILE; // // Internal functions // #ifdef KERNEL_MODE HANDLE OpenFontFile(HANDLE, HANDLE, HANDLE, PWSTR); #else HANDLE OpenFontFile(HANDLE, HANDLE, PWSTR); #endif BOOL WriteData(PFI_FILE, PDATA_HEADER); void Qsort(PUFF_FONTDIRECTORY, int, int); void Exchange(PUFF_FONTDIRECTORY, DWORD, DWORD); BOOL GetFontCartridgeFile(HANDLE, HANDLE); #define FONT_INFO_SIGNATURE 'fnti' #define FI_FLAG_READ 0x00000001 #define FI_FLAG_WRITE 0x00000002 #define IsValidFontInfo(pfi) ((pfi) && (pfi)->dwSignature == FONT_INFO_SIGNATURE) #ifdef KERNEL_MODE #define ALLOC(hHeap, dwSize) MemAlloc(dwSize) #define FREE(hHeap, pBuf) MemFree(pBuf) #else #define ALLOC(hHeap, dwSize) HeapAlloc((hHeap), HEAP_ZERO_MEMORY, (dwSize)) #define FREE(hHeap, pBuf) HeapFree((hHeap), 0, (pBuf)) #endif /****************************************************************************** * Functions that handle files that have been opened with read privileges ******************************************************************************/ /****************************************************************************** * * FIOpenFontFile * * Function: * This function opens the font file associated with the specified printer * for read access. * * Arguments: * hPrinter - Handle identifying printer * hHeap - Handle of heap to use for memory allocations * bCartridgeFile - Specifies if the font cartridge file is to be opened * or the currently installed fonts file * * Returns: * Handle to use in subsequent calls if successful, NULL otherwise * ******************************************************************************/ HANDLE FIOpenFontFile( HANDLE hPrinter, #ifdef KERNEL_MODE HANDLE hdev, #endif HANDLE hHeap ) { #ifdef KERNEL_MODE return OpenFontFile(hPrinter, hdev, hHeap, REGVAL_FONTFILENAME); #else return OpenFontFile(hPrinter, hHeap, REGVAL_FONTFILENAME); #endif } HANDLE FIOpenCartridgeFile( HANDLE hPrinter, #ifdef KERNEL_MODE HANDLE hdev, #endif HANDLE hHeap ) { #ifdef KERNEL_MODE return OpenFontFile(hPrinter, hdev, hHeap, REGVAL_CARTRIDGEFILENAME); #else return OpenFontFile(hPrinter, hHeap, REGVAL_CARTRIDGEFILENAME); #endif } HANDLE OpenFontFile( HANDLE hPrinter, #ifdef KERNEL_MODE HANDLE hdev, #endif HANDLE hHeap, PWSTR pwstrRegVal ) { FI_FILE *pFIFile = NULL; DWORD dwSize, dwStatus, dwType; BOOL bRc = FALSE; // // Allocate FI_FILE structure // if (!(pFIFile = (FI_FILE *)ALLOC(hHeap, sizeof(FI_FILE)))) { WARNING(("Could not allocate memory for opening Font File\n")); return NULL; } pFIFile->dwSignature = FONT_INFO_SIGNATURE; pFIFile->hPrinter = hPrinter; pFIFile->hHeap = hHeap; pFIFile->pView = NULL; pFIFile->dwFlags = 0; // // If we are opening the cartridge file, and we are on the client, get it // from the server // #ifndef KERNEL_MODE if (wcscmp(pwstrRegVal, REGVAL_CARTRIDGEFILENAME) == 0) { if (!BGetFontCartridgeFile(hPrinter, hHeap)) goto EndOpenRead; } #endif // // Get the name of the font file - strip off the directory path as it may have the // server path - generate the local path instead // { WCHAR wchFileName[MAX_PATH]; PWSTR pName; #ifdef KERNEL_MODE PDRIVER_INFO_3 pdi3; if (!(pdi3 = MyGetPrinterDriver(hPrinter, hdev, 3))) goto EndOpenRead; StringCchCopyW(pFIFile->wchFileName, CCHOF(pFIFile->wchFileName), pdi3->pDriverPath); MemFree(pdi3); // // We have something like "c:\nt\system32\spool\drivers\w32x86\3\unidrv.dll". // We need only till drivers, so we search backwards for the 3rd '\\'. // if (pName = wcsrchr(pFIFile->wchFileName, '\\')) { *pName = '\0'; if (pName = wcsrchr(pFIFile->wchFileName, '\\')) { *pName = '\0'; if (pName = wcsrchr(pFIFile->wchFileName, '\\')) *pName = '\0'; } } if (!pName) goto EndOpenRead; #else dwSize = sizeof(pFIFile->wchFileName); if (!GetPrinterDriverDirectoryW(NULL, NULL, 1, (PBYTE)pFIFile->wchFileName, dwSize, &dwSize)) goto EndOpenRead; // // Get rid of the processor architecture part // if (pName = wcsrchr(pFIFile->wchFileName, '\\')) *pName = '\0'; #endif // // Add "unifont" // StringCchCatW(pFIFile->wchFileName, CCHOF(pFIFile->wchFileName), FONTDIR); // // Get font file name from registry // dwSize = sizeof(wchFileName); dwStatus = GetPrinterData(hPrinter, pwstrRegVal, &dwType, (PBYTE)wchFileName, dwSize, &dwSize); if (dwStatus != ERROR_MORE_DATA && dwStatus != ERROR_SUCCESS) goto EndOpenRead; // No font file is available // // Strip any directory prefix from the font filename // if (pName = wcsrchr(wchFileName, '\\')) pName++; else pName = wchFileName; StringCchCatW(pFIFile->wchFileName, CCHOF(pFIFile->wchFileName), pName); } // // Memory map the file // #if defined(KERNEL_MODE) && !defined(USERMODE_DRIVER) { PBYTE pTemp = NULL; DWORD dwSize; HANDLE hFile; hFile = MapFileIntoMemory(pFIFile->wchFileName, &pTemp, &dwSize); if (!pTemp) { goto EndOpenRead; } pFIFile->pView = ALLOC(hHeap, dwSize); if (pFIFile->pView) { memcpy(pFIFile->pView, pTemp, dwSize); } UnmapFileFromMemory((HFILEMAP)hFile); } #else pFIFile->hFile = MapFileIntoMemory(pFIFile->wchFileName, &pFIFile->pView, NULL); #endif if (!pFIFile->pView) { WARNING(("Err %ld, could not create view of profile %s\n", GetLastError(), pFIFile->wchFileName)); goto EndOpenRead; } // // Check validity of font file // pFIFile->pFileHdr = (PUFF_FILEHEADER)pFIFile->pView; if (pFIFile->pFileHdr->dwSignature != UFF_FILE_MAGIC || pFIFile->pFileHdr->dwVersion != UFF_VERSION_NUMBER || pFIFile->pFileHdr->dwSize != sizeof(UFF_FILEHEADER)) { WARNING(("Invalid font file %s\n", pFIFile->wchFileName)); goto EndOpenRead; } // // Set other fields // if (pFIFile->pFileHdr->offFontDir) { pFIFile->pFontDir = (PUFF_FONTDIRECTORY)(pFIFile->pView + pFIFile->pFileHdr->offFontDir); } pFIFile->dwCurPos = 0; pFIFile->dwFlags = FI_FLAG_READ; pFIFile->pGlyphData = NULL; pFIFile->nGlyphs = 0; bRc = TRUE; EndOpenRead: if (!bRc) { FICloseFontFile((HANDLE)pFIFile); pFIFile = NULL; } return (HANDLE)pFIFile; } /****************************************************************************** * * FICloseFontFile * * Function: * This function closes the given font file and frees all memory * associated with it * * Arguments: * hFontFile - Handle identifying font file to close * * Returns: * Nothing * ******************************************************************************/ VOID FICloseFontFile( HANDLE hFontFile ) { FI_FILE *pFIFile = (FI_FILE*)hFontFile; if (IsValidFontInfo(pFIFile)) { if (pFIFile->dwFlags & FI_FLAG_READ) { // // Memory mapped file was opened, close it // if (pFIFile->pView) { #if defined(KERNEL_MODE) && !defined(USERMODE_DRIVER) FREE(pFIFile->hHeap, pFIFile->pView); #else UnmapFileFromMemory((HFILEMAP)pFIFile->hFile); #endif } } #ifndef KERNEL_MODE else { // // New file was created, free all allocated memory // if (pFIFile->pFileHdr) { FREE(pFIFile->hHeap, pFIFile->pFileHdr); } if (pFIFile->pFontDir) { FREE(pFIFile->hHeap, pFIFile->pFontDir); } if (pFIFile->hFile != INVALID_HANDLE_VALUE) { CloseHandle(pFIFile->hFile); } if (pFIFile->pGlyphData) { FREE(pFIFile->hHeap, pFIFile->pGlyphData); } } #endif FREE(pFIFile->hHeap, pFIFile); } return; } /****************************************************************************** * * FIGetNumFonts * * Function: * This function retrieves the number of fonts present in the given * font file * * Arguments: * hFontFile - Handle identifying font file * * Returns: * Number of font present if successful, 0 otherwise * ******************************************************************************/ DWORD FIGetNumFonts( HANDLE hFontFile ) { FI_FILE *pFIFile = (FI_FILE*)hFontFile; return IsValidFontInfo(pFIFile) ? pFIFile->pFileHdr->nFonts : 0; } /****************************************************************************** * * FIGetFontDir * * Function: * This function retrieves a pointer to the font directory of the * given font file * * Arguments: * hFontFile - Handle identifying font file * * Returns: * Pointer to font directory if successful, NULL otherwise * ******************************************************************************/ PUFF_FONTDIRECTORY FIGetFontDir( HANDLE hFontFile ) { FI_FILE *pFIFile = (FI_FILE*)hFontFile; return IsValidFontInfo(pFIFile) ? pFIFile->pFontDir : NULL; } /****************************************************************************** * * FIGetFontName * * Function: * This function retrieves a pointer to the name of the iFontIndex'th font * in the given font file * * Arguments: * hFontFile - Handle identifying font file * iFontIndex - Index of the font whose name is to be retrieved * * Returns: * Pointer to font name if successful, NULL otherwise * ******************************************************************************/ PWSTR FIGetFontName( HANDLE hFontFile, DWORD iFontIndex ) { FI_FILE *pFIFile = (FI_FILE*)hFontFile; PWSTR pwstrFontName = NULL; if (IsValidFontInfo(pFIFile) && (pFIFile->dwFlags & FI_FLAG_READ)) { if (iFontIndex < pFIFile->pFileHdr->nFonts) { pwstrFontName = (PWSTR)(pFIFile->pView + pFIFile->pFontDir[iFontIndex].offFontName); } } return pwstrFontName; } /****************************************************************************** * * FIGetFontCartridgeName * * Function: * This function retrieves a pointer to the name of the iFontIndex'th font * cartridge in the given font file * * Arguments: * hFontFile - Handle identifying font file * iFontIndex - Index of the font whose cartridge name is to be retrieved * * Returns: * Pointer to font cartridge name if present, NULL otherwise * ******************************************************************************/ PWSTR FIGetFontCartridgeName( HANDLE hFontFile, DWORD iFontIndex ) { FI_FILE *pFIFile = (FI_FILE*)hFontFile; PWSTR pwstrCartridgeName = NULL; if (IsValidFontInfo(pFIFile) && (pFIFile->dwFlags & FI_FLAG_READ)) { if (iFontIndex < pFIFile->pFileHdr->nFonts) { pwstrCartridgeName = pFIFile->pFontDir[iFontIndex].offCartridgeName ? (PWSTR)(pFIFile->pView + pFIFile->pFontDir[iFontIndex].offCartridgeName) : NULL; } } return pwstrCartridgeName; } /****************************************************************************** * * FIGetFontData * * Function: * This function retrieves a pointer to the font data for the * iFontIndex'th font in the given font file * * Arguments: * hFontFile - Handle identifying font file * iFontIndex - Index of the font whose font data is to be retrieved * * Returns: * Pointer to font data if successful, NULL otherwise * ******************************************************************************/ PDATA_HEADER FIGetFontData( HANDLE hFontFile, DWORD iFontIndex ) { FI_FILE *pFIFile = (FI_FILE*)hFontFile; PDATA_HEADER pData = NULL; if (IsValidFontInfo(pFIFile) && (pFIFile->dwFlags & FI_FLAG_READ)) { if (iFontIndex < pFIFile->pFileHdr->nFonts) { pData = (PDATA_HEADER)(pFIFile->pView + pFIFile->pFontDir[iFontIndex].offFontData); } } return pData; } /****************************************************************************** * * FIGetGlyphData * * Function: * This function retrieves a pointer to the glyph data for the * iFontIndex'th font in the given font file * * Arguments: * hFontFile - Handle identifying font file * iFontIndex - Index of the font whose glyph data is to be retrieved * * Returns: * Pointer to glyph data if successful, NULL otherwise * ******************************************************************************/ PDATA_HEADER FIGetGlyphData( HANDLE hFontFile, DWORD iFontIndex ) { FI_FILE *pFIFile = (FI_FILE*)hFontFile; PDATA_HEADER pData = NULL; if (IsValidFontInfo(pFIFile) && (pFIFile->dwFlags & FI_FLAG_READ)) { if (iFontIndex < pFIFile->pFileHdr->nFonts) { pData = pFIFile->pFontDir[iFontIndex].offGlyphData ? (PDATA_HEADER)(pFIFile->pView + pFIFile->pFontDir[iFontIndex].offGlyphData) : NULL; } } return pData; } /****************************************************************************** * * FIGetVarData * * Function: * This function retrieves a pointer to the variable data for the * iFontIndex'th font in the given font file * * Arguments: * hFontFile - Handle identifying font file * iFontIndex - Index of the font whose variable data is to be retrieved * * Returns: * Pointer to variable data if present, NULL otherwise * ******************************************************************************/ PDATA_HEADER FIGetVarData( HANDLE hFontFile, DWORD iFontIndex ) { FI_FILE *pFIFile = (FI_FILE*)hFontFile; PDATA_HEADER pData = NULL; if (IsValidFontInfo(pFIFile) && (pFIFile->dwFlags & FI_FLAG_READ)) { if (iFontIndex < pFIFile->pFileHdr->nFonts) { pData = pFIFile->pFontDir[iFontIndex].offVarData ? (PDATA_HEADER)(pFIFile->pView + pFIFile->pFontDir[iFontIndex].offVarData) : NULL; } } return pData; } #ifndef KERNEL_MODE /****************************************************************************** * Functions that handle files that have been opened with write privileges ******************************************************************************/ /****************************************************************************** * * FICreateFontFile * * Function: * This function creates a new font file with only write access. * * Arguments: * hPrinter - Handle identifying printer * hHeap - Handle of heap to use for memory allocations * * Returns: * Handle to use in subsequent calls if successful, NULL otherwise * ******************************************************************************/ HANDLE FICreateFontFile( HANDLE hPrinter, HANDLE hHeap, DWORD cFonts ) { FI_FILE *pFIFile = NULL; PWSTR pName, pstrGuid; DWORD dwSize; UUID guid; BOOL bRc = FALSE; // // Allocate FI_FILE structure // if (!(pFIFile = (FI_FILE *)ALLOC(hHeap, sizeof(FI_FILE)))) { WARNING(("Could not allocate memory for creating Font File\n")); return NULL; } pFIFile->dwSignature = FONT_INFO_SIGNATURE; pFIFile->hPrinter = hPrinter; pFIFile->hHeap = hHeap; // // Generate file name for font file // dwSize = sizeof(pFIFile->wchFileName); if (!GetPrinterDriverDirectoryW(NULL, NULL, 1, (PBYTE)pFIFile->wchFileName, dwSize, &dwSize)) { WARNING(("Error getting printer driver directory")); goto EndCreateNew; } // // Get rid of the processor architecture part // if (pName = wcsrchr(pFIFile->wchFileName, '\\')) *pName = '\0'; // // Add "unifont" // StringCchCatW(pFIFile->wchFileName, CCHOF(pFIFile->wchFileName), FONTDIR); // // Make sure the local directory is created // if ( ! CreateDirectory(pFIFile->wchFileName, NULL) ) { WARNING(("Error creating directory %s", pFIFile->wchFileName)); goto EndCreateNew; } if ((UuidCreate(&guid) != RPC_S_OK) || (UuidToString(&guid, &pstrGuid) != RPC_S_OK)) { WARNING(("Error getting a guid string\n")); goto EndCreateNew; } StringCchCatW(pFIFile->wchFileName, CCHOF(pFIFile->wchFileName), pstrGuid); StringCchCatW(pFIFile->wchFileName, CCHOF(pFIFile->wchFileName), L".UFF"); RpcStringFree(&pstrGuid); pFIFile->hFile = CreateFile(pFIFile->wchFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS | SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS, NULL); if (pFIFile->hFile == INVALID_HANDLE_VALUE) { WARNING(("Error creating file %s", pFIFile->wchFileName)); goto EndCreateNew; } // // Set other fields // pFIFile->dwFlags = FI_FLAG_WRITE; // Give write access alone pFIFile->dwCurPos = 0; // // Allocate memory for remembering glyph datas that have been written. // Max memory needed is if each font has a different glyph data. // pFIFile->pGlyphData = (PFI_GLYPHDATA)ALLOC(hHeap, cFonts * sizeof(FI_GLYPHDATA)); if (!pFIFile->pGlyphData) { WARNING(("Error allocating memory for tracking glyph data\n")); goto EndCreateNew; } pFIFile->nGlyphs = 0; // // Allocate memory for the file header and font directory // pFIFile->pFileHdr = (PUFF_FILEHEADER)ALLOC(hHeap, sizeof(UFF_FILEHEADER)); pFIFile->pFontDir = (PUFF_FONTDIRECTORY)ALLOC(hHeap, cFonts * sizeof(UFF_FONTDIRECTORY)); if (!pFIFile->pFileHdr || !pFIFile->pFontDir) { WARNING(("Error allocating memory for file header or font directory\n")); goto EndCreateNew; } // // Initialize file header // pFIFile->pFileHdr->dwSignature = UFF_FILE_MAGIC; pFIFile->pFileHdr->dwVersion = UFF_VERSION_NUMBER; pFIFile->pFileHdr->dwSize = sizeof(UFF_FILEHEADER); pFIFile->pFileHdr->nFonts = cFonts; if (cFonts) { pFIFile->pFileHdr->offFontDir = sizeof(UFF_FILEHEADER); } bRc = TRUE; EndCreateNew: if (!bRc) { FICloseFontFile((HANDLE)pFIFile); pFIFile = NULL; } return (HANDLE)pFIFile; } /****************************************************************************** * * FIWriteFileHeader * * Function: * This function seeks to the beginning of the file and writes the * file header * * Arguments: * hFontFile - Handle identifying font file * * Returns: * TRUE if successful, FALSE otherwise * ******************************************************************************/ BOOL FIWriteFileHeader( HANDLE hFontFile ) { FI_FILE *pFIFile = (FI_FILE*)hFontFile; DWORD dwSize; if (IsValidFontInfo(pFIFile) && (pFIFile->dwFlags & FI_FLAG_WRITE)) { if (pFIFile->dwCurPos != 0) { pFIFile->dwCurPos = SetFilePointer(pFIFile->hFile, 0, 0, FILE_BEGIN); } if (!WriteFile(pFIFile->hFile, (PVOID)pFIFile->pFileHdr, sizeof(UFF_FILEHEADER), &dwSize, NULL)) { return FALSE; } pFIFile->dwCurPos += dwSize; } return TRUE; } /****************************************************************************** * * FIWriteFontDirectory * * Function: * This function seeks to the right place in the file and writes the * font directory. It sorts it by font ID if it is not already sorted. * * Arguments: * hFontFile - Handle identifying font file * * Returns: * TRUE if successful, FALSE otherwise * ******************************************************************************/ BOOL FIWriteFontDirectory( HANDLE hFontFile ) { FI_FILE *pFIFile = (FI_FILE*)hFontFile; DWORD dwSize; if (IsValidFontInfo(pFIFile) && (pFIFile->dwFlags & FI_FLAG_WRITE)) { // // If there are no fonts, there is nothing to write // if (pFIFile->pFileHdr->offFontDir == 0) return TRUE; // // Seek to right place // if (pFIFile->dwCurPos != pFIFile->pFileHdr->offFontDir) { pFIFile->dwCurPos = SetFilePointer(pFIFile->hFile, pFIFile->pFileHdr->offFontDir, 0, FILE_BEGIN); } // // Sort the font directory // Qsort(pFIFile->pFontDir, (int)0, (int)pFIFile->pFileHdr->nFonts-1); pFIFile->pFileHdr->dwFlags |= FONT_DIR_SORTED; if (!WriteFile(pFIFile->hFile, (PVOID)pFIFile->pFontDir, pFIFile->pFileHdr->nFonts*sizeof(UFF_FONTDIRECTORY), &dwSize, NULL)) { return FALSE; } pFIFile->dwCurPos += dwSize; } return TRUE; } /****************************************************************************** * * FIAlignedSeek * * Function: * This function seeks forward by the specified amount and then some if * required so you end up DWORD aligned * * Arguments: * hFontFile - Handle identifying font file * lSeekDist - Amount to seek forward by * * Returns: * Handle to use in subsequent calls if successful, NULL otherwise * ******************************************************************************/ VOID FIAlignedSeek( HANDLE hFontFile, DWORD dwSeekDist ) { FI_FILE *pFIFile = (FI_FILE*)hFontFile; if (IsValidFontInfo(pFIFile) && (pFIFile->dwFlags & FI_FLAG_WRITE)) { pFIFile->dwCurPos += dwSeekDist; pFIFile->dwCurPos = (pFIFile->dwCurPos + 3) & ~3; // DWORD align pFIFile->dwCurPos = SetFilePointer(pFIFile->hFile, pFIFile->dwCurPos, 0, FILE_BEGIN); } return; } /****************************************************************************** * * FICopyFontRecord * * Function: * This function copies a font record including the directory entry, * font meetrics, glyph data and variable data from one font file * to another. * * Arguments: * hWriteFile - Handle identifying font file to write into * hReadFile - Handle identifying font file to read from * dwWrIndex - Index of font to write into in write file * dwRdIndex - Index of font to read from in read file * * Returns: * TRUE if successful, FALSE otherwise * ******************************************************************************/ BOOL FICopyFontRecord( HANDLE hWriteFile, HANDLE hReadFile, DWORD dwWrIndex, DWORD dwRdIndex ) { FI_FILE *pFIWrFile = (FI_FILE*)hWriteFile; FI_FILE *pFIRdFile = (FI_FILE*)hReadFile; PDATA_HEADER pData; PWSTR pName; DWORD dwSize; DWORD j, gdPos; if (!IsValidFontInfo(pFIWrFile) || !IsValidFontInfo(pFIRdFile) || !(pFIWrFile->dwFlags & FI_FLAG_WRITE) || !(pFIRdFile->dwFlags & FI_FLAG_READ)) { return FALSE; } // // Copy the font directory entry // pFIWrFile->pFontDir[dwWrIndex].dwSignature = FONT_REC_SIG; pFIWrFile->pFontDir[dwWrIndex].wSize = (WORD)sizeof(UFF_FONTDIRECTORY); pFIWrFile->pFontDir[dwWrIndex].wFontID = (WORD)dwWrIndex; pFIWrFile->pFontDir[dwWrIndex].sGlyphID = pFIRdFile->pFontDir[dwRdIndex].sGlyphID; pFIWrFile->pFontDir[dwWrIndex].wFlags = pFIRdFile->pFontDir[dwRdIndex].wFlags; pFIWrFile->pFontDir[dwWrIndex].dwInstallerSig = pFIRdFile->pFontDir[dwRdIndex].dwInstallerSig; // // Write font name // pName = FIGetFontName(hReadFile, dwRdIndex); ASSERT(pName != NULL); // Can't have NULL font name if (NULL == pName) { return FALSE; } pFIWrFile->pFontDir[dwWrIndex].offFontName = pFIWrFile->dwCurPos; if (!WriteFile(pFIWrFile->hFile, (PVOID)pName, (lstrlen(pName)+1) * sizeof(TCHAR), &dwSize, NULL)) { WARNING(("Error writing font name\n")); return FALSE; } pFIWrFile->dwCurPos += dwSize; pFIWrFile->dwCurPos = (pFIWrFile->dwCurPos + 3) & ~3; pFIWrFile->dwCurPos = SetFilePointer(pFIWrFile->hFile, pFIWrFile->dwCurPos, 0, FILE_BEGIN); // // Write font cartridge name // pName = FIGetFontCartridgeName(hReadFile, dwRdIndex); if (pName == NULL) { pFIWrFile->pFontDir[dwRdIndex].offCartridgeName = 0; } else { pFIWrFile->pFontDir[dwWrIndex].offCartridgeName = pFIWrFile->dwCurPos; if (!WriteFile(pFIWrFile->hFile, (PVOID)pName, (lstrlen(pName)+1) * sizeof(TCHAR), &dwSize, NULL)) { WARNING(("Error writing font cartridge name\n")); return FALSE; } pFIWrFile->dwCurPos += dwSize; pFIWrFile->dwCurPos = (pFIWrFile->dwCurPos + 3) & ~3; pFIWrFile->dwCurPos = SetFilePointer(pFIWrFile->hFile, pFIWrFile->dwCurPos, 0, FILE_BEGIN); } // // Write font data // pData = FIGetFontData(hReadFile, dwRdIndex); ASSERT(pData != NULL); // Can't have NULL font data pFIWrFile->pFontDir[dwWrIndex].offFontData = pFIWrFile->dwCurPos; if (!WriteData(pFIWrFile, pData)) return FALSE; // // Get glyph data from read file // pData = FIGetGlyphData(pFIRdFile, dwRdIndex); if (pData) { // // Check if it is already in write file // gdPos = 0; for (j=0; jnGlyphs; j++) { if (pFIWrFile->pGlyphData[j].sGlyphID == pFIWrFile->pFontDir[dwWrIndex].sGlyphID) { gdPos = pFIWrFile->pGlyphData[j].gdPos; } } if (gdPos == 0) { // // Not there yet - add to set of glyph data's that have been // added to file, and write it into write file // pFIWrFile->pGlyphData[pFIWrFile->nGlyphs].sGlyphID = pFIWrFile->pFontDir[dwWrIndex].sGlyphID; pFIWrFile->pGlyphData[pFIWrFile->nGlyphs].gdPos = pFIWrFile->dwCurPos; pFIWrFile->nGlyphs++; pFIWrFile->pFontDir[dwWrIndex].offGlyphData = pFIWrFile->dwCurPos; if (!WriteData(pFIWrFile, pData)) return FALSE; pFIWrFile->pFileHdr->nGlyphSets++; } else { // // Already in file, just update location // pFIWrFile->pFontDir[dwWrIndex].offGlyphData = gdPos; } } else { // // Glyph data not present // pFIWrFile->pFontDir[dwWrIndex].offGlyphData = 0; } // // Write var data // pData = FIGetVarData(pFIRdFile, dwRdIndex); if (pData) { pFIWrFile->pFontDir[dwWrIndex].offVarData = pFIWrFile->dwCurPos; if (!WriteData(pFIWrFile, pData)) return FALSE; pFIWrFile->pFileHdr->nVarData++; } else pFIWrFile->pFontDir[dwWrIndex].offVarData = 0; return TRUE; } /****************************************************************************** * * FIAddFontRecord * * Function: * This function adds a font record including the directory entry, * font meetrics, glyph data and variable data * * Arguments: * hFontFile - Handle identifying font file to write * dwIndex - Index of font to write * pFntDat - Information about font to add * * Returns: * TRUE if successful, FALSE otherwise * ******************************************************************************/ BOOL FIAddFontRecord( HANDLE hFontFile, DWORD dwIndex, FNTDAT *pFntDat ) { FI_FILE *pFIFile = (FI_FILE*)hFontFile; PDATA_HEADER pData; PWSTR pName; DWORD dwSize; DWORD j, gdPos; if (!IsValidFontInfo(pFIFile) || !(pFIFile->dwFlags & FI_FLAG_WRITE)) { return FALSE; } // // Initialize the font directory entry // pFIFile->pFontDir[dwIndex].dwSignature = FONT_REC_SIG; pFIFile->pFontDir[dwIndex].wSize = sizeof(UFF_FONTDIRECTORY); pFIFile->pFontDir[dwIndex].wFontID = (WORD)dwIndex; pFIFile->pFontDir[dwIndex].sGlyphID = (short)pFntDat->fid.dsCTT.cBytes; pFIFile->pFontDir[dwIndex].wFlags = FONT_FL_SOFTFONT | FONT_FL_IFI | FONT_FL_GLYPHSET_RLE; pFIFile->pFontDir[dwIndex].dwInstallerSig = WINNT_INSTALLER_SIG; // // Write font name // pName = pFntDat->fid.dsIdentStr.pvData; ASSERT(pName != NULL); // Can't have NULL font name pFIFile->pFontDir[dwIndex].offFontName = pFIFile->dwCurPos; if (!WriteFile(pFIFile->hFile, (PVOID)pName, (lstrlen(pName)+1) * sizeof(TCHAR), &dwSize, NULL)) { WARNING(("Error writing font name\n")); return FALSE; } pFIFile->dwCurPos += dwSize; pFIFile->dwCurPos = (pFIFile->dwCurPos + 3) & ~3; pFIFile->dwCurPos = SetFilePointer(pFIFile->hFile, pFIFile->dwCurPos, 0, FILE_BEGIN); // // No font cartridge name // pFIFile->pFontDir[dwIndex].offCartridgeName = 0; // // Write font data // pFIFile->pFontDir[dwIndex].offFontData = pFIFile->dwCurPos; if ((dwSize = FIWriteFix(pFIFile->hFile, (WORD)dwIndex, &pFntDat->fid)) == 0) { WARNING(("Error writing fixed part of font data\n")); return FALSE; } pFIFile->dwCurPos += dwSize; pFIFile->dwCurPos = (pFIFile->dwCurPos + 3) & ~3; pFIFile->dwCurPos = SetFilePointer(pFIFile->hFile, pFIFile->dwCurPos, 0, FILE_BEGIN); // // Check if glyph data is already in new file // gdPos = 0; for (j=0; jnGlyphs; j++) { if (pFIFile->pGlyphData[j].sGlyphID == pFIFile->pFontDir[dwIndex].sGlyphID) { gdPos = pFIFile->pGlyphData[j].gdPos; break; } } if (gdPos == 0) { HRSRC hrsrc; // // Get resource from our file // if (pFIFile->pFontDir[dwIndex].sGlyphID > 0) { hrsrc = FindResource(ghInstance, MAKEINTRESOURCE(pFIFile->pFontDir[dwIndex].sGlyphID), (LPWSTR)RC_TRANSTAB); if (!hrsrc) { WARNING(("Unable to find RLE resource %d in unidrvui\n", pFIFile->pFontDir[dwIndex].sGlyphID)); return FALSE; } pData = (PDATA_HEADER)LockResource(LoadResource(ghInstance, hrsrc)); } else pData = NULL; if (pData) { DATA_HEADER dh; dh.dwSignature = DATA_CTT_SIG; dh.wSize = (WORD)sizeof(DATA_HEADER); dh.wDataID = (WORD)pFIFile->pFontDir[dwIndex].sGlyphID; dh.dwDataSize = SizeofResource(ghInstance, hrsrc); dh.dwReserved = 0; pFIFile->pFontDir[dwIndex].offGlyphData = pFIFile->dwCurPos; if (!WriteFile(pFIFile->hFile, (PVOID)&dh, sizeof(DATA_HEADER), &dwSize, NULL) || !WriteFile(pFIFile->hFile, (PVOID)pData, dh.dwDataSize, &dwSize, NULL)) { WARNING(("Error writing glyph data to font file\n")); return FALSE; } // // Add to set of glyph data's that have been added to file // pFIFile->pGlyphData[pFIFile->nGlyphs].sGlyphID = pFIFile->pFontDir[dwIndex].sGlyphID; pFIFile->pGlyphData[pFIFile->nGlyphs].gdPos = pFIFile->dwCurPos; pFIFile->nGlyphs++; // // Increment number of glyph sets written // pFIFile->pFileHdr->nGlyphSets++; // // Update file position // pFIFile->dwCurPos += sizeof(DATA_HEADER) + dwSize; pFIFile->dwCurPos = (pFIFile->dwCurPos + 3) & ~3; pFIFile->dwCurPos = SetFilePointer(pFIFile->hFile, pFIFile->dwCurPos, 0, FILE_BEGIN); } else { pFIFile->pFontDir[dwIndex].offGlyphData = 0; } } else { // // Already in file, just update location // pFIFile->pFontDir[dwIndex].offGlyphData = gdPos; } // // Write var data // pFIFile->pFontDir[dwIndex].offVarData = pFIFile->dwCurPos; if (!pFntDat->pVarData) { dwSize = FIWriteVar(pFIFile->hFile, pFntDat->wchFileName); } else { dwSize = FIWriteRawVar(pFIFile->hFile, pFntDat->pVarData, pFntDat->dwSize); } if (dwSize == 0) { WARNING(("Error writing variable part of font data\n")); return FALSE; } pFIFile->dwCurPos += dwSize; pFIFile->dwCurPos = (pFIFile->dwCurPos + 3) & ~3; pFIFile->dwCurPos = SetFilePointer(pFIFile->hFile, pFIFile->dwCurPos, 0, FILE_BEGIN); return TRUE; } /****************************************************************************** * * FIUpdateFontFile * * Function: * This function closes both files, and if bReplace, it deletes the current * file,and sets the new file as the current font installer file in the * registry. In !bReplace, it closes both files and deletes the new file. * * Arguments: * hCurFile - Handle identifying current font file * hNewFile - Handle identifying new font file * bReplace - Whether the new file should replace the current file * * Returns: * TRUE if successful, FALSE otherwise * ******************************************************************************/ BOOL FIUpdateFontFile( HANDLE hCurFile, HANDLE hNewFile, BOOL bReplace ) { FI_FILE *pFICurFile = (FI_FILE*)hCurFile; FI_FILE *pFINewFile = (FI_FILE*)hNewFile; WCHAR wchCurFileName[MAX_PATH]; WCHAR wchNewFileName[MAX_PATH]; HANDLE hPrinter; DWORD dwSize; // // Validate pFINewFile // Validate pFINewFile->wchFileName is valid. // Validate pFINewFile->hPrinter is valid as well. // // IsValidFontInfo checks if pFI is not NULL and the signature is valid. // // pFICurFile could be NULL. In this case this is the first time to install soft fonts. // if ((pFICurFile && !IsValidFontInfo(pFICurFile)) || (pFINewFile && !IsValidFontInfo(pFINewFile))) { return FALSE; } // // Initialize local variables // wchCurFileName[0] = '\0'; wchNewFileName[0] = '\0'; // // Remember name of the current & new files. We check for non-NULL value // because // this function can be called in a failure situation with bReplace set // to FALSE, and we need to handle all possible faillure cases. // If bReplace is TRUE, pFINewFile must be non NULL, so we get hPrinter // there // if (pFINewFile) { StringCchCopyW(wchNewFileName, CCHOF(wchNewFileName), pFINewFile->wchFileName); hPrinter = pFINewFile->hPrinter; } else { hPrinter = NULL; } if (pFICurFile) { StringCchCopyW(wchCurFileName, CCHOF(wchCurFileName), pFICurFile->wchFileName); } // // Close both files // FICloseFontFile(hCurFile); FICloseFontFile(hNewFile); if (bReplace) { // // Copy new file to current file // if (wchCurFileName[0]) { if (CopyFile(wchNewFileName, wchCurFileName, FALSE)) { // // Set printer data so client side caches get updated // dwSize = (lstrlen(wchCurFileName) + 1) * sizeof(TCHAR); if (hPrinter) { SetPrinterData(hPrinter, REGVAL_FONTFILENAME, REG_SZ, (PBYTE)wchCurFileName, dwSize); } } } else { // // Set new file as font file and return (do not delete it!) // dwSize = (lstrlen(wchNewFileName) + 1) * sizeof(TCHAR); if (hPrinter) { SetPrinterData(hPrinter, REGVAL_FONTFILENAME, REG_SZ, (PBYTE)wchNewFileName, dwSize); } return TRUE; } } // // Delete the new file // if (wchNewFileName[0]) { DeleteFile(wchNewFileName); } return TRUE; } /****************************************************************************** * Internal helper functions ******************************************************************************/ BOOL WriteData( PFI_FILE pFIFile, PDATA_HEADER pData ) { DWORD dwSize; if (!WriteFile(pFIFile->hFile, (PVOID)pData, (DWORD)(pData->wSize + pData->dwDataSize), &dwSize, NULL)) return FALSE; pFIFile->dwCurPos += dwSize; pFIFile->dwCurPos = (pFIFile->dwCurPos + 3) & ~3; pFIFile->dwCurPos = SetFilePointer(pFIFile->hFile, pFIFile->dwCurPos, 0, FILE_BEGIN); return TRUE; } /****************************************************************************** * * Qsort * * Function: * This function sorts the given font directory array based on the * wFontID field. It used quick sort. * * Arguments: * lpData - Pointer to the font directory array to sort * start - Starting index of array * end - Ending index of array * * Returns: * Nothing * ******************************************************************************/ void Qsort( PUFF_FONTDIRECTORY lpData, int start, int end ) { int i, j; if (start < end) { i = start; j = end + 1; while (1) { while (i < j) { i++; if (lpData[i].wFontID >= lpData[start].wFontID) break; } while(1) { j--; if (lpData[j].wFontID <= lpData[start].wFontID) break; } if (i < j) Exchange(lpData, i, j); else break; } Exchange(lpData, start, j); Qsort(lpData, start, j-1); Qsort(lpData, j+1, end); } } /****************************************************************************** * * Exchange * * Function: * This function exchanges two entries in the font directory array * * Arguments: * lpData - Pointer to the font directory array * i, j - Indices of the two entries to exchange * * Returns: * Nothing * ******************************************************************************/ void Exchange( PUFF_FONTDIRECTORY lpData, DWORD i, DWORD j ) { UFF_FONTDIRECTORY fd; if ( i != j) { memcpy((LPSTR)&fd, (LPSTR)&lpData[i], sizeof(UFF_FONTDIRECTORY)); memcpy((LPSTR)&lpData[i], (LPSTR)&lpData[j], sizeof(UFF_FONTDIRECTORY)); memcpy((LPSTR)&lpData[j], (LPSTR)&fd, sizeof(UFF_FONTDIRECTORY)); } } #endif // #ifndef KERNEL_MODE