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.

2008 lines
57 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: mapfile.c
  3. *
  4. * Created: 25-Jun-1992 14:33:45
  5. * Author: Bodin Dresevic [BodinD]
  6. *
  7. * Copyright (c) 1990-1999 Microsoft Corporation
  8. \**************************************************************************/
  9. #include "engine.h"
  10. #include "ntnls.h"
  11. #include "stdlib.h"
  12. #include "ugdiport.h"
  13. extern HFASTMUTEX ghfmMemory;
  14. ULONG LastCodePageTranslated = 0; // I'm assuming 0 is not a valid codepage
  15. PVOID LastNlsTableBuffer = NULL;
  16. CPTABLEINFO LastCPTableInfo;
  17. UINT NlsTableUseCount = 0;
  18. ULONG ulCharsetToCodePage(UINT);
  19. /******************************Public*Routine******************************\
  20. *
  21. * vSort, N^2 alg, might want to replace by qsort
  22. *
  23. * Effects:
  24. *
  25. * Warnings:
  26. *
  27. * History:
  28. * 25-Jun-1992 -by- Bodin Dresevic [BodinD]
  29. * Wrote it.
  30. \**************************************************************************/
  31. VOID vSort(
  32. WCHAR *pwc, // input buffer with a sorted array of cChar supported WCHAR's
  33. BYTE *pj, // input buffer with original ansi values
  34. INT cChar
  35. )
  36. {
  37. INT i;
  38. for (i = 1; i < cChar; i++)
  39. {
  40. // upon every entry to this loop the array 0,1,..., (i-1) will be sorted
  41. INT j;
  42. WCHAR wcTmp = pwc[i];
  43. BYTE jTmp = pj[i];
  44. for (j = i - 1; (j >= 0) && (pwc[j] > wcTmp); j--)
  45. {
  46. pwc[j+1] = pwc[j];
  47. pj[j+1] = pj[j];
  48. }
  49. pwc[j+1] = wcTmp;
  50. pj[j+1] = jTmp;
  51. }
  52. }
  53. /******************************Public*Routine******************************\
  54. *
  55. * cComputeGlyphSet
  56. *
  57. * computes the number of contiguous ranges supported in a font.
  58. *
  59. * Input is a sorted array (which may contain duplicates)
  60. * such as 1 1 1 2 3 4 5 7 8 9 10 10 11 12 etc
  61. * of cChar unicode code points that are
  62. * supported in a font
  63. *
  64. * fills the FD_GLYPSET structure if the pgset buffer is provided
  65. *
  66. * History:
  67. * 25-Jun-1992 -by- Bodin Dresevic [BodinD]
  68. * Wrote it.
  69. \**************************************************************************/
  70. INT cComputeGlyphSet(
  71. WCHAR *pwc, // input buffer with a sorted array of cChar supported WCHAR's
  72. BYTE *pj, // input buffer with original ansi values
  73. INT cChar,
  74. INT cRuns, // if nonzero, the same as return value
  75. FD_GLYPHSET *pgset // output buffer to be filled with cRanges runs
  76. )
  77. {
  78. INT iRun, iFirst, iFirstNext;
  79. HGLYPH *phg, *phgEnd = NULL;
  80. BYTE *pjTmp;
  81. if (pgset != NULL)
  82. {
  83. pgset->cjThis = SZ_GLYPHSET(cRuns,cChar);
  84. // BUG, BUG
  85. // this line may seem confusing because 256 characters still fit in a byte
  86. // with values [0, 255]. The reason is that tt and ps fonts, who otherwise
  87. // would qualify as an 8 bit report bogus last and first char
  88. // (win31 compatibility) which confuses our engine.
  89. // tt and ps drivers therefore, for the purpose of computing glyphsets
  90. // of tt symbol fonts and ps fonts set firstChar to 0 and LastChar to 255.
  91. // For now we force such fonts through more general 16bit handle case
  92. // which does not rely on the fact that chFirst and chLast are correct
  93. pgset->flAccel = (cChar != 256) ? GS_8BIT_HANDLES : GS_16BIT_HANDLES;
  94. pgset->cRuns = cRuns;
  95. // init the sum before entering the loop
  96. pgset->cGlyphsSupported = 0;
  97. // glyph handles are stored at the bottom, below runs:
  98. phg = (HGLYPH *) ((BYTE *)pgset + (offsetof(FD_GLYPHSET,awcrun) + cRuns * sizeof(WCRUN)));
  99. }
  100. // now compute cRuns if pgset == 0 and fill the glyphset if pgset != 0
  101. for (iFirst = 0, iRun = 0; iFirst < cChar; iRun++, iFirst = iFirstNext)
  102. {
  103. // find iFirst corresponding to the next range.
  104. for (iFirstNext = iFirst + 1; iFirstNext < cChar; iFirstNext++)
  105. {
  106. if ((pwc[iFirstNext] - pwc[iFirstNext - 1]) > 1)
  107. break;
  108. }
  109. if (pgset != NULL)
  110. {
  111. pgset->awcrun[iRun].wcLow = pwc[iFirst];
  112. pgset->awcrun[iRun].cGlyphs =
  113. (USHORT)(pwc[iFirstNext-1] - pwc[iFirst] + 1);
  114. pgset->awcrun[iRun].phg = phg;
  115. // now store the handles, i.e. the original ansi values
  116. phgEnd = phg + pgset->awcrun[iRun].cGlyphs;
  117. for (pjTmp = &pj[iFirst]; phg < phgEnd; phg++,pjTmp++)
  118. {
  119. *phg = (HGLYPH)*pjTmp;
  120. }
  121. pgset->cGlyphsSupported += pgset->awcrun[iRun].cGlyphs;
  122. }
  123. }
  124. #if DBG
  125. if (pgset != NULL)
  126. ASSERTGDI(iRun == cRuns, "gdisrv! iRun != cRun\n");
  127. #endif
  128. return iRun;
  129. }
  130. /******************************Public*Routine******************************\
  131. *
  132. * cUnicodeRangesSupported
  133. *
  134. * Effects:
  135. *
  136. * Warnings:
  137. *
  138. * History:
  139. * 25-Jun-1992 -by- Bodin Dresevic [BodinD]
  140. * Wrote it.
  141. \**************************************************************************/
  142. INT cUnicodeRangesSupported (
  143. INT cp, // code page, not used for now, the default system code page is used
  144. INT iFirstChar, // first ansi char supported
  145. INT cChar, // # of ansi chars supported, cChar = iLastChar + 1 - iFirstChar
  146. WCHAR *pwc, // input buffer with a sorted array of cChar supported WCHAR's
  147. BYTE *pj
  148. )
  149. {
  150. BYTE jFirst = (BYTE)iFirstChar;
  151. INT i;
  152. USHORT AnsiCodePage, OemCodePage;
  153. ASSERTGDI((iFirstChar < 256) && (cChar <= 256),
  154. "gdisrvl! iFirst or cChar\n");
  155. //
  156. // fill the array with cCharConsecutive ansi values
  157. //
  158. for (i = 0; i < cChar; i++)
  159. {
  160. pj[i] = (BYTE)iFirstChar++;
  161. }
  162. // If the default code page is DBCS then use 1252, otherwise use
  163. // use the default code page
  164. //
  165. if (IS_ANY_DBCS_CODEPAGE(cp))
  166. {
  167. // Suppose we have a system without correspoding DBCS codepage installed.
  168. // We would still like to load this font. But we will do so as CP 1252.
  169. // To do that try to translate one character using DBCS codepage and see if it
  170. // suceeds.
  171. if(EngMultiByteToWideChar(cp,&pwc[0],2,&pj[0],1) == -1)
  172. {
  173. WARNING("DBCS Codepage not installed using 1252\n");
  174. cp = 1252;
  175. }
  176. for(i = 0; i < cChar; i++)
  177. {
  178. // this is a shift-jis charset so we need special handling
  179. INT Result = EngMultiByteToWideChar(cp,&pwc[i],2,&pj[i],1);
  180. #if DBG
  181. if (Result == -1) WARNING("gdisrvl! EngMultiByteToWideChar failed\n");
  182. #endif
  183. if ((Result == -1) || (pwc[i] == 0 && pj[i] != 0))
  184. {
  185. // this must have been a DBCS lead byte so just return 0xFFFF or a failure
  186. // failure of EngMultiByteToWideChar could be cause by low memory condition
  187. pwc[i] = 0xFFFF;
  188. }
  189. }
  190. }
  191. else
  192. {
  193. INT Result;
  194. if ((cp == CP_ACP) || (cp == CP_OEMCP))
  195. {
  196. RtlGetDefaultCodePage(&AnsiCodePage,&OemCodePage);
  197. if(IS_ANY_DBCS_CODEPAGE(AnsiCodePage))
  198. {
  199. AnsiCodePage = 1252;
  200. }
  201. }
  202. else
  203. {
  204. AnsiCodePage = (USHORT)cp;
  205. }
  206. Result = EngMultiByteToWideChar(AnsiCodePage,
  207. pwc,
  208. (ULONG)(cChar * sizeof(WCHAR)),
  209. (PCH) pj,
  210. (ULONG) cChar);
  211. ASSERTGDI(Result != -1, "gdisrvl! EngMultiByteToWideChar failed\n");
  212. }
  213. // now subtract the first char from all ansi values so that the
  214. // glyph handle is equal to glyph index, rather than to the ansi value
  215. for (i = 0; i < cChar; i++)
  216. {
  217. pj[i] -= (BYTE)jFirst;
  218. }
  219. // now sort out pwc array and permute pj array accordingly
  220. vSort(pwc,pj, cChar);
  221. //
  222. // compute the number of ranges
  223. //
  224. return cComputeGlyphSet (pwc,pj, cChar, 0, NULL);
  225. }
  226. /******************************Private*Routine******************************\
  227. * pcpComputeGlyphset,
  228. *
  229. * Computes the FD_GLYPHSET struct based on chFirst and chLast. If such a
  230. * FD_GLYPHSET already exists in our global list of FD structs it updates
  231. * the ref count for this FD_GLYPHSET in the global list points pcrd->pcp->pgset
  232. * to it. Otherwise it makes a new FD_GLYPHSET entry in the global list
  233. * and points pcrd->pcp->pgset to it.
  234. *
  235. * Thu 03-Dec-1992 -by- Bodin Dresevic [BodinD]
  236. * update: redid them to make them usable in vtfd
  237. *
  238. * History:
  239. * 24-July-1992 -by- Gerrit van Wingerden [gerritv]
  240. * Wrote it.
  241. *
  242. \**************************************************************************/
  243. CP_GLYPHSET *pcpComputeGlyphset(
  244. CP_GLYPHSET **pcpHead, // head of the list
  245. UINT uiFirst,
  246. UINT uiLast,
  247. BYTE jCharset
  248. )
  249. {
  250. CP_GLYPHSET *pcpTmp;
  251. CP_GLYPHSET *pcpRet = NULL;
  252. // First we need to see if a FD_GLYPHSET already exists for this first and
  253. // last range.
  254. for( pcpTmp = *pcpHead;
  255. pcpTmp != NULL;
  256. pcpTmp = pcpTmp->pcpNext )
  257. {
  258. if((pcpTmp->uiFirstChar == uiFirst) &&
  259. (pcpTmp->jCharset == jCharset) &&
  260. (pcpTmp->uiLastChar == uiLast))
  261. break;
  262. }
  263. if( pcpTmp != NULL )
  264. {
  265. //
  266. // We found a match.
  267. //
  268. pcpTmp->uiRefCount +=1;
  269. //
  270. // We should never have so many references as to wrap around but if we ever
  271. // do we must fail the call.
  272. //
  273. if( pcpTmp->uiRefCount == 0 )
  274. {
  275. WARNING("BMFD!Too many references to glyphset\n");
  276. pcpRet = NULL;
  277. }
  278. else
  279. {
  280. pcpRet = pcpTmp;
  281. }
  282. }
  283. else
  284. {
  285. //
  286. // We need to allocate a new CP_GLYPHSET
  287. // For SYMBOL_CHARSET, it also needs to cover xf020 to xf0ff unicode range
  288. BYTE aj[2*256-32];
  289. WCHAR awc[2*256-32];
  290. INT cNumRuns;
  291. BOOL isSymbol = FALSE;
  292. UINT i,j;
  293. UINT uiCodePage = (UINT)ulCharsetToCodePage(jCharset);
  294. UINT cGlyphs = uiLast - uiFirst + 1;
  295. // use CP_ACP for SYMBOL_CHARSET
  296. if (uiCodePage == 42)
  297. {
  298. uiCodePage = CP_ACP;
  299. isSymbol = TRUE;
  300. }
  301. cNumRuns = cUnicodeRangesSupported(
  302. uiCodePage,
  303. uiFirst,
  304. cGlyphs,
  305. awc,aj);
  306. if (isSymbol)
  307. {
  308. // add range subset of a range [f020, f0ff]
  309. for (i = uiFirst, j = cGlyphs; i< (uiFirst+cGlyphs); i++)
  310. {
  311. // if i < 0x20, we do not report the glyph in f020-f0ff range, it has been reported already in the current code page range
  312. if (i >= 0x20)
  313. {
  314. awc[j] = 0xf000 + i;
  315. aj[j] = i - uiFirst;
  316. j++;
  317. }
  318. }
  319. // make sure we resort if needed
  320. if (awc[cGlyphs-1] > 0xf020)
  321. vSort(awc,aj,j);
  322. if (cGlyphs != j)
  323. {
  324. cNumRuns++;
  325. cGlyphs = j;
  326. }
  327. }
  328. if ( (pcpTmp = (CP_GLYPHSET*)
  329. (PALLOCNOZ((SZ_GLYPHSET(cNumRuns,cGlyphs) +
  330. offsetof(CP_GLYPHSET,gset)),
  331. 'slgG'))
  332. ) == (CP_GLYPHSET*) NULL)
  333. {
  334. WARNING("BMFD!pcpComputeGlyphset memory allocation error.\n");
  335. pcpRet = NULL;
  336. }
  337. else
  338. {
  339. pcpTmp->uiRefCount = 1;
  340. pcpTmp->uiFirstChar = uiFirst;
  341. pcpTmp->uiLastChar = uiLast;
  342. pcpTmp->jCharset = jCharset;
  343. // Fill in the Glyphset structure
  344. cComputeGlyphSet(awc,aj, cGlyphs, cNumRuns, &pcpTmp->gset);
  345. // Insert at beginning of list
  346. pcpTmp->pcpNext = *pcpHead;
  347. *pcpHead = pcpTmp;
  348. // point CVTRESDATA to new CP_GLYPHSET
  349. pcpRet = pcpTmp;
  350. }
  351. }
  352. return pcpRet;
  353. }
  354. /***************************************************************************
  355. * vUnloadGlyphset( PCP pcpTarget )
  356. *
  357. * Decrements the ref count of a CP_GLYPHSET and unloads it from the global
  358. * list of CP_GLYPHSETS if the ref count is zero.
  359. *
  360. * IN
  361. * PCP pcpTarget pointer to CP_GLYPHSET to be unloaded or decremented
  362. *
  363. * History
  364. *
  365. * Thu 03-Dec-1992 -by- Bodin Dresevic [BodinD]
  366. * update: redid them to make them usable in vtfd
  367. *
  368. * 7-25-92 Gerrit van Wingerden [gerritv]
  369. * Wrote it.
  370. *
  371. ***************************************************************************/
  372. VOID vUnloadGlyphset(
  373. CP_GLYPHSET **pcpHead,
  374. CP_GLYPHSET *pcpTarget
  375. )
  376. {
  377. CP_GLYPHSET *pcpLast, *pcpCurrent;
  378. if( *pcpHead == NULL )
  379. {
  380. WARNING1("vUnloadGlyphset called with NULL Head\n");
  381. return;
  382. }
  383. pcpCurrent = *pcpHead;
  384. pcpLast = NULL;
  385. //
  386. // Find the right CP_GLYPSHET
  387. //
  388. while( 1 )
  389. {
  390. ASSERTGDI( pcpCurrent != NULL, "CP_GLYPHSET list problem.\n" );
  391. if( pcpCurrent == pcpTarget )
  392. break;
  393. pcpLast = pcpCurrent;
  394. pcpCurrent = pcpCurrent->pcpNext;
  395. }
  396. if( --pcpCurrent->uiRefCount == 0 )
  397. {
  398. //
  399. // We need to deallocate and remove from list
  400. //
  401. if( pcpLast == NULL )
  402. *pcpHead = pcpCurrent->pcpNext;
  403. else
  404. pcpLast->pcpNext = pcpCurrent->pcpNext;
  405. VFREEMEM(pcpCurrent);
  406. }
  407. }
  408. PVOID __nw(unsigned int ui)
  409. {
  410. DONTUSE(ui);
  411. RIP("Bogus __nw call");
  412. return(NULL);
  413. }
  414. VOID __dl(PVOID pv)
  415. {
  416. DONTUSE(pv);
  417. RIP("Bogus __dl call");
  418. }
  419. // the definition of this variable is in ntgdi\inc\hmgshare.h
  420. CHARSET_ARRAYS
  421. /******************************Public*Routine******************************\
  422. *
  423. * ULONG ulCharsetToCodePage(UINT uiCharSet)
  424. *
  425. *
  426. * Effects: figure out which code page to unicode translation table
  427. * should be used for this realization
  428. *
  429. * History:
  430. * 31-Jan-1995 -by- Bodin Dresevic [BodinD]
  431. * Wrote it.
  432. \**************************************************************************/
  433. ULONG ulCharsetToCodePage(UINT uiCharSet)
  434. {
  435. int i;
  436. if (uiCharSet != OEM_CHARSET)
  437. {
  438. for (i = 0; i < NCHARSETS; i++)
  439. {
  440. if (charsets[i] == uiCharSet)
  441. return codepages[i];
  442. }
  443. // in case of some random charset
  444. // (this is likely an old bm or vecrot font) we will just use the current
  445. // global code page translation table. This is enough to ensure
  446. // the correct round trip: ansi->unicode->ansi
  447. // if CP_ACP is a DBCS code page then we better use 1252 to ensure
  448. // proper rountrip conversion
  449. return( gbDBCSCodePage ? 1252 : CP_ACP);
  450. }
  451. else // to make merced compiler happy
  452. {
  453. return CP_OEMCP;
  454. }
  455. }
  456. // inverse function
  457. VOID vConvertCodePageToCharSet(WORD src, DWORD *pfsRet, BYTE *pjRet)
  458. {
  459. UINT i;
  460. *pjRet = ANSI_CHARSET;
  461. *pfsRet = FS_LATIN1;
  462. for (i = 0; i < nCharsets; i++)
  463. {
  464. if ( codepages[i] == src )
  465. {
  466. // cs.ciACP = src ;
  467. // cs.ciCharset = charsets[i] ;
  468. *pfsRet = fs[i];
  469. *pjRet = (BYTE)charsets[i] ;
  470. break;
  471. }
  472. }
  473. }
  474. /****************************************************************************
  475. * LONG EngParseFontResources
  476. *
  477. * This routine takes a handle to a mapped image and returns an array of
  478. * pointers to the base of all the font resources in that image.
  479. *
  480. * Parameters
  481. *
  482. * HANDLE hFontFile -- Handle (really a pointer) to a FONTFILEVIEW
  483. * image in which the fonts are to be found.
  484. * ULONG BufferSize -- Number of entries that ppvResourceBases can hold.
  485. * PVOID *ppvResourceBases -- Buffer to hold the array of pointers to font
  486. * resources. If NULL then only the number of resources is returned,
  487. * and this value is ignored.
  488. *
  489. * Returns
  490. *
  491. * Number of font resources in the image or 0 if error or none.
  492. *
  493. * History
  494. * 7-3-95 Gerrit van Wingerden [gerritv]
  495. * Wrote it.
  496. *
  497. ****************************************************************************/
  498. PVOID EngFindResourceFD(
  499. HANDLE h,
  500. int iName,
  501. int iType,
  502. PULONG pulSize);
  503. ULONG cParseFontResources(
  504. HANDLE hFontFile,
  505. PVOID **ppvResourceBases)
  506. {
  507. PIMAGE_DOS_HEADER pDosHeader;
  508. NTSTATUS Status;
  509. ULONG_PTR IdPath[ 1 ];
  510. INT i;
  511. HANDLE DllHandle;
  512. PIMAGE_RESOURCE_DIRECTORY ResourceDirectory;
  513. PIMAGE_RESOURCE_DIRECTORY_ENTRY ResourceDirectoryEntry;
  514. PVOID pvImageBase;
  515. INT cEntries = 0;
  516. // Fail call if this is a bogus DOS image without an NE header.
  517. pDosHeader = (PIMAGE_DOS_HEADER)((PFONTFILEVIEW)hFontFile)->fv.pvViewFD;
  518. if (pDosHeader->e_magic == IMAGE_DOS_SIGNATURE &&
  519. (ULONG)(pDosHeader->e_lfanew) > ((PFONTFILEVIEW)hFontFile)->fv.cjView) {
  520. TRACE_FONT(("cParseFontResources: Cant map bogus DOS image files for fonts\n"));
  521. return 0;
  522. }
  523. // the LDR routines expect a one or'd in if this file mas mapped as an
  524. // image
  525. pvImageBase = (PVOID) (((ULONG_PTR) ((PFONTFILEVIEW) hFontFile)->fv.pvViewFD)|1);
  526. // Later on we'll call EngFindResource which expects a handle to FILEVIEW
  527. // struct. It really just grabs the pvView field from the structure so
  528. // make sure that pvView field is the same place in both FILEVIEW and
  529. // FONTFILEVIEW structs
  530. IdPath[0] = 8; // 8 is RT_FONT
  531. Status = LdrFindResourceDirectory_U(pvImageBase,
  532. IdPath,
  533. 1,
  534. &ResourceDirectory);
  535. if (NT_SUCCESS( Status ))
  536. {
  537. // For now we'll assume that the only types of FONT entries will be Id
  538. // entries. If for some reason this turns out not to be the case we'll
  539. // have to add more code (see windows\base\module.c) under the FindResource
  540. // function to get an idea how to do this.
  541. ASSERTGDI(ResourceDirectory->NumberOfNamedEntries == 0,
  542. "EngParseFontResources: NamedEntries in font file.\n");
  543. *ppvResourceBases = (PVOID *) EngAllocMem(FL_ZERO_MEMORY,ResourceDirectory->NumberOfIdEntries * sizeof(PVOID *),'dfmB');
  544. if (*ppvResourceBases)
  545. {
  546. PVOID *ppvResource = *ppvResourceBases;
  547. cEntries = ResourceDirectory->NumberOfIdEntries;
  548. try
  549. {
  550. ResourceDirectoryEntry =
  551. (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResourceDirectory+1);
  552. for (i=0; i < cEntries ; ResourceDirectoryEntry++, i++ )
  553. {
  554. DWORD dwSize;
  555. *ppvResource = EngFindResourceFD(hFontFile,
  556. ResourceDirectoryEntry->Id,
  557. 8, // RT_FONT
  558. &dwSize );
  559. if( *ppvResource++ == NULL )
  560. {
  561. WARNING("EngParseFontResources: EngFindResourceFailed\n");
  562. cEntries = -1;
  563. break;
  564. }
  565. }
  566. }
  567. except (EXCEPTION_EXECUTE_HANDLER)
  568. {
  569. cEntries = 0;
  570. }
  571. }
  572. }
  573. return(cEntries);
  574. }
  575. /*****************************************************************************\
  576. * MakeSystemRelativePath
  577. *
  578. * Takes a path in X:\...\system32\.... format and makes it into
  579. * \SystemRoot\System32 format so that KernelMode API's can recognize it.
  580. *
  581. * This will ensure security by forcing any image being loaded to come from
  582. * the system32 directory.
  583. *
  584. * The AppendDLL flag indicates if the name should get .dll appended at the end
  585. * (for display drivers coming from USER) if it's not already there.
  586. *
  587. \*****************************************************************************/
  588. BOOL MakeSystemRelativePath(
  589. LPWSTR pOriginalPath,
  590. PUNICODE_STRING pUnicode,
  591. BOOL bAppendDLL
  592. )
  593. {
  594. LPWSTR pOriginalEnd;
  595. ULONG OriginalLength = wcslen(pOriginalPath);
  596. ULONG cbLength = OriginalLength * sizeof(WCHAR) +
  597. sizeof(L"\\SystemRoot\\System32\\");
  598. ULONG tmp;
  599. tmp = (sizeof(L".DLL") / sizeof (WCHAR) - 1);
  600. //
  601. // Given append = TRUE, we check if we really need to append.
  602. // (printer drivers with .dll come through LDEVREF which specifies TRUE)
  603. //
  604. if (bAppendDLL)
  605. {
  606. if ((OriginalLength >= tmp) &&
  607. (!_wcsnicmp(pOriginalPath + OriginalLength - tmp,
  608. L".DLL",
  609. tmp)))
  610. {
  611. bAppendDLL = FALSE;
  612. }
  613. else
  614. {
  615. cbLength += tmp * sizeof(WCHAR);
  616. }
  617. }
  618. pUnicode->Length = 0;
  619. pUnicode->MaximumLength = (USHORT) cbLength;
  620. if (pUnicode->Buffer = PALLOCNOZ(cbLength, 'liFG'))
  621. {
  622. //
  623. // First parse the input string for \System32\. We parse from the end
  624. // of the string because some weirdo could have \System32\Nt\System32
  625. // as his/her root directory and this would throw us off if we scanned
  626. // from the front.
  627. //
  628. // It should only (and always) be printer drivers that pass down
  629. // fully qualified path names.
  630. //
  631. tmp = (sizeof(L"\\system32\\") / sizeof(WCHAR) - 1);
  632. for (pOriginalEnd = pOriginalPath + OriginalLength - tmp;
  633. pOriginalEnd >= pOriginalPath;
  634. pOriginalEnd --)
  635. {
  636. if (!_wcsnicmp(pOriginalEnd ,
  637. L"\\system32\\",
  638. tmp))
  639. {
  640. //
  641. // We found the system32 in the string.
  642. // Lets update the location of the string.
  643. //
  644. pOriginalPath = pOriginalEnd + tmp;
  645. break;
  646. }
  647. }
  648. //
  649. // Now put \SystemRoot\System32\ at the front of the name and append
  650. // the rest at the end
  651. //
  652. RtlAppendUnicodeToString(pUnicode, L"\\SystemRoot\\System32\\");
  653. RtlAppendUnicodeToString(pUnicode, pOriginalPath);
  654. if (bAppendDLL)
  655. {
  656. RtlAppendUnicodeToString(pUnicode, L".dll");
  657. }
  658. return (TRUE);
  659. }
  660. return (FALSE);
  661. }
  662. /*****************************************************************************\
  663. * MakeSystemDriversRelativePath
  664. *
  665. * Takes a path in X:\...\system32\.... format and makes it into
  666. * \SystemRoot\System32\Drivers format so that KernelMode API's can recognize it.
  667. *
  668. * This will ensure security by forcing any image being loaded to come from
  669. * the system32 directory.
  670. *
  671. * The AppendDLL flag indicates if the name should get .dll appended at the end
  672. * (for display drivers coming from USER) if it's not already there.
  673. *
  674. \*****************************************************************************/
  675. BOOL MakeSystemDriversRelativePath(
  676. LPWSTR pOriginalPath,
  677. PUNICODE_STRING pUnicode,
  678. BOOL bAppendDLL
  679. )
  680. {
  681. LPWSTR pOriginalEnd;
  682. ULONG OriginalLength = wcslen(pOriginalPath);
  683. ULONG cbLength = OriginalLength * sizeof(WCHAR) +
  684. sizeof(L"\\SystemRoot\\System32\\Drivers");
  685. ULONG tmp;
  686. tmp = (sizeof(L".DLL") / sizeof (WCHAR) - 1);
  687. //
  688. // Given append = TRUE, we check if we really need to append.
  689. // (printer drivers with .dll come through LDEVREF which specifies TRUE)
  690. //
  691. if (bAppendDLL)
  692. {
  693. if ((OriginalLength >= tmp) &&
  694. (!_wcsnicmp(pOriginalPath + OriginalLength - tmp,
  695. L".DLL",
  696. tmp)))
  697. {
  698. bAppendDLL = FALSE;
  699. }
  700. else
  701. {
  702. cbLength += tmp * sizeof(WCHAR);
  703. }
  704. }
  705. pUnicode->Length = 0;
  706. pUnicode->MaximumLength = (USHORT) cbLength;
  707. if (pUnicode->Buffer = PALLOCNOZ(cbLength, 'liFG'))
  708. {
  709. //
  710. // First parse the input string for \System32\Drivers. We parse from the end
  711. // of the string because some weirdo could have \System32\Nt\System32
  712. // as his/her root directory and this would throw us off if we scanned
  713. // from the front.
  714. //
  715. // It should only (and always) be printer drivers that pass down
  716. // fully qualified path names.
  717. //
  718. tmp = (sizeof(L"\\system32\\Drivers") / sizeof(WCHAR) - 1);
  719. for (pOriginalEnd = pOriginalPath + OriginalLength - tmp;
  720. pOriginalEnd >= pOriginalPath;
  721. pOriginalEnd --)
  722. {
  723. if (!_wcsnicmp(pOriginalEnd ,
  724. L"\\system32\\Drivers",
  725. tmp))
  726. {
  727. //
  728. // We found the system32 in the string.
  729. // Lets update the location of the string.
  730. //
  731. pOriginalPath = pOriginalEnd + tmp;
  732. break;
  733. }
  734. }
  735. //
  736. // Now put \SystemRoot\System32\Drivers\ at the front of the name and append
  737. // the rest at the end
  738. //
  739. RtlAppendUnicodeToString(pUnicode, L"\\SystemRoot\\System32\\Drivers\\");
  740. RtlAppendUnicodeToString(pUnicode, pOriginalPath);
  741. if (bAppendDLL)
  742. {
  743. RtlAppendUnicodeToString(pUnicode, L".dll");
  744. }
  745. return (TRUE);
  746. }
  747. return (FALSE);
  748. }
  749. /******************************Public*Routine******************************\
  750. *
  751. * Routine Name:
  752. *
  753. * EngGetFilePath
  754. *
  755. \**************************************************************************/
  756. BOOL EngGetFilePath(HANDLE h, WCHAR (*pDest)[MAX_PATH+1])
  757. {
  758. wchar_t *pSrc = ((PFONTFILEVIEW) h)->pwszPath;
  759. if ( pSrc )
  760. {
  761. wcscpy((wchar_t*) pDest, pSrc );
  762. }
  763. return( pSrc != 0 );
  764. }
  765. /******************************Public*Routine******************************\
  766. *
  767. * Routine Name:
  768. *
  769. * EngGetFileChangeTime
  770. *
  771. * Routine Description:
  772. *
  773. * Arguments:
  774. *
  775. * Called by:
  776. *
  777. * Return Value:
  778. *
  779. \**************************************************************************/
  780. BOOL EngGetFileChangeTime(
  781. HANDLE h,
  782. LARGE_INTEGER *pChangeTime)
  783. {
  784. UNICODE_STRING unicodeString;
  785. OBJECT_ATTRIBUTES objectAttributes;
  786. NTSTATUS ntStatus = STATUS_SUCCESS;
  787. HANDLE fileHandle = NULL;
  788. BOOL bResult = FALSE;
  789. IO_STATUS_BLOCK ioStatusBlock;
  790. FILE_BASIC_INFORMATION fileBasicInfo;
  791. PVOID sectionObject = NULL;
  792. PFONTFILEVIEW pffv = (PFONTFILEVIEW) h;
  793. ULONG viewSize;
  794. if(pffv->pwszPath)
  795. {
  796. if (pffv->fv.bLastUpdated)
  797. {
  798. *pChangeTime = pffv->fv.LastWriteTime;
  799. bResult = TRUE;
  800. }
  801. else
  802. {
  803. RtlInitUnicodeString(&unicodeString,
  804. pffv->pwszPath
  805. );
  806. InitializeObjectAttributes(&objectAttributes,
  807. &unicodeString,
  808. OBJ_CASE_INSENSITIVE,
  809. (HANDLE) NULL,
  810. (PSECURITY_DESCRIPTOR) NULL);
  811. ntStatus = ZwCreateFile(&fileHandle,
  812. FILE_READ_ATTRIBUTES,
  813. &objectAttributes,
  814. &ioStatusBlock,
  815. 0,
  816. FILE_ATTRIBUTE_NORMAL,
  817. 0,
  818. FILE_OPEN_IF,
  819. FILE_SYNCHRONOUS_IO_ALERT,
  820. 0,
  821. 0);
  822. if(NT_SUCCESS(ntStatus))
  823. {
  824. ntStatus = ZwQueryInformationFile(fileHandle,
  825. &ioStatusBlock,
  826. &fileBasicInfo,
  827. sizeof(FILE_BASIC_INFORMATION),
  828. FileBasicInformation);
  829. if (NT_SUCCESS(ntStatus))
  830. {
  831. *pChangeTime = fileBasicInfo.LastWriteTime;
  832. bResult = TRUE;
  833. }
  834. else
  835. {
  836. WARNING("EngGetFileTime:QueryInformationFile failed\n");
  837. }
  838. ZwClose(fileHandle);
  839. }
  840. else
  841. {
  842. WARNING("EngGetFileTime:Create/Open file failed\n");
  843. }
  844. }
  845. }
  846. else
  847. {
  848. // This is a remote font. In order for ATM to work we must always return
  849. // the same time for a remote font. One way to do this is to return a zero
  850. // time for all remote fonts.
  851. pChangeTime->HighPart = pChangeTime->LowPart = 0;
  852. bResult = TRUE;
  853. }
  854. return(bResult);
  855. }
  856. /*******************************************************************************
  857. * EngFindResource
  858. *
  859. * This function returns a size and ptr to a resource in a module.
  860. *
  861. * History:
  862. * 4/24/1995 by Gerrit van Wingerden [gerritv]
  863. * Wrote it.
  864. *******************************************************************************/
  865. PVOID pvFindResource(
  866. PVOID pView,
  867. PVOID pViewEnd,
  868. int iName,
  869. int iType,
  870. PULONG pulSize)
  871. {
  872. NTSTATUS Status;
  873. PVOID p,pRet;
  874. ULONG_PTR IdPath[ 3 ];
  875. IdPath[0] = (ULONG_PTR) iType;
  876. IdPath[1] = (ULONG_PTR) iName;
  877. IdPath[2] = (ULONG_PTR) 0;
  878. // add one to pvView to let LdrFindResource know that this has been mapped as a
  879. // datafile
  880. Status = LdrFindResource_U( pView,
  881. IdPath,
  882. 3,
  883. (PIMAGE_RESOURCE_DATA_ENTRY *)&p
  884. );
  885. if( !NT_SUCCESS( Status ) )
  886. {
  887. WARNING("EngFindResource: LdrFindResource_U failed.\n");
  888. return(NULL);
  889. }
  890. pRet = NULL;
  891. Status = LdrAccessResource( pView,
  892. (PIMAGE_RESOURCE_DATA_ENTRY) p,
  893. &pRet,
  894. pulSize );
  895. if( !NT_SUCCESS( Status ) )
  896. {
  897. WARNING("EngFindResource: LdrAccessResource failed.\n" );
  898. }
  899. return( pRet < pViewEnd ? pRet : NULL );
  900. }
  901. PVOID EngFindResourcePlainOrFD(
  902. PVOID pvViewBase,
  903. HANDLE h,
  904. int iName,
  905. int iType,
  906. PULONG pulSize
  907. )
  908. {
  909. PVOID pView,pViewEnd;
  910. pView = (PVOID) (((ULONG_PTR) pvViewBase)+1);
  911. pViewEnd = (PVOID) ((PBYTE)pvViewBase + ((PFILEVIEW) h)->cjView);
  912. return pvFindResource(pView, pViewEnd, iName, iType, pulSize);
  913. }
  914. PVOID EngFindResource(
  915. HANDLE h,
  916. int iName,
  917. int iType,
  918. PULONG pulSize)
  919. {
  920. return EngFindResourcePlainOrFD(((PFILEVIEW) h)->pvKView, h, iName, iType, pulSize);
  921. }
  922. PVOID EngFindResourceFD(
  923. HANDLE h,
  924. int iName,
  925. int iType,
  926. PULONG pulSize)
  927. {
  928. return EngFindResourcePlainOrFD(((PFILEVIEW) h)->pvViewFD, h, iName, iType, pulSize);
  929. }
  930. /******************************Public*Routine******************************\
  931. *
  932. * VOID vCheckCharSet(USHORT * pusCharSet)
  933. *
  934. *
  935. * Effects: validate charset in font sub section of the registry
  936. *
  937. * History:
  938. * 27-Jun-1995 -by- Bodin Dresevic [BodinD]
  939. * Wrote it.
  940. \**************************************************************************/
  941. VOID vCheckCharSet(FACE_CHARSET *pfcs, const WCHAR * pwsz)
  942. {
  943. UINT i;
  944. UNICODE_STRING String;
  945. ULONG ulCharSet = DEFAULT_CHARSET;
  946. pfcs->jCharSet = DEFAULT_CHARSET;
  947. pfcs->fjFlags = 0;
  948. String.Buffer = (WCHAR*)pwsz;
  949. String.MaximumLength = String.Length = wcslen(pwsz) * sizeof(WCHAR);
  950. // read the value and compare it against the allowed set of values, if
  951. // not found to be correct return default
  952. if (RtlUnicodeStringToInteger(&String, 10, &ulCharSet) == STATUS_SUCCESS)
  953. {
  954. if (ulCharSet <= 255)
  955. {
  956. pfcs->jCharSet = (BYTE)ulCharSet;
  957. for (i = 0; i < nCharsets; i++)
  958. {
  959. if (ulCharSet == charsets[i])
  960. {
  961. // both jCharSet and fjFlags are set correctly, can exit
  962. return;
  963. }
  964. }
  965. }
  966. }
  967. // If somebody entered the garbage in the Font Substitution section of "win.ini"
  968. // we will mark this as a "garbage charset" by setting the upper byte in the
  969. // usCharSet field. I believe that it is Ok to have garbage charset in the
  970. // value name, that is on the left hand side of the substitution entry.
  971. // This may be whatever garbage the application is passing to the
  972. // system. But the value on the right hand side, that is in value data, has to
  973. // be meaningfull, for we need to know which code page translation table
  974. // we should use with this font.
  975. pfcs->fjFlags |= FJ_GARBAGECHARSET;
  976. }
  977. /******************************Public*Routine******************************\
  978. *
  979. * EngComputeGlyphSet
  980. *
  981. \**************************************************************************/
  982. FD_GLYPHSET *EngComputeGlyphSet(
  983. INT nCodePage,
  984. INT nFirstChar,
  985. INT cChars
  986. )
  987. {
  988. BYTE *cbuf;
  989. INT cRuns;
  990. ULONG ByteCount;
  991. WCHAR *wcbuf;
  992. FD_GLYPHSET *pGlyphSet = 0;
  993. if ( 0 <= cChars && cChars < 65536 )
  994. {
  995. wcbuf = (WCHAR *) PALLOCMEM(cChars * (sizeof(WCHAR) + sizeof(BYTE)),'slgG');
  996. if ( wcbuf )
  997. {
  998. cbuf = (BYTE *) &wcbuf[cChars];
  999. cRuns = cUnicodeRangesSupported(
  1000. nCodePage,
  1001. nFirstChar,
  1002. cChars,
  1003. wcbuf,
  1004. cbuf);
  1005. ByteCount = SZ_GLYPHSET(cRuns, cChars);
  1006. // Allocate via EngAllocMem instead of PALLOCMEM because driver
  1007. // will free via EngAllocFree.
  1008. pGlyphSet = (FD_GLYPHSET*) EngAllocMem(0, ByteCount,'slgG');
  1009. if ( pGlyphSet )
  1010. {
  1011. cComputeGlyphSet(
  1012. wcbuf,
  1013. cbuf,
  1014. cChars,
  1015. cRuns,
  1016. pGlyphSet
  1017. );
  1018. }
  1019. VFREEMEM( wcbuf );
  1020. }
  1021. }
  1022. return( pGlyphSet );
  1023. }
  1024. /******************************Public*Routine******************************\
  1025. *
  1026. * Routine Name:
  1027. *
  1028. * vMoveFD_GLYPHSET
  1029. *
  1030. * Routine Description:
  1031. *
  1032. * Copies an FD_GLYPHSET from one location to another. The pointers
  1033. * in the destination are fixed up.
  1034. *
  1035. * Arguments:
  1036. *
  1037. * pgsDst pointer to destination FD_GLYPHSET
  1038. *
  1039. * pgsSrc pointer to source FD_GLYPHSET
  1040. *
  1041. * Called by:
  1042. *
  1043. * bComputeGlyphSet
  1044. *
  1045. * Return Value:
  1046. *
  1047. * none
  1048. *
  1049. \**************************************************************************/
  1050. void vMoveFD_GLYPHSET(FD_GLYPHSET *pgsDst, FD_GLYPHSET *pgsSrc)
  1051. {
  1052. char *pSrc, *pSrcLast, *pDst;
  1053. ULONG_PTR dp;
  1054. //
  1055. // move the structure
  1056. //
  1057. RtlCopyMemory(pgsDst, pgsSrc, pgsSrc->cjThis);
  1058. //
  1059. // if necessary, fix up the pointers
  1060. //
  1061. if (!(pgsSrc->flAccel & GS_UNICODE_HANDLES ))
  1062. {
  1063. pSrc = (char*) &pgsSrc->awcrun[0].phg;
  1064. pDst = (char*) &pgsDst->awcrun[0].phg;
  1065. pSrcLast = pSrc + sizeof(WCRUN) * pgsSrc->cRuns;
  1066. dp = pDst - pSrc;
  1067. for ( ; pSrc < pSrcLast; pSrc += sizeof(WCRUN), pDst += sizeof(WCRUN))
  1068. {
  1069. *(char**)pDst = *(char**)pSrc + dp;
  1070. }
  1071. }
  1072. }
  1073. /******************************Public*Routine******************************\
  1074. *
  1075. * Routine Name:
  1076. *
  1077. * bComputeGlyphSet
  1078. *
  1079. * Routine Description:
  1080. *
  1081. * This procedure provides safe access to GreComputeGlyphSet from user
  1082. * mode. All addresses supplied by the caller, except for pCall, are
  1083. * probed and access is surrounded by try/except pairs.
  1084. *
  1085. * Arguments:
  1086. *
  1087. * pCall a pointer to a GDICALL structure in kernel mode. This is
  1088. * a copy of the user mode structure passed to NtGdiCall.
  1089. *
  1090. * Called by:
  1091. *
  1092. * NtGdiCall
  1093. *
  1094. * Return Value:
  1095. *
  1096. \**************************************************************************/
  1097. BOOL bComputeGlyphSet(GDICALL *pCall)
  1098. {
  1099. extern VOID vMoveFD_GLYPHSET( FD_GLYPHSET *pDst, FD_GLYPHSET *pSrc);
  1100. static FD_GLYPHSET *pGlyphSet;
  1101. ASSERTGDI(pCall->Id == ComputeGlyphSet_,"pCall->Id == ComputeGlyphSet_\n");
  1102. pCall->ComputeGlyphSetArgs.ReturnValue = FALSE;
  1103. if ( pCall->ComputeGlyphSetArgs.ppGlyphSet == 0 )
  1104. {
  1105. if ( pCall->ComputeGlyphSetArgs.ByteCount == 0 )
  1106. {
  1107. if ( pGlyphSet == 0 )
  1108. {
  1109. pGlyphSet =
  1110. EngComputeGlyphSet(
  1111. pCall->ComputeGlyphSetArgs.nCodePage,
  1112. pCall->ComputeGlyphSetArgs.nFirstChar,
  1113. pCall->ComputeGlyphSetArgs.cChars
  1114. );
  1115. if ( pGlyphSet )
  1116. {
  1117. pCall->ComputeGlyphSetArgs.ppGlyphSet = &pGlyphSet;
  1118. pCall->ComputeGlyphSetArgs.ByteCount = pGlyphSet->cjThis;
  1119. pCall->ComputeGlyphSetArgs.ReturnValue = TRUE;
  1120. }
  1121. }
  1122. else
  1123. {
  1124. VFREEMEM( pGlyphSet );
  1125. pGlyphSet = 0;
  1126. }
  1127. }
  1128. }
  1129. else if (pCall->ComputeGlyphSetArgs.ppGlyphSet == &pGlyphSet && pGlyphSet != 0)
  1130. {
  1131. pCall->ComputeGlyphSetArgs.ReturnValue = TRUE;
  1132. try
  1133. {
  1134. ProbeForWrite(
  1135. pCall->ComputeGlyphSetArgs.pGlyphSet
  1136. , pGlyphSet->cjThis
  1137. , 8
  1138. );
  1139. vMoveFD_GLYPHSET(
  1140. pCall->ComputeGlyphSetArgs.pGlyphSet
  1141. , pGlyphSet
  1142. );
  1143. }
  1144. except( EXCEPTION_EXECUTE_HANDLER )
  1145. {
  1146. pCall->ComputeGlyphSetArgs.ReturnValue = FALSE;
  1147. }
  1148. VFREEMEM( pGlyphSet );
  1149. pGlyphSet = 0;
  1150. }
  1151. return( pCall->ComputeGlyphSetArgs.ReturnValue );
  1152. }
  1153. #define NLS_TABLE_KEY \
  1154. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Nls\\CodePage"
  1155. BOOL GetNlsTablePath(
  1156. UINT CodePage,
  1157. PWCHAR PathBuffer
  1158. )
  1159. /*++
  1160. Routine Description:
  1161. This routine takes a code page identifier, queries the registry to find the
  1162. appropriate NLS table for that code page, and then returns a path to the
  1163. table.
  1164. Arguments;
  1165. CodePage - specifies the code page to look for
  1166. PathBuffer - Specifies a buffer into which to copy the path of the NLS
  1167. file. This routine assumes that the size is at least MAX_PATH
  1168. Return Value:
  1169. TRUE if successful, FALSE otherwise.
  1170. Gerrit van Wingerden [gerritv] 1/22/96
  1171. --*/
  1172. {
  1173. NTSTATUS NtStatus;
  1174. BOOL Result = FALSE;
  1175. HANDLE RegistryKeyHandle;
  1176. OBJECT_ATTRIBUTES ObjectAttributes;
  1177. UNICODE_STRING UnicodeString;
  1178. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
  1179. RtlInitUnicodeString(&UnicodeString, NLS_TABLE_KEY);
  1180. InitializeObjectAttributes(&ObjectAttributes,
  1181. &UnicodeString,
  1182. OBJ_CASE_INSENSITIVE,
  1183. NULL,
  1184. NULL);
  1185. NtStatus = ZwOpenKey(&RegistryKeyHandle, GENERIC_READ, &ObjectAttributes);
  1186. if(NT_SUCCESS(NtStatus))
  1187. {
  1188. WCHAR *ResultBuffer;
  1189. ULONG BufferSize = sizeof(WCHAR) * MAX_PATH +
  1190. sizeof(KEY_VALUE_FULL_INFORMATION);
  1191. ResultBuffer = PALLOCMEM(BufferSize,'slnG');
  1192. if(ResultBuffer)
  1193. {
  1194. ULONG ValueReturnedLength;
  1195. WCHAR CodePageStringBuffer[20];
  1196. swprintf(CodePageStringBuffer, L"%d", CodePage);
  1197. RtlInitUnicodeString(&UnicodeString,CodePageStringBuffer);
  1198. KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION) ResultBuffer;
  1199. NtStatus = ZwQueryValueKey(RegistryKeyHandle,
  1200. &UnicodeString,
  1201. KeyValuePartialInformation,
  1202. KeyValueInformation,
  1203. BufferSize,
  1204. &BufferSize);
  1205. if(NT_SUCCESS(NtStatus))
  1206. {
  1207. swprintf(PathBuffer,L"\\SystemRoot\\System32\\%ws",
  1208. (WCHAR *)&(KeyValueInformation->Data[0]));
  1209. Result = TRUE;
  1210. }
  1211. else
  1212. {
  1213. WARNING("GetNlsTablePath failed to get NLS table\n");
  1214. }
  1215. VFREEMEM(ResultBuffer);
  1216. }
  1217. else
  1218. {
  1219. WARNING("GetNlsTablePath out of memory\n");
  1220. }
  1221. ZwCloseKey(RegistryKeyHandle);
  1222. }
  1223. else
  1224. {
  1225. WARNING("GetNlsTablePath failed to open NLS key\n");
  1226. }
  1227. return(Result);
  1228. }
  1229. INT ConvertToAndFromWideCharSymCP(
  1230. IN LPWSTR WideCharString,
  1231. IN INT BytesInWideCharString,
  1232. IN LPSTR MultiByteString,
  1233. IN INT BytesInMultiByteString,
  1234. IN BOOL ConvertToWideChar
  1235. )
  1236. /*++
  1237. Routine Description:
  1238. This routine converts a SB character string to or from a wide char string
  1239. assuming the CP_SYMBOL code page. We simply using the following rules to map
  1240. the single byte char to Unicode:
  1241. 0x00->0x1f map to 0x0000->0x001f
  1242. 0x20->0xff map to 0xf020->0xf0ff
  1243. Return Value:
  1244. Success - The number of bytes in the converted WideCharString
  1245. Failure - -1
  1246. Tessiew [Xudong Wu] Sept/25/97
  1247. -- */
  1248. {
  1249. INT cSB, cMaxSB, cWC, cMaxWC;
  1250. if ((BytesInWideCharString && (WideCharString == NULL)) ||
  1251. (BytesInMultiByteString && (MultiByteString == NULL)))
  1252. {
  1253. return 0;
  1254. }
  1255. if (ConvertToWideChar)
  1256. {
  1257. cMaxSB = MIN(BytesInMultiByteString, BytesInWideCharString / (INT)sizeof(WCHAR));
  1258. for (cSB = 0; cSB < cMaxSB; cSB++)
  1259. {
  1260. WideCharString[cSB] = ((BYTE)MultiByteString[cSB] < 0x20) ?
  1261. (WCHAR)MultiByteString[cSB] :
  1262. (WCHAR)((BYTE)MultiByteString[cSB] | ((WCHAR)(0xf0) << 8));
  1263. }
  1264. return (cMaxSB * sizeof(WCHAR));
  1265. }
  1266. else
  1267. {
  1268. cMaxWC = MIN(BytesInWideCharString / (INT)sizeof(WCHAR), BytesInMultiByteString);
  1269. for (cWC = 0; cWC < cMaxWC; cWC++)
  1270. {
  1271. // there is some error wchar in the string
  1272. // but we still return however many we finished
  1273. if ((WideCharString[cWC] >= 0x0020) &&
  1274. ((WideCharString[cWC] < 0xf020) ||
  1275. (WideCharString[cWC] > 0xf0ff)))
  1276. {
  1277. return (cWC);
  1278. }
  1279. MultiByteString[cWC] = (BYTE)WideCharString[cWC];
  1280. }
  1281. return (cMaxWC);
  1282. }
  1283. }
  1284. INT ConvertToAndFromWideChar(
  1285. IN UINT CodePage,
  1286. IN LPWSTR WideCharString,
  1287. IN INT BytesInWideCharString,
  1288. IN LPSTR MultiByteString,
  1289. IN INT BytesInMultiByteString,
  1290. IN BOOL ConvertToWideChar
  1291. )
  1292. /*++
  1293. Routine Description:
  1294. This routine converts a character string to or from a wide char string
  1295. assuming a specified code page. Most of the actual work is done inside
  1296. RtlCustomCPToUnicodeN, but this routine still needs to manage the loading
  1297. of the NLS files before passing them to the RtlRoutine. We will cache
  1298. the mapped NLS file for the most recently used code page which ought to
  1299. suffice for out purposes.
  1300. Arguments:
  1301. CodePage - the code page to use for doing the translation.
  1302. WideCharString - buffer the string is to be translated into.
  1303. BytesInWideCharString - number of bytes in the WideCharString buffer
  1304. if converting to wide char and the buffer isn't large enough then the
  1305. string in truncated and no error results.
  1306. MultiByteString - the multibyte string to be translated to Unicode.
  1307. BytesInMultiByteString - number of bytes in the multibyte string if
  1308. converting to multibyte and the buffer isn't large enough the string
  1309. is truncated and no error results
  1310. ConvertToWideChar - if TRUE then convert from multibyte to widechar
  1311. otherwise convert from wide char to multibyte
  1312. Return Value:
  1313. Success - The number of bytes in the converted WideCharString
  1314. Failure - -1
  1315. Gerrit van Wingerden [gerritv] 1/22/96
  1316. --*/
  1317. {
  1318. NTSTATUS NtStatus;
  1319. USHORT OemCodePage, AnsiCodePage;
  1320. CPTABLEINFO LocalTableInfo;
  1321. PCPTABLEINFO TableInfo = NULL;
  1322. PVOID LocalTableBase = NULL;
  1323. INT BytesConverted = 0;
  1324. ASSERTGDI(CodePage != 0, "EngMultiByteToWideChar invalid code page\n");
  1325. RtlGetDefaultCodePage(&AnsiCodePage,&OemCodePage);
  1326. // see if we can use the default translation routinte
  1327. if(AnsiCodePage == CodePage)
  1328. {
  1329. if(ConvertToWideChar)
  1330. {
  1331. NtStatus = RtlMultiByteToUnicodeN(WideCharString,
  1332. BytesInWideCharString,
  1333. &BytesConverted,
  1334. MultiByteString,
  1335. BytesInMultiByteString);
  1336. }
  1337. else
  1338. {
  1339. NtStatus = RtlUnicodeToMultiByteN(MultiByteString,
  1340. BytesInMultiByteString,
  1341. &BytesConverted,
  1342. WideCharString,
  1343. BytesInWideCharString);
  1344. }
  1345. if(NT_SUCCESS(NtStatus))
  1346. {
  1347. return(BytesConverted);
  1348. }
  1349. else
  1350. {
  1351. return(-1);
  1352. }
  1353. }
  1354. if (CodePage == CP_SYMBOL)
  1355. {
  1356. return (ConvertToAndFromWideCharSymCP(WideCharString, BytesInWideCharString,
  1357. MultiByteString, BytesInMultiByteString, ConvertToWideChar));
  1358. }
  1359. TRACE_FONT(("GreAcquireFastMutex(ghfmMemory) 006\n")); GreAcquireFastMutex(ghfmMemory);
  1360. if(CodePage == LastCodePageTranslated)
  1361. {
  1362. // we can use the cached code page information
  1363. TableInfo = &LastCPTableInfo;
  1364. NlsTableUseCount += 1;
  1365. }
  1366. GreReleaseFastMutex(ghfmMemory); TRACE_FONT(("GreReleaseFastMutex(ghfmMemory) 006\n"));
  1367. if(TableInfo == NULL)
  1368. {
  1369. // get a pointer to the path of the NLS table
  1370. WCHAR NlsTablePath[MAX_PATH];
  1371. if(GetNlsTablePath(CodePage,NlsTablePath))
  1372. {
  1373. UNICODE_STRING UnicodeString;
  1374. IO_STATUS_BLOCK IoStatus;
  1375. HANDLE NtFileHandle;
  1376. OBJECT_ATTRIBUTES ObjectAttributes;
  1377. RtlInitUnicodeString(&UnicodeString,NlsTablePath);
  1378. InitializeObjectAttributes(&ObjectAttributes,
  1379. &UnicodeString,
  1380. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  1381. NULL,
  1382. NULL);
  1383. NtStatus = ZwCreateFile(&NtFileHandle,
  1384. SYNCHRONIZE | FILE_READ_DATA,
  1385. &ObjectAttributes,
  1386. &IoStatus,
  1387. NULL,
  1388. 0,
  1389. FILE_SHARE_READ,
  1390. FILE_OPEN,
  1391. FILE_SYNCHRONOUS_IO_NONALERT,
  1392. NULL,
  1393. 0);
  1394. if(NT_SUCCESS(NtStatus))
  1395. {
  1396. FILE_STANDARD_INFORMATION StandardInfo;
  1397. // Query the object to determine its length.
  1398. NtStatus = ZwQueryInformationFile(NtFileHandle,
  1399. &IoStatus,
  1400. &StandardInfo,
  1401. sizeof(FILE_STANDARD_INFORMATION),
  1402. FileStandardInformation);
  1403. if(NT_SUCCESS(NtStatus) && StandardInfo.EndOfFile.LowPart)
  1404. {
  1405. UINT LengthOfFile = StandardInfo.EndOfFile.LowPart;
  1406. LocalTableBase = PALLOCMEM(LengthOfFile,'cwcG');
  1407. if(LocalTableBase)
  1408. {
  1409. // Read the file into our buffer.
  1410. NtStatus = ZwReadFile(NtFileHandle,
  1411. NULL,
  1412. NULL,
  1413. NULL,
  1414. &IoStatus,
  1415. LocalTableBase,
  1416. LengthOfFile,
  1417. NULL,
  1418. NULL);
  1419. if(!NT_SUCCESS(NtStatus))
  1420. {
  1421. WARNING("EngMultiByteToWideChar unable to read file\n");
  1422. VFREEMEM(LocalTableBase);
  1423. LocalTableBase = NULL;
  1424. }
  1425. }
  1426. else
  1427. {
  1428. WARNING("EngMultiByteToWideChar out of memory\n");
  1429. }
  1430. }
  1431. else
  1432. {
  1433. WARNING("EngMultiByteToWideChar unable query NLS file\n");
  1434. }
  1435. ZwClose(NtFileHandle);
  1436. }
  1437. else
  1438. {
  1439. WARNING("EngMultiByteToWideChar unable to open NLS file\n");
  1440. }
  1441. }
  1442. else
  1443. {
  1444. WARNING("EngMultiByteToWideChar get registry entry for NLS file failed\n");
  1445. }
  1446. if(LocalTableBase == NULL)
  1447. {
  1448. return(-1);
  1449. }
  1450. // now that we've got the table use it to initialize the CodePage table
  1451. RtlInitCodePageTable(LocalTableBase,&LocalTableInfo);
  1452. TableInfo = &LocalTableInfo;
  1453. }
  1454. // Once we are here TableInfo points to the the CPTABLEINFO struct we want
  1455. if(ConvertToWideChar)
  1456. {
  1457. NtStatus = RtlCustomCPToUnicodeN(TableInfo,
  1458. WideCharString,
  1459. BytesInWideCharString,
  1460. &BytesConverted,
  1461. MultiByteString,
  1462. BytesInMultiByteString);
  1463. }
  1464. else
  1465. {
  1466. NtStatus = RtlUnicodeToCustomCPN(TableInfo,
  1467. MultiByteString,
  1468. BytesInMultiByteString,
  1469. &BytesConverted,
  1470. WideCharString,
  1471. BytesInWideCharString);
  1472. }
  1473. if(!NT_SUCCESS(NtStatus))
  1474. {
  1475. // signal failure
  1476. BytesConverted = -1;
  1477. }
  1478. // see if we need to update the cached CPTABLEINFO information
  1479. if(TableInfo != &LocalTableInfo)
  1480. {
  1481. // we must have used the cached CPTABLEINFO data for the conversion
  1482. // simple decrement the reference count
  1483. TRACE_FONT(("GreAcquireFastMutex(ghfmMemory) 007\n")); GreAcquireFastMutex(ghfmMemory);
  1484. NlsTableUseCount -= 1;
  1485. GreReleaseFastMutex(ghfmMemory); TRACE_FONT(("GreReleaseFastMutex(ghfmMemory) 007\n"));
  1486. }
  1487. else
  1488. {
  1489. PVOID FreeTable;
  1490. // we must have just allocated a new CPTABLE structure so cache it
  1491. // unless another thread is using current cached entry
  1492. TRACE_FONT(("GreAcquireFastMutex(ghfmMemory) 008\n")); GreAcquireFastMutex(ghfmMemory);
  1493. if(!NlsTableUseCount)
  1494. {
  1495. LastCodePageTranslated = CodePage;
  1496. RtlMoveMemory(&LastCPTableInfo, TableInfo, sizeof(CPTABLEINFO));
  1497. FreeTable = LastNlsTableBuffer;
  1498. LastNlsTableBuffer = LocalTableBase;
  1499. }
  1500. else
  1501. {
  1502. FreeTable = LocalTableBase;
  1503. }
  1504. GreReleaseFastMutex(ghfmMemory); TRACE_FONT(("GreReleaseFastMutex(ghfmMemory) 008\n"));
  1505. // Now free the memory for either the old table or the one we allocated
  1506. // depending on whether we update the cache. Note that if this is
  1507. // the first time we are adding a cached value to the local table, then
  1508. // FreeTable will be NULL since LastNlsTableBuffer will be NULL
  1509. if(FreeTable)
  1510. {
  1511. VFREEMEM(FreeTable);
  1512. }
  1513. }
  1514. // we are done
  1515. return(BytesConverted);
  1516. }
  1517. VOID EngGetCurrentCodePage(
  1518. PUSHORT OemCodePage,
  1519. PUSHORT AnsiCodePage
  1520. )
  1521. {
  1522. RtlGetDefaultCodePage(AnsiCodePage,OemCodePage);
  1523. }
  1524. INT EngMultiByteToWideChar(
  1525. UINT CodePage,
  1526. LPWSTR WideCharString,
  1527. INT BytesInWideCharString,
  1528. LPSTR MultiByteString,
  1529. INT BytesInMultiByteString
  1530. )
  1531. {
  1532. return(ConvertToAndFromWideChar(CodePage,
  1533. WideCharString,
  1534. BytesInWideCharString,
  1535. MultiByteString,
  1536. BytesInMultiByteString,
  1537. TRUE));
  1538. }
  1539. INT APIENTRY EngWideCharToMultiByte(
  1540. UINT CodePage,
  1541. LPWSTR WideCharString,
  1542. INT BytesInWideCharString,
  1543. LPSTR MultiByteString,
  1544. INT BytesInMultiByteString
  1545. )
  1546. {
  1547. return(ConvertToAndFromWideChar(CodePage,
  1548. WideCharString,
  1549. BytesInWideCharString,
  1550. MultiByteString,
  1551. BytesInMultiByteString,
  1552. FALSE));
  1553. }
  1554. /******************************Public*Routine******************************\
  1555. * BOOL EngDeleteFile
  1556. *
  1557. * Delete a file.
  1558. *
  1559. * Parameters
  1560. * IN pwszFileName - Name of the file to be deleted
  1561. *
  1562. * Return Value
  1563. * TRUE - sucess
  1564. * FALSE - fail
  1565. *
  1566. * History:
  1567. * 4-Nov-1996 -by- Lingyun Wang [LingyunW]
  1568. * Wrote it.
  1569. \**************************************************************************/
  1570. BOOL EngDeleteFile (
  1571. PWSZ pwszFileName
  1572. )
  1573. {
  1574. UNICODE_STRING unicodeString;
  1575. OBJECT_ATTRIBUTES objectAttributes;
  1576. NTSTATUS ntStatus;
  1577. BOOL bRet = TRUE;
  1578. RtlInitUnicodeString(&unicodeString,
  1579. pwszFileName);
  1580. InitializeObjectAttributes(&objectAttributes,
  1581. &unicodeString,
  1582. OBJ_CASE_INSENSITIVE,
  1583. (HANDLE) NULL,
  1584. (PSECURITY_DESCRIPTOR) NULL);
  1585. ntStatus = ZwDeleteFile (&objectAttributes);
  1586. if (ntStatus != STATUS_SUCCESS)
  1587. {
  1588. WARNING ("EngDeleteFile failed \n");
  1589. bRet = FALSE;
  1590. }
  1591. return (bRet);
  1592. }
  1593. /******************************Public*Routine******************************\
  1594. * BOOL EngQueryFileTimeStamp
  1595. *
  1596. * Query a file timetimep.
  1597. *
  1598. * Parameters
  1599. * IN pwsz - Name of the file
  1600. *
  1601. * Return Value
  1602. * Timestamp
  1603. *
  1604. * History:
  1605. * 22-Nov-1996 -by- Lingyun Wang [LingyunW]
  1606. * Wrote it.
  1607. \**************************************************************************/
  1608. LARGE_INTEGER EngQueryFileTimeStamp (
  1609. PWSZ pwsz
  1610. )
  1611. {
  1612. HANDLE FileHandle;
  1613. UNICODE_STRING unicodeString;
  1614. OBJECT_ATTRIBUTES objectAttributes;
  1615. IO_STATUS_BLOCK IoStatusBlock;
  1616. NTSTATUS ntStatus;
  1617. LARGE_INTEGER SystemTime, LocalTime;
  1618. FILE_BASIC_INFORMATION File_Info;
  1619. SystemTime.QuadPart = 0;
  1620. LocalTime.QuadPart = 0;
  1621. RtlInitUnicodeString(&unicodeString,
  1622. pwsz
  1623. );
  1624. InitializeObjectAttributes(&objectAttributes,
  1625. &unicodeString,
  1626. OBJ_CASE_INSENSITIVE,
  1627. (HANDLE) NULL,
  1628. (PSECURITY_DESCRIPTOR) NULL);
  1629. ntStatus = ZwOpenFile(&FileHandle,
  1630. FILE_GENERIC_READ,
  1631. &objectAttributes,
  1632. &IoStatusBlock,
  1633. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  1634. FILE_SYNCHRONOUS_IO_ALERT);
  1635. if(!NT_SUCCESS(ntStatus))
  1636. {
  1637. WARNING("fail to get handle of file file\n");
  1638. }
  1639. ntStatus = ZwQueryInformationFile (FileHandle,
  1640. &IoStatusBlock,
  1641. &File_Info,
  1642. sizeof(FILE_BASIC_INFORMATION),
  1643. FileBasicInformation
  1644. );
  1645. if (ntStatus != STATUS_SUCCESS)
  1646. {
  1647. WARNING("failed queryinformationfile\n");
  1648. return (LocalTime);
  1649. }
  1650. ZwClose (FileHandle);
  1651. SystemTime = File_Info.LastWriteTime;
  1652. GreSystemTimeToLocalTime(&SystemTime, &LocalTime);
  1653. return(LocalTime);
  1654. }