Leaked source code of windows server 2003
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

  1. #include "precomp.hpp"
  2. #include <shlobj.h>
  3. #include <strsafe.h>
  4. #define FONTFILECACHEPATH_W TEXT("\\GDIPFONTCACHEV1.DAT")
  5. #define FONTFILECACHEPATH_A "\\GDIPFONTCACHEV1.DAT"
  6. #define FONTFILECACHEREGLOC_W TEXT("Software\\Microsoft\\GDIPlus")
  7. #define FONTFILECACHEREGKEY_W TEXT("FontCachePath")
  8. #define FONTLOADCACHE_NAMEOBJ "GdiplusFontCacheFileV1"
  9. #define FONT_CACHE_EXTRA_SIZE (8 * 1024)
  10. // Just for tempary use
  11. #define FONTFILECACHE_VER 0x185
  12. //--------------------------------------------------------------------------
  13. // Unicode wrappers for win9x - defined in imgutils.hpp (include file conflict)
  14. //--------------------------------------------------------------------------
  15. LONG
  16. _RegCreateKey(
  17. HKEY rootKey,
  18. const WCHAR* keyname,
  19. REGSAM samDesired,
  20. HKEY* hkeyResult
  21. );
  22. LONG
  23. _RegSetString(
  24. HKEY hkey,
  25. const WCHAR* name,
  26. const WCHAR* value
  27. );
  28. // todo: this should replace _RegGetString and go away to better place (mikhaill 2/14/2002)
  29. LONG
  30. _RegGetStringSafe(
  31. HKEY hkey,
  32. const WCHAR* name,
  33. WCHAR* buf,
  34. DWORD size
  35. )
  36. {
  37. LONG status;
  38. DWORD regtype;
  39. DWORD regsize;
  40. if (OSInfo::IsNT)
  41. { // Windows NT - Unicode
  42. regsize = size;
  43. status = RegQueryValueExW(
  44. hkey,
  45. name,
  46. NULL,
  47. &regtype,
  48. (BYTE*) buf,
  49. &regsize);
  50. if (status != ERROR_SUCCESS) return status;
  51. if (regtype != REG_SZ) return ERROR_INVALID_DATA;
  52. DWORD wregsize = regsize/sizeof(WCHAR);
  53. if (wregsize == 0 || buf[wregsize-1] != 0) return ERROR_INVALID_DATA;
  54. return ERROR_SUCCESS;
  55. }
  56. else
  57. { // Windows 9x - non-Unicode
  58. CHAR ansibuf[MAX_PATH];
  59. AnsiStrFromUnicode nameStr(name);
  60. if (!nameStr.IsValid())
  61. return ERROR_INVALID_DATA;
  62. regsize = MAX_PATH;
  63. status = RegQueryValueExA(
  64. hkey,
  65. nameStr,
  66. NULL,
  67. &regtype,
  68. (BYTE*) ansibuf,
  69. &regsize);
  70. if (status != ERROR_SUCCESS) return status;
  71. if (regtype != REG_SZ) return ERROR_INVALID_DATA;
  72. if (regsize == 0 || ansibuf[regsize-1] != 0
  73. || regsize*sizeof(WCHAR) > size) return ERROR_INVALID_DATA;
  74. BOOL ok = AnsiToUnicodeStr(ansibuf, buf, regsize);
  75. return ok ? ERROR_SUCCESS : ERROR_INVALID_DATA;
  76. }
  77. }
  78. #define SIZED(x) x, sizeof(x)
  79. #define STRCPY_W(dst, src, fail) if ( FAILED( StringCbCopyW ( SIZED(dst), src ) ) ) goto fail
  80. #define STRCAT_W(dst, src, fail) if ( FAILED( StringCbCatW ( SIZED(dst), src ) ) ) goto fail
  81. #define STRCPY_A(dst, src, fail) if ( FAILED( StringCbCopyA ( SIZED(dst), src ) ) ) goto fail
  82. #define STRCAT_A(dst, src, fail) if ( FAILED( StringCbCatA ( SIZED(dst), src ) ) ) goto fail
  83. #define STRCHK_W( src, fail) if ( FAILED( StringCbLengthW( SIZED(src), 0 ) ) ) goto fail
  84. // There are 2 levels synchronization mechanism need to take care
  85. // First level: The lock for GDIPFONTCACHEV1.DAT
  86. // GDIPFONTCACHEV1.DAT is a gloabl file and will be share by different process
  87. // Second level: The lock fof gflFontCacheState and gFontFileCache
  88. // They should be shared by different thread in the same process.
  89. // We define a CriticalSec in gFontFileCache.
  90. // mikhaill 02/15/02: at this time there is no separate critical section for cache file;
  91. // instead the common Globals::TextCriticalSection is used - see comments by claudebe in globals.hpp.
  92. FLONG gflFontCacheState;
  93. FONTFILECACHE gFontFileCache;
  94. HANDLE ghsemFontFileCache = NULL;
  95. ULONG CalcFontFileCacheCheckSum(PVOID pvFile, ULONG cjFileSize);
  96. VOID vReleaseFontCacheFile(VOID);
  97. typedef HRESULT (* PSHGETFOLDERPATHA) (HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPSTR pszPath);
  98. typedef HRESULT (* PSHGETFOLDERPATHW) (HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath);
  99. /*****************************************************************************
  100. * VOID vReleaseFontCacheFile(VOID)
  101. *
  102. * Unmap the view of the file
  103. *
  104. * History
  105. * 11-09-99 Yung-Jen Tony Tsai [YungT]
  106. * Wrote it.
  107. *****************************************************************************/
  108. VOID vReleaseFontCacheFile(VOID)
  109. {
  110. if (gFontFileCache.pFile)
  111. {
  112. UnmapViewOfFile(gFontFileCache.pFile);
  113. gFontFileCache.pFile = NULL;
  114. }
  115. if (gFontFileCache.hFileMapping)
  116. {
  117. CloseHandle(gFontFileCache.hFileMapping);
  118. gFontFileCache.hFileMapping = 0;
  119. }
  120. if (gFontFileCache.hFile)
  121. {
  122. CloseHandle(gFontFileCache.hFile);
  123. gFontFileCache.hFile = 0;
  124. }
  125. }
  126. /*****************************************************************************
  127. * BOOL bOpenFontFileCache()
  128. *
  129. * Initialize font file cache, open the cacheplus.dat file and create hash table
  130. *
  131. * History
  132. * 11-09-99 Yung-Jen Tony Tsai [YungT]
  133. * Wrote it.
  134. *****************************************************************************/
  135. BOOL bOpenFontCacheFile(BOOL bOpenOnly, ULONG cjFileSize, BOOL bReAlloc)
  136. {
  137. HANDLE hFile = INVALID_HANDLE_VALUE;
  138. PBYTE pFile = NULL;
  139. BOOL bOK = FALSE;
  140. DWORD dwCreation = 0;
  141. #if DBG
  142. DWORD dwError = 0;
  143. #endif
  144. WCHAR wszFilePath[MAX_PATH];
  145. WCHAR wszPathOnly[MAX_PATH];
  146. CHAR szFilePath[MAX_PATH];
  147. CHAR szPathOnly[MAX_PATH];
  148. BOOL bRegValid = FALSE;
  149. // initialize strings...
  150. wszFilePath[0] = 0;
  151. wszPathOnly[0] = 0;
  152. szFilePath[0] = 0;
  153. szPathOnly[0] = 0;
  154. if (bOpenOnly)
  155. {
  156. dwCreation = OPEN_EXISTING;
  157. }
  158. else
  159. {
  160. dwCreation = CREATE_ALWAYS;
  161. }
  162. // First check the registry to see if we can bypass loading SHFolder
  163. HKEY hkey = (HKEY)NULL;
  164. const WCHAR wchLocation[] = FONTFILECACHEREGLOC_W;
  165. const WCHAR wchValue[] = FONTFILECACHEREGKEY_W;
  166. DWORD valueLength = sizeof(wszFilePath);
  167. // If this fails, we cannot access the registry key...
  168. if (_RegCreateKey(HKEY_CURRENT_USER, wchLocation, KEY_ALL_ACCESS, &hkey) != ERROR_SUCCESS)
  169. hkey = NULL;
  170. if (hkey && _RegGetStringSafe(hkey, wchValue, wszFilePath, valueLength) == ERROR_SUCCESS)
  171. {
  172. // The key exists, so we should read the location of the font file
  173. // from there instead of loading the SHFolder.DLL...
  174. STRCPY_W(wszPathOnly, wszFilePath, fail_1);
  175. // Append the name of cache file
  176. STRCAT_W(wszFilePath, FONTFILECACHEPATH_W, fail_1);
  177. if (Globals::IsNt)
  178. {
  179. hFile = CreateFileW(
  180. wszFilePath,
  181. GENERIC_READ | GENERIC_WRITE,
  182. FILE_SHARE_READ | FILE_SHARE_WRITE,
  183. NULL,
  184. dwCreation,
  185. FILE_ATTRIBUTE_NORMAL,
  186. NULL);
  187. }
  188. else
  189. {
  190. AnsiStrFromUnicode ansiStr(wszFilePath);
  191. if (ansiStr.IsValid())
  192. {
  193. hFile = CreateFileA(
  194. ansiStr,
  195. GENERIC_READ | GENERIC_WRITE,
  196. FILE_SHARE_READ | FILE_SHARE_WRITE,
  197. NULL,
  198. dwCreation,
  199. FILE_ATTRIBUTE_NORMAL,
  200. NULL);
  201. }
  202. }
  203. if (hFile != INVALID_HANDLE_VALUE)
  204. bRegValid = TRUE;
  205. fail_1:;
  206. }
  207. if (hFile == INVALID_HANDLE_VALUE)
  208. {
  209. // Use SHFolder.DLL to find the proper location for the file if the
  210. // registry key is not present or is incorrect.
  211. if (Globals::IsNt)
  212. {
  213. // Two steps to get the cache file
  214. // If SHFolder.DLL is existed then we will put the cache file in CSIDL_LOCAL_APPDATA
  215. // Or put it on %SystemRoot%\system32 for WINNT
  216. PSHGETFOLDERPATHW pfnSHGetFolderPathW = NULL;
  217. // Load SHFolder.DLL
  218. if (!gFontFileCache.hShFolder)
  219. gFontFileCache.hShFolder = LoadLibraryW(L"ShFolder.DLL");
  220. // If SHFolder.DLL is existed then we will put the cache file in CSIDL_LOCAL_APPDATA
  221. if (gFontFileCache.hShFolder)
  222. {
  223. // Get the function SHGetFolderPath
  224. pfnSHGetFolderPathW = (PSHGETFOLDERPATHW) GetProcAddress(gFontFileCache.hShFolder, "SHGetFolderPathW");
  225. if (pfnSHGetFolderPathW)
  226. {
  227. // On NT and higher we should use the CSIDL_LOCAL_APPDATA so that this data
  228. // does not roam...
  229. if ((*pfnSHGetFolderPathW) (NULL, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE,
  230. NULL, 0, wszFilePath) == E_INVALIDARG)
  231. {
  232. // CSIDL_LOCAL_APPDATA not understood, use CSIDL_APPDATA (IE 5.0 not present)
  233. (*pfnSHGetFolderPathW) (NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE,
  234. NULL, 0, wszFilePath);
  235. }
  236. // Check whether ShFolder.DLL generated good string
  237. STRCHK_W(wszFilePath, fail_2);
  238. // Keep a copy of the path for registry update...
  239. STRCPY_W(wszPathOnly, wszFilePath, fail_2);
  240. // Append the name of cache file
  241. STRCAT_W(wszFilePath, FONTFILECACHEPATH_W, fail_2);
  242. hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
  243. NULL, dwCreation, FILE_ATTRIBUTE_NORMAL, NULL);
  244. fail_2:;
  245. }
  246. }
  247. // Try to put it on %SystemRoot%\system32 for WINNT
  248. if (hFile == INVALID_HANDLE_VALUE)
  249. {
  250. // Get path for system Dircectory
  251. UINT size = GetSystemDirectoryW(wszFilePath, MAX_PATH);
  252. if (size >= MAX_PATH) goto fail_3;
  253. // Keep a copy of the path for registry update...
  254. STRCPY_W(wszPathOnly, wszFilePath, fail_3);
  255. // Append the name of the cache file
  256. STRCAT_W(wszFilePath, FONTFILECACHEPATH_W, fail_3);
  257. hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
  258. NULL, dwCreation, FILE_ATTRIBUTE_NORMAL, NULL);
  259. fail_3:;
  260. }
  261. }
  262. else
  263. {
  264. // Windows 9x - non-Unicode
  265. // Two steps to get the cache file
  266. // If SHFolder.DLL is existed then we will put the cache file in CSIDL_APPDATA
  267. // Or put it on %SystemRoot%\system for Win9x
  268. if (!gFontFileCache.hShFolder)
  269. gFontFileCache.hShFolder = LoadLibraryA("ShFolder.DLL");
  270. if (gFontFileCache.hShFolder)
  271. {
  272. PSHGETFOLDERPATHA pfnSHGetFolderPathA;
  273. pfnSHGetFolderPathA = (PSHGETFOLDERPATHA) GetProcAddress(gFontFileCache.hShFolder, "SHGetFolderPathA");
  274. if (pfnSHGetFolderPathA)
  275. {
  276. (*pfnSHGetFolderPathA) (NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE,
  277. NULL, 0, szFilePath);
  278. // Keep a copy of the path for registry update...
  279. STRCPY_A(szPathOnly, szFilePath, fail_4);
  280. STRCAT_A(szFilePath, FONTFILECACHEPATH_A, fail_4);
  281. hFile = CreateFileA(szFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
  282. NULL, dwCreation, FILE_ATTRIBUTE_NORMAL, NULL);
  283. fail_4:;
  284. }
  285. }
  286. if (hFile == INVALID_HANDLE_VALUE)
  287. {
  288. UINT size = GetSystemDirectoryA(szFilePath, MAX_PATH);
  289. if (size >= MAX_PATH) goto fail_5;
  290. // Keep a copy of the path for registry update...
  291. STRCPY_A(szPathOnly, szFilePath, fail_5);
  292. STRCAT_A(szFilePath, FONTFILECACHEPATH_A, fail_5);
  293. hFile = CreateFileA(szFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
  294. NULL, dwCreation, FILE_ATTRIBUTE_NORMAL, NULL);
  295. fail_5:;
  296. }
  297. if (hFile != INVALID_HANDLE_VALUE)
  298. {
  299. // szFilePath contains the ANSI full path, convert to unicode...
  300. AnsiToUnicodeStr(szPathOnly, wszPathOnly, sizeof(wszPathOnly)/sizeof(wszPathOnly[0]));
  301. }
  302. }
  303. }
  304. if (hkey)
  305. {
  306. if (hFile != INVALID_HANDLE_VALUE && !bRegValid)
  307. {
  308. // wszPathOnly contains the full path to the font cache file
  309. // so write it out to the registry key...
  310. _RegSetString(hkey, wchValue, wszPathOnly);
  311. }
  312. RegCloseKey(hkey);
  313. }
  314. if (hFile != INVALID_HANDLE_VALUE)
  315. {
  316. if ((dwCreation == OPEN_EXISTING) && !bReAlloc)
  317. {
  318. cjFileSize = GetFileSize(hFile, NULL);
  319. }
  320. if (cjFileSize != 0xffffffff)
  321. {
  322. HANDLE hFileMapping;
  323. if (Globals::IsNt)
  324. {
  325. hFileMapping = CreateFileMappingW(hFile, 0, PAGE_READWRITE, 0, cjFileSize, NULL);
  326. }
  327. else
  328. {
  329. hFileMapping = CreateFileMappingA(hFile, 0, PAGE_READWRITE, 0, cjFileSize, NULL);
  330. }
  331. if (hFileMapping)
  332. {
  333. pFile = (PBYTE)MapViewOfFile(hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, cjFileSize);
  334. // It should not be NULL if it is then we must know something wrong
  335. if (pFile)
  336. {
  337. gFontFileCache.cjFileSize = cjFileSize;
  338. gFontFileCache.hFile = hFile;
  339. gFontFileCache.hFileMapping = hFileMapping;
  340. gFontFileCache.pFile = (FONTFILECACHEHEADER *) pFile;
  341. bOK = TRUE;
  342. }
  343. else
  344. {
  345. CloseHandle(hFile);
  346. #if DBG
  347. dwError = GetLastError();
  348. TERSE(("Error to map a view of a file %x", dwError));
  349. #endif
  350. }
  351. }
  352. else
  353. {
  354. CloseHandle(hFile);
  355. #if DBG
  356. dwError = GetLastError();
  357. TERSE(("Error to map a file %x", dwError));
  358. #endif
  359. }
  360. }
  361. }
  362. #if DBG
  363. else
  364. {
  365. if (!bOpenOnly)
  366. {
  367. dwError = GetLastError();
  368. TERSE(("Error to create a file %x", dwError));
  369. }
  370. }
  371. #endif
  372. if (!bOK)
  373. {
  374. vReleaseFontCacheFile();
  375. }
  376. return bOK;
  377. }
  378. /*****************************************************************************
  379. * BOOL bReAllocCacheFile(ULONG ulSize)
  380. *
  381. * ReAlloc font cache buffer
  382. *
  383. * History
  384. * 11/16/99 YungT create it
  385. * Wrote it.
  386. *****************************************************************************/
  387. BOOL bReAllocCacheFile(ULONG ulSize)
  388. {
  389. BOOL bOK = FALSE;
  390. ULONG ulFileSizeOrg;
  391. ULONG ulSizeExtra;
  392. ULONG ulFileSize;
  393. ulFileSizeOrg = gFontFileCache.pFile->ulFileSize;
  394. ASSERT(ulSize > gFontFileCache.pFile->ulDataSize);
  395. // Calculate the extra cache we need
  396. ulSizeExtra = QWORD_ALIGN(ulSize - gFontFileCache.pFile->ulDataSize);
  397. ulFileSize = ulFileSizeOrg + ulSizeExtra;
  398. if (gFontFileCache.pFile)
  399. {
  400. vReleaseFontCacheFile();
  401. }
  402. if (bOpenFontCacheFile(TRUE, ulFileSize, TRUE))
  403. {
  404. gFontFileCache.pFile->ulFileSize = ulFileSize;
  405. gFontFileCache.pFile->ulDataSize = ulSize;
  406. gFontFileCache.pCacheBuf = (PBYTE) gFontFileCache.pFile + SZ_FONTCACHE_HEADER();
  407. bOK = TRUE;
  408. }
  409. return bOK;
  410. }
  411. /*****************************************************************************
  412. * BOOL FontFileCacheReadRegistry()
  413. *
  414. * Decide we need to open registry or not when load from cache
  415. *
  416. * History
  417. * 07-28-2k Yung-Jen Tony Tsai [YungT]
  418. * Wrote it.
  419. *****************************************************************************/
  420. BOOL FontFileCacheReadRegistry()
  421. {
  422. return gFontFileCache.bReadFromRegistry;
  423. }
  424. /*****************************************************************************
  425. * VOID FontFileCacheFault()
  426. *
  427. * Fault reprot for Engine font cache.
  428. *
  429. * History
  430. * 11-15-99 Yung-Jen Tony Tsai [YungT]
  431. * Wrote it.
  432. *****************************************************************************/
  433. VOID FontFileCacheFault()
  434. {
  435. gflFontCacheState = FONT_CACHE_ERROR_MODE;
  436. }
  437. /*****************************************************************************
  438. * PVOID FontFileCacheAlloc(ULONG ulFastCheckSum, ULONG ulSize)
  439. *
  440. * Alloc the cached buffer for font driver
  441. *
  442. * History
  443. * 11-15-99 Yung-Jen Tony Tsai [YungT]
  444. * Wrote it.
  445. *****************************************************************************/
  446. PVOID FontFileCacheAlloc(ULONG ulSize)
  447. {
  448. PVOID pvIfi = NULL;
  449. {
  450. ASSERT(gflFontCacheState & FONT_CACHE_CREATE_MODE);
  451. if (ghsemFontFileCache == NULL)
  452. return pvIfi;
  453. if (gflFontCacheState & FONT_CACHE_CREATE_MODE)
  454. {
  455. if ( (QWORD_ALIGN(ulSize) < gFontFileCache.pFile->ulDataSize)
  456. || bReAllocCacheFile(ulSize))
  457. {
  458. pvIfi = (PVOID) gFontFileCache.pCacheBuf;
  459. // Gaurantee the cache pointer is at 8 byte boundary
  460. gFontFileCache.pFile->ulDataSize = ulSize;
  461. }
  462. else
  463. {
  464. gflFontCacheState = FONT_CACHE_ERROR_MODE;
  465. }
  466. }
  467. }
  468. return pvIfi;
  469. }
  470. /*****************************************************************************
  471. * PVOID FontFileCacheLookUp(ULONG FastCheckSum, ULONG *pcjData)
  472. *
  473. * Lookup font cache
  474. *
  475. * History
  476. * 11-15-99 Yung-Jen Tony Tsai [YungT]
  477. * Wrote it.
  478. *****************************************************************************/
  479. PVOID FontFileCacheLookUp(ULONG *pcjData)
  480. {
  481. PBYTE pCache = NULL;
  482. *pcjData = 0;
  483. ASSERT(ghsemFontFileCache);
  484. if (ghsemFontFileCache == NULL)
  485. return pCache;
  486. if (gflFontCacheState & FONT_CACHE_LOOKUP_MODE)
  487. {
  488. ASSERT(gFontFileCache.pFile);
  489. ASSERT(gFontFileCache.pCacheBuf == ((PBYTE) gFontFileCache.pFile +
  490. SZ_FONTCACHE_HEADER()));
  491. *pcjData = gFontFileCache.pFile->ulDataSize;
  492. pCache = gFontFileCache.pCacheBuf;
  493. gFontFileCache.pCacheBuf += QWORD_ALIGN(*pcjData);
  494. }
  495. return (PVOID) pCache;
  496. }
  497. /*****************************************************************************
  498. * VOID GetFontFileCacheState()
  499. *
  500. * Clean font file cache after load or update the cache file.
  501. *
  502. * History
  503. * 11-12-99 Yung-Jen Tony Tsai [YungT]
  504. * Wrote it.
  505. *****************************************************************************/
  506. FLONG GetFontFileCacheState()
  507. {
  508. return gflFontCacheState;
  509. }
  510. /*****************************************************************************
  511. * VOID vCloseFontFileCache()
  512. *
  513. * Clean font file cache after load or update the cache file.
  514. *
  515. * History
  516. * 11-12-99 Yung-Jen Tony Tsai [YungT]
  517. * Wrote it.
  518. *****************************************************************************/
  519. VOID vCloseFontFileCache()
  520. {
  521. // do paranoid check
  522. if (!ghsemFontFileCache)
  523. return;
  524. if (gflFontCacheState & FONT_CACHE_MASK)
  525. {
  526. if (gflFontCacheState & FONT_CACHE_CREATE_MODE)
  527. {
  528. // Close the file, we are done recreating it
  529. if (gFontFileCache.pFile)
  530. {
  531. gFontFileCache.pFile->CheckSum = CalcFontFileCacheCheckSum((PVOID) ((PBYTE) gFontFileCache.pFile + 4), (gFontFileCache.cjFileSize - 4));
  532. }
  533. }
  534. }
  535. if (gFontFileCache.hShFolder)
  536. {
  537. FreeLibrary(gFontFileCache.hShFolder);
  538. gFontFileCache.hShFolder = NULL;
  539. }
  540. vReleaseFontCacheFile();
  541. ReleaseSemaphore(ghsemFontFileCache, 1, NULL);
  542. CloseHandle(ghsemFontFileCache);
  543. ghsemFontFileCache = NULL;
  544. gflFontCacheState = 0;
  545. }
  546. /*****************************************************************************
  547. * ULONG CalcFontFileCacheCheckSum(PVOID pvFile, ULONG cjFileSize)
  548. *
  549. * Helper function for query fonts information from font registry
  550. *
  551. * History
  552. * 11-11-99 Yung-Jen Tony Tsai [YungT]
  553. * Wrote it.
  554. *****************************************************************************/
  555. ULONG CalcFontFileCacheCheckSum(PVOID pvFile, ULONG cjFileSize)
  556. {
  557. ULONG sum;
  558. PULONG pulCur,pulEnd;
  559. pulCur = (PULONG) pvFile;
  560. __try
  561. {
  562. for (sum = 0, pulEnd = pulCur + cjFileSize / sizeof(ULONG); pulCur < pulEnd; pulCur += 1)
  563. {
  564. sum += 256 * sum + *pulCur;
  565. }
  566. }
  567. __except (EXCEPTION_EXECUTE_HANDLER)
  568. {
  569. sum = 0; // oh well, not very unique.
  570. }
  571. return ( sum < 2 ) ? 2 : sum; // 0 is reserved for device fonts
  572. // 1 is reserved for TYPE1 fonts
  573. }
  574. /*****************************************************************************
  575. * ULONG QueryFontReg(ULARGE_INTEGER *pFontRegLastWriteTime, ULONG *pulFonts)
  576. *
  577. * Helper function for query fonts information from font registry
  578. *
  579. * History
  580. * 11-15-99 Yung-Jen Tony Tsai [YungT]
  581. * Wrote it.
  582. *****************************************************************************/
  583. BOOL QueryFontReg(ULARGE_INTEGER *pFontRegLastWriteTime)
  584. {
  585. BOOL bOK = FALSE;
  586. ULONG ulFonts;
  587. HKEY hkey;
  588. LONG error = (Globals::IsNt) ? RegOpenKeyExW(HKEY_LOCAL_MACHINE, Globals::FontsKeyW, 0, KEY_QUERY_VALUE, &hkey)
  589. : RegOpenKeyExA(HKEY_LOCAL_MACHINE, Globals::FontsKeyA, 0, KEY_QUERY_VALUE, &hkey);
  590. if (error == ERROR_SUCCESS)
  591. {
  592. // There is no difference between A or W APIs at this case.
  593. error = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, &ulFonts, NULL, NULL, NULL,
  594. (FILETIME *)pFontRegLastWriteTime);
  595. if (error == ERROR_SUCCESS)
  596. {
  597. bOK = TRUE;
  598. }
  599. RegCloseKey(hkey);
  600. }
  601. return bOK;
  602. }
  603. /*****************************************************************************
  604. * BOOL bCreateFontFileCache()
  605. *
  606. * Initialize font file cache, open the cacheplus.dat file and create hash table
  607. *
  608. * History
  609. * 11-09-99 Yung-Jen Tony Tsai [YungT]
  610. * Wrote it.
  611. *****************************************************************************/
  612. BOOL bCreateFontCacheFile(ULARGE_INTEGER FntRegLWT)
  613. {
  614. ULONG ulSize;
  615. BOOL bOk = FALSE;
  616. ulSize = SZ_FONTCACHE_HEADER() + FONT_CACHE_EXTRA_SIZE;
  617. if (gFontFileCache.pFile)
  618. {
  619. vReleaseFontCacheFile();
  620. }
  621. if(bOpenFontCacheFile(FALSE, ulSize, FALSE))
  622. {
  623. gFontFileCache.pFile->ulLanguageID = (ULONG) Globals::LanguageID;
  624. gFontFileCache.pFile->CheckSum = 0;
  625. gFontFileCache.pFile->ulMajorVersionNumber = FONTFILECACHE_VER;
  626. gFontFileCache.pFile->FntRegLWT.QuadPart = FntRegLWT.QuadPart;
  627. gFontFileCache.pFile->ulFileSize = ulSize;
  628. gFontFileCache.pFile->ulDataSize = FONT_CACHE_EXTRA_SIZE;
  629. bOk = TRUE;
  630. }
  631. return bOk;
  632. }
  633. #if DBG
  634. /*****************************************************************************
  635. * BOOL bFontFileCacheDisabled()
  636. *
  637. * Tempary routine for performance evaluation
  638. *
  639. * History
  640. * 11-29-99 Yung-Jen Tony Tsai [YungT]
  641. * Wrote it.
  642. *****************************************************************************/
  643. BOOL bFontFileCacheDisabled()
  644. {
  645. return FALSE;
  646. }
  647. #endif
  648. BOOL bScanRegistry()
  649. {
  650. ASSERT(!Globals::IsNt);
  651. BOOL bOK = TRUE;
  652. ULONG index = 0;
  653. ULONG registrySize = 0;
  654. ULONG numExpected;
  655. // Open the key
  656. HKEY hkey;
  657. PBYTE pCached = (PBYTE) gFontFileCache.pFile + SZ_FONTCACHE_HEADER();
  658. if (*((ULONG *) pCached) != 0xBFBFBFBF)
  659. return FALSE;
  660. LONG error = RegOpenKeyExA(HKEY_LOCAL_MACHINE, Globals::FontsKeyA, 0, KEY_QUERY_VALUE, &hkey);
  661. if (error == ERROR_SUCCESS)
  662. {
  663. DWORD allDataSize = 0;
  664. error = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, &numExpected, NULL, NULL, NULL, NULL);
  665. if (error != ERROR_SUCCESS)
  666. {
  667. RegCloseKey(hkey);
  668. return FALSE;
  669. }
  670. PBYTE pRegistryData;
  671. registrySize = *((ULONG *) (pCached + 4)) ;
  672. pRegistryData = pCached + 8;
  673. while (index < numExpected)
  674. {
  675. DWORD regType = 0;
  676. DWORD labelSize = MAX_PATH;
  677. DWORD dataSize = MAX_PATH;
  678. CHAR label[MAX_PATH];
  679. BYTE data[MAX_PATH];
  680. error = RegEnumValueA(hkey, index, label, &labelSize, NULL, &regType, data, &dataSize);
  681. if (error == ERROR_NO_MORE_ITEMS)
  682. {
  683. bOK = FALSE;
  684. break;
  685. }
  686. if (allDataSize >= registrySize)
  687. {
  688. bOK = FALSE;
  689. break;
  690. }
  691. if (memcmp(pRegistryData, data, dataSize))
  692. {
  693. bOK = FALSE;
  694. break;
  695. }
  696. pRegistryData += dataSize;
  697. allDataSize += dataSize;
  698. index ++;
  699. }
  700. RegCloseKey(hkey);
  701. if (bOK && (allDataSize == registrySize))
  702. return TRUE;
  703. }
  704. return FALSE;
  705. }
  706. /*****************************************************************************
  707. * VOID InitFontFileCache()
  708. *
  709. * Initialize font file cache, open the cacheplus.dat file and create hash table
  710. *
  711. * History
  712. * 11-09-99 Yung-Jen Tony Tsai [YungT]
  713. * Wrote it.
  714. *****************************************************************************/
  715. VOID InitFontFileCache()
  716. {
  717. ULARGE_INTEGER FntRegLWT = { 0, 0};
  718. if (gflFontCacheState)
  719. {
  720. return;
  721. }
  722. #if DBG
  723. // Only for performance evaluation.
  724. if (bFontFileCacheDisabled())
  725. {
  726. goto CleanUp;
  727. }
  728. #endif
  729. // If the named semaphore object existed before the function call,
  730. // the function returns a handle to the existing object and
  731. // GetLastError returns ERROR_ALREADY_EXISTS.
  732. ghsemFontFileCache = CreateSemaphoreA( NULL, 1, 1, FONTLOADCACHE_NAMEOBJ);
  733. // Something wrong, we can not go with font file cache
  734. if (ghsemFontFileCache == NULL)
  735. {
  736. goto CleanUp;
  737. }
  738. else
  739. {
  740. // Wait 5 seconds until the semaphore released.
  741. // No further attempts to create font file cache on timeout.
  742. // This does not mean deial of service - just will work
  743. // slower using GpFontTable::LoadAllFontsFromRegistry(FALSE).
  744. DWORD dwr = WaitForSingleObject(ghsemFontFileCache, 5000);
  745. if (dwr == WAIT_TIMEOUT) goto CleanUp;
  746. }
  747. gFontFileCache.pFile = NULL;
  748. // now open the TT Fonts key :
  749. if (!QueryFontReg(&FntRegLWT))
  750. {
  751. goto CleanUp;
  752. }
  753. if (bOpenFontCacheFile(TRUE, 0, FALSE))
  754. {
  755. // File did not change from last time boot.
  756. if (gFontFileCache.pFile->CheckSum && gFontFileCache.cjFileSize == gFontFileCache.pFile->ulFileSize &&
  757. gFontFileCache.pFile->CheckSum == CalcFontFileCacheCheckSum((PVOID) ((PBYTE) gFontFileCache.pFile + 4), (gFontFileCache.cjFileSize - 4)) &&
  758. gFontFileCache.pFile->ulMajorVersionNumber == FONTFILECACHE_VER &&
  759. gFontFileCache.pFile->ulLanguageID == (ULONG) Globals::LanguageID && // If locale changed, we need to re-create the cache
  760. gFontFileCache.pFile->FntRegLWT.QuadPart == FntRegLWT.QuadPart && // If registry has been updated we need to re-create the cache file
  761. (FntRegLWT.QuadPart != 0 || bScanRegistry())
  762. )
  763. {
  764. gflFontCacheState = FONT_CACHE_LOOKUP_MODE;
  765. }
  766. else
  767. {
  768. if(bCreateFontCacheFile(FntRegLWT))
  769. {
  770. // If something will not match, then it means we need to create FNTCACHE again
  771. gflFontCacheState = FONT_CACHE_CREATE_MODE;
  772. }
  773. }
  774. }
  775. else
  776. {
  777. // If there is no GDIPFONTCACHE.DAT file
  778. // Then we need to create it.
  779. if(bCreateFontCacheFile(FntRegLWT))
  780. {
  781. gflFontCacheState = FONT_CACHE_CREATE_MODE;
  782. }
  783. }
  784. CleanUp:
  785. // Semaphore initialized
  786. if (gflFontCacheState & FONT_CACHE_MASK)
  787. {
  788. // Initialize the start pointer of current Cache table
  789. gFontFileCache.pCacheBuf = (PBYTE) gFontFileCache.pFile + SZ_FONTCACHE_HEADER();
  790. if (FntRegLWT.QuadPart == (ULONGLONG) 0)
  791. gFontFileCache.bReadFromRegistry = TRUE;
  792. else
  793. gFontFileCache.bReadFromRegistry = FALSE;
  794. }
  795. else
  796. {
  797. gflFontCacheState = 0;
  798. // Clean up the memory
  799. if (gFontFileCache.pFile)
  800. {
  801. vReleaseFontCacheFile();
  802. }
  803. if (ghsemFontFileCache)
  804. {
  805. ReleaseSemaphore(ghsemFontFileCache, 1, NULL);
  806. CloseHandle( ghsemFontFileCache);
  807. ghsemFontFileCache = NULL;
  808. }
  809. }
  810. }