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.

1302 lines
44 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: fntsweep.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. * Author: Bodin Dresevic [BodinD]
  6. *
  7. * Copyright (c) 1990 Microsoft Corporation
  8. *
  9. * This file contains font sweeper related stuff.
  10. * On the boot of ths system, i.e. initialization of userk, the
  11. * [Fonts] section of win.ini is checked to
  12. * find out if any new fonts have been added by any font installers.
  13. * If third party installers have installed fonts in the system directory
  14. * those are copied to fonts directory. Any fot entries are replaced
  15. * by appropriate *.ttf entries, any fot files are deleted if they were
  16. * ever installed.
  17. *
  18. \**************************************************************************/
  19. #include "precomp.h"
  20. #pragma hdrstop
  21. #include <setupbat.h> // in sdkinc
  22. CONST WCHAR pwszType1Key[] = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Type 1 Installer\\Type 1 Fonts";
  23. CONST WCHAR pwszSweepType1Key[] = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Type 1 Installer\\LastType1Sweep";
  24. CONST WCHAR pwszUpdType1Key[] = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Type 1 Installer\\Upgraded Type1";
  25. CONST WCHAR pwszFontsKey[] = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";
  26. CONST WCHAR pwszSweepKey[] = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\LastFontSweep";
  27. CONST WCHAR pwszFontDrivers[] = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Font Drivers";
  28. #define LAST_SWEEP_TIME L"LastSweepTime"
  29. #define UPGRADED_TYPE1 L"UpgradedType1"
  30. #define DWORDALIGN(X) (((X) + 3) & ~3)
  31. WCHAR *gpwcSystemDir;
  32. WCHAR *gpwcFontsDir;
  33. BOOL gbWin31Upgrade;
  34. BOOL bCheckIfDualBootingWithWin31()
  35. {
  36. WCHAR Buffer[32];
  37. WCHAR awcWindowsDir[MAX_PATH];
  38. DWORD dwRet;
  39. UINT cwchWinPath;
  40. awcWindowsDir[0] = L'\0'; // prefix:make sure to zero terminated
  41. cwchWinPath = GetSystemWindowsDirectoryW(awcWindowsDir, MAX_PATH);
  42. if ((cwchWinPath == 0) || (cwchWinPath > MAX_PATH))
  43. return FALSE;
  44. // the cwchWinPath value does not include the terminating zero
  45. if (awcWindowsDir[cwchWinPath - 1] == L'\\')
  46. {
  47. cwchWinPath -= 1;
  48. }
  49. awcWindowsDir[cwchWinPath] = L'\0'; // make sure to zero terminated
  50. lstrcatW(awcWindowsDir, L"\\system32\\");
  51. lstrcatW(awcWindowsDir, WINNT_GUI_FILE_W);
  52. dwRet = GetPrivateProfileStringW(
  53. WINNT_DATA_W,
  54. WINNT_D_WIN31UPGRADE_W,
  55. WINNT_A_NO_W,
  56. Buffer,
  57. sizeof(Buffer)/sizeof(WCHAR),
  58. awcWindowsDir
  59. );
  60. #if DBGSWEEP
  61. DbgPrint("\n dwRet = %ld, win31upgrade = %ws\n\n", dwRet, Buffer);
  62. #endif
  63. return (BOOL)(dwRet ? (!lstrcmpiW(Buffer,WINNT_A_YES)) : 0);
  64. }
  65. /******************************Public*Routine******************************\
  66. *
  67. * VOID vNullTermWideString (WCHAR *pwcDest, WCHAR *pwcSrc, ULONG ulLength)
  68. *
  69. * Given pwcSrc, which is not necessarily null-terminated, copy ulLength characters
  70. * the into pwcDest and place a null character after it.
  71. *
  72. * History:
  73. * 03-Feb-99 -by- Donald Chinn [dchinn]
  74. * Wrote it.
  75. \**************************************************************************/
  76. VOID vNullTermWideString (WCHAR *pwcDest, WCHAR *pwcSrc, ULONG ulLength)
  77. {
  78. ULONG index;
  79. for (index = 0; index < ulLength; index++) {
  80. *pwcDest++ = *pwcSrc++;
  81. }
  82. *pwcDest = '\0';
  83. }
  84. /******************************Public*Routine******************************\
  85. *
  86. * BOOL bCheckFontEntry(WCHAR *pwcName, WCHAR *pwcExtension)
  87. *
  88. * This function assumes that both pwcName and pwcExtension are null-terminated.
  89. *
  90. * History:
  91. * 25-Oct-1995 -by- Bodin Dresevic [BodinD]
  92. * Wrote it.
  93. \**************************************************************************/
  94. BOOL bCheckFontEntry(WCHAR *pwcName, WCHAR *pwcExtension)
  95. {
  96. BOOL bRet = FALSE;
  97. LONG cwc = (LONG)wcslen(pwcName) - (LONG)wcslen(pwcExtension);
  98. if (cwc > 0)
  99. {
  100. bRet = !_wcsicmp(&pwcName[cwc], pwcExtension);
  101. }
  102. return bRet;
  103. }
  104. /******************************Public*Routine******************************\
  105. * Process win.ini line
  106. *
  107. * History:
  108. * 24-Oct-1995 -by- Bodin Dresevic [BodinD]
  109. * Wrote it.
  110. \**************************************************************************/
  111. #define EXT_TRUETYPE L"(TrueType)"
  112. #define EXT_FOT L".FOT"
  113. VOID vProcessFontEntry(
  114. HKEY hkey,
  115. WCHAR *pwcValueName,
  116. ULONG ulValueNameLength,
  117. WCHAR *pwcFileName,
  118. ULONG ulFileNameLength
  119. )
  120. {
  121. NTSTATUS Status;
  122. UNICODE_STRING UnicodeString;
  123. BOOL bFot = FALSE;
  124. WCHAR awcTTF[MAX_PATH];
  125. WCHAR awcTmpBuf[MAX_PATH];
  126. WCHAR *pwcTTF;
  127. FLONG fl, fl2;
  128. FLONG flEmbed;
  129. DWORD dwPidTid;
  130. WCHAR awcValueName[MAX_PATH]; // null-terminated pwcValueName
  131. WCHAR awcFileName[MAX_PATH]; // null-terminated pwcFileName
  132. // Make sure the ValueName is null-terminated
  133. ulValueNameLength = min(MAX_PATH - 1, ulValueNameLength);
  134. vNullTermWideString (awcValueName, pwcValueName, ulValueNameLength);
  135. // Make sure the FileName is null-terminated
  136. ulFileNameLength = min(MAX_PATH - 1, ulFileNameLength);
  137. vNullTermWideString (awcFileName, pwcFileName, ulFileNameLength);
  138. if (bCheckFontEntry(awcValueName, EXT_TRUETYPE))
  139. {
  140. // This is a tt entry, either .fot or .ttf
  141. if (bFot = bCheckFontEntry(awcFileName, EXT_FOT))
  142. {
  143. // this is an .fot entry, must find ttf pointed to by .fot,
  144. // but first must get the full path to the .fot file
  145. // for cGetTTFFromFOT routine expects it. We will also need
  146. // the full path to the .fot file so that we can delete it
  147. // eventually.
  148. if (bMakePathNameW(awcTmpBuf, awcFileName, NULL, &fl2))
  149. {
  150. if (cGetTTFFromFOT(awcTmpBuf, MAX_PATH, awcTTF, &fl, &flEmbed, &dwPidTid, TRUE) &&
  151. !(fl & FONT_ISNOT_FOT))
  152. {
  153. // fix the entry to point to .ttf file. At this point
  154. // awcTTF points to the FULL path to the .ttf file.
  155. // However, we will only need a relative path to the
  156. // .ttf file, when the .ttf file is in the %windir%\system
  157. // or %windir%\fonts directories. In case the file is in the
  158. // %windir%\system directory we shall copy it to %windir%\fonts
  159. // directory and write the relative path to the registry.
  160. // In case it is in the %windir%\fonts directory we do not
  161. // touch the file and also just write the relative path to the
  162. // registry. In any other case we just write the full .ttf
  163. // path to the registry.
  164. // first delete the .fot file, it is no longer needed
  165. if (bFot && !gbWin31Upgrade)
  166. {
  167. UserVerify(DeleteFileW(awcTmpBuf));
  168. }
  169. if ((fl & (FONT_IN_FONTS_DIR | FONT_IN_SYSTEM_DIR)) == 0)
  170. {
  171. // if ttf file is not in either the system or the fonts
  172. // directories, just write the full path to the registry
  173. pwcTTF = awcTTF;
  174. }
  175. else
  176. {
  177. // find the bare file part, this is what will be written
  178. // in the registry
  179. pwcTTF = &awcTTF[wcslen(awcTTF) - 1];
  180. while ((pwcTTF >= awcTTF) && (*pwcTTF != L'\\') && (*pwcTTF != L':'))
  181. pwcTTF--;
  182. pwcTTF++;
  183. if (fl & FONT_IN_SYSTEM_DIR)
  184. {
  185. // need to move the ttf to fonts dir, can reuse the
  186. // buffer on the stack:
  187. wcscpy(awcTmpBuf, gpwcFontsDir);
  188. lstrcatW(awcTmpBuf, L"\\");
  189. lstrcatW(awcTmpBuf, pwcTTF);
  190. // note that MoveFile should succeed, for if there was
  191. // a ttf file of the same file name in %windir%\fonts dir
  192. // we would not have been in this code path.
  193. RIPMSG2(RIP_VERBOSE, "Moving %ws to %ws", awcTTF, awcTmpBuf);
  194. if (!gbWin31Upgrade)
  195. {
  196. UserVerify(MoveFileW(awcTTF, awcTmpBuf));
  197. }
  198. else
  199. {
  200. // Boolean value TRUE means "do not copy if target exists"
  201. UserVerify(CopyFileW(awcTTF, awcTmpBuf, TRUE));
  202. }
  203. }
  204. }
  205. RIPMSG2(RIP_VERBOSE, "writing to the registry:\n %ws=%ws", pwcValueName, pwcTTF);
  206. RtlInitUnicodeString(&UnicodeString, awcValueName);
  207. Status = NtSetValueKey(hkey,
  208. &UnicodeString,
  209. 0,
  210. REG_SZ,
  211. pwcTTF,
  212. (wcslen(pwcTTF)+1) * sizeof(WCHAR));
  213. UserAssert(NT_SUCCESS(Status));
  214. }
  215. #if DBG
  216. else
  217. {
  218. RIPMSG1(RIP_WARNING, "Could not locate ttf pointed to by %ws", awcTmpBuf);
  219. }
  220. #endif
  221. }
  222. #if DBG
  223. else
  224. {
  225. RIPMSG1(RIP_WARNING, "Could not locate .fot: %ws", awcFileName);
  226. }
  227. #endif
  228. }
  229. }
  230. else
  231. {
  232. // not a true type case. little bit simpler,
  233. // we will use awcTTF buffer for the full path name, and pwcTTF
  234. // as local variable even though these TTF names are misnomer
  235. // for these are not tt fonts
  236. if (bMakePathNameW(awcTTF, awcFileName,NULL, &fl))
  237. {
  238. // At this point
  239. // awcTTF points to the FULL path to the font file.
  240. // If the font is in the system subdirectory we will just move it
  241. // to the fonts subdirectory. If the path in the registry is relative
  242. // we will leave it alone. If it is an absolute path, we shall
  243. // fix the registry entry to only contain relative path, the
  244. // absolute path is redundant.
  245. if (fl & (FONT_IN_SYSTEM_DIR | FONT_IN_FONTS_DIR))
  246. {
  247. // find the bare file part, this is what will be written
  248. // in the registry
  249. pwcTTF = &awcTTF[wcslen(awcTTF) - 1];
  250. while ((pwcTTF >= awcTTF) && (*pwcTTF != L'\\') && (*pwcTTF != L':'))
  251. pwcTTF--;
  252. pwcTTF++;
  253. if (fl & FONT_IN_SYSTEM_DIR)
  254. {
  255. // need to move the font to fonts dir, can reuse the
  256. // buffer on the stack to build the full destination path
  257. wcscpy(awcTmpBuf, gpwcFontsDir);
  258. lstrcatW(awcTmpBuf, L"\\");
  259. lstrcatW(awcTmpBuf, pwcTTF);
  260. // note that MoveFile should succeed, for if there was
  261. // a font file of the same file name in %windir%\fonts dir
  262. // we would not have been in this code path. The only time
  263. // it could fail if the path in the registry is absolute.
  264. RIPMSG2(RIP_VERBOSE, "Moving %ws to %ws", awcTTF, awcTmpBuf);
  265. if (!gbWin31Upgrade)
  266. {
  267. UserVerify(MoveFileW(awcTTF, awcTmpBuf));
  268. }
  269. else
  270. {
  271. // Boolean value TRUE means "do not copy if target exists"
  272. UserVerify(CopyFileW(awcTTF, awcTmpBuf, TRUE));
  273. }
  274. }
  275. // check if the file path in the registry is absolute,
  276. // if so make it relative:
  277. if (!(fl & FONT_RELATIVE_PATH))
  278. {
  279. RIPMSG2(RIP_VERBOSE, "writing to the registry:\n %ws=%ws", pwcValueName, pwcTTF);
  280. RtlInitUnicodeString(&UnicodeString, awcValueName);
  281. Status = NtSetValueKey(hkey,
  282. &UnicodeString,
  283. 0,
  284. REG_SZ,
  285. pwcTTF,
  286. (wcslen(pwcTTF)+1) * sizeof(WCHAR));
  287. UserAssert(NT_SUCCESS(Status));
  288. }
  289. }
  290. }
  291. }
  292. }
  293. /******************************Public*Routine******************************\
  294. *
  295. * VOID vMoveFileFromSystemToFontsDir(WCHAR *pwcFile)
  296. *
  297. * History:
  298. * 24-Apr-1996 -by- Bodin Dresevic [BodinD]
  299. * Wrote it.
  300. \**************************************************************************/
  301. VOID vMoveFileFromSystemToFontsDir(WCHAR *pwcFile)
  302. {
  303. WCHAR awcTmpBuf[MAX_PATH];
  304. WCHAR awcTmp[MAX_PATH];
  305. FLONG fl;
  306. WCHAR *pwcTmp;
  307. #if DBG
  308. BOOL bOk;
  309. #endif
  310. if (bMakePathNameW(awcTmp, pwcFile,NULL, &fl))
  311. {
  312. // If the font is in the system subdirectory we will just move it
  313. // to the fonts subdirectory. The path in the registry is relative
  314. // and we will leave it alone.
  315. if
  316. (
  317. (fl & (FONT_IN_SYSTEM_DIR | FONT_RELATIVE_PATH)) ==
  318. (FONT_IN_SYSTEM_DIR | FONT_RELATIVE_PATH)
  319. )
  320. {
  321. // find the bare file part, this is what will be written
  322. // in the registry
  323. pwcTmp = &awcTmp[wcslen(awcTmp) - 1];
  324. while ((pwcTmp >= awcTmp) && (*pwcTmp != L'\\') && (*pwcTmp != L':'))
  325. pwcTmp--;
  326. if (pwcTmp > awcTmp)
  327. pwcTmp++;
  328. // need to move the font to fonts dir, can reuse the
  329. // buffer on the stack to build the full destination path
  330. wcscpy(awcTmpBuf, gpwcFontsDir);
  331. lstrcatW(awcTmpBuf, L"\\");
  332. lstrcatW(awcTmpBuf, pwcTmp);
  333. // note that MoveFile should succeed, for if there was
  334. // a font file of the same file name in %windir%\fonts dir
  335. // we would not have been in this code path.
  336. #if DBG
  337. bOk =
  338. #endif
  339. MoveFileW(awcTmp, awcTmpBuf);
  340. RIPMSG3(RIP_VERBOSE,
  341. "move %ws to %ws %s",
  342. awcTmp,
  343. awcTmpBuf,
  344. (bOk) ? "succeeded" : "failed");
  345. }
  346. #if DBG
  347. else
  348. {
  349. RIPMSG2(RIP_WARNING,
  350. "File %ws not in system directory, fl = 0x%lx\n",
  351. awcTmp, fl);
  352. }
  353. #endif
  354. }
  355. #if DBG
  356. else
  357. {
  358. RIPMSG1(RIP_WARNING, "Could not locate %ws", pwcFile);
  359. }
  360. #endif
  361. }
  362. /******************************Public*Routine******************************\
  363. *
  364. * VOID vProcessType1FontEntry
  365. *
  366. *
  367. * Effects: All this routine does is to check if pwcPFM and pwcPFB pointed to
  368. * by pwcValueData point to files in the %windir%system directory
  369. * and if so copies these type 1 files to %windir%\fonts directory
  370. *
  371. * History:
  372. * 20-Nov-1995 -by- Bodin Dresevic [BodinD]
  373. * Wrote it.
  374. \**************************************************************************/
  375. VOID vProcessType1FontEntry(
  376. HKEY hkey,
  377. WCHAR *pwcValueName,
  378. ULONG ulValueNameLength,
  379. WCHAR *pwcValueData,
  380. ULONG ulValueDataLength
  381. )
  382. {
  383. WCHAR *pwcPFM, *pwcPFB;
  384. UNREFERENCED_PARAMETER(hkey);
  385. UNREFERENCED_PARAMETER(pwcValueName);
  386. UNREFERENCED_PARAMETER(ulValueNameLength);
  387. UNREFERENCED_PARAMETER(ulValueDataLength);
  388. // skip unused boolean value in this multi reg_sz string:
  389. if ((pwcValueData[0] != L'\0') && (pwcValueData[1] == L'\0'))
  390. {
  391. pwcPFM = &pwcValueData[2];
  392. pwcPFB = pwcPFM + wcslen(pwcPFM) + 1; // add 1 for zero separator
  393. vMoveFileFromSystemToFontsDir(pwcPFM);
  394. vMoveFileFromSystemToFontsDir(pwcPFB);
  395. }
  396. }
  397. /******************************Public*Routine******************************\
  398. *
  399. * VOID vAddRemote/LocalType1Font
  400. *
  401. * History:
  402. * 25-Apr-1996 -by- Bodin Dresevic [BodinD]
  403. * Wrote it.
  404. \**************************************************************************/
  405. VOID vAddType1Font(
  406. WCHAR *pwcValueData,
  407. DWORD dwFlags
  408. )
  409. {
  410. WCHAR *pwcPFM, *pwcPFB, *pwcMMM;
  411. #if DBG
  412. int iRet;
  413. #endif
  414. // skip unused boolean value in this multi reg_sz string:
  415. if ((pwcValueData[0] != L'\0') && (pwcValueData[1] == L'\0'))
  416. {
  417. pwcPFM = &pwcValueData[2];
  418. pwcPFB = pwcPFM + wcslen(pwcPFM) + 1; // add 1 for zero separator
  419. pwcMMM = pwcPFB + wcslen(pwcPFB) + 1; // may of may not be there.
  420. // replace space by separator and call addfontresourcew
  421. pwcPFB[-1] = PATH_SEPARATOR;
  422. // if this is a multiple master font, need one more separator:
  423. if (pwcMMM[0] != L'\0')
  424. pwcMMM[-1] = PATH_SEPARATOR;
  425. #if DBG
  426. iRet =
  427. #endif
  428. GdiAddFontResourceW(pwcPFM, dwFlags, NULL);
  429. #if DBGSWEEP
  430. DbgPrint("%ld = GdiAddFontResourceW(%ws, 0x%lx);\n",
  431. iRet, pwcPFM, dwFlags);
  432. #endif
  433. }
  434. }
  435. VOID vAddRemoteType1Font(
  436. HKEY hkey,
  437. WCHAR *pwcValueName,
  438. ULONG ulValueNameLength,
  439. WCHAR *pwcValueData,
  440. ULONG ulValueDataLength
  441. )
  442. {
  443. UNREFERENCED_PARAMETER(hkey);
  444. UNREFERENCED_PARAMETER(pwcValueName);
  445. UNREFERENCED_PARAMETER(ulValueNameLength);
  446. UNREFERENCED_PARAMETER(ulValueDataLength);
  447. vAddType1Font(pwcValueData, AFRW_ADD_REMOTE_FONT);
  448. }
  449. VOID vAddLocalType1Font(
  450. HKEY hkey,
  451. WCHAR *pwcValueName,
  452. ULONG ulValueNameLength,
  453. WCHAR *pwcValueData,
  454. ULONG ulValueDataLength
  455. )
  456. {
  457. UNREFERENCED_PARAMETER(hkey);
  458. UNREFERENCED_PARAMETER(pwcValueName);
  459. UNREFERENCED_PARAMETER(ulValueNameLength);
  460. UNREFERENCED_PARAMETER(ulValueDataLength);
  461. vAddType1Font(pwcValueData, AFRW_ADD_LOCAL_FONT);
  462. }
  463. typedef VOID (*PFNENTRY)(HKEY hkey, WCHAR *, ULONG, WCHAR *, ULONG);
  464. /******************************Public*Routine******************************\
  465. *
  466. * VOID vFontSweep()
  467. *
  468. * This is the main routine in this module. Checks if the fonts need to be
  469. * "sweeped" and does so if need be.
  470. *
  471. * History:
  472. * 27-Oct-1995 -by- Bodin Dresevic [BodinD]
  473. * Wrote it.
  474. \**************************************************************************/
  475. VOID vSweepFonts(
  476. PCWSTR pwszFontListKey, // font list key
  477. PCWSTR pwszFontSweepKey, // the corresponding sweep key
  478. PFNENTRY pfnProcessFontEntry, // function that processes individual entry
  479. BOOL bForceEnum // force enumeration
  480. )
  481. {
  482. DWORD cjMaxValueName;
  483. DWORD iFont;
  484. NTSTATUS Status;
  485. UNICODE_STRING UnicodeString;
  486. OBJECT_ATTRIBUTES ObjA;
  487. KEY_FULL_INFORMATION KeyInfo;
  488. DWORD dwReturnLength;
  489. PKEY_VALUE_FULL_INFORMATION KeyValueInfo;
  490. BYTE *pjValueData;
  491. HKEY hkey = NULL;
  492. struct {
  493. KEY_VALUE_PARTIAL_INFORMATION;
  494. LARGE_INTEGER;
  495. } SweepValueInfo;
  496. LARGE_INTEGER LastSweepTime;
  497. BOOL bSweep = FALSE;
  498. HKEY hkeyLastSweep;
  499. DWORD cjData;
  500. if (!bForceEnum)
  501. {
  502. // first check if anything needs to be done, that is, if anybody
  503. // touched the [Fonts] section of the registry since the last time we sweeped it.
  504. // get the time of the last sweep of the fonts section of the registry:
  505. RtlInitUnicodeString(&UnicodeString, pwszFontSweepKey);
  506. InitializeObjectAttributes(&ObjA,
  507. &UnicodeString,
  508. OBJ_CASE_INSENSITIVE,
  509. NULL,
  510. NULL);
  511. Status = NtOpenKey(&hkeyLastSweep,
  512. KEY_READ | KEY_WRITE,
  513. &ObjA);
  514. if (!NT_SUCCESS(Status))
  515. {
  516. DWORD dwDisposition;
  517. // We are running for the first time, we need to create the key
  518. // for it does not exist as yet at this time
  519. bSweep = TRUE;
  520. // Create the key, open it for writing, since we will have to
  521. // store the time when the [Fonts] section of the registry was last swept
  522. Status = NtCreateKey(&hkeyLastSweep,
  523. KEY_WRITE,
  524. &ObjA,
  525. 0,
  526. NULL,
  527. REG_OPTION_NON_VOLATILE,
  528. &dwDisposition);
  529. if (!NT_SUCCESS(Status))
  530. return;
  531. }
  532. else
  533. {
  534. RtlInitUnicodeString(&UnicodeString, LAST_SWEEP_TIME);
  535. Status = NtQueryValueKey(hkeyLastSweep,
  536. &UnicodeString,
  537. KeyValuePartialInformation,
  538. &SweepValueInfo,
  539. sizeof(SweepValueInfo),
  540. &dwReturnLength);
  541. if (!NT_SUCCESS(Status))
  542. {
  543. bSweep = TRUE; // force sweep, something is suspicious
  544. }
  545. else
  546. {
  547. UserAssert(SweepValueInfo.Type == REG_BINARY);
  548. UserAssert(SweepValueInfo.DataLength == sizeof(LastSweepTime));
  549. RtlCopyMemory(&LastSweepTime, &SweepValueInfo.Data, sizeof(LastSweepTime));
  550. }
  551. }
  552. }
  553. else
  554. {
  555. bSweep = TRUE;
  556. }
  557. // now open the Fonts key and get the time the key last changed:
  558. // now get the time of the time of the last change is bigger than
  559. // the time of last sweep, must sweep again:
  560. RtlInitUnicodeString(&UnicodeString, pwszFontListKey);
  561. InitializeObjectAttributes(&ObjA,
  562. &UnicodeString,
  563. OBJ_CASE_INSENSITIVE,
  564. NULL,
  565. NULL);
  566. Status = NtOpenKey(&hkey,
  567. KEY_READ | KEY_WRITE,
  568. &ObjA);
  569. if (NT_SUCCESS(Status))
  570. {
  571. // get the number of entries in the [Fonts] section
  572. Status = NtQueryKey(hkey,
  573. KeyFullInformation,
  574. &KeyInfo,
  575. sizeof(KeyInfo),
  576. &dwReturnLength);
  577. if (NT_SUCCESS(Status) && KeyInfo.Values)
  578. {
  579. UserAssert(!(KeyInfo.ClassLength | KeyInfo.SubKeys | KeyInfo.MaxNameLen | KeyInfo.MaxClassLen));
  580. // now let us check if the fonts need to be sweeped. This is the case
  581. // when the registry last write time is bigger than the last sweep time
  582. if (!bSweep)
  583. {
  584. if (KeyInfo.LastWriteTime.QuadPart != LastSweepTime.QuadPart ) {
  585. bSweep = TRUE;
  586. }
  587. }
  588. // init system dir, we will need it:
  589. if (bSweep &&
  590. bInitSystemAndFontsDirectoriesW(&gpwcSystemDir, &gpwcFontsDir))
  591. {
  592. // alloc buffer big enough to hold the biggest ValueName and ValueData
  593. cjMaxValueName = DWORDALIGN(KeyInfo.MaxValueNameLen + sizeof(WCHAR));
  594. // allocate temporary buffer into which we are going to pull the contents
  595. // of the registry
  596. KeyInfo.MaxValueDataLen = DWORDALIGN(KeyInfo.MaxValueDataLen);
  597. cjData = cjMaxValueName + // space for the value name
  598. KeyInfo.MaxValueDataLen ; // space for the value data
  599. if (KeyValueInfo = UserLocalAlloc(0, sizeof(*KeyValueInfo) + cjData))
  600. {
  601. for (iFont = 0; iFont < KeyInfo.Values; iFont++)
  602. {
  603. Status = NtEnumerateValueKey(
  604. hkey,
  605. iFont,
  606. KeyValueFullInformation,
  607. KeyValueInfo,
  608. sizeof(*KeyValueInfo) + cjData,
  609. &dwReturnLength);
  610. if (NT_SUCCESS(Status))
  611. {
  612. UserAssert(KeyValueInfo->NameLength <= KeyInfo.MaxValueNameLen);
  613. UserAssert(KeyValueInfo->DataLength <= KeyInfo.MaxValueDataLen);
  614. UserAssert((KeyValueInfo->Type == REG_SZ) || (KeyValueInfo->Type == REG_MULTI_SZ));
  615. // data goes into the second half of the buffer
  616. pjValueData = (BYTE *)KeyValueInfo + KeyValueInfo->DataOffset;
  617. // see if the font files are where the registry claims they are.
  618. // It is unfortunate we have to do this because SearchPathW
  619. // is slow because it touches the disk.
  620. (*pfnProcessFontEntry)(hkey,
  621. KeyValueInfo->Name,
  622. KeyValueInfo->NameLength / sizeof(WCHAR),
  623. (WCHAR *)pjValueData,
  624. KeyValueInfo->DataLength / sizeof(WCHAR));
  625. }
  626. }
  627. if (!bForceEnum)
  628. {
  629. // now that the sweep is completed, get the last write time
  630. // and store it as the LastSweepTime at the appropriate location
  631. Status = NtQueryKey(hkey,
  632. KeyFullInformation,
  633. &KeyInfo,
  634. sizeof(KeyInfo),
  635. &dwReturnLength);
  636. UserAssert(NT_SUCCESS(Status));
  637. // now remember the result
  638. RtlInitUnicodeString(&UnicodeString, LAST_SWEEP_TIME);
  639. Status = NtSetValueKey(hkeyLastSweep,
  640. &UnicodeString,
  641. 0,
  642. REG_BINARY,
  643. &KeyInfo.LastWriteTime,
  644. sizeof(KeyInfo.LastWriteTime));
  645. UserAssert(NT_SUCCESS(Status));
  646. }
  647. // free the memory that will be no longer needed
  648. UserLocalFree(KeyValueInfo);
  649. }
  650. }
  651. }
  652. NtClose(hkey);
  653. }
  654. if (!bForceEnum)
  655. {
  656. NtClose(hkeyLastSweep);
  657. }
  658. }
  659. /******************************Public*Routine******************************\
  660. *
  661. * BOOL bLoadableFontDrivers()
  662. *
  663. * open the font drivers key and check if there are any entries, if so
  664. * return true. If that is the case we will call AddFontResourceW on
  665. * Type 1 fonts at boot time, right after user had logged on
  666. * PostScript printer drivers are not initialized at this time yet,
  667. * it is safe to do it at this time.
  668. * Effects:
  669. *
  670. * Warnings:
  671. *
  672. * History:
  673. * 24-Apr-1996 -by- Bodin Dresevic [BodinD]
  674. * Wrote it.
  675. \**************************************************************************/
  676. BOOL bLoadableFontDrivers()
  677. {
  678. NTSTATUS Status;
  679. UNICODE_STRING UnicodeString;
  680. OBJECT_ATTRIBUTES ObjA;
  681. KEY_FULL_INFORMATION KeyInfo;
  682. DWORD dwReturnLength;
  683. HKEY hkey = NULL;
  684. BOOL bRet = FALSE;
  685. // open the font drivers key and check if there are any entries, if so
  686. // return true. If that is the case we will call AddFontResourceW on
  687. // Type 1 fonts at boot time, right after user had logged on
  688. // PostScript printer drivers are not initialized at this time yet,
  689. // it is safe to do it at this time.
  690. RtlInitUnicodeString(&UnicodeString, pwszFontDrivers);
  691. InitializeObjectAttributes(&ObjA,
  692. &UnicodeString,
  693. OBJ_CASE_INSENSITIVE,
  694. NULL,
  695. NULL);
  696. Status = NtOpenKey(&hkey,
  697. KEY_READ,
  698. &ObjA);
  699. if (NT_SUCCESS(Status))
  700. {
  701. // get the number of entries in the [Fonts] section
  702. Status = NtQueryKey(hkey,
  703. KeyFullInformation,
  704. &KeyInfo,
  705. sizeof(KeyInfo),
  706. &dwReturnLength);
  707. if (NT_SUCCESS(Status) && KeyInfo.Values)
  708. {
  709. UserAssert(!(KeyInfo.ClassLength | KeyInfo.SubKeys | KeyInfo.MaxNameLen | KeyInfo.MaxClassLen));
  710. // externally loadable drivers are present, force sweep
  711. bRet = TRUE;
  712. }
  713. NtClose(hkey);
  714. }
  715. return bRet;
  716. }
  717. /***********************Public*Routine******************************\
  718. *
  719. * BOOL bCheckAndDeleteTTF()
  720. *
  721. * Checks whether there is a converted TTF corresponding to
  722. * a Type1 font. Delete the TTF file and the reg entry if there is.
  723. *
  724. * History:
  725. * 29-Jan-1998 -by- Xudong Wu [TessieW]
  726. * Wrote it.
  727. \*******************************************************************/
  728. BOOL bCheckAndDeleteTTF
  729. (
  730. HKEY hkey,
  731. PKEY_FULL_INFORMATION pKeyInfo,
  732. PKEY_VALUE_FULL_INFORMATION KeyValueInfo,
  733. PKEY_VALUE_BASIC_INFORMATION KeyValueBasicInfo,
  734. DWORD cjData
  735. )
  736. {
  737. NTSTATUS Status;
  738. UNICODE_STRING UnicodeString;
  739. DWORD dwReturnLength;
  740. ULONG iFont;
  741. WCHAR awcTmp[MAX_PATH], *pFontName, *pType1Name, *pwcFile;
  742. BOOL bDelTTFfile, bRet = TRUE;
  743. FLONG fl;
  744. WCHAR awcType1Name[MAX_PATH]; // null-terminated pType1Name
  745. WCHAR awcFontName[MAX_PATH]; // null-terminated pFontName
  746. WCHAR awcFile[MAX_PATH]; // null-terminated pwcFile
  747. // pKeyInfo holds the full info on the key "Fonts"
  748. for (iFont = 0; iFont < pKeyInfo->Values; iFont++)
  749. {
  750. RtlZeroMemory(KeyValueInfo->Name, cjData);
  751. Status = NtEnumerateValueKey(
  752. hkey,
  753. iFont,
  754. KeyValueFullInformation,
  755. KeyValueInfo,
  756. sizeof(*KeyValueInfo) + cjData,
  757. &dwReturnLength);
  758. if (NT_SUCCESS(Status))
  759. {
  760. UserAssert(KeyValueInfo->NameLength <= pKeyInfo->MaxValueNameLen);
  761. UserAssert(KeyValueInfo->DataLength <= pKeyInfo->MaxValueDataLen);
  762. UserAssert(KeyValueInfo->Type == REG_SZ);
  763. bDelTTFfile = FALSE;
  764. // Make sure we use null-terminated strings
  765. vNullTermWideString (awcType1Name,
  766. KeyValueBasicInfo->Name,
  767. KeyValueBasicInfo->NameLength / sizeof(WCHAR));
  768. vNullTermWideString (awcFontName,
  769. KeyValueInfo->Name,
  770. KeyValueInfo->NameLength / sizeof(WCHAR));
  771. vNullTermWideString (awcFile,
  772. (WCHAR *) ((BYTE *)KeyValueInfo + KeyValueInfo->DataOffset),
  773. KeyValueInfo->DataLength / sizeof(WCHAR));
  774. pType1Name = awcType1Name;
  775. pFontName = awcFontName;
  776. pwcFile = awcFile;
  777. while((*pType1Name) && (*pType1Name++ == *pFontName++))
  778. ;
  779. // if the font name match the type1 name
  780. // check whether this is a ttf font
  781. if ((*pType1Name == 0) && (*pFontName++ == L' '))
  782. {
  783. WCHAR *pTrueType = L"(TrueType)";
  784. while(*pTrueType && (*pTrueType++ == *pFontName++))
  785. ;
  786. if (*pTrueType == 0)
  787. {
  788. bDelTTFfile = TRUE;
  789. }
  790. }
  791. if (bDelTTFfile)
  792. {
  793. // delete the converted TTF file
  794. if (bRet = bMakePathNameW(awcTmp, pwcFile, NULL, &fl))
  795. {
  796. UserVerify((bRet = DeleteFileW(awcTmp)));
  797. }
  798. // remove the reg entry
  799. *pFontName = 0;
  800. RtlInitUnicodeString(&UnicodeString, awcFontName);
  801. Status = NtDeleteValueKey(hkey, (PUNICODE_STRING)&UnicodeString);
  802. // decrement the number of values under [Fonts]
  803. if (NT_SUCCESS(Status))
  804. pKeyInfo->Values--;
  805. else
  806. bRet = FALSE;
  807. break;
  808. }
  809. }
  810. else
  811. {
  812. bRet = FALSE;
  813. break;
  814. }
  815. }
  816. return bRet;
  817. }
  818. /***********************Public*Routine**************************\
  819. *
  820. * BOOL bCleanConvertedTTFs()
  821. *
  822. * Enumerate each entry under "Upgrade Type1" key, call
  823. * bCheckAndDeleteTTF() to remove the coverted TTFs.
  824. *
  825. * History:
  826. * 29-Jan-1998 -by- Xudong Wu [TessieW]
  827. * Wrote it.
  828. \***************************************************************/
  829. BOOL bCleanConvertedTTFs()
  830. {
  831. UNICODE_STRING UnicodeString;
  832. OBJECT_ATTRIBUTES ObjA;
  833. NTSTATUS Status;
  834. HKEY hkeyFonts = NULL, hkeyType1 = NULL;
  835. DWORD dwReturnLength;
  836. DWORD iFontT1, cjData;
  837. DWORD cjMaxValueNameT1, cjMaxValueNameFonts;
  838. BOOL bRet = FALSE, bError = FALSE;
  839. KEY_FULL_INFORMATION KeyInfoType1, KeyInfoFonts;
  840. PKEY_VALUE_BASIC_INFORMATION KeyValueBasicInfo;
  841. PKEY_VALUE_FULL_INFORMATION KeyValueInfo;
  842. // Open and query the value from the "Type1 Fonts" key
  843. // No need to continue if not succeed or no Type1 font listed
  844. RtlInitUnicodeString(&UnicodeString, pwszType1Key);
  845. InitializeObjectAttributes(&ObjA,
  846. &UnicodeString,
  847. OBJ_CASE_INSENSITIVE,
  848. NULL,
  849. NULL);
  850. Status = NtOpenKey(&hkeyType1,
  851. KEY_READ | KEY_WRITE,
  852. &ObjA);
  853. if (NT_SUCCESS(Status))
  854. {
  855. Status = NtQueryKey(hkeyType1,
  856. KeyFullInformation,
  857. &KeyInfoType1,
  858. sizeof(KeyInfoType1),
  859. &dwReturnLength);
  860. if (NT_SUCCESS(Status) && KeyInfoType1.Values)
  861. {
  862. UserAssert(!(KeyInfoType1.ClassLength | KeyInfoType1.SubKeys |
  863. KeyInfoType1.MaxNameLen | KeyInfoType1.MaxClassLen));
  864. cjMaxValueNameT1 = DWORDALIGN(KeyInfoType1.MaxValueNameLen + sizeof(WCHAR));
  865. // Alloc buffer big enough to hold the longest Name
  866. if (KeyValueBasicInfo = UserLocalAlloc(0, sizeof(*KeyValueBasicInfo) + cjMaxValueNameT1))
  867. {
  868. RtlInitUnicodeString(&UnicodeString, pwszFontsKey);
  869. InitializeObjectAttributes(&ObjA,
  870. &UnicodeString,
  871. OBJ_CASE_INSENSITIVE,
  872. NULL,
  873. NULL);
  874. Status = NtOpenKey(&hkeyFonts,
  875. KEY_READ | KEY_WRITE,
  876. &ObjA);
  877. if (NT_SUCCESS(Status)) {
  878. Status = NtQueryKey(hkeyFonts,
  879. KeyFullInformation,
  880. &KeyInfoFonts,
  881. sizeof(KeyInfoFonts),
  882. &dwReturnLength);
  883. if (NT_SUCCESS(Status) && KeyInfoFonts.Values) {
  884. UserAssert(!(KeyInfoFonts.ClassLength | KeyInfoFonts.SubKeys |
  885. KeyInfoFonts.MaxNameLen | KeyInfoFonts.MaxClassLen));
  886. cjMaxValueNameFonts = DWORDALIGN(KeyInfoFonts.MaxValueNameLen + sizeof(WCHAR));
  887. KeyInfoFonts.MaxValueDataLen = DWORDALIGN(KeyInfoFonts.MaxValueDataLen);
  888. cjData = cjMaxValueNameFonts + KeyInfoFonts.MaxValueDataLen;
  889. // Alloc buffer big enough to hold the longest Name and Value
  890. if (KeyValueInfo = UserLocalAlloc(0, sizeof(*KeyValueInfo) + cjData))
  891. {
  892. // Enum the "Type1 Fonts" key
  893. for (iFontT1 = 0; iFontT1 < KeyInfoType1.Values; iFontT1++)
  894. {
  895. RtlZeroMemory(KeyValueBasicInfo->Name, cjMaxValueNameT1);
  896. Status = NtEnumerateValueKey(
  897. hkeyType1,
  898. iFontT1,
  899. KeyValueBasicInformation,
  900. KeyValueBasicInfo,
  901. sizeof(*KeyValueBasicInfo) + cjMaxValueNameT1,
  902. &dwReturnLength);
  903. if (NT_SUCCESS(Status))
  904. {
  905. UserAssert(KeyValueBasicInfo->NameLength <= KeyInfoType1.MaxValueNameLen);
  906. UserAssert(KeyValueBasicInfo->Type == REG_MULTI_SZ);
  907. // For each Type1 font, check to see whether
  908. // there is corresponding converted TTF
  909. // Delete the TTF file and reg entry if any
  910. bRet = bCheckAndDeleteTTF(hkeyFonts, &KeyInfoFonts, KeyValueInfo,
  911. KeyValueBasicInfo, cjData);
  912. if (!bRet)
  913. {
  914. bError = TRUE;
  915. }
  916. }
  917. }
  918. UserLocalFree(KeyValueInfo);
  919. // no type1 fonts installed
  920. if (KeyInfoType1.Values == 0)
  921. {
  922. bRet = TRUE;
  923. }
  924. }
  925. }
  926. NtClose(hkeyFonts);
  927. } // NtOpenKey (hkeyFonts)
  928. UserLocalFree(KeyValueBasicInfo);
  929. }
  930. } // NtQueryKey (hkeyType1)
  931. NtClose(hkeyType1);
  932. }
  933. return (bRet && !bError);
  934. }
  935. /***********************Public*Routine******************************\
  936. *
  937. * VOID vCleanConvertedTTFs()
  938. *
  939. * Delete the converted TTFs and clean the registry if there is any
  940. * TTFs generated from Type1 fonts.
  941. *
  942. * History:
  943. * 29-Jan-1998 -by- Xudong Wu [TessieW]
  944. * Wrote it.
  945. \*******************************************************************/
  946. VOID vCleanConvertedTTFs()
  947. {
  948. BOOL bNeedUpgrade = FALSE;
  949. UNICODE_STRING UnicodeString;
  950. OBJECT_ATTRIBUTES ObjA;
  951. DWORD dwReturnLength;
  952. NTSTATUS Status;
  953. HKEY hkeyUpgradeType1 = NULL;
  954. struct {
  955. KEY_VALUE_PARTIAL_INFORMATION;
  956. LARGE_INTEGER;
  957. } UpgradeValueInfo;
  958. DWORD UpgradeValue = 0;
  959. RtlInitUnicodeString(&UnicodeString, pwszUpdType1Key);
  960. InitializeObjectAttributes(&ObjA,
  961. &UnicodeString,
  962. OBJ_CASE_INSENSITIVE,
  963. NULL,
  964. NULL);
  965. Status = NtOpenKey(&hkeyUpgradeType1,
  966. KEY_READ | KEY_WRITE,
  967. &ObjA);
  968. if (!NT_SUCCESS(Status))
  969. {
  970. // Key doesn't exist, run for the first time
  971. // Create the key, open it for writing
  972. DWORD dwDisposition;
  973. Status = NtCreateKey(&hkeyUpgradeType1,
  974. KEY_WRITE,
  975. &ObjA,
  976. 0,
  977. NULL,
  978. REG_OPTION_NON_VOLATILE,
  979. &dwDisposition);
  980. if (NT_SUCCESS(Status))
  981. {
  982. bNeedUpgrade = TRUE;
  983. }
  984. }
  985. else
  986. {
  987. RtlInitUnicodeString(&UnicodeString, UPGRADED_TYPE1);
  988. Status = NtQueryValueKey(hkeyUpgradeType1,
  989. &UnicodeString,
  990. KeyValuePartialInformation,
  991. &UpgradeValueInfo,
  992. sizeof(UpgradeValueInfo),
  993. &dwReturnLength);
  994. if (NT_SUCCESS(Status))
  995. {
  996. UserAssert(UpgradeValueInfo.Type == REG_DWORD);
  997. UserAssert(UpgradeValueInfo.DataLength == sizeof(UpgradeValue));
  998. RtlCopyMemory(&UpgradeValue, &UpgradeValueInfo.Data, sizeof(UpgradeValue));
  999. // Done if the value is non-zero.
  1000. if (UpgradeValue == 0)
  1001. {
  1002. bNeedUpgrade = TRUE;
  1003. }
  1004. }
  1005. }
  1006. if (bNeedUpgrade)
  1007. {
  1008. if (bCleanConvertedTTFs())
  1009. {
  1010. UpgradeValue = 1;
  1011. }
  1012. RtlInitUnicodeString(&UnicodeString, UPGRADED_TYPE1);
  1013. Status = NtSetValueKey(hkeyUpgradeType1,
  1014. &UnicodeString,
  1015. 0,
  1016. REG_DWORD,
  1017. &UpgradeValue,
  1018. sizeof(UpgradeValue));
  1019. UserAssert(NT_SUCCESS(Status));
  1020. }
  1021. if (hkeyUpgradeType1)
  1022. {
  1023. NtClose(hkeyUpgradeType1);
  1024. }
  1025. }
  1026. /******************************Public*Routine******************************\
  1027. *
  1028. * VOID vFontSweep()
  1029. *
  1030. * Effects: The main routine, calls vSweepFonts to sweep "regular" fonts
  1031. * and then to sweep type 1 fonts
  1032. *
  1033. * History:
  1034. * 20-Nov-1995 -by- Bodin Dresevic [BodinD]
  1035. * Wrote it.
  1036. \**************************************************************************/
  1037. VOID vFontSweep(
  1038. VOID)
  1039. {
  1040. /*
  1041. * Check if shared windows directory installation.
  1042. */
  1043. gbWin31Upgrade = bCheckIfDualBootingWithWin31();
  1044. /*
  1045. * Before we sweep the files to the Fonts directory, check whether the
  1046. * 'converted' TTFs have been removed.
  1047. */
  1048. vCleanConvertedTTFs();
  1049. /*
  1050. * Sweep fonts in the [Fonts] key.
  1051. */
  1052. vSweepFonts(pwszFontsKey, pwszSweepKey, vProcessFontEntry, FALSE);
  1053. /*
  1054. * Now sweep type 1 fonts, if any.
  1055. */
  1056. vSweepFonts(pwszType1Key, pwszSweepType1Key, vProcessType1FontEntry, FALSE);
  1057. if (gpwcSystemDir) {
  1058. UserLocalFree(gpwcSystemDir);
  1059. gpwcSystemDir = NULL;
  1060. }
  1061. }
  1062. /******************************Public*Routine******************************\
  1063. * vLoadLT1Fonts
  1064. *
  1065. * History:
  1066. * 30-Apr-1996 -by- Bodin Dresevic [BodinD]
  1067. * Wrote it.
  1068. \**************************************************************************/
  1069. VOID vLoadT1Fonts(
  1070. PFNENTRY pfnProcessFontEntry)
  1071. {
  1072. if (bLoadableFontDrivers()) {
  1073. /*
  1074. * Now enum and add remote type1 fonts if any.
  1075. */
  1076. vSweepFonts(pwszType1Key, pwszSweepType1Key, pfnProcessFontEntry, TRUE);
  1077. if (gpwcSystemDir) {
  1078. UserLocalFree(gpwcSystemDir);
  1079. gpwcSystemDir = NULL;
  1080. }
  1081. }
  1082. }
  1083. VOID vLoadLocalT1Fonts(
  1084. VOID)
  1085. {
  1086. vLoadT1Fonts(vAddLocalType1Font);
  1087. }
  1088. VOID vLoadRemoteT1Fonts(
  1089. VOID)
  1090. {
  1091. vLoadT1Fonts(vAddRemoteType1Font);
  1092. }