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.

587 lines
16 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: fon16.c
  3. *
  4. * routines for accessing font resources within *.fon files
  5. * (win 3.0 16 bit dlls)
  6. *
  7. * Created: 08-May-1991 12:55:14
  8. * Author: Bodin Dresevic [BodinD]
  9. *
  10. * Copyright (c) 1990 Microsoft Corporation
  11. *
  12. \**************************************************************************/
  13. /*
  14. local Hungarian
  15. j byte
  16. cj count of bytes
  17. pj pointer to byte
  18. off offset
  19. rt resource type
  20. rn resource name
  21. dp offset (ptrdiff_t)
  22. ne new exe, Win16 format, see windows\core\ntgdi\inc\exehdr.h
  23. */
  24. #include "fd.h"
  25. #include "exehdr.h"
  26. // GETS ushort at (PBYTE)pv + off. both pv and off must be even
  27. #define US_GET(pv,off) ( *(UNALIGNED PUSHORT)((PBYTE)(pv) + (off)) )
  28. #if DBG
  29. DWORD g_BreakAboutBadFonts;
  30. DWORD g_PrintAboutBadFonts = TRUE;
  31. #endif
  32. VOID
  33. __cdecl
  34. NotifyBadFont(
  35. PCSTR Format,
  36. ...
  37. )
  38. {
  39. #if DBG
  40. if (g_PrintAboutBadFonts
  41. || g_BreakAboutBadFonts
  42. )
  43. {
  44. va_list Args;
  45. va_start(Args, Format);
  46. vDbgPrintEx(DPFLTR_SYSTEM_ID, DPFLTR_ERROR_LEVEL, (PSTR)Format, Args);
  47. va_end(Args);
  48. }
  49. if (g_BreakAboutBadFonts)
  50. {
  51. DbgBreakPoint();
  52. }
  53. #endif
  54. }
  55. BOOL
  56. bMappedViewStrlen(
  57. PVOID pvViewBase,
  58. SIZE_T cjViewSize,
  59. PVOID pvString,
  60. OUT PSIZE_T pcjOutLength OPTIONAL
  61. )
  62. /*++
  63. Routine Description:
  64. Given a mapped view and size and starting address, verify that the 8bit string
  65. starting at the address is nul terminated within the mapped view, optionally
  66. returning the length of the string.
  67. Arguments:
  68. pvViewBase -
  69. cjViewSize -
  70. pvString -
  71. pcjOutLength -
  72. Return Value:
  73. TRUE: the string is nul terminated within the view
  74. FALSE: the string is not nul terminated within the view
  75. --*/
  76. {
  77. BOOL bSuccess;
  78. PBYTE pjViewBase;
  79. PBYTE pjViewEnd;
  80. PBYTE pjString;
  81. PBYTE pjStringEnd;
  82. bSuccess = FALSE;
  83. if (pcjOutLength != NULL)
  84. {
  85. *pcjOutLength = 0;
  86. }
  87. pjViewBase = (PBYTE)pvViewBase;
  88. pjViewEnd = cjViewSize + pjViewBase;
  89. pjString = (PBYTE)pvString;
  90. if (!(pjString >= pjViewBase && pjString < pjViewEnd))
  91. {
  92. goto Exit;
  93. }
  94. for (pjStringEnd = pjString ; pjStringEnd != pjViewEnd && *pjStringEnd != 0 ; ++pjStringEnd)
  95. {
  96. // nothing
  97. }
  98. if (pjStringEnd == pjViewEnd)
  99. {
  100. goto Exit;
  101. }
  102. if (pcjOutLength != NULL)
  103. {
  104. *pcjOutLength = (SIZE_T)(pjStringEnd - pjString);
  105. }
  106. bSuccess = TRUE;
  107. Exit:
  108. #if DBG
  109. if (!bSuccess)
  110. {
  111. NotifyBadFont(
  112. "WIN32K: bMappedViewStrlen(%p,0x%Ix,%p) returning false\n",
  113. pvViewBase,
  114. cjViewSize,
  115. pvString
  116. );
  117. }
  118. #endif
  119. return bSuccess;
  120. }
  121. BOOL
  122. bMappedViewRangeCheck(
  123. PVOID ViewBase,
  124. SIZE_T ViewSize,
  125. PVOID DataAddress,
  126. SIZE_T DataSize
  127. )
  128. /*++
  129. Routine Description:
  130. Given a mapped view and size, range check a data address and size.
  131. Arguments:
  132. ViewBase -
  133. ViewSize -
  134. DataAddress -
  135. DataSize -
  136. Return Value:
  137. TRUE: all of the data is within the view
  138. FALSE: some of the data is outside the view
  139. --*/
  140. {
  141. ULONG_PTR iViewBegin;
  142. ULONG_PTR iViewEnd;
  143. ULONG_PTR iDataBegin;
  144. ULONG_PTR iDataEnd;
  145. BOOL fResult;
  146. //
  147. // iDataBegin is a valid address.
  148. // iDataEnd is one past a valid address.
  149. // We must not allow iDataBegin == iViewEnd.
  150. // We must allow iDataEnd == iViewEnd.
  151. // Therefore, we must not allow iDataBegin == iDataEnd.
  152. // This can be achieved by not allowing DataSize == 0.
  153. //
  154. if (DataSize == 0)
  155. {
  156. DataSize = 1;
  157. }
  158. iViewBegin = (ULONG_PTR)ViewBase;
  159. iViewEnd = iViewBegin + ViewSize;
  160. iDataBegin = (ULONG_PTR)DataAddress;
  161. iDataEnd = iDataBegin + DataSize;
  162. fResult =
  163. ( iDataBegin >= iViewBegin
  164. && iDataBegin < iDataEnd
  165. && iDataEnd <= iViewEnd
  166. && DataSize <= ViewSize
  167. );
  168. #if DBG
  169. if (!fResult)
  170. {
  171. NotifyBadFont(
  172. "WIN32K: bMappedViewRangeCheck(%p,0x%Ix,%p,0x%Ix) returning false\n",
  173. ViewBase,
  174. ViewSize,
  175. DataAddress,
  176. DataSize
  177. );
  178. }
  179. #endif
  180. return fResult;
  181. }
  182. /******************************Public*Routine******************************\
  183. * bInitWinResData
  184. *
  185. * Initializes the fields of the WINRESDATA structure so as to make it
  186. * possible for the user to access *.fnt resources within the
  187. * corresponding *.fon file
  188. *
  189. * The function returns True if *.fnt resources found in the *.fon
  190. * file, otherwise false (if not an *.fon file or if it contains no
  191. * *.fnt resources
  192. *
  193. *
  194. * History:
  195. * January 2002 -by- Jay Krell [JayKrell]
  196. * range check memory mapped i/o
  197. * 09-May-1991 -by- Bodin Dresevic [BodinD]
  198. * Wrote it.
  199. \**************************************************************************/
  200. BOOL
  201. bInitWinResData(
  202. PVOID pvView,
  203. COUNT cjView,
  204. PWINRESDATA pwrd
  205. )
  206. {
  207. PBYTE pjNewExe; // ptr to the beginning of the new exe hdr
  208. PBYTE pjResType; // ptr to the beginning of TYPEINFO struct
  209. PBYTE pjResName; // ptr to the beginning of NAMEINFO struct
  210. ULONG iResID; // resource type id
  211. COUNT cFdirEntries;
  212. BOOL bZeroUponFailure;
  213. BOOL bSuccess;
  214. ULONG crn;
  215. PBYTE pjView;
  216. PBYTE pjResType_FNT;
  217. PBYTE pjResType_FDIR;
  218. BOOL bBreakWhile;
  219. #ifdef DUMPCALL
  220. DbgPrint("\nbInitWinResData(");
  221. DbgPrint("\n PFILEVIEW pfvw = %-#8lx", pfvw);
  222. DbgPrint("\n PWINRESDATA pwrd = %-#8lx", pwrd);
  223. DbgPrint("\n )\n");
  224. #endif
  225. bSuccess = FALSE;
  226. bZeroUponFailure = FALSE;
  227. pwrd->pvView = pvView;
  228. pwrd->cjView = cjView;
  229. pjView = (PBYTE)pvView;
  230. // check the magic # at the beginning of the old header
  231. { C_ASSERT(OFF_e_lfanew > OFF_e_magic); }
  232. if (!bMappedViewRangeCheck(pjView, cjView, pjView + OFF_e_lfanew, sizeof(DWORD)))
  233. {
  234. goto Exit;
  235. }
  236. if (US_GET(pjView, OFF_e_magic) != EMAGIC)
  237. {
  238. goto Exit;
  239. }
  240. pwrd->dpNewExe = (PTRDIFF)READ_DWORD(pjView + OFF_e_lfanew);
  241. pjNewExe = pjView + pwrd->dpNewExe;
  242. // make sure that offset is consistent
  243. { C_ASSERT(OFF_ne_magic < CJ_NEW_EXE);
  244. C_ASSERT(OFF_ne_restab < CJ_NEW_EXE);
  245. C_ASSERT(OFF_ne_rsrctab < CJ_NEW_EXE);
  246. }
  247. if (!bMappedViewRangeCheck(pjView, cjView, pjNewExe, CJ_NEW_EXE))
  248. {
  249. goto Exit;
  250. }
  251. if (US_GET(pjNewExe, OFF_ne_magic) != NEMAGIC)
  252. {
  253. goto Exit;
  254. }
  255. pwrd->cjResTab = (ULONG)(US_GET(pjNewExe, OFF_ne_restab) -
  256. US_GET(pjNewExe, OFF_ne_rsrctab));
  257. if (pwrd->cjResTab == 0L)
  258. {
  259. //
  260. // The following test is applied by DOS, so I presume that it is
  261. // legitimate. The assumption is that the resident name table
  262. // FOLLOWS the resource table directly, and that if it points to
  263. // the same location as the resource table, then there are no
  264. // resources.
  265. WARNING("No resources in *.fon file\n");
  266. goto Exit;
  267. }
  268. // want offset from pvView, not from pjNewExe => must add dpNewExe
  269. pwrd->dpResTab = (PTRDIFF)US_GET(pjNewExe, OFF_ne_rsrctab) + pwrd->dpNewExe;
  270. // make sure that offset is consistent
  271. if (!bMappedViewRangeCheck(pjView, cjView, pjView + pwrd->dpResTab, sizeof(USHORT) + CJ_TYPEINFO))
  272. {
  273. goto Exit;
  274. }
  275. // what really lies at the offset OFF_ne_rsrctab is a NEW_RSRC.rs_align field
  276. // that is used in computing resource data offsets and sizes as a shift factor.
  277. // This field occupies two bytes on the disk and the first TYPEINFO structure
  278. // follows right after. We want pwrd->dpResTab to point to the first
  279. // TYPEINFO structure, so we must add 2 to get there and subtract 2 from
  280. // the length
  281. pwrd->ulShift = (ULONG) US_GET(pjView, pwrd->dpResTab);
  282. pwrd->dpResTab += 2;
  283. pwrd->cjResTab -= 2;
  284. // Now we want to determine where the resource data is located.
  285. // The data consists of a RSRC_TYPEINFO structure, followed by
  286. // an array of RSRC_NAMEINFO structures, which are then followed
  287. // by a RSRC_TYPEINFO structure, again followed by an array of
  288. // RSRC_NAMEINFO structures. This continues until an RSRC_TYPEINFO
  289. // structure which has a 0 in the rt_id field.
  290. pjResType = pjView + pwrd->dpResTab;
  291. pjResType_FNT = NULL;
  292. pjResType_FDIR = NULL;
  293. bBreakWhile = FALSE;
  294. while (TRUE)
  295. {
  296. iResID = (ULONG) US_GET(pjResType,OFF_rt_id);
  297. switch (iResID)
  298. {
  299. default:
  300. break;
  301. case 0:
  302. bBreakWhile = TRUE;
  303. break;
  304. case RT_FNT:
  305. pjResType_FNT = pjResType;
  306. if (pjResType_FDIR != NULL)
  307. bBreakWhile = TRUE;
  308. break;
  309. case RT_FDIR:
  310. pjResType_FDIR = pjResType;
  311. if (pjResType_FNT != NULL)
  312. bBreakWhile = TRUE;
  313. break;
  314. }
  315. if (bBreakWhile)
  316. break;
  317. // # of NAMEINFO structures that follow = resources of this type
  318. crn = (ULONG)US_GET(pjResType, OFF_rt_nres);
  319. // get ptr to the new TYPEINFO struc and the new resource id
  320. pjResType = pjResType + CJ_TYPEINFO + crn * CJ_NAMEINFO;
  321. if (!bMappedViewRangeCheck(pjView, cjView, pjResType, CJ_TYPEINFO))
  322. {
  323. goto Exit;
  324. }
  325. }
  326. bZeroUponFailure = TRUE;
  327. ASSERT((iResID == 0) == (pjResType_FNT == NULL || pjResType_FDIR == NULL));
  328. if (iResID == 0)
  329. { // we did not find one or both of them
  330. goto Exit;
  331. }
  332. pjResType = pjResType_FNT;
  333. // # of NAMEINFO structures that follow == # of font resources
  334. pwrd->cFntRes = (ULONG)US_GET(pjResType, OFF_rt_nres);
  335. // this is ptr to the first NAMEINFO struct that follows
  336. // an RT_FNT TYPEINFO structure
  337. pjResName = pjResType + CJ_TYPEINFO;
  338. pwrd->dpFntTab = (PTRDIFF)(pjResName - pjView);
  339. // make sure that offset is consistent
  340. if ((ULONG)pwrd->dpFntTab > pwrd->cjView)
  341. {
  342. goto Exit;
  343. }
  344. // Now we search for the FONDIR resource. Windows actually grabs facenames
  345. // from the FONDIR entries and not the FNT entries. For some wierd fonts this
  346. // makes a difference. [gerritv]
  347. pjResType = pjResType_FDIR;
  348. // this is ptr to the first NAMEINFO struct that follows
  349. // an RT_FDIR TYPEINFO structure
  350. pjResName = pjResType + CJ_TYPEINFO;
  351. if (!bMappedViewRangeCheck(pjView, cjView, pjResName, CJ_NAMEINFO))
  352. {
  353. goto Exit;
  354. }
  355. // Get the offset to res data computed from the top of the new header
  356. pwrd->dpFdirRes = (PTRDIFF)((ULONG)US_GET(pjResName,OFF_rn_offset) <<
  357. pwrd->ulShift);
  358. // Now pwrd->dpFdirRes is an offset to the FONTDIR resource, the first
  359. // byte [ushort?] will be the number of entries in the font dir. Lets make sure it
  360. // matches the number of FNT resources in the file.
  361. if (!bMappedViewRangeCheck(pjView, cjView, pjView + pwrd->dpFdirRes, sizeof(USHORT)))
  362. {
  363. goto Exit;
  364. }
  365. cFdirEntries = (ULONG)US_GET(pjView,pwrd->dpFdirRes);
  366. if( cFdirEntries != pwrd->cFntRes )
  367. {
  368. WARNING( "bInitWinResData: # of FONTDIR entries != # of FNT entries.\n");
  369. goto Exit;
  370. }
  371. // now increment dpFdirRes so it points passed the count of entries and
  372. // to the first entry.
  373. pwrd->dpFdirRes += 2;
  374. bSuccess = TRUE;
  375. Exit:
  376. if (!bSuccess)
  377. {
  378. #if DBG
  379. NotifyBadFont("WIN32K: %s failing\n", __FUNCTION__);
  380. #endif
  381. if (bZeroUponFailure && pwrd != NULL)
  382. {
  383. pwrd->cFntRes = (ULONG)0;
  384. pwrd->dpFntTab = (PTRDIFF)0;
  385. }
  386. }
  387. return bSuccess;
  388. }
  389. /******************************Public*Routine******************************\
  390. * bGetFntResource
  391. *
  392. * Writes the pointer to and the size of the iFntRes-th *.fnt resource
  393. * of the *.fon file identified by pwrd. The info is written into RES_ELEM
  394. * structure if successful. The function returns FALSE if it is not possible
  395. * to locate iFntRes-th *.fnt resource in the file.
  396. *
  397. *
  398. * History:
  399. * January 2002 -by- Jay Krell [JayKrell]
  400. * range check memory mapped i/o
  401. * 09-May-1991 -by- Bodin Dresevic [BodinD]
  402. * Wrote it.
  403. \**************************************************************************/
  404. BOOL
  405. bGetFntResource(
  406. PWINRESDATA pwrd ,
  407. ULONG iFntRes,
  408. PRES_ELEM pre
  409. )
  410. {
  411. //
  412. // This function is called in a loop for iFntRes in [0..pwrd->cFntRes),
  413. // and therefore has quadratic perf.
  414. //
  415. PBYTE pjResName;
  416. PBYTE pjFaceName;
  417. PTRDIFF dpResData;
  418. BOOL bSuccess;
  419. PBYTE pjView;
  420. PBYTE pjViewEnd;
  421. SIZE_T cjView;
  422. SIZE_T cjFaceNameLength;
  423. #ifdef DUMPCALL
  424. DbgPrint("\nbGetFntResource(");
  425. DbgPrint("\n PWINRESDATA pwrd = %-#8lx", pwrd);
  426. DbgPrint("\n ULONG iFntRes = %-#8lx", iFntRes);
  427. DbgPrint("\n PRES_ELEM pre = %-#8lx", pre);
  428. DbgPrint("\n )\n");
  429. #endif
  430. ASSERTGDI((pwrd->cFntRes != 0L) && (iFntRes < pwrd->cFntRes),
  431. "bGetFntResource\n");
  432. bSuccess = FALSE;
  433. pjView = (PBYTE)pwrd->pvView;
  434. cjView = pwrd->cjView;
  435. // get to the Beginning of the NAMEINFO struct that correspoonds to
  436. // the iFntRes-th *.fnt resource. (Note: iFntRes is zero based)
  437. pjResName = pjView + pwrd->dpFntTab + iFntRes * CJ_NAMEINFO;
  438. // Get the offset to res data computed from the top of the new header
  439. if (!bMappedViewRangeCheck(pjView, cjView, pjResName, CJ_NAMEINFO))
  440. {
  441. goto Exit;
  442. }
  443. dpResData = (PTRDIFF)((ULONG)US_GET(pjResName,OFF_rn_offset) <<
  444. pwrd->ulShift);
  445. pre->pvResData = (PVOID)(pjView + dpResData);
  446. pre->dpResData = dpResData;
  447. pre->cjResData = (ULONG)US_GET(pjResName,OFF_rn_length) << pwrd->ulShift;
  448. if (!bMappedViewRangeCheck(pjView, cjView, pre->pvResData, pre->cjResData))
  449. {
  450. goto Exit;
  451. }
  452. // Get the face name from the FONTDIR
  453. pjFaceName = pjView + pwrd->dpFdirRes;
  454. pjViewEnd = pjView + cjView;
  455. do
  456. {
  457. // The first two bytes of the entry are the resource index so we will skip
  458. // past that. After that add in the size of the font header. This will
  459. // point us to the string for the device_name
  460. pjFaceName += 2 + OFF_BitsOffset;
  461. if (!bMappedViewStrlen(pjView, cjView, pjFaceName, &cjFaceNameLength))
  462. {
  463. goto Exit;
  464. }
  465. pjFaceName += cjFaceNameLength + 1;
  466. // pjFaceName now really points to the facename
  467. if( iFntRes )
  468. {
  469. if (!bMappedViewStrlen(pjView, cjView, pjFaceName, &cjFaceNameLength))
  470. {
  471. goto Exit;
  472. }
  473. pjFaceName += cjFaceNameLength + 1;
  474. }
  475. }
  476. while( iFntRes-- );
  477. //
  478. // Later on strlen is going to be called on pjFaceName.
  479. // Let's do a range checked version first.
  480. //
  481. if (!bMappedViewStrlen(pjView, cjView, pjFaceName, NULL))
  482. {
  483. goto Exit;
  484. }
  485. pre->pjFaceName = pjFaceName;
  486. #ifdef FOOGOO
  487. KdPrint(("%s: offset= 0x%lx, charset = %ld\n", pjFaceName, dpResData + OFF_CharSet, *((BYTE *)pjView + dpResData + OFF_CharSet)));
  488. #endif
  489. bSuccess = TRUE;
  490. Exit:
  491. return bSuccess;
  492. }