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.
1030 lines
30 KiB
1030 lines
30 KiB
#include "precomp.hpp"
|
|
#include <shlobj.h>
|
|
#include <strsafe.h>
|
|
|
|
#define FONTFILECACHEPATH_W TEXT("\\GDIPFONTCACHEV1.DAT")
|
|
#define FONTFILECACHEPATH_A "\\GDIPFONTCACHEV1.DAT"
|
|
#define FONTFILECACHEREGLOC_W TEXT("Software\\Microsoft\\GDIPlus")
|
|
#define FONTFILECACHEREGKEY_W TEXT("FontCachePath")
|
|
|
|
#define FONTLOADCACHE_NAMEOBJ "GdiplusFontCacheFileV1"
|
|
|
|
#define FONT_CACHE_EXTRA_SIZE (8 * 1024)
|
|
|
|
// Just for tempary use
|
|
#define FONTFILECACHE_VER 0x185
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Unicode wrappers for win9x - defined in imgutils.hpp (include file conflict)
|
|
//--------------------------------------------------------------------------
|
|
|
|
LONG
|
|
_RegCreateKey(
|
|
HKEY rootKey,
|
|
const WCHAR* keyname,
|
|
REGSAM samDesired,
|
|
HKEY* hkeyResult
|
|
);
|
|
|
|
LONG
|
|
_RegSetString(
|
|
HKEY hkey,
|
|
const WCHAR* name,
|
|
const WCHAR* value
|
|
);
|
|
|
|
// todo: this should replace _RegGetString and go away to better place (mikhaill 2/14/2002)
|
|
LONG
|
|
_RegGetStringSafe(
|
|
HKEY hkey,
|
|
const WCHAR* name,
|
|
WCHAR* buf,
|
|
DWORD size
|
|
)
|
|
{
|
|
LONG status;
|
|
DWORD regtype;
|
|
DWORD regsize;
|
|
|
|
if (OSInfo::IsNT)
|
|
{ // Windows NT - Unicode
|
|
|
|
regsize = size;
|
|
|
|
status = RegQueryValueExW(
|
|
hkey,
|
|
name,
|
|
NULL,
|
|
®type,
|
|
(BYTE*) buf,
|
|
®size);
|
|
|
|
if (status != ERROR_SUCCESS) return status;
|
|
if (regtype != REG_SZ) return ERROR_INVALID_DATA;
|
|
DWORD wregsize = regsize/sizeof(WCHAR);
|
|
if (wregsize == 0 || buf[wregsize-1] != 0) return ERROR_INVALID_DATA;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{ // Windows 9x - non-Unicode
|
|
|
|
CHAR ansibuf[MAX_PATH];
|
|
AnsiStrFromUnicode nameStr(name);
|
|
|
|
if (!nameStr.IsValid())
|
|
return ERROR_INVALID_DATA;
|
|
|
|
regsize = MAX_PATH;
|
|
|
|
status = RegQueryValueExA(
|
|
hkey,
|
|
nameStr,
|
|
NULL,
|
|
®type,
|
|
(BYTE*) ansibuf,
|
|
®size);
|
|
|
|
if (status != ERROR_SUCCESS) return status;
|
|
if (regtype != REG_SZ) return ERROR_INVALID_DATA;
|
|
if (regsize == 0 || ansibuf[regsize-1] != 0
|
|
|| regsize*sizeof(WCHAR) > size) return ERROR_INVALID_DATA;
|
|
|
|
BOOL ok = AnsiToUnicodeStr(ansibuf, buf, regsize);
|
|
return ok ? ERROR_SUCCESS : ERROR_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
#define SIZED(x) x, sizeof(x)
|
|
|
|
#define STRCPY_W(dst, src, fail) if ( FAILED( StringCbCopyW ( SIZED(dst), src ) ) ) goto fail
|
|
#define STRCAT_W(dst, src, fail) if ( FAILED( StringCbCatW ( SIZED(dst), src ) ) ) goto fail
|
|
#define STRCPY_A(dst, src, fail) if ( FAILED( StringCbCopyA ( SIZED(dst), src ) ) ) goto fail
|
|
#define STRCAT_A(dst, src, fail) if ( FAILED( StringCbCatA ( SIZED(dst), src ) ) ) goto fail
|
|
#define STRCHK_W( src, fail) if ( FAILED( StringCbLengthW( SIZED(src), 0 ) ) ) goto fail
|
|
|
|
|
|
// There are 2 levels synchronization mechanism need to take care
|
|
// First level: The lock for GDIPFONTCACHEV1.DAT
|
|
// GDIPFONTCACHEV1.DAT is a gloabl file and will be share by different process
|
|
// Second level: The lock fof gflFontCacheState and gFontFileCache
|
|
// They should be shared by different thread in the same process.
|
|
// We define a CriticalSec in gFontFileCache.
|
|
|
|
// mikhaill 02/15/02: at this time there is no separate critical section for cache file;
|
|
// instead the common Globals::TextCriticalSection is used - see comments by claudebe in globals.hpp.
|
|
|
|
FLONG gflFontCacheState;
|
|
FONTFILECACHE gFontFileCache;
|
|
HANDLE ghsemFontFileCache = NULL;
|
|
|
|
ULONG CalcFontFileCacheCheckSum(PVOID pvFile, ULONG cjFileSize);
|
|
VOID vReleaseFontCacheFile(VOID);
|
|
|
|
typedef HRESULT (* PSHGETFOLDERPATHA) (HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPSTR pszPath);
|
|
typedef HRESULT (* PSHGETFOLDERPATHW) (HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath);
|
|
|
|
/*****************************************************************************
|
|
* VOID vReleaseFontCacheFile(VOID)
|
|
*
|
|
* Unmap the view of the file
|
|
*
|
|
* History
|
|
* 11-09-99 Yung-Jen Tony Tsai [YungT]
|
|
* Wrote it.
|
|
*****************************************************************************/
|
|
|
|
VOID vReleaseFontCacheFile(VOID)
|
|
{
|
|
|
|
if (gFontFileCache.pFile)
|
|
{
|
|
UnmapViewOfFile(gFontFileCache.pFile);
|
|
gFontFileCache.pFile = NULL;
|
|
}
|
|
|
|
if (gFontFileCache.hFileMapping)
|
|
{
|
|
CloseHandle(gFontFileCache.hFileMapping);
|
|
gFontFileCache.hFileMapping = 0;
|
|
}
|
|
|
|
if (gFontFileCache.hFile)
|
|
{
|
|
CloseHandle(gFontFileCache.hFile);
|
|
gFontFileCache.hFile = 0;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* BOOL bOpenFontFileCache()
|
|
*
|
|
* Initialize font file cache, open the cacheplus.dat file and create hash table
|
|
*
|
|
* History
|
|
* 11-09-99 Yung-Jen Tony Tsai [YungT]
|
|
* Wrote it.
|
|
*****************************************************************************/
|
|
|
|
BOOL bOpenFontCacheFile(BOOL bOpenOnly, ULONG cjFileSize, BOOL bReAlloc)
|
|
{
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
PBYTE pFile = NULL;
|
|
BOOL bOK = FALSE;
|
|
DWORD dwCreation = 0;
|
|
#if DBG
|
|
DWORD dwError = 0;
|
|
#endif
|
|
WCHAR wszFilePath[MAX_PATH];
|
|
WCHAR wszPathOnly[MAX_PATH];
|
|
CHAR szFilePath[MAX_PATH];
|
|
CHAR szPathOnly[MAX_PATH];
|
|
BOOL bRegValid = FALSE;
|
|
|
|
// initialize strings...
|
|
wszFilePath[0] = 0;
|
|
wszPathOnly[0] = 0;
|
|
szFilePath[0] = 0;
|
|
szPathOnly[0] = 0;
|
|
|
|
if (bOpenOnly)
|
|
{
|
|
dwCreation = OPEN_EXISTING;
|
|
}
|
|
else
|
|
{
|
|
dwCreation = CREATE_ALWAYS;
|
|
}
|
|
|
|
// First check the registry to see if we can bypass loading SHFolder
|
|
HKEY hkey = (HKEY)NULL;
|
|
const WCHAR wchLocation[] = FONTFILECACHEREGLOC_W;
|
|
const WCHAR wchValue[] = FONTFILECACHEREGKEY_W;
|
|
DWORD valueLength = sizeof(wszFilePath);
|
|
|
|
// If this fails, we cannot access the registry key...
|
|
if (_RegCreateKey(HKEY_CURRENT_USER, wchLocation, KEY_ALL_ACCESS, &hkey) != ERROR_SUCCESS)
|
|
hkey = NULL;
|
|
|
|
|
|
if (hkey && _RegGetStringSafe(hkey, wchValue, wszFilePath, valueLength) == ERROR_SUCCESS)
|
|
{
|
|
// The key exists, so we should read the location of the font file
|
|
// from there instead of loading the SHFolder.DLL...
|
|
|
|
STRCPY_W(wszPathOnly, wszFilePath, fail_1);
|
|
|
|
// Append the name of cache file
|
|
STRCAT_W(wszFilePath, FONTFILECACHEPATH_W, fail_1);
|
|
|
|
if (Globals::IsNt)
|
|
{
|
|
hFile = CreateFileW(
|
|
wszFilePath,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
dwCreation,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
AnsiStrFromUnicode ansiStr(wszFilePath);
|
|
|
|
if (ansiStr.IsValid())
|
|
{
|
|
hFile = CreateFileA(
|
|
ansiStr,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
dwCreation,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
}
|
|
}
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
bRegValid = TRUE;
|
|
|
|
fail_1:;
|
|
}
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
// Use SHFolder.DLL to find the proper location for the file if the
|
|
// registry key is not present or is incorrect.
|
|
|
|
if (Globals::IsNt)
|
|
{
|
|
// Two steps to get the cache file
|
|
// If SHFolder.DLL is existed then we will put the cache file in CSIDL_LOCAL_APPDATA
|
|
// Or put it on %SystemRoot%\system32 for WINNT
|
|
|
|
PSHGETFOLDERPATHW pfnSHGetFolderPathW = NULL;
|
|
|
|
// Load SHFolder.DLL
|
|
if (!gFontFileCache.hShFolder)
|
|
gFontFileCache.hShFolder = LoadLibraryW(L"ShFolder.DLL");
|
|
|
|
// If SHFolder.DLL is existed then we will put the cache file in CSIDL_LOCAL_APPDATA
|
|
if (gFontFileCache.hShFolder)
|
|
{
|
|
// Get the function SHGetFolderPath
|
|
pfnSHGetFolderPathW = (PSHGETFOLDERPATHW) GetProcAddress(gFontFileCache.hShFolder, "SHGetFolderPathW");
|
|
|
|
if (pfnSHGetFolderPathW)
|
|
{
|
|
// On NT and higher we should use the CSIDL_LOCAL_APPDATA so that this data
|
|
// does not roam...
|
|
|
|
if ((*pfnSHGetFolderPathW) (NULL, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE,
|
|
NULL, 0, wszFilePath) == E_INVALIDARG)
|
|
{
|
|
// CSIDL_LOCAL_APPDATA not understood, use CSIDL_APPDATA (IE 5.0 not present)
|
|
(*pfnSHGetFolderPathW) (NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE,
|
|
NULL, 0, wszFilePath);
|
|
}
|
|
|
|
// Check whether ShFolder.DLL generated good string
|
|
STRCHK_W(wszFilePath, fail_2);
|
|
|
|
// Keep a copy of the path for registry update...
|
|
STRCPY_W(wszPathOnly, wszFilePath, fail_2);
|
|
|
|
// Append the name of cache file
|
|
STRCAT_W(wszFilePath, FONTFILECACHEPATH_W, fail_2);
|
|
|
|
hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, dwCreation, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
fail_2:;
|
|
}
|
|
}
|
|
|
|
// Try to put it on %SystemRoot%\system32 for WINNT
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
// Get path for system Dircectory
|
|
UINT size = GetSystemDirectoryW(wszFilePath, MAX_PATH);
|
|
if (size >= MAX_PATH) goto fail_3;
|
|
|
|
// Keep a copy of the path for registry update...
|
|
STRCPY_W(wszPathOnly, wszFilePath, fail_3);
|
|
|
|
// Append the name of the cache file
|
|
STRCAT_W(wszFilePath, FONTFILECACHEPATH_W, fail_3);
|
|
|
|
hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, dwCreation, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
fail_3:;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Windows 9x - non-Unicode
|
|
|
|
// Two steps to get the cache file
|
|
// If SHFolder.DLL is existed then we will put the cache file in CSIDL_APPDATA
|
|
// Or put it on %SystemRoot%\system for Win9x
|
|
|
|
if (!gFontFileCache.hShFolder)
|
|
gFontFileCache.hShFolder = LoadLibraryA("ShFolder.DLL");
|
|
|
|
if (gFontFileCache.hShFolder)
|
|
{
|
|
PSHGETFOLDERPATHA pfnSHGetFolderPathA;
|
|
|
|
pfnSHGetFolderPathA = (PSHGETFOLDERPATHA) GetProcAddress(gFontFileCache.hShFolder, "SHGetFolderPathA");
|
|
|
|
if (pfnSHGetFolderPathA)
|
|
{
|
|
(*pfnSHGetFolderPathA) (NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE,
|
|
NULL, 0, szFilePath);
|
|
|
|
// Keep a copy of the path for registry update...
|
|
STRCPY_A(szPathOnly, szFilePath, fail_4);
|
|
|
|
STRCAT_A(szFilePath, FONTFILECACHEPATH_A, fail_4);
|
|
|
|
hFile = CreateFileA(szFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, dwCreation, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
fail_4:;
|
|
}
|
|
}
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
UINT size = GetSystemDirectoryA(szFilePath, MAX_PATH);
|
|
if (size >= MAX_PATH) goto fail_5;
|
|
|
|
// Keep a copy of the path for registry update...
|
|
STRCPY_A(szPathOnly, szFilePath, fail_5);
|
|
|
|
STRCAT_A(szFilePath, FONTFILECACHEPATH_A, fail_5);
|
|
|
|
hFile = CreateFileA(szFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, dwCreation, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
fail_5:;
|
|
}
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
// szFilePath contains the ANSI full path, convert to unicode...
|
|
AnsiToUnicodeStr(szPathOnly, wszPathOnly, sizeof(wszPathOnly)/sizeof(wszPathOnly[0]));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hkey)
|
|
{
|
|
if (hFile != INVALID_HANDLE_VALUE && !bRegValid)
|
|
{
|
|
// wszPathOnly contains the full path to the font cache file
|
|
// so write it out to the registry key...
|
|
|
|
_RegSetString(hkey, wchValue, wszPathOnly);
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
if ((dwCreation == OPEN_EXISTING) && !bReAlloc)
|
|
{
|
|
cjFileSize = GetFileSize(hFile, NULL);
|
|
}
|
|
|
|
if (cjFileSize != 0xffffffff)
|
|
{
|
|
HANDLE hFileMapping;
|
|
|
|
if (Globals::IsNt)
|
|
{
|
|
hFileMapping = CreateFileMappingW(hFile, 0, PAGE_READWRITE, 0, cjFileSize, NULL);
|
|
}
|
|
else
|
|
{
|
|
hFileMapping = CreateFileMappingA(hFile, 0, PAGE_READWRITE, 0, cjFileSize, NULL);
|
|
}
|
|
|
|
if (hFileMapping)
|
|
{
|
|
|
|
pFile = (PBYTE)MapViewOfFile(hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, cjFileSize);
|
|
|
|
// It should not be NULL if it is then we must know something wrong
|
|
|
|
if (pFile)
|
|
{
|
|
gFontFileCache.cjFileSize = cjFileSize;
|
|
gFontFileCache.hFile = hFile;
|
|
gFontFileCache.hFileMapping = hFileMapping;
|
|
gFontFileCache.pFile = (FONTFILECACHEHEADER *) pFile;
|
|
bOK = TRUE;
|
|
}
|
|
else
|
|
{
|
|
CloseHandle(hFile);
|
|
#if DBG
|
|
dwError = GetLastError();
|
|
TERSE(("Error to map a view of a file %x", dwError));
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CloseHandle(hFile);
|
|
#if DBG
|
|
dwError = GetLastError();
|
|
TERSE(("Error to map a file %x", dwError));
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
#if DBG
|
|
else
|
|
{
|
|
if (!bOpenOnly)
|
|
{
|
|
dwError = GetLastError();
|
|
TERSE(("Error to create a file %x", dwError));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (!bOK)
|
|
{
|
|
vReleaseFontCacheFile();
|
|
}
|
|
|
|
return bOK;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* BOOL bReAllocCacheFile(ULONG ulSize)
|
|
*
|
|
* ReAlloc font cache buffer
|
|
*
|
|
* History
|
|
* 11/16/99 YungT create it
|
|
* Wrote it.
|
|
*****************************************************************************/
|
|
|
|
BOOL bReAllocCacheFile(ULONG ulSize)
|
|
{
|
|
BOOL bOK = FALSE;
|
|
ULONG ulFileSizeOrg;
|
|
ULONG ulSizeExtra;
|
|
ULONG ulFileSize;
|
|
|
|
ulFileSizeOrg = gFontFileCache.pFile->ulFileSize;
|
|
|
|
ASSERT(ulSize > gFontFileCache.pFile->ulDataSize);
|
|
|
|
// Calculate the extra cache we need
|
|
|
|
ulSizeExtra = QWORD_ALIGN(ulSize - gFontFileCache.pFile->ulDataSize);
|
|
|
|
ulFileSize = ulFileSizeOrg + ulSizeExtra;
|
|
|
|
if (gFontFileCache.pFile)
|
|
{
|
|
vReleaseFontCacheFile();
|
|
}
|
|
|
|
if (bOpenFontCacheFile(TRUE, ulFileSize, TRUE))
|
|
{
|
|
|
|
gFontFileCache.pFile->ulFileSize = ulFileSize;
|
|
gFontFileCache.pFile->ulDataSize = ulSize;
|
|
|
|
gFontFileCache.pCacheBuf = (PBYTE) gFontFileCache.pFile + SZ_FONTCACHE_HEADER();
|
|
|
|
bOK = TRUE;
|
|
}
|
|
|
|
return bOK;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* BOOL FontFileCacheReadRegistry()
|
|
*
|
|
* Decide we need to open registry or not when load from cache
|
|
*
|
|
* History
|
|
* 07-28-2k Yung-Jen Tony Tsai [YungT]
|
|
* Wrote it.
|
|
*****************************************************************************/
|
|
|
|
BOOL FontFileCacheReadRegistry()
|
|
{
|
|
return gFontFileCache.bReadFromRegistry;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* VOID FontFileCacheFault()
|
|
*
|
|
* Fault reprot for Engine font cache.
|
|
*
|
|
* History
|
|
* 11-15-99 Yung-Jen Tony Tsai [YungT]
|
|
* Wrote it.
|
|
*****************************************************************************/
|
|
|
|
VOID FontFileCacheFault()
|
|
{
|
|
gflFontCacheState = FONT_CACHE_ERROR_MODE;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* PVOID FontFileCacheAlloc(ULONG ulFastCheckSum, ULONG ulSize)
|
|
*
|
|
* Alloc the cached buffer for font driver
|
|
*
|
|
* History
|
|
* 11-15-99 Yung-Jen Tony Tsai [YungT]
|
|
* Wrote it.
|
|
*****************************************************************************/
|
|
|
|
PVOID FontFileCacheAlloc(ULONG ulSize)
|
|
{
|
|
|
|
PVOID pvIfi = NULL;
|
|
|
|
{
|
|
ASSERT(gflFontCacheState & FONT_CACHE_CREATE_MODE);
|
|
|
|
if (ghsemFontFileCache == NULL)
|
|
return pvIfi;
|
|
|
|
if (gflFontCacheState & FONT_CACHE_CREATE_MODE)
|
|
{
|
|
|
|
if ( (QWORD_ALIGN(ulSize) < gFontFileCache.pFile->ulDataSize)
|
|
|| bReAllocCacheFile(ulSize))
|
|
{
|
|
pvIfi = (PVOID) gFontFileCache.pCacheBuf;
|
|
|
|
// Gaurantee the cache pointer is at 8 byte boundary
|
|
gFontFileCache.pFile->ulDataSize = ulSize;
|
|
}
|
|
else
|
|
{
|
|
gflFontCacheState = FONT_CACHE_ERROR_MODE;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return pvIfi;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* PVOID FontFileCacheLookUp(ULONG FastCheckSum, ULONG *pcjData)
|
|
*
|
|
* Lookup font cache
|
|
*
|
|
* History
|
|
* 11-15-99 Yung-Jen Tony Tsai [YungT]
|
|
* Wrote it.
|
|
*****************************************************************************/
|
|
|
|
PVOID FontFileCacheLookUp(ULONG *pcjData)
|
|
{
|
|
PBYTE pCache = NULL;
|
|
|
|
*pcjData = 0;
|
|
|
|
ASSERT(ghsemFontFileCache);
|
|
|
|
if (ghsemFontFileCache == NULL)
|
|
return pCache;
|
|
|
|
|
|
if (gflFontCacheState & FONT_CACHE_LOOKUP_MODE)
|
|
{
|
|
ASSERT(gFontFileCache.pFile);
|
|
ASSERT(gFontFileCache.pCacheBuf == ((PBYTE) gFontFileCache.pFile +
|
|
SZ_FONTCACHE_HEADER()));
|
|
*pcjData = gFontFileCache.pFile->ulDataSize;
|
|
pCache = gFontFileCache.pCacheBuf;
|
|
|
|
gFontFileCache.pCacheBuf += QWORD_ALIGN(*pcjData);
|
|
}
|
|
|
|
|
|
return (PVOID) pCache;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* VOID GetFontFileCacheState()
|
|
*
|
|
* Clean font file cache after load or update the cache file.
|
|
*
|
|
* History
|
|
* 11-12-99 Yung-Jen Tony Tsai [YungT]
|
|
* Wrote it.
|
|
*****************************************************************************/
|
|
|
|
FLONG GetFontFileCacheState()
|
|
{
|
|
return gflFontCacheState;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* VOID vCloseFontFileCache()
|
|
*
|
|
* Clean font file cache after load or update the cache file.
|
|
*
|
|
* History
|
|
* 11-12-99 Yung-Jen Tony Tsai [YungT]
|
|
* Wrote it.
|
|
*****************************************************************************/
|
|
|
|
VOID vCloseFontFileCache()
|
|
{
|
|
|
|
// do paranoid check
|
|
|
|
if (!ghsemFontFileCache)
|
|
return;
|
|
|
|
|
|
if (gflFontCacheState & FONT_CACHE_MASK)
|
|
{
|
|
|
|
if (gflFontCacheState & FONT_CACHE_CREATE_MODE)
|
|
{
|
|
// Close the file, we are done recreating it
|
|
|
|
if (gFontFileCache.pFile)
|
|
{
|
|
gFontFileCache.pFile->CheckSum = CalcFontFileCacheCheckSum((PVOID) ((PBYTE) gFontFileCache.pFile + 4), (gFontFileCache.cjFileSize - 4));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (gFontFileCache.hShFolder)
|
|
{
|
|
FreeLibrary(gFontFileCache.hShFolder);
|
|
gFontFileCache.hShFolder = NULL;
|
|
}
|
|
|
|
vReleaseFontCacheFile();
|
|
|
|
ReleaseSemaphore(ghsemFontFileCache, 1, NULL);
|
|
|
|
CloseHandle(ghsemFontFileCache);
|
|
|
|
ghsemFontFileCache = NULL;
|
|
|
|
gflFontCacheState = 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* ULONG CalcFontFileCacheCheckSum(PVOID pvFile, ULONG cjFileSize)
|
|
*
|
|
* Helper function for query fonts information from font registry
|
|
*
|
|
* History
|
|
* 11-11-99 Yung-Jen Tony Tsai [YungT]
|
|
* Wrote it.
|
|
*****************************************************************************/
|
|
|
|
ULONG CalcFontFileCacheCheckSum(PVOID pvFile, ULONG cjFileSize)
|
|
{
|
|
ULONG sum;
|
|
PULONG pulCur,pulEnd;
|
|
|
|
pulCur = (PULONG) pvFile;
|
|
|
|
__try
|
|
{
|
|
for (sum = 0, pulEnd = pulCur + cjFileSize / sizeof(ULONG); pulCur < pulEnd; pulCur += 1)
|
|
{
|
|
sum += 256 * sum + *pulCur;
|
|
}
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
sum = 0; // oh well, not very unique.
|
|
}
|
|
|
|
return ( sum < 2 ) ? 2 : sum; // 0 is reserved for device fonts
|
|
// 1 is reserved for TYPE1 fonts
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* ULONG QueryFontReg(ULARGE_INTEGER *pFontRegLastWriteTime, ULONG *pulFonts)
|
|
*
|
|
* Helper function for query fonts information from font registry
|
|
*
|
|
* History
|
|
* 11-15-99 Yung-Jen Tony Tsai [YungT]
|
|
* Wrote it.
|
|
*****************************************************************************/
|
|
|
|
BOOL QueryFontReg(ULARGE_INTEGER *pFontRegLastWriteTime)
|
|
{
|
|
BOOL bOK = FALSE;
|
|
ULONG ulFonts;
|
|
|
|
HKEY hkey;
|
|
|
|
LONG error = (Globals::IsNt) ? RegOpenKeyExW(HKEY_LOCAL_MACHINE, Globals::FontsKeyW, 0, KEY_QUERY_VALUE, &hkey)
|
|
: RegOpenKeyExA(HKEY_LOCAL_MACHINE, Globals::FontsKeyA, 0, KEY_QUERY_VALUE, &hkey);
|
|
|
|
if (error == ERROR_SUCCESS)
|
|
{
|
|
// There is no difference between A or W APIs at this case.
|
|
|
|
error = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, &ulFonts, NULL, NULL, NULL,
|
|
(FILETIME *)pFontRegLastWriteTime);
|
|
|
|
if (error == ERROR_SUCCESS)
|
|
{
|
|
bOK = TRUE;
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
return bOK;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* BOOL bCreateFontFileCache()
|
|
*
|
|
* Initialize font file cache, open the cacheplus.dat file and create hash table
|
|
*
|
|
* History
|
|
* 11-09-99 Yung-Jen Tony Tsai [YungT]
|
|
* Wrote it.
|
|
*****************************************************************************/
|
|
|
|
BOOL bCreateFontCacheFile(ULARGE_INTEGER FntRegLWT)
|
|
{
|
|
ULONG ulSize;
|
|
BOOL bOk = FALSE;
|
|
|
|
ulSize = SZ_FONTCACHE_HEADER() + FONT_CACHE_EXTRA_SIZE;
|
|
|
|
if (gFontFileCache.pFile)
|
|
{
|
|
vReleaseFontCacheFile();
|
|
}
|
|
|
|
|
|
if(bOpenFontCacheFile(FALSE, ulSize, FALSE))
|
|
{
|
|
gFontFileCache.pFile->ulLanguageID = (ULONG) Globals::LanguageID;
|
|
gFontFileCache.pFile->CheckSum = 0;
|
|
gFontFileCache.pFile->ulMajorVersionNumber = FONTFILECACHE_VER;
|
|
gFontFileCache.pFile->FntRegLWT.QuadPart = FntRegLWT.QuadPart;
|
|
gFontFileCache.pFile->ulFileSize = ulSize;
|
|
gFontFileCache.pFile->ulDataSize = FONT_CACHE_EXTRA_SIZE;
|
|
bOk = TRUE;
|
|
}
|
|
|
|
return bOk;
|
|
}
|
|
|
|
#if DBG
|
|
/*****************************************************************************
|
|
* BOOL bFontFileCacheDisabled()
|
|
*
|
|
* Tempary routine for performance evaluation
|
|
*
|
|
* History
|
|
* 11-29-99 Yung-Jen Tony Tsai [YungT]
|
|
* Wrote it.
|
|
*****************************************************************************/
|
|
|
|
BOOL bFontFileCacheDisabled()
|
|
{
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
|
|
BOOL bScanRegistry()
|
|
{
|
|
ASSERT(!Globals::IsNt);
|
|
|
|
BOOL bOK = TRUE;
|
|
ULONG index = 0;
|
|
ULONG registrySize = 0;
|
|
ULONG numExpected;
|
|
|
|
// Open the key
|
|
|
|
HKEY hkey;
|
|
|
|
|
|
PBYTE pCached = (PBYTE) gFontFileCache.pFile + SZ_FONTCACHE_HEADER();
|
|
|
|
if (*((ULONG *) pCached) != 0xBFBFBFBF)
|
|
return FALSE;
|
|
|
|
LONG error = RegOpenKeyExA(HKEY_LOCAL_MACHINE, Globals::FontsKeyA, 0, KEY_QUERY_VALUE, &hkey);
|
|
|
|
if (error == ERROR_SUCCESS)
|
|
{
|
|
|
|
DWORD allDataSize = 0;
|
|
error = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, &numExpected, NULL, NULL, NULL, NULL);
|
|
|
|
if (error != ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hkey);
|
|
return FALSE;
|
|
}
|
|
|
|
PBYTE pRegistryData;
|
|
|
|
registrySize = *((ULONG *) (pCached + 4)) ;
|
|
|
|
pRegistryData = pCached + 8;
|
|
|
|
while (index < numExpected)
|
|
{
|
|
DWORD regType = 0;
|
|
DWORD labelSize = MAX_PATH;
|
|
DWORD dataSize = MAX_PATH;
|
|
CHAR label[MAX_PATH];
|
|
BYTE data[MAX_PATH];
|
|
|
|
error = RegEnumValueA(hkey, index, label, &labelSize, NULL, ®Type, data, &dataSize);
|
|
|
|
if (error == ERROR_NO_MORE_ITEMS)
|
|
{
|
|
bOK = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (allDataSize >= registrySize)
|
|
{
|
|
bOK = FALSE;
|
|
break;
|
|
}
|
|
|
|
|
|
if (memcmp(pRegistryData, data, dataSize))
|
|
{
|
|
bOK = FALSE;
|
|
break;
|
|
}
|
|
|
|
pRegistryData += dataSize;
|
|
|
|
allDataSize += dataSize;
|
|
|
|
index ++;
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
|
|
if (bOK && (allDataSize == registrySize))
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
/*****************************************************************************
|
|
* VOID InitFontFileCache()
|
|
*
|
|
* Initialize font file cache, open the cacheplus.dat file and create hash table
|
|
*
|
|
* History
|
|
* 11-09-99 Yung-Jen Tony Tsai [YungT]
|
|
* Wrote it.
|
|
*****************************************************************************/
|
|
|
|
VOID InitFontFileCache()
|
|
{
|
|
ULARGE_INTEGER FntRegLWT = { 0, 0};
|
|
|
|
|
|
if (gflFontCacheState)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#if DBG
|
|
// Only for performance evaluation.
|
|
if (bFontFileCacheDisabled())
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
#endif
|
|
|
|
// If the named semaphore object existed before the function call,
|
|
// the function returns a handle to the existing object and
|
|
// GetLastError returns ERROR_ALREADY_EXISTS.
|
|
|
|
ghsemFontFileCache = CreateSemaphoreA( NULL, 1, 1, FONTLOADCACHE_NAMEOBJ);
|
|
|
|
// Something wrong, we can not go with font file cache
|
|
if (ghsemFontFileCache == NULL)
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
else
|
|
{
|
|
// Wait 5 seconds until the semaphore released.
|
|
// No further attempts to create font file cache on timeout.
|
|
// This does not mean deial of service - just will work
|
|
// slower using GpFontTable::LoadAllFontsFromRegistry(FALSE).
|
|
DWORD dwr = WaitForSingleObject(ghsemFontFileCache, 5000);
|
|
if (dwr == WAIT_TIMEOUT) goto CleanUp;
|
|
}
|
|
|
|
gFontFileCache.pFile = NULL;
|
|
|
|
// now open the TT Fonts key :
|
|
|
|
if (!QueryFontReg(&FntRegLWT))
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
|
|
if (bOpenFontCacheFile(TRUE, 0, FALSE))
|
|
{
|
|
|
|
// File did not change from last time boot.
|
|
|
|
if (gFontFileCache.pFile->CheckSum && gFontFileCache.cjFileSize == gFontFileCache.pFile->ulFileSize &&
|
|
gFontFileCache.pFile->CheckSum == CalcFontFileCacheCheckSum((PVOID) ((PBYTE) gFontFileCache.pFile + 4), (gFontFileCache.cjFileSize - 4)) &&
|
|
gFontFileCache.pFile->ulMajorVersionNumber == FONTFILECACHE_VER &&
|
|
gFontFileCache.pFile->ulLanguageID == (ULONG) Globals::LanguageID && // If locale changed, we need to re-create the cache
|
|
gFontFileCache.pFile->FntRegLWT.QuadPart == FntRegLWT.QuadPart && // If registry has been updated we need to re-create the cache file
|
|
(FntRegLWT.QuadPart != 0 || bScanRegistry())
|
|
)
|
|
{
|
|
gflFontCacheState = FONT_CACHE_LOOKUP_MODE;
|
|
}
|
|
else
|
|
{
|
|
if(bCreateFontCacheFile(FntRegLWT))
|
|
{
|
|
// If something will not match, then it means we need to create FNTCACHE again
|
|
|
|
gflFontCacheState = FONT_CACHE_CREATE_MODE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
// If there is no GDIPFONTCACHE.DAT file
|
|
// Then we need to create it.
|
|
|
|
if(bCreateFontCacheFile(FntRegLWT))
|
|
{
|
|
gflFontCacheState = FONT_CACHE_CREATE_MODE;
|
|
|
|
}
|
|
}
|
|
|
|
CleanUp:
|
|
|
|
// Semaphore initialized
|
|
|
|
if (gflFontCacheState & FONT_CACHE_MASK)
|
|
{
|
|
|
|
// Initialize the start pointer of current Cache table
|
|
|
|
gFontFileCache.pCacheBuf = (PBYTE) gFontFileCache.pFile + SZ_FONTCACHE_HEADER();
|
|
|
|
if (FntRegLWT.QuadPart == (ULONGLONG) 0)
|
|
gFontFileCache.bReadFromRegistry = TRUE;
|
|
else
|
|
gFontFileCache.bReadFromRegistry = FALSE;
|
|
}
|
|
else
|
|
{
|
|
gflFontCacheState = 0;
|
|
|
|
// Clean up the memory
|
|
|
|
if (gFontFileCache.pFile)
|
|
{
|
|
vReleaseFontCacheFile();
|
|
}
|
|
|
|
if (ghsemFontFileCache)
|
|
{
|
|
ReleaseSemaphore(ghsemFontFileCache, 1, NULL);
|
|
CloseHandle( ghsemFontFileCache);
|
|
ghsemFontFileCache = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|