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
2008 lines
57 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: mapfile.c
|
|
*
|
|
* Created: 25-Jun-1992 14:33:45
|
|
* Author: Bodin Dresevic [BodinD]
|
|
*
|
|
* Copyright (c) 1990-1999 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "engine.h"
|
|
#include "ntnls.h"
|
|
#include "stdlib.h"
|
|
|
|
#include "ugdiport.h"
|
|
|
|
extern HFASTMUTEX ghfmMemory;
|
|
|
|
ULONG LastCodePageTranslated = 0; // I'm assuming 0 is not a valid codepage
|
|
PVOID LastNlsTableBuffer = NULL;
|
|
CPTABLEINFO LastCPTableInfo;
|
|
UINT NlsTableUseCount = 0;
|
|
|
|
ULONG ulCharsetToCodePage(UINT);
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* vSort, N^2 alg, might want to replace by qsort
|
|
*
|
|
* Effects:
|
|
*
|
|
* Warnings:
|
|
*
|
|
* History:
|
|
* 25-Jun-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vSort(
|
|
WCHAR *pwc, // input buffer with a sorted array of cChar supported WCHAR's
|
|
BYTE *pj, // input buffer with original ansi values
|
|
INT cChar
|
|
)
|
|
{
|
|
INT i;
|
|
|
|
for (i = 1; i < cChar; i++)
|
|
{
|
|
// upon every entry to this loop the array 0,1,..., (i-1) will be sorted
|
|
|
|
INT j;
|
|
WCHAR wcTmp = pwc[i];
|
|
BYTE jTmp = pj[i];
|
|
|
|
for (j = i - 1; (j >= 0) && (pwc[j] > wcTmp); j--)
|
|
{
|
|
pwc[j+1] = pwc[j];
|
|
pj[j+1] = pj[j];
|
|
}
|
|
pwc[j+1] = wcTmp;
|
|
pj[j+1] = jTmp;
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* cComputeGlyphSet
|
|
*
|
|
* computes the number of contiguous ranges supported in a font.
|
|
*
|
|
* Input is a sorted array (which may contain duplicates)
|
|
* such as 1 1 1 2 3 4 5 7 8 9 10 10 11 12 etc
|
|
* of cChar unicode code points that are
|
|
* supported in a font
|
|
*
|
|
* fills the FD_GLYPSET structure if the pgset buffer is provided
|
|
*
|
|
* History:
|
|
* 25-Jun-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
INT cComputeGlyphSet(
|
|
WCHAR *pwc, // input buffer with a sorted array of cChar supported WCHAR's
|
|
BYTE *pj, // input buffer with original ansi values
|
|
INT cChar,
|
|
INT cRuns, // if nonzero, the same as return value
|
|
FD_GLYPHSET *pgset // output buffer to be filled with cRanges runs
|
|
)
|
|
{
|
|
INT iRun, iFirst, iFirstNext;
|
|
HGLYPH *phg, *phgEnd = NULL;
|
|
BYTE *pjTmp;
|
|
|
|
if (pgset != NULL)
|
|
{
|
|
pgset->cjThis = SZ_GLYPHSET(cRuns,cChar);
|
|
|
|
// BUG, BUG
|
|
|
|
// this line may seem confusing because 256 characters still fit in a byte
|
|
// with values [0, 255]. The reason is that tt and ps fonts, who otherwise
|
|
// would qualify as an 8 bit report bogus last and first char
|
|
// (win31 compatibility) which confuses our engine.
|
|
// tt and ps drivers therefore, for the purpose of computing glyphsets
|
|
// of tt symbol fonts and ps fonts set firstChar to 0 and LastChar to 255.
|
|
// For now we force such fonts through more general 16bit handle case
|
|
// which does not rely on the fact that chFirst and chLast are correct
|
|
|
|
pgset->flAccel = (cChar != 256) ? GS_8BIT_HANDLES : GS_16BIT_HANDLES;
|
|
pgset->cRuns = cRuns;
|
|
|
|
// init the sum before entering the loop
|
|
|
|
pgset->cGlyphsSupported = 0;
|
|
|
|
// glyph handles are stored at the bottom, below runs:
|
|
|
|
phg = (HGLYPH *) ((BYTE *)pgset + (offsetof(FD_GLYPHSET,awcrun) + cRuns * sizeof(WCRUN)));
|
|
}
|
|
|
|
// now compute cRuns if pgset == 0 and fill the glyphset if pgset != 0
|
|
|
|
for (iFirst = 0, iRun = 0; iFirst < cChar; iRun++, iFirst = iFirstNext)
|
|
{
|
|
// find iFirst corresponding to the next range.
|
|
|
|
for (iFirstNext = iFirst + 1; iFirstNext < cChar; iFirstNext++)
|
|
{
|
|
if ((pwc[iFirstNext] - pwc[iFirstNext - 1]) > 1)
|
|
break;
|
|
}
|
|
|
|
if (pgset != NULL)
|
|
{
|
|
pgset->awcrun[iRun].wcLow = pwc[iFirst];
|
|
|
|
pgset->awcrun[iRun].cGlyphs =
|
|
(USHORT)(pwc[iFirstNext-1] - pwc[iFirst] + 1);
|
|
|
|
pgset->awcrun[iRun].phg = phg;
|
|
|
|
// now store the handles, i.e. the original ansi values
|
|
|
|
phgEnd = phg + pgset->awcrun[iRun].cGlyphs;
|
|
|
|
for (pjTmp = &pj[iFirst]; phg < phgEnd; phg++,pjTmp++)
|
|
{
|
|
*phg = (HGLYPH)*pjTmp;
|
|
}
|
|
|
|
pgset->cGlyphsSupported += pgset->awcrun[iRun].cGlyphs;
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
if (pgset != NULL)
|
|
ASSERTGDI(iRun == cRuns, "gdisrv! iRun != cRun\n");
|
|
#endif
|
|
|
|
return iRun;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* cUnicodeRangesSupported
|
|
*
|
|
* Effects:
|
|
*
|
|
* Warnings:
|
|
*
|
|
* History:
|
|
* 25-Jun-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
INT cUnicodeRangesSupported (
|
|
INT cp, // code page, not used for now, the default system code page is used
|
|
INT iFirstChar, // first ansi char supported
|
|
INT cChar, // # of ansi chars supported, cChar = iLastChar + 1 - iFirstChar
|
|
WCHAR *pwc, // input buffer with a sorted array of cChar supported WCHAR's
|
|
BYTE *pj
|
|
)
|
|
{
|
|
BYTE jFirst = (BYTE)iFirstChar;
|
|
INT i;
|
|
|
|
USHORT AnsiCodePage, OemCodePage;
|
|
|
|
ASSERTGDI((iFirstChar < 256) && (cChar <= 256),
|
|
"gdisrvl! iFirst or cChar\n");
|
|
|
|
//
|
|
// fill the array with cCharConsecutive ansi values
|
|
//
|
|
|
|
for (i = 0; i < cChar; i++)
|
|
{
|
|
pj[i] = (BYTE)iFirstChar++;
|
|
}
|
|
|
|
// If the default code page is DBCS then use 1252, otherwise use
|
|
// use the default code page
|
|
//
|
|
|
|
if (IS_ANY_DBCS_CODEPAGE(cp))
|
|
{
|
|
// Suppose we have a system without correspoding DBCS codepage installed.
|
|
// We would still like to load this font. But we will do so as CP 1252.
|
|
// To do that try to translate one character using DBCS codepage and see if it
|
|
// suceeds.
|
|
|
|
if(EngMultiByteToWideChar(cp,&pwc[0],2,&pj[0],1) == -1)
|
|
{
|
|
WARNING("DBCS Codepage not installed using 1252\n");
|
|
cp = 1252;
|
|
}
|
|
|
|
for(i = 0; i < cChar; i++)
|
|
{
|
|
// this is a shift-jis charset so we need special handling
|
|
|
|
INT Result = EngMultiByteToWideChar(cp,&pwc[i],2,&pj[i],1);
|
|
#if DBG
|
|
if (Result == -1) WARNING("gdisrvl! EngMultiByteToWideChar failed\n");
|
|
#endif
|
|
|
|
if ((Result == -1) || (pwc[i] == 0 && pj[i] != 0))
|
|
{
|
|
// this must have been a DBCS lead byte so just return 0xFFFF or a failure
|
|
// failure of EngMultiByteToWideChar could be cause by low memory condition
|
|
|
|
pwc[i] = 0xFFFF;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
INT Result;
|
|
if ((cp == CP_ACP) || (cp == CP_OEMCP))
|
|
{
|
|
RtlGetDefaultCodePage(&AnsiCodePage,&OemCodePage);
|
|
|
|
if(IS_ANY_DBCS_CODEPAGE(AnsiCodePage))
|
|
{
|
|
AnsiCodePage = 1252;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AnsiCodePage = (USHORT)cp;
|
|
}
|
|
|
|
Result = EngMultiByteToWideChar(AnsiCodePage,
|
|
pwc,
|
|
(ULONG)(cChar * sizeof(WCHAR)),
|
|
(PCH) pj,
|
|
(ULONG) cChar);
|
|
|
|
ASSERTGDI(Result != -1, "gdisrvl! EngMultiByteToWideChar failed\n");
|
|
}
|
|
|
|
// now subtract the first char from all ansi values so that the
|
|
// glyph handle is equal to glyph index, rather than to the ansi value
|
|
|
|
for (i = 0; i < cChar; i++)
|
|
{
|
|
pj[i] -= (BYTE)jFirst;
|
|
}
|
|
|
|
// now sort out pwc array and permute pj array accordingly
|
|
|
|
vSort(pwc,pj, cChar);
|
|
|
|
//
|
|
// compute the number of ranges
|
|
//
|
|
|
|
return cComputeGlyphSet (pwc,pj, cChar, 0, NULL);
|
|
}
|
|
|
|
/******************************Private*Routine******************************\
|
|
* pcpComputeGlyphset,
|
|
*
|
|
* Computes the FD_GLYPHSET struct based on chFirst and chLast. If such a
|
|
* FD_GLYPHSET already exists in our global list of FD structs it updates
|
|
* the ref count for this FD_GLYPHSET in the global list points pcrd->pcp->pgset
|
|
* to it. Otherwise it makes a new FD_GLYPHSET entry in the global list
|
|
* and points pcrd->pcp->pgset to it.
|
|
*
|
|
* Thu 03-Dec-1992 -by- Bodin Dresevic [BodinD]
|
|
* update: redid them to make them usable in vtfd
|
|
*
|
|
* History:
|
|
* 24-July-1992 -by- Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
|
|
CP_GLYPHSET *pcpComputeGlyphset(
|
|
CP_GLYPHSET **pcpHead, // head of the list
|
|
UINT uiFirst,
|
|
UINT uiLast,
|
|
BYTE jCharset
|
|
)
|
|
{
|
|
CP_GLYPHSET *pcpTmp;
|
|
CP_GLYPHSET *pcpRet = NULL;
|
|
|
|
// First we need to see if a FD_GLYPHSET already exists for this first and
|
|
// last range.
|
|
|
|
for( pcpTmp = *pcpHead;
|
|
pcpTmp != NULL;
|
|
pcpTmp = pcpTmp->pcpNext )
|
|
{
|
|
if((pcpTmp->uiFirstChar == uiFirst) &&
|
|
(pcpTmp->jCharset == jCharset) &&
|
|
(pcpTmp->uiLastChar == uiLast))
|
|
break;
|
|
}
|
|
if( pcpTmp != NULL )
|
|
{
|
|
//
|
|
// We found a match.
|
|
//
|
|
pcpTmp->uiRefCount +=1;
|
|
|
|
//
|
|
// We should never have so many references as to wrap around but if we ever
|
|
// do we must fail the call.
|
|
//
|
|
if( pcpTmp->uiRefCount == 0 )
|
|
{
|
|
WARNING("BMFD!Too many references to glyphset\n");
|
|
pcpRet = NULL;
|
|
}
|
|
else
|
|
{
|
|
pcpRet = pcpTmp;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We need to allocate a new CP_GLYPHSET
|
|
// For SYMBOL_CHARSET, it also needs to cover xf020 to xf0ff unicode range
|
|
|
|
BYTE aj[2*256-32];
|
|
WCHAR awc[2*256-32];
|
|
INT cNumRuns;
|
|
BOOL isSymbol = FALSE;
|
|
UINT i,j;
|
|
|
|
UINT uiCodePage = (UINT)ulCharsetToCodePage(jCharset);
|
|
UINT cGlyphs = uiLast - uiFirst + 1;
|
|
|
|
// use CP_ACP for SYMBOL_CHARSET
|
|
|
|
if (uiCodePage == 42)
|
|
{
|
|
uiCodePage = CP_ACP;
|
|
isSymbol = TRUE;
|
|
}
|
|
|
|
cNumRuns = cUnicodeRangesSupported(
|
|
uiCodePage,
|
|
uiFirst,
|
|
cGlyphs,
|
|
awc,aj);
|
|
|
|
if (isSymbol)
|
|
{
|
|
// add range subset of a range [f020, f0ff]
|
|
|
|
for (i = uiFirst, j = cGlyphs; i< (uiFirst+cGlyphs); i++)
|
|
{
|
|
// if i < 0x20, we do not report the glyph in f020-f0ff range, it has been reported already in the current code page range
|
|
|
|
if (i >= 0x20)
|
|
{
|
|
awc[j] = 0xf000 + i;
|
|
aj[j] = i - uiFirst;
|
|
j++;
|
|
}
|
|
}
|
|
|
|
// make sure we resort if needed
|
|
|
|
if (awc[cGlyphs-1] > 0xf020)
|
|
vSort(awc,aj,j);
|
|
|
|
if (cGlyphs != j)
|
|
{
|
|
cNumRuns++;
|
|
cGlyphs = j;
|
|
}
|
|
}
|
|
|
|
if ( (pcpTmp = (CP_GLYPHSET*)
|
|
(PALLOCNOZ((SZ_GLYPHSET(cNumRuns,cGlyphs) +
|
|
offsetof(CP_GLYPHSET,gset)),
|
|
'slgG'))
|
|
) == (CP_GLYPHSET*) NULL)
|
|
{
|
|
WARNING("BMFD!pcpComputeGlyphset memory allocation error.\n");
|
|
pcpRet = NULL;
|
|
}
|
|
else
|
|
{
|
|
pcpTmp->uiRefCount = 1;
|
|
pcpTmp->uiFirstChar = uiFirst;
|
|
pcpTmp->uiLastChar = uiLast;
|
|
pcpTmp->jCharset = jCharset;
|
|
|
|
// Fill in the Glyphset structure
|
|
|
|
cComputeGlyphSet(awc,aj, cGlyphs, cNumRuns, &pcpTmp->gset);
|
|
|
|
// Insert at beginning of list
|
|
|
|
pcpTmp->pcpNext = *pcpHead;
|
|
*pcpHead = pcpTmp;
|
|
|
|
// point CVTRESDATA to new CP_GLYPHSET
|
|
|
|
pcpRet = pcpTmp;
|
|
}
|
|
}
|
|
|
|
return pcpRet;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* vUnloadGlyphset( PCP pcpTarget )
|
|
*
|
|
* Decrements the ref count of a CP_GLYPHSET and unloads it from the global
|
|
* list of CP_GLYPHSETS if the ref count is zero.
|
|
*
|
|
* IN
|
|
* PCP pcpTarget pointer to CP_GLYPHSET to be unloaded or decremented
|
|
*
|
|
* History
|
|
*
|
|
* Thu 03-Dec-1992 -by- Bodin Dresevic [BodinD]
|
|
* update: redid them to make them usable in vtfd
|
|
*
|
|
* 7-25-92 Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
*
|
|
***************************************************************************/
|
|
|
|
VOID vUnloadGlyphset(
|
|
CP_GLYPHSET **pcpHead,
|
|
CP_GLYPHSET *pcpTarget
|
|
)
|
|
{
|
|
CP_GLYPHSET *pcpLast, *pcpCurrent;
|
|
|
|
if( *pcpHead == NULL )
|
|
{
|
|
WARNING1("vUnloadGlyphset called with NULL Head\n");
|
|
return;
|
|
}
|
|
|
|
pcpCurrent = *pcpHead;
|
|
pcpLast = NULL;
|
|
|
|
//
|
|
// Find the right CP_GLYPSHET
|
|
//
|
|
while( 1 )
|
|
{
|
|
ASSERTGDI( pcpCurrent != NULL, "CP_GLYPHSET list problem.\n" );
|
|
if( pcpCurrent == pcpTarget )
|
|
break;
|
|
pcpLast = pcpCurrent;
|
|
pcpCurrent = pcpCurrent->pcpNext;
|
|
}
|
|
|
|
if( --pcpCurrent->uiRefCount == 0 )
|
|
{
|
|
//
|
|
// We need to deallocate and remove from list
|
|
//
|
|
if( pcpLast == NULL )
|
|
*pcpHead = pcpCurrent->pcpNext;
|
|
else
|
|
pcpLast->pcpNext = pcpCurrent->pcpNext;
|
|
|
|
VFREEMEM(pcpCurrent);
|
|
}
|
|
}
|
|
|
|
|
|
PVOID __nw(unsigned int ui)
|
|
{
|
|
DONTUSE(ui);
|
|
RIP("Bogus __nw call");
|
|
return(NULL);
|
|
}
|
|
|
|
VOID __dl(PVOID pv)
|
|
{
|
|
DONTUSE(pv);
|
|
RIP("Bogus __dl call");
|
|
}
|
|
|
|
// the definition of this variable is in ntgdi\inc\hmgshare.h
|
|
|
|
CHARSET_ARRAYS
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* ULONG ulCharsetToCodePage(UINT uiCharSet)
|
|
*
|
|
*
|
|
* Effects: figure out which code page to unicode translation table
|
|
* should be used for this realization
|
|
*
|
|
* History:
|
|
* 31-Jan-1995 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
ULONG ulCharsetToCodePage(UINT uiCharSet)
|
|
{
|
|
int i;
|
|
|
|
if (uiCharSet != OEM_CHARSET)
|
|
{
|
|
for (i = 0; i < NCHARSETS; i++)
|
|
{
|
|
if (charsets[i] == uiCharSet)
|
|
return codepages[i];
|
|
}
|
|
|
|
// in case of some random charset
|
|
// (this is likely an old bm or vecrot font) we will just use the current
|
|
// global code page translation table. This is enough to ensure
|
|
// the correct round trip: ansi->unicode->ansi
|
|
|
|
// if CP_ACP is a DBCS code page then we better use 1252 to ensure
|
|
// proper rountrip conversion
|
|
|
|
return( gbDBCSCodePage ? 1252 : CP_ACP);
|
|
|
|
}
|
|
else // to make merced compiler happy
|
|
{
|
|
return CP_OEMCP;
|
|
}
|
|
|
|
}
|
|
|
|
// inverse function
|
|
|
|
VOID vConvertCodePageToCharSet(WORD src, DWORD *pfsRet, BYTE *pjRet)
|
|
{
|
|
UINT i;
|
|
|
|
|
|
*pjRet = ANSI_CHARSET;
|
|
*pfsRet = FS_LATIN1;
|
|
|
|
for (i = 0; i < nCharsets; i++)
|
|
{
|
|
if ( codepages[i] == src )
|
|
{
|
|
// cs.ciACP = src ;
|
|
// cs.ciCharset = charsets[i] ;
|
|
|
|
*pfsRet = fs[i];
|
|
*pjRet = (BYTE)charsets[i] ;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* LONG EngParseFontResources
|
|
*
|
|
* This routine takes a handle to a mapped image and returns an array of
|
|
* pointers to the base of all the font resources in that image.
|
|
*
|
|
* Parameters
|
|
*
|
|
* HANDLE hFontFile -- Handle (really a pointer) to a FONTFILEVIEW
|
|
* image in which the fonts are to be found.
|
|
* ULONG BufferSize -- Number of entries that ppvResourceBases can hold.
|
|
* PVOID *ppvResourceBases -- Buffer to hold the array of pointers to font
|
|
* resources. If NULL then only the number of resources is returned,
|
|
* and this value is ignored.
|
|
*
|
|
* Returns
|
|
*
|
|
* Number of font resources in the image or 0 if error or none.
|
|
*
|
|
* History
|
|
* 7-3-95 Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
*
|
|
****************************************************************************/
|
|
|
|
PVOID EngFindResourceFD(
|
|
HANDLE h,
|
|
int iName,
|
|
int iType,
|
|
PULONG pulSize);
|
|
|
|
|
|
ULONG cParseFontResources(
|
|
HANDLE hFontFile,
|
|
PVOID **ppvResourceBases)
|
|
{
|
|
PIMAGE_DOS_HEADER pDosHeader;
|
|
NTSTATUS Status;
|
|
ULONG_PTR IdPath[ 1 ];
|
|
INT i;
|
|
HANDLE DllHandle;
|
|
PIMAGE_RESOURCE_DIRECTORY ResourceDirectory;
|
|
PIMAGE_RESOURCE_DIRECTORY_ENTRY ResourceDirectoryEntry;
|
|
PVOID pvImageBase;
|
|
INT cEntries = 0;
|
|
|
|
// Fail call if this is a bogus DOS image without an NE header.
|
|
|
|
pDosHeader = (PIMAGE_DOS_HEADER)((PFONTFILEVIEW)hFontFile)->fv.pvViewFD;
|
|
if (pDosHeader->e_magic == IMAGE_DOS_SIGNATURE &&
|
|
(ULONG)(pDosHeader->e_lfanew) > ((PFONTFILEVIEW)hFontFile)->fv.cjView) {
|
|
TRACE_FONT(("cParseFontResources: Cant map bogus DOS image files for fonts\n"));
|
|
return 0;
|
|
}
|
|
|
|
// the LDR routines expect a one or'd in if this file mas mapped as an
|
|
// image
|
|
|
|
pvImageBase = (PVOID) (((ULONG_PTR) ((PFONTFILEVIEW) hFontFile)->fv.pvViewFD)|1);
|
|
|
|
// Later on we'll call EngFindResource which expects a handle to FILEVIEW
|
|
// struct. It really just grabs the pvView field from the structure so
|
|
// make sure that pvView field is the same place in both FILEVIEW and
|
|
// FONTFILEVIEW structs
|
|
|
|
|
|
IdPath[0] = 8; // 8 is RT_FONT
|
|
|
|
Status = LdrFindResourceDirectory_U(pvImageBase,
|
|
IdPath,
|
|
1,
|
|
&ResourceDirectory);
|
|
|
|
if (NT_SUCCESS( Status ))
|
|
{
|
|
// For now we'll assume that the only types of FONT entries will be Id
|
|
// entries. If for some reason this turns out not to be the case we'll
|
|
// have to add more code (see windows\base\module.c) under the FindResource
|
|
// function to get an idea how to do this.
|
|
|
|
ASSERTGDI(ResourceDirectory->NumberOfNamedEntries == 0,
|
|
"EngParseFontResources: NamedEntries in font file.\n");
|
|
|
|
*ppvResourceBases = (PVOID *) EngAllocMem(FL_ZERO_MEMORY,ResourceDirectory->NumberOfIdEntries * sizeof(PVOID *),'dfmB');
|
|
|
|
if (*ppvResourceBases)
|
|
{
|
|
|
|
PVOID *ppvResource = *ppvResourceBases;
|
|
|
|
cEntries = ResourceDirectory->NumberOfIdEntries;
|
|
|
|
try
|
|
{
|
|
ResourceDirectoryEntry =
|
|
(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResourceDirectory+1);
|
|
|
|
for (i=0; i < cEntries ; ResourceDirectoryEntry++, i++ )
|
|
{
|
|
|
|
DWORD dwSize;
|
|
|
|
*ppvResource = EngFindResourceFD(hFontFile,
|
|
ResourceDirectoryEntry->Id,
|
|
8, // RT_FONT
|
|
&dwSize );
|
|
|
|
if( *ppvResource++ == NULL )
|
|
{
|
|
WARNING("EngParseFontResources: EngFindResourceFailed\n");
|
|
cEntries = -1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
cEntries = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(cEntries);
|
|
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
* MakeSystemRelativePath
|
|
*
|
|
* Takes a path in X:\...\system32\.... format and makes it into
|
|
* \SystemRoot\System32 format so that KernelMode API's can recognize it.
|
|
*
|
|
* This will ensure security by forcing any image being loaded to come from
|
|
* the system32 directory.
|
|
*
|
|
* The AppendDLL flag indicates if the name should get .dll appended at the end
|
|
* (for display drivers coming from USER) if it's not already there.
|
|
*
|
|
\*****************************************************************************/
|
|
|
|
BOOL MakeSystemRelativePath(
|
|
LPWSTR pOriginalPath,
|
|
PUNICODE_STRING pUnicode,
|
|
BOOL bAppendDLL
|
|
)
|
|
{
|
|
LPWSTR pOriginalEnd;
|
|
ULONG OriginalLength = wcslen(pOriginalPath);
|
|
ULONG cbLength = OriginalLength * sizeof(WCHAR) +
|
|
sizeof(L"\\SystemRoot\\System32\\");
|
|
ULONG tmp;
|
|
|
|
tmp = (sizeof(L".DLL") / sizeof (WCHAR) - 1);
|
|
|
|
//
|
|
// Given append = TRUE, we check if we really need to append.
|
|
// (printer drivers with .dll come through LDEVREF which specifies TRUE)
|
|
//
|
|
|
|
if (bAppendDLL)
|
|
{
|
|
if ((OriginalLength >= tmp) &&
|
|
(!_wcsnicmp(pOriginalPath + OriginalLength - tmp,
|
|
L".DLL",
|
|
tmp)))
|
|
{
|
|
bAppendDLL = FALSE;
|
|
}
|
|
else
|
|
{
|
|
cbLength += tmp * sizeof(WCHAR);
|
|
}
|
|
}
|
|
|
|
pUnicode->Length = 0;
|
|
pUnicode->MaximumLength = (USHORT) cbLength;
|
|
|
|
if (pUnicode->Buffer = PALLOCNOZ(cbLength, 'liFG'))
|
|
{
|
|
//
|
|
// First parse the input string for \System32\. We parse from the end
|
|
// of the string because some weirdo could have \System32\Nt\System32
|
|
// as his/her root directory and this would throw us off if we scanned
|
|
// from the front.
|
|
//
|
|
// It should only (and always) be printer drivers that pass down
|
|
// fully qualified path names.
|
|
//
|
|
|
|
tmp = (sizeof(L"\\system32\\") / sizeof(WCHAR) - 1);
|
|
|
|
|
|
for (pOriginalEnd = pOriginalPath + OriginalLength - tmp;
|
|
pOriginalEnd >= pOriginalPath;
|
|
pOriginalEnd --)
|
|
{
|
|
if (!_wcsnicmp(pOriginalEnd ,
|
|
L"\\system32\\",
|
|
tmp))
|
|
{
|
|
//
|
|
// We found the system32 in the string.
|
|
// Lets update the location of the string.
|
|
//
|
|
|
|
pOriginalPath = pOriginalEnd + tmp;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now put \SystemRoot\System32\ at the front of the name and append
|
|
// the rest at the end
|
|
//
|
|
|
|
RtlAppendUnicodeToString(pUnicode, L"\\SystemRoot\\System32\\");
|
|
RtlAppendUnicodeToString(pUnicode, pOriginalPath);
|
|
|
|
if (bAppendDLL)
|
|
{
|
|
RtlAppendUnicodeToString(pUnicode, L".dll");
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
return (FALSE);
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
* MakeSystemDriversRelativePath
|
|
*
|
|
* Takes a path in X:\...\system32\.... format and makes it into
|
|
* \SystemRoot\System32\Drivers format so that KernelMode API's can recognize it.
|
|
*
|
|
* This will ensure security by forcing any image being loaded to come from
|
|
* the system32 directory.
|
|
*
|
|
* The AppendDLL flag indicates if the name should get .dll appended at the end
|
|
* (for display drivers coming from USER) if it's not already there.
|
|
*
|
|
\*****************************************************************************/
|
|
|
|
BOOL MakeSystemDriversRelativePath(
|
|
LPWSTR pOriginalPath,
|
|
PUNICODE_STRING pUnicode,
|
|
BOOL bAppendDLL
|
|
)
|
|
{
|
|
LPWSTR pOriginalEnd;
|
|
ULONG OriginalLength = wcslen(pOriginalPath);
|
|
ULONG cbLength = OriginalLength * sizeof(WCHAR) +
|
|
sizeof(L"\\SystemRoot\\System32\\Drivers");
|
|
ULONG tmp;
|
|
|
|
tmp = (sizeof(L".DLL") / sizeof (WCHAR) - 1);
|
|
|
|
//
|
|
// Given append = TRUE, we check if we really need to append.
|
|
// (printer drivers with .dll come through LDEVREF which specifies TRUE)
|
|
//
|
|
|
|
if (bAppendDLL)
|
|
{
|
|
if ((OriginalLength >= tmp) &&
|
|
(!_wcsnicmp(pOriginalPath + OriginalLength - tmp,
|
|
L".DLL",
|
|
tmp)))
|
|
{
|
|
bAppendDLL = FALSE;
|
|
}
|
|
else
|
|
{
|
|
cbLength += tmp * sizeof(WCHAR);
|
|
}
|
|
}
|
|
|
|
pUnicode->Length = 0;
|
|
pUnicode->MaximumLength = (USHORT) cbLength;
|
|
|
|
if (pUnicode->Buffer = PALLOCNOZ(cbLength, 'liFG'))
|
|
{
|
|
//
|
|
// First parse the input string for \System32\Drivers. We parse from the end
|
|
// of the string because some weirdo could have \System32\Nt\System32
|
|
// as his/her root directory and this would throw us off if we scanned
|
|
// from the front.
|
|
//
|
|
// It should only (and always) be printer drivers that pass down
|
|
// fully qualified path names.
|
|
//
|
|
|
|
tmp = (sizeof(L"\\system32\\Drivers") / sizeof(WCHAR) - 1);
|
|
|
|
|
|
for (pOriginalEnd = pOriginalPath + OriginalLength - tmp;
|
|
pOriginalEnd >= pOriginalPath;
|
|
pOriginalEnd --)
|
|
{
|
|
if (!_wcsnicmp(pOriginalEnd ,
|
|
L"\\system32\\Drivers",
|
|
tmp))
|
|
{
|
|
//
|
|
// We found the system32 in the string.
|
|
// Lets update the location of the string.
|
|
//
|
|
|
|
pOriginalPath = pOriginalEnd + tmp;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now put \SystemRoot\System32\Drivers\ at the front of the name and append
|
|
// the rest at the end
|
|
//
|
|
|
|
RtlAppendUnicodeToString(pUnicode, L"\\SystemRoot\\System32\\Drivers\\");
|
|
RtlAppendUnicodeToString(pUnicode, pOriginalPath);
|
|
|
|
if (bAppendDLL)
|
|
{
|
|
RtlAppendUnicodeToString(pUnicode, L".dll");
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
return (FALSE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* Routine Name:
|
|
*
|
|
* EngGetFilePath
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL EngGetFilePath(HANDLE h, WCHAR (*pDest)[MAX_PATH+1])
|
|
{
|
|
wchar_t *pSrc = ((PFONTFILEVIEW) h)->pwszPath;
|
|
|
|
if ( pSrc )
|
|
{
|
|
wcscpy((wchar_t*) pDest, pSrc );
|
|
}
|
|
return( pSrc != 0 );
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* Routine Name:
|
|
*
|
|
* EngGetFileChangeTime
|
|
*
|
|
* Routine Description:
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Called by:
|
|
*
|
|
* Return Value:
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL EngGetFileChangeTime(
|
|
HANDLE h,
|
|
LARGE_INTEGER *pChangeTime)
|
|
{
|
|
|
|
UNICODE_STRING unicodeString;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
HANDLE fileHandle = NULL;
|
|
BOOL bResult = FALSE;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
FILE_BASIC_INFORMATION fileBasicInfo;
|
|
PVOID sectionObject = NULL;
|
|
PFONTFILEVIEW pffv = (PFONTFILEVIEW) h;
|
|
ULONG viewSize;
|
|
|
|
if(pffv->pwszPath)
|
|
{
|
|
if (pffv->fv.bLastUpdated)
|
|
{
|
|
*pChangeTime = pffv->fv.LastWriteTime;
|
|
bResult = TRUE;
|
|
}
|
|
else
|
|
{
|
|
RtlInitUnicodeString(&unicodeString,
|
|
pffv->pwszPath
|
|
);
|
|
|
|
|
|
InitializeObjectAttributes(&objectAttributes,
|
|
&unicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
(HANDLE) NULL,
|
|
(PSECURITY_DESCRIPTOR) NULL);
|
|
|
|
ntStatus = ZwCreateFile(&fileHandle,
|
|
FILE_READ_ATTRIBUTES,
|
|
&objectAttributes,
|
|
&ioStatusBlock,
|
|
0,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
0,
|
|
FILE_OPEN_IF,
|
|
FILE_SYNCHRONOUS_IO_ALERT,
|
|
0,
|
|
0);
|
|
|
|
|
|
if(NT_SUCCESS(ntStatus))
|
|
{
|
|
ntStatus = ZwQueryInformationFile(fileHandle,
|
|
&ioStatusBlock,
|
|
&fileBasicInfo,
|
|
sizeof(FILE_BASIC_INFORMATION),
|
|
FileBasicInformation);
|
|
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
*pChangeTime = fileBasicInfo.LastWriteTime;
|
|
bResult = TRUE;
|
|
}
|
|
else
|
|
{
|
|
WARNING("EngGetFileTime:QueryInformationFile failed\n");
|
|
}
|
|
|
|
ZwClose(fileHandle);
|
|
|
|
}
|
|
else
|
|
{
|
|
WARNING("EngGetFileTime:Create/Open file failed\n");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// This is a remote font. In order for ATM to work we must always return
|
|
// the same time for a remote font. One way to do this is to return a zero
|
|
// time for all remote fonts.
|
|
|
|
pChangeTime->HighPart = pChangeTime->LowPart = 0;
|
|
bResult = TRUE;
|
|
}
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* EngFindResource
|
|
*
|
|
* This function returns a size and ptr to a resource in a module.
|
|
*
|
|
* History:
|
|
* 4/24/1995 by Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
*******************************************************************************/
|
|
|
|
PVOID pvFindResource(
|
|
PVOID pView,
|
|
PVOID pViewEnd,
|
|
int iName,
|
|
int iType,
|
|
PULONG pulSize)
|
|
{
|
|
NTSTATUS Status;
|
|
PVOID p,pRet;
|
|
ULONG_PTR IdPath[ 3 ];
|
|
|
|
IdPath[0] = (ULONG_PTR) iType;
|
|
IdPath[1] = (ULONG_PTR) iName;
|
|
IdPath[2] = (ULONG_PTR) 0;
|
|
|
|
// add one to pvView to let LdrFindResource know that this has been mapped as a
|
|
// datafile
|
|
|
|
Status = LdrFindResource_U( pView,
|
|
IdPath,
|
|
3,
|
|
(PIMAGE_RESOURCE_DATA_ENTRY *)&p
|
|
);
|
|
|
|
if( !NT_SUCCESS( Status ) )
|
|
{
|
|
|
|
WARNING("EngFindResource: LdrFindResource_U failed.\n");
|
|
return(NULL);
|
|
}
|
|
|
|
pRet = NULL;
|
|
|
|
Status = LdrAccessResource( pView,
|
|
(PIMAGE_RESOURCE_DATA_ENTRY) p,
|
|
&pRet,
|
|
pulSize );
|
|
|
|
if( !NT_SUCCESS( Status ) )
|
|
{
|
|
WARNING("EngFindResource: LdrAccessResource failed.\n" );
|
|
}
|
|
|
|
return( pRet < pViewEnd ? pRet : NULL );
|
|
|
|
}
|
|
|
|
PVOID EngFindResourcePlainOrFD(
|
|
PVOID pvViewBase,
|
|
HANDLE h,
|
|
int iName,
|
|
int iType,
|
|
PULONG pulSize
|
|
)
|
|
{
|
|
PVOID pView,pViewEnd;
|
|
|
|
pView = (PVOID) (((ULONG_PTR) pvViewBase)+1);
|
|
pViewEnd = (PVOID) ((PBYTE)pvViewBase + ((PFILEVIEW) h)->cjView);
|
|
|
|
return pvFindResource(pView, pViewEnd, iName, iType, pulSize);
|
|
}
|
|
|
|
PVOID EngFindResource(
|
|
HANDLE h,
|
|
int iName,
|
|
int iType,
|
|
PULONG pulSize)
|
|
{
|
|
return EngFindResourcePlainOrFD(((PFILEVIEW) h)->pvKView, h, iName, iType, pulSize);
|
|
}
|
|
|
|
PVOID EngFindResourceFD(
|
|
HANDLE h,
|
|
int iName,
|
|
int iType,
|
|
PULONG pulSize)
|
|
{
|
|
return EngFindResourcePlainOrFD(((PFILEVIEW) h)->pvViewFD, h, iName, iType, pulSize);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* VOID vCheckCharSet(USHORT * pusCharSet)
|
|
*
|
|
*
|
|
* Effects: validate charset in font sub section of the registry
|
|
*
|
|
* History:
|
|
* 27-Jun-1995 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vCheckCharSet(FACE_CHARSET *pfcs, const WCHAR * pwsz)
|
|
{
|
|
UINT i;
|
|
UNICODE_STRING String;
|
|
ULONG ulCharSet = DEFAULT_CHARSET;
|
|
|
|
pfcs->jCharSet = DEFAULT_CHARSET;
|
|
pfcs->fjFlags = 0;
|
|
|
|
String.Buffer = (WCHAR*)pwsz;
|
|
String.MaximumLength = String.Length = wcslen(pwsz) * sizeof(WCHAR);
|
|
|
|
// read the value and compare it against the allowed set of values, if
|
|
// not found to be correct return default
|
|
|
|
if (RtlUnicodeStringToInteger(&String, 10, &ulCharSet) == STATUS_SUCCESS)
|
|
{
|
|
if (ulCharSet <= 255)
|
|
{
|
|
pfcs->jCharSet = (BYTE)ulCharSet;
|
|
|
|
for (i = 0; i < nCharsets; i++)
|
|
{
|
|
if (ulCharSet == charsets[i])
|
|
{
|
|
// both jCharSet and fjFlags are set correctly, can exit
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If somebody entered the garbage in the Font Substitution section of "win.ini"
|
|
// we will mark this as a "garbage charset" by setting the upper byte in the
|
|
// usCharSet field. I believe that it is Ok to have garbage charset in the
|
|
// value name, that is on the left hand side of the substitution entry.
|
|
// This may be whatever garbage the application is passing to the
|
|
// system. But the value on the right hand side, that is in value data, has to
|
|
// be meaningfull, for we need to know which code page translation table
|
|
// we should use with this font.
|
|
|
|
pfcs->fjFlags |= FJ_GARBAGECHARSET;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* EngComputeGlyphSet
|
|
*
|
|
\**************************************************************************/
|
|
|
|
FD_GLYPHSET *EngComputeGlyphSet(
|
|
INT nCodePage,
|
|
INT nFirstChar,
|
|
INT cChars
|
|
)
|
|
{
|
|
BYTE *cbuf;
|
|
INT cRuns;
|
|
ULONG ByteCount;
|
|
WCHAR *wcbuf;
|
|
FD_GLYPHSET *pGlyphSet = 0;
|
|
|
|
if ( 0 <= cChars && cChars < 65536 )
|
|
{
|
|
wcbuf = (WCHAR *) PALLOCMEM(cChars * (sizeof(WCHAR) + sizeof(BYTE)),'slgG');
|
|
if ( wcbuf )
|
|
{
|
|
cbuf = (BYTE *) &wcbuf[cChars];
|
|
|
|
cRuns = cUnicodeRangesSupported(
|
|
nCodePage,
|
|
nFirstChar,
|
|
cChars,
|
|
wcbuf,
|
|
cbuf);
|
|
|
|
ByteCount = SZ_GLYPHSET(cRuns, cChars);
|
|
|
|
// Allocate via EngAllocMem instead of PALLOCMEM because driver
|
|
// will free via EngAllocFree.
|
|
|
|
pGlyphSet = (FD_GLYPHSET*) EngAllocMem(0, ByteCount,'slgG');
|
|
|
|
if ( pGlyphSet )
|
|
{
|
|
cComputeGlyphSet(
|
|
wcbuf,
|
|
cbuf,
|
|
cChars,
|
|
cRuns,
|
|
pGlyphSet
|
|
);
|
|
}
|
|
VFREEMEM( wcbuf );
|
|
}
|
|
}
|
|
|
|
return( pGlyphSet );
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* Routine Name:
|
|
*
|
|
* vMoveFD_GLYPHSET
|
|
*
|
|
* Routine Description:
|
|
*
|
|
* Copies an FD_GLYPHSET from one location to another. The pointers
|
|
* in the destination are fixed up.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pgsDst pointer to destination FD_GLYPHSET
|
|
*
|
|
* pgsSrc pointer to source FD_GLYPHSET
|
|
*
|
|
* Called by:
|
|
*
|
|
* bComputeGlyphSet
|
|
*
|
|
* Return Value:
|
|
*
|
|
* none
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void vMoveFD_GLYPHSET(FD_GLYPHSET *pgsDst, FD_GLYPHSET *pgsSrc)
|
|
{
|
|
char *pSrc, *pSrcLast, *pDst;
|
|
ULONG_PTR dp;
|
|
|
|
//
|
|
// move the structure
|
|
//
|
|
|
|
RtlCopyMemory(pgsDst, pgsSrc, pgsSrc->cjThis);
|
|
|
|
//
|
|
// if necessary, fix up the pointers
|
|
//
|
|
|
|
if (!(pgsSrc->flAccel & GS_UNICODE_HANDLES ))
|
|
{
|
|
pSrc = (char*) &pgsSrc->awcrun[0].phg;
|
|
pDst = (char*) &pgsDst->awcrun[0].phg;
|
|
pSrcLast = pSrc + sizeof(WCRUN) * pgsSrc->cRuns;
|
|
dp = pDst - pSrc;
|
|
for ( ; pSrc < pSrcLast; pSrc += sizeof(WCRUN), pDst += sizeof(WCRUN))
|
|
{
|
|
*(char**)pDst = *(char**)pSrc + dp;
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* Routine Name:
|
|
*
|
|
* bComputeGlyphSet
|
|
*
|
|
* Routine Description:
|
|
*
|
|
* This procedure provides safe access to GreComputeGlyphSet from user
|
|
* mode. All addresses supplied by the caller, except for pCall, are
|
|
* probed and access is surrounded by try/except pairs.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pCall a pointer to a GDICALL structure in kernel mode. This is
|
|
* a copy of the user mode structure passed to NtGdiCall.
|
|
*
|
|
* Called by:
|
|
*
|
|
* NtGdiCall
|
|
*
|
|
* Return Value:
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bComputeGlyphSet(GDICALL *pCall)
|
|
{
|
|
extern VOID vMoveFD_GLYPHSET( FD_GLYPHSET *pDst, FD_GLYPHSET *pSrc);
|
|
static FD_GLYPHSET *pGlyphSet;
|
|
|
|
ASSERTGDI(pCall->Id == ComputeGlyphSet_,"pCall->Id == ComputeGlyphSet_\n");
|
|
|
|
pCall->ComputeGlyphSetArgs.ReturnValue = FALSE;
|
|
|
|
if ( pCall->ComputeGlyphSetArgs.ppGlyphSet == 0 )
|
|
{
|
|
if ( pCall->ComputeGlyphSetArgs.ByteCount == 0 )
|
|
{
|
|
if ( pGlyphSet == 0 )
|
|
{
|
|
pGlyphSet =
|
|
EngComputeGlyphSet(
|
|
pCall->ComputeGlyphSetArgs.nCodePage,
|
|
pCall->ComputeGlyphSetArgs.nFirstChar,
|
|
pCall->ComputeGlyphSetArgs.cChars
|
|
);
|
|
if ( pGlyphSet )
|
|
{
|
|
pCall->ComputeGlyphSetArgs.ppGlyphSet = &pGlyphSet;
|
|
pCall->ComputeGlyphSetArgs.ByteCount = pGlyphSet->cjThis;
|
|
pCall->ComputeGlyphSetArgs.ReturnValue = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
VFREEMEM( pGlyphSet );
|
|
pGlyphSet = 0;
|
|
}
|
|
}
|
|
}
|
|
else if (pCall->ComputeGlyphSetArgs.ppGlyphSet == &pGlyphSet && pGlyphSet != 0)
|
|
{
|
|
pCall->ComputeGlyphSetArgs.ReturnValue = TRUE;
|
|
try
|
|
{
|
|
ProbeForWrite(
|
|
pCall->ComputeGlyphSetArgs.pGlyphSet
|
|
, pGlyphSet->cjThis
|
|
, 8
|
|
);
|
|
vMoveFD_GLYPHSET(
|
|
pCall->ComputeGlyphSetArgs.pGlyphSet
|
|
, pGlyphSet
|
|
);
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
pCall->ComputeGlyphSetArgs.ReturnValue = FALSE;
|
|
}
|
|
VFREEMEM( pGlyphSet );
|
|
pGlyphSet = 0;
|
|
}
|
|
|
|
return( pCall->ComputeGlyphSetArgs.ReturnValue );
|
|
}
|
|
|
|
|
|
#define NLS_TABLE_KEY \
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Nls\\CodePage"
|
|
|
|
BOOL GetNlsTablePath(
|
|
UINT CodePage,
|
|
PWCHAR PathBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine takes a code page identifier, queries the registry to find the
|
|
appropriate NLS table for that code page, and then returns a path to the
|
|
table.
|
|
|
|
Arguments;
|
|
|
|
CodePage - specifies the code page to look for
|
|
|
|
PathBuffer - Specifies a buffer into which to copy the path of the NLS
|
|
file. This routine assumes that the size is at least MAX_PATH
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise.
|
|
|
|
Gerrit van Wingerden [gerritv] 1/22/96
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
BOOL Result = FALSE;
|
|
HANDLE RegistryKeyHandle;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING UnicodeString;
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
|
|
|
|
RtlInitUnicodeString(&UnicodeString, NLS_TABLE_KEY);
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
NtStatus = ZwOpenKey(&RegistryKeyHandle, GENERIC_READ, &ObjectAttributes);
|
|
|
|
if(NT_SUCCESS(NtStatus))
|
|
{
|
|
WCHAR *ResultBuffer;
|
|
ULONG BufferSize = sizeof(WCHAR) * MAX_PATH +
|
|
sizeof(KEY_VALUE_FULL_INFORMATION);
|
|
|
|
ResultBuffer = PALLOCMEM(BufferSize,'slnG');
|
|
|
|
if(ResultBuffer)
|
|
{
|
|
ULONG ValueReturnedLength;
|
|
WCHAR CodePageStringBuffer[20];
|
|
swprintf(CodePageStringBuffer, L"%d", CodePage);
|
|
|
|
RtlInitUnicodeString(&UnicodeString,CodePageStringBuffer);
|
|
|
|
KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION) ResultBuffer;
|
|
|
|
NtStatus = ZwQueryValueKey(RegistryKeyHandle,
|
|
&UnicodeString,
|
|
KeyValuePartialInformation,
|
|
KeyValueInformation,
|
|
BufferSize,
|
|
&BufferSize);
|
|
|
|
if(NT_SUCCESS(NtStatus))
|
|
{
|
|
|
|
swprintf(PathBuffer,L"\\SystemRoot\\System32\\%ws",
|
|
(WCHAR *)&(KeyValueInformation->Data[0]));
|
|
Result = TRUE;
|
|
}
|
|
else
|
|
{
|
|
WARNING("GetNlsTablePath failed to get NLS table\n");
|
|
}
|
|
VFREEMEM(ResultBuffer);
|
|
}
|
|
else
|
|
{
|
|
WARNING("GetNlsTablePath out of memory\n");
|
|
}
|
|
|
|
ZwCloseKey(RegistryKeyHandle);
|
|
}
|
|
else
|
|
{
|
|
WARNING("GetNlsTablePath failed to open NLS key\n");
|
|
}
|
|
|
|
return(Result);
|
|
}
|
|
|
|
|
|
INT ConvertToAndFromWideCharSymCP(
|
|
IN LPWSTR WideCharString,
|
|
IN INT BytesInWideCharString,
|
|
IN LPSTR MultiByteString,
|
|
IN INT BytesInMultiByteString,
|
|
IN BOOL ConvertToWideChar
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine converts a SB character string to or from a wide char string
|
|
assuming the CP_SYMBOL code page. We simply using the following rules to map
|
|
the single byte char to Unicode:
|
|
0x00->0x1f map to 0x0000->0x001f
|
|
0x20->0xff map to 0xf020->0xf0ff
|
|
|
|
Return Value:
|
|
|
|
Success - The number of bytes in the converted WideCharString
|
|
Failure - -1
|
|
|
|
Tessiew [Xudong Wu] Sept/25/97
|
|
|
|
-- */
|
|
{
|
|
INT cSB, cMaxSB, cWC, cMaxWC;
|
|
|
|
if ((BytesInWideCharString && (WideCharString == NULL)) ||
|
|
(BytesInMultiByteString && (MultiByteString == NULL)))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (ConvertToWideChar)
|
|
{
|
|
cMaxSB = MIN(BytesInMultiByteString, BytesInWideCharString / (INT)sizeof(WCHAR));
|
|
|
|
for (cSB = 0; cSB < cMaxSB; cSB++)
|
|
{
|
|
WideCharString[cSB] = ((BYTE)MultiByteString[cSB] < 0x20) ?
|
|
(WCHAR)MultiByteString[cSB] :
|
|
(WCHAR)((BYTE)MultiByteString[cSB] | ((WCHAR)(0xf0) << 8));
|
|
}
|
|
return (cMaxSB * sizeof(WCHAR));
|
|
}
|
|
else
|
|
{
|
|
cMaxWC = MIN(BytesInWideCharString / (INT)sizeof(WCHAR), BytesInMultiByteString);
|
|
|
|
for (cWC = 0; cWC < cMaxWC; cWC++)
|
|
{
|
|
// there is some error wchar in the string
|
|
// but we still return however many we finished
|
|
|
|
if ((WideCharString[cWC] >= 0x0020) &&
|
|
((WideCharString[cWC] < 0xf020) ||
|
|
(WideCharString[cWC] > 0xf0ff)))
|
|
{
|
|
return (cWC);
|
|
}
|
|
|
|
MultiByteString[cWC] = (BYTE)WideCharString[cWC];
|
|
}
|
|
|
|
return (cMaxWC);
|
|
}
|
|
}
|
|
|
|
|
|
INT ConvertToAndFromWideChar(
|
|
IN UINT CodePage,
|
|
IN LPWSTR WideCharString,
|
|
IN INT BytesInWideCharString,
|
|
IN LPSTR MultiByteString,
|
|
IN INT BytesInMultiByteString,
|
|
IN BOOL ConvertToWideChar
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine converts a character string to or from a wide char string
|
|
assuming a specified code page. Most of the actual work is done inside
|
|
RtlCustomCPToUnicodeN, but this routine still needs to manage the loading
|
|
of the NLS files before passing them to the RtlRoutine. We will cache
|
|
the mapped NLS file for the most recently used code page which ought to
|
|
suffice for out purposes.
|
|
|
|
Arguments:
|
|
CodePage - the code page to use for doing the translation.
|
|
|
|
WideCharString - buffer the string is to be translated into.
|
|
|
|
BytesInWideCharString - number of bytes in the WideCharString buffer
|
|
if converting to wide char and the buffer isn't large enough then the
|
|
string in truncated and no error results.
|
|
|
|
MultiByteString - the multibyte string to be translated to Unicode.
|
|
|
|
BytesInMultiByteString - number of bytes in the multibyte string if
|
|
converting to multibyte and the buffer isn't large enough the string
|
|
is truncated and no error results
|
|
|
|
ConvertToWideChar - if TRUE then convert from multibyte to widechar
|
|
otherwise convert from wide char to multibyte
|
|
|
|
Return Value:
|
|
|
|
Success - The number of bytes in the converted WideCharString
|
|
Failure - -1
|
|
|
|
Gerrit van Wingerden [gerritv] 1/22/96
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
USHORT OemCodePage, AnsiCodePage;
|
|
CPTABLEINFO LocalTableInfo;
|
|
PCPTABLEINFO TableInfo = NULL;
|
|
PVOID LocalTableBase = NULL;
|
|
INT BytesConverted = 0;
|
|
|
|
ASSERTGDI(CodePage != 0, "EngMultiByteToWideChar invalid code page\n");
|
|
|
|
RtlGetDefaultCodePage(&AnsiCodePage,&OemCodePage);
|
|
|
|
// see if we can use the default translation routinte
|
|
|
|
if(AnsiCodePage == CodePage)
|
|
{
|
|
if(ConvertToWideChar)
|
|
{
|
|
NtStatus = RtlMultiByteToUnicodeN(WideCharString,
|
|
BytesInWideCharString,
|
|
&BytesConverted,
|
|
MultiByteString,
|
|
BytesInMultiByteString);
|
|
}
|
|
else
|
|
{
|
|
NtStatus = RtlUnicodeToMultiByteN(MultiByteString,
|
|
BytesInMultiByteString,
|
|
&BytesConverted,
|
|
WideCharString,
|
|
BytesInWideCharString);
|
|
}
|
|
|
|
|
|
if(NT_SUCCESS(NtStatus))
|
|
{
|
|
return(BytesConverted);
|
|
}
|
|
else
|
|
{
|
|
return(-1);
|
|
}
|
|
}
|
|
|
|
if (CodePage == CP_SYMBOL)
|
|
{
|
|
return (ConvertToAndFromWideCharSymCP(WideCharString, BytesInWideCharString,
|
|
MultiByteString, BytesInMultiByteString, ConvertToWideChar));
|
|
}
|
|
|
|
TRACE_FONT(("GreAcquireFastMutex(ghfmMemory) 006\n")); GreAcquireFastMutex(ghfmMemory);
|
|
|
|
if(CodePage == LastCodePageTranslated)
|
|
{
|
|
// we can use the cached code page information
|
|
TableInfo = &LastCPTableInfo;
|
|
NlsTableUseCount += 1;
|
|
}
|
|
|
|
GreReleaseFastMutex(ghfmMemory); TRACE_FONT(("GreReleaseFastMutex(ghfmMemory) 006\n"));
|
|
|
|
if(TableInfo == NULL)
|
|
{
|
|
// get a pointer to the path of the NLS table
|
|
|
|
WCHAR NlsTablePath[MAX_PATH];
|
|
|
|
if(GetNlsTablePath(CodePage,NlsTablePath))
|
|
{
|
|
UNICODE_STRING UnicodeString;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
HANDLE NtFileHandle;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
RtlInitUnicodeString(&UnicodeString,NlsTablePath);
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
NULL,
|
|
NULL);
|
|
|
|
NtStatus = ZwCreateFile(&NtFileHandle,
|
|
SYNCHRONIZE | FILE_READ_DATA,
|
|
&ObjectAttributes,
|
|
&IoStatus,
|
|
NULL,
|
|
0,
|
|
FILE_SHARE_READ,
|
|
FILE_OPEN,
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
0);
|
|
|
|
if(NT_SUCCESS(NtStatus))
|
|
{
|
|
FILE_STANDARD_INFORMATION StandardInfo;
|
|
|
|
// Query the object to determine its length.
|
|
|
|
NtStatus = ZwQueryInformationFile(NtFileHandle,
|
|
&IoStatus,
|
|
&StandardInfo,
|
|
sizeof(FILE_STANDARD_INFORMATION),
|
|
FileStandardInformation);
|
|
|
|
if(NT_SUCCESS(NtStatus) && StandardInfo.EndOfFile.LowPart)
|
|
{
|
|
UINT LengthOfFile = StandardInfo.EndOfFile.LowPart;
|
|
|
|
LocalTableBase = PALLOCMEM(LengthOfFile,'cwcG');
|
|
|
|
if(LocalTableBase)
|
|
{
|
|
// Read the file into our buffer.
|
|
|
|
NtStatus = ZwReadFile(NtFileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
LocalTableBase,
|
|
LengthOfFile,
|
|
NULL,
|
|
NULL);
|
|
|
|
if(!NT_SUCCESS(NtStatus))
|
|
{
|
|
WARNING("EngMultiByteToWideChar unable to read file\n");
|
|
VFREEMEM(LocalTableBase);
|
|
LocalTableBase = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("EngMultiByteToWideChar out of memory\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("EngMultiByteToWideChar unable query NLS file\n");
|
|
}
|
|
|
|
ZwClose(NtFileHandle);
|
|
}
|
|
else
|
|
{
|
|
WARNING("EngMultiByteToWideChar unable to open NLS file\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("EngMultiByteToWideChar get registry entry for NLS file failed\n");
|
|
}
|
|
|
|
if(LocalTableBase == NULL)
|
|
{
|
|
return(-1);
|
|
}
|
|
|
|
// now that we've got the table use it to initialize the CodePage table
|
|
|
|
RtlInitCodePageTable(LocalTableBase,&LocalTableInfo);
|
|
TableInfo = &LocalTableInfo;
|
|
}
|
|
|
|
// Once we are here TableInfo points to the the CPTABLEINFO struct we want
|
|
|
|
|
|
if(ConvertToWideChar)
|
|
{
|
|
NtStatus = RtlCustomCPToUnicodeN(TableInfo,
|
|
WideCharString,
|
|
BytesInWideCharString,
|
|
&BytesConverted,
|
|
MultiByteString,
|
|
BytesInMultiByteString);
|
|
}
|
|
else
|
|
{
|
|
NtStatus = RtlUnicodeToCustomCPN(TableInfo,
|
|
MultiByteString,
|
|
BytesInMultiByteString,
|
|
&BytesConverted,
|
|
WideCharString,
|
|
BytesInWideCharString);
|
|
}
|
|
|
|
|
|
if(!NT_SUCCESS(NtStatus))
|
|
{
|
|
// signal failure
|
|
|
|
BytesConverted = -1;
|
|
}
|
|
|
|
|
|
// see if we need to update the cached CPTABLEINFO information
|
|
|
|
if(TableInfo != &LocalTableInfo)
|
|
{
|
|
// we must have used the cached CPTABLEINFO data for the conversion
|
|
// simple decrement the reference count
|
|
|
|
TRACE_FONT(("GreAcquireFastMutex(ghfmMemory) 007\n")); GreAcquireFastMutex(ghfmMemory);
|
|
NlsTableUseCount -= 1;
|
|
GreReleaseFastMutex(ghfmMemory); TRACE_FONT(("GreReleaseFastMutex(ghfmMemory) 007\n"));
|
|
}
|
|
else
|
|
{
|
|
PVOID FreeTable;
|
|
|
|
// we must have just allocated a new CPTABLE structure so cache it
|
|
// unless another thread is using current cached entry
|
|
|
|
TRACE_FONT(("GreAcquireFastMutex(ghfmMemory) 008\n")); GreAcquireFastMutex(ghfmMemory);
|
|
if(!NlsTableUseCount)
|
|
{
|
|
LastCodePageTranslated = CodePage;
|
|
RtlMoveMemory(&LastCPTableInfo, TableInfo, sizeof(CPTABLEINFO));
|
|
FreeTable = LastNlsTableBuffer;
|
|
LastNlsTableBuffer = LocalTableBase;
|
|
}
|
|
else
|
|
{
|
|
FreeTable = LocalTableBase;
|
|
}
|
|
GreReleaseFastMutex(ghfmMemory); TRACE_FONT(("GreReleaseFastMutex(ghfmMemory) 008\n"));
|
|
|
|
// Now free the memory for either the old table or the one we allocated
|
|
// depending on whether we update the cache. Note that if this is
|
|
// the first time we are adding a cached value to the local table, then
|
|
// FreeTable will be NULL since LastNlsTableBuffer will be NULL
|
|
|
|
if(FreeTable)
|
|
{
|
|
VFREEMEM(FreeTable);
|
|
}
|
|
}
|
|
|
|
// we are done
|
|
|
|
return(BytesConverted);
|
|
}
|
|
|
|
VOID EngGetCurrentCodePage(
|
|
PUSHORT OemCodePage,
|
|
PUSHORT AnsiCodePage
|
|
)
|
|
{
|
|
RtlGetDefaultCodePage(AnsiCodePage,OemCodePage);
|
|
}
|
|
|
|
INT EngMultiByteToWideChar(
|
|
UINT CodePage,
|
|
LPWSTR WideCharString,
|
|
INT BytesInWideCharString,
|
|
LPSTR MultiByteString,
|
|
INT BytesInMultiByteString
|
|
)
|
|
{
|
|
return(ConvertToAndFromWideChar(CodePage,
|
|
WideCharString,
|
|
BytesInWideCharString,
|
|
MultiByteString,
|
|
BytesInMultiByteString,
|
|
TRUE));
|
|
}
|
|
|
|
INT APIENTRY EngWideCharToMultiByte(
|
|
UINT CodePage,
|
|
LPWSTR WideCharString,
|
|
INT BytesInWideCharString,
|
|
LPSTR MultiByteString,
|
|
INT BytesInMultiByteString
|
|
)
|
|
{
|
|
return(ConvertToAndFromWideChar(CodePage,
|
|
WideCharString,
|
|
BytesInWideCharString,
|
|
MultiByteString,
|
|
BytesInMultiByteString,
|
|
FALSE));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL EngDeleteFile
|
|
*
|
|
* Delete a file.
|
|
*
|
|
* Parameters
|
|
* IN pwszFileName - Name of the file to be deleted
|
|
*
|
|
* Return Value
|
|
* TRUE - sucess
|
|
* FALSE - fail
|
|
*
|
|
* History:
|
|
* 4-Nov-1996 -by- Lingyun Wang [LingyunW]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL EngDeleteFile (
|
|
PWSZ pwszFileName
|
|
)
|
|
{
|
|
UNICODE_STRING unicodeString;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
NTSTATUS ntStatus;
|
|
BOOL bRet = TRUE;
|
|
|
|
RtlInitUnicodeString(&unicodeString,
|
|
pwszFileName);
|
|
|
|
InitializeObjectAttributes(&objectAttributes,
|
|
&unicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
(HANDLE) NULL,
|
|
(PSECURITY_DESCRIPTOR) NULL);
|
|
|
|
ntStatus = ZwDeleteFile (&objectAttributes);
|
|
|
|
if (ntStatus != STATUS_SUCCESS)
|
|
{
|
|
WARNING ("EngDeleteFile failed \n");
|
|
bRet = FALSE;
|
|
}
|
|
return (bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL EngQueryFileTimeStamp
|
|
*
|
|
* Query a file timetimep.
|
|
*
|
|
* Parameters
|
|
* IN pwsz - Name of the file
|
|
*
|
|
* Return Value
|
|
* Timestamp
|
|
*
|
|
* History:
|
|
* 22-Nov-1996 -by- Lingyun Wang [LingyunW]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
LARGE_INTEGER EngQueryFileTimeStamp (
|
|
PWSZ pwsz
|
|
)
|
|
{
|
|
HANDLE FileHandle;
|
|
UNICODE_STRING unicodeString;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
NTSTATUS ntStatus;
|
|
LARGE_INTEGER SystemTime, LocalTime;
|
|
FILE_BASIC_INFORMATION File_Info;
|
|
|
|
SystemTime.QuadPart = 0;
|
|
LocalTime.QuadPart = 0;
|
|
|
|
RtlInitUnicodeString(&unicodeString,
|
|
pwsz
|
|
);
|
|
|
|
|
|
InitializeObjectAttributes(&objectAttributes,
|
|
&unicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
(HANDLE) NULL,
|
|
(PSECURITY_DESCRIPTOR) NULL);
|
|
|
|
ntStatus = ZwOpenFile(&FileHandle,
|
|
FILE_GENERIC_READ,
|
|
&objectAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
|
|
FILE_SYNCHRONOUS_IO_ALERT);
|
|
|
|
if(!NT_SUCCESS(ntStatus))
|
|
{
|
|
WARNING("fail to get handle of file file\n");
|
|
}
|
|
|
|
ntStatus = ZwQueryInformationFile (FileHandle,
|
|
&IoStatusBlock,
|
|
&File_Info,
|
|
sizeof(FILE_BASIC_INFORMATION),
|
|
FileBasicInformation
|
|
);
|
|
|
|
if (ntStatus != STATUS_SUCCESS)
|
|
{
|
|
WARNING("failed queryinformationfile\n");
|
|
return (LocalTime);
|
|
}
|
|
|
|
ZwClose (FileHandle);
|
|
|
|
SystemTime = File_Info.LastWriteTime;
|
|
|
|
GreSystemTimeToLocalTime(&SystemTime, &LocalTime);
|
|
|
|
return(LocalTime);
|
|
|
|
}
|