Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

2136 lines
58 KiB

/******************************Module*Header*******************************\
* Module Name: mapfile.c
*
* (Brief description)
*
* Created: 25-Jun-1992 14:33:45
* Author: Bodin Dresevic [BodinD]
*
* Copyright (c) 1990 Microsoft Corporation
\**************************************************************************/
#include "engine.h"
#include "ntnls.h"
#include "stdlib.h"
extern PFAST_MUTEX pgfmMemory;
ULONG LastCodePageTranslated = 0; // I'm assuming 0 is not a valid codepage
PVOID LastNlsTableBuffer = NULL;
CPTABLEINFO LastCPTableInfo;
UINT NlsTableUseCount = 0;
void FreeFileView(PFONTFILEVIEW apfv[], ULONG cFiles)
{
// could be a device font if pFileView is NULL
if ( apfv )
{
FONTFILEVIEW **ppfv; // loop variable
for ( ppfv = apfv; ppfv < apfv + cFiles; ppfv++ )
{
FONTFILEVIEW *pfv = *ppfv;
if ( pfv->ulRegionSize )
{
// This is a remote font so delete the memory for the view
// CAUTION
//
// This code is intimately linked with NtGdiAddRemoteFontToDC
// so any changes here should be synchronized there.
// the pool memory starts with a DOWNLOADHEADER followed
// by the file image pointed to by pvView. We must
// pass the pointer to the beginning of the pool allocation
// to the free routine.
NTSTATUS ntStatus;
COUNT cjHeaderSize = ((offsetof(DOWNLOADFONTHEADER,FileOffsets)+
cFiles * sizeof(ULONG))+7)&~7;
ASSERTGDI(pfv->Pid == W32GetCurrentPID(),
"FreeFileView: wrong process freeing remote font data\n");
pfv->fv.pvView = (PBYTE) pfv->fv.pvView - cjHeaderSize;
MmUnsecureVirtualMemory(pfv->hSecureMem);
ntStatus = ZwFreeVirtualMemory(NtCurrentProcess(),
&(pfv->fv.pvView),
&(pfv->ulRegionSize),
MEM_RELEASE);
if(!NT_SUCCESS(ntStatus))
{
WARNING("FreeFileView: error freeing virtual memory\n");
}
}
}
VFREEMEM( apfv );
}
}
VOID vGetTimeZoneBias(LARGE_INTEGER *pTimeZoneBias)
{
LARGE_INTEGER SystemTime;
SystemTime.QuadPart = 0;
ExSystemTimeToLocalTime(&SystemTime, pTimeZoneBias);
}
/******************************Public*Routine******************************\
* BOOL bMapFileUNICODE
*
* Similar to PosMapFile except that it takes unicode file name
*
* If iFileSize is -1 then the file is module is mapped for read/write. If
* iFileSize is > 0 then the file is extended or truncated to be iFileSize
* bytes in size and is mapped for read/write.
*
* History:
* 21-May-1991 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
BOOL bMapFileUNICODE(PWSTR pwszFileName, FILEVIEW *pfvw,INT iFileSize)
{
UNICODE_STRING unicodeString;
OBJECT_ATTRIBUTES objectAttributes;
NTSTATUS ntStatus = STATUS_SUCCESS;
HANDLE fileHandle = NULL;
IO_STATUS_BLOCK ioStatusBlock;
FILE_STANDARD_INFORMATION fileStandardInfo;
LARGE_INTEGER byteOffset;
PVOID sectionObject = NULL;
ULONG viewSize;
TRACE_FONT((
"bMapFileUNICODE\n"
"\t*pwszFileName = \"%ws\"\n"
"\tFILEVIEW *pfvw = %-#x\n"
, pwszFileName, pfvw
));
//
// If the parameter was a file to be opened, perform the operation
// here. Otherwise just return the data.
//
//
// For the name of the file to be valid, we must first append
// \DosDevices in front of it.
//
RtlInitUnicodeString(&unicodeString,
pwszFileName);
InitializeObjectAttributes(&objectAttributes,
&unicodeString,
OBJ_CASE_INSENSITIVE,
(HANDLE) NULL,
(PSECURITY_DESCRIPTOR) NULL);
if(iFileSize)
{
ntStatus = ZwCreateFile(&fileHandle,
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
&objectAttributes,
&ioStatusBlock,
0,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
FILE_OPEN_IF,
FILE_SYNCHRONOUS_IO_ALERT,
0,
0);
}
else
ntStatus = ZwOpenFile(&fileHandle,
FILE_GENERIC_READ | FILE_GENERIC_EXECUTE | SYNCHRONIZE,
&objectAttributes,
&ioStatusBlock,
FILE_SHARE_READ,
FILE_SYNCHRONOUS_IO_ALERT);
if (!NT_SUCCESS(ntStatus)) {
TRACE_FONT(("bMapFileUNICODE: Could not open file\n"));
goto EndRegistryCallback;
}
ntStatus = ZwQueryInformationFile(fileHandle,
&ioStatusBlock,
&fileStandardInfo,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation);
// Get the time stamp
if ( NT_SUCCESS( ntStatus ))
{
FILE_BASIC_INFORMATION BasicFileInfo;
ntStatus =
ZwQueryInformationFile(
fileHandle,
&ioStatusBlock,
&BasicFileInfo,
sizeof(BasicFileInfo),
FileBasicInformation);
if ( NT_SUCCESS( ntStatus ))
{
pfvw->LastWriteTime = BasicFileInfo.LastWriteTime;
vGetTimeZoneBias(&pfvw->TimeZoneBias);
}
}
// Note that we must call ZwSetInformation even in the case where iFileSize
// is -1. By doing so we force the file time to change. It turns out that
// just mapping a file for write (and writing to the section) is not enough
// to cause the file time to change.
if((NT_SUCCESS(ntStatus)) && iFileSize)
{
LARGE_INTEGER desiredSize;
desiredSize.LowPart = iFileSize > 0 ? (ULONG) iFileSize :
fileStandardInfo.EndOfFile.LowPart;
desiredSize.HighPart = 0;
// set the file length to the requested size
ntStatus = ZwSetInformationFile(fileHandle,
&ioStatusBlock,
&desiredSize,
sizeof(desiredSize),
FileEndOfFileInformation);
// set fileStandardInfo and fall through to the case where we called
// ZwQueryInfo to get the file size
fileStandardInfo.EndOfFile.LowPart = (ULONG) desiredSize.LowPart;
fileStandardInfo.EndOfFile.HighPart = 0;
}
if (!NT_SUCCESS(ntStatus)) {
TRACE_FONT(("bMapFileUNICODE: Could not get size of file\n"));
goto EndRegistryCallback;
}
if (fileStandardInfo.EndOfFile.HighPart) {
//
// If file is too big, do not try to go further.
//
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto EndRegistryCallback;
}
pfvw->cjView = fileStandardInfo.EndOfFile.LowPart;
ntStatus = MmCreateSection( &sectionObject,
SECTION_ALL_ACCESS,
(POBJECT_ATTRIBUTES) NULL,
&fileStandardInfo.EndOfFile,
(iFileSize) ? PAGE_READWRITE :
PAGE_EXECUTE_READ,
SEC_COMMIT,
fileHandle,
NULL );
if (!NT_SUCCESS(ntStatus)) {
TRACE_FONT(("bMapFileUNICODE: Could not create section\n"));
goto EndRegistryCallback;
}
viewSize = 0; // specifies that the whole view must be mapped
ntStatus = MmMapViewInSystemSpace( sectionObject,
&pfvw->pvView,
&viewSize );
if (!NT_SUCCESS(ntStatus)) {
TRACE_FONT(("bMapFileUNICODE: Could not map view in system space\n"));
goto EndRegistryCallback;
}
TRACE_FONT((
"bMapFileUnicode\n"
"\tpfvw->pvView = %-#x\n"
"\tpfvw->cjView = %-#x\n"
"\treturn(TRUE)\n"
, pfvw->pvView, pfvw->cjView
));
EndRegistryCallback:
if (fileHandle) {
ZwClose(fileHandle);
}
if( sectionObject )
{
ObDereferenceObject( sectionObject );
}
return (NT_SUCCESS(ntStatus));
}
/******************************Public*Routine******************************\
* vUnmapFile
*
* Unmaps file whose view is based at pv
*
* 14-Dec-1990 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
VOID vUnmapFile(PFILEVIEW pfv)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
TRACE_FONT((
"vUnmapFile\n"
"\tFILEVIEW *pfv = %-#x\n"
"\t\tpvView = %-#x\n"
"\t\tcjView = %-#x\n"
, pfv
, pfv->pvView
, pfv->cjView
));
ntStatus = MmUnmapViewInSystemSpace( pfv->pvView );
if( !NT_SUCCESS( ntStatus ) )
{
WARNING("vUnmapFile unable to unmap section\n");
}
pfv->pvView = NULL;
return;
}
/******************************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 the hell out of 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;
INT Result;
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
//
RtlGetDefaultCodePage(&AnsiCodePage,&OemCodePage);
if(IS_ANY_DBCS_CODEPAGE(AnsiCodePage))
{
AnsiCodePage = 1252;
}
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
)
{
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->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
//
BYTE aj[256];
WCHAR awc[256];
INT cNumRuns;
UINT cGlyphs = uiLast - uiFirst + 1;
cNumRuns = cUnicodeRangesSupported(0, uiFirst, cGlyphs, awc,aj);
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;
//
// 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;
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) && (uiCharSet != SYMBOL_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
#ifdef FE_SB
// if CP_ACP is a DBCS code page then we better use 1252 to ensure
// proper rountrip conversion
return( gbDBCSCodePage ? 1252 : CP_ACP);
#else
return CP_ACP; // reasonable default
#endif
}
if (uiCharSet == OEM_CHARSET)
return CP_OEMCP;
if (uiCharSet == SYMBOL_CHARSET)
#ifdef FE_SB
// if CP_ACP is a DBCS code page then we better use 1252 to ensure
// proper rountrip conversion
return( gbDBCSCodePage ? 1252 : CP_ACP);
#else
return CP_ACP;
#endif
}
/******************************Public*Routine******************************\
*
* BOOL EngMapFontFile
*
* This is called by font drivers to return a buffer containing the
* raw bytes for a font file, given a handle passed to DrvLoadFontFile.
* The handle is really a pointer to the PFF for this file.
*
* Warnings:
*
* History:
* 20-Jan-1995 -by- Gerrit van Wingerden
*
\**************************************************************************/
BOOL
EngMapFontFile(
ULONG iFile,
PULONG *ppjBuf,
ULONG *pcjBuf)
{
PFONTFILEVIEW pffv = (PFONTFILEVIEW) iFile;
FILEVIEW fv;
BOOL bMapIt,bRet;
TRACE_FONT((
"EngMapFontFile\n"
" FONTFILEVIEW* = %-#x\n"
" fv.pvView = %-#x\n"
" fv.cjView = %-#x\n"
" *pwszPath = \"%ws\"\n"
" cRefCount = %d\n"
" ppjBuf = %-#x\n"
" pcjBuf = %-#x\n"
, iFile
, ((FONTFILEVIEW*) iFile)->fv.pvView
, ((FONTFILEVIEW*) iFile)->fv.cjView
, ((FONTFILEVIEW*) iFile)->pwszPath
, ((FONTFILEVIEW*) iFile)->cRefCount
, ppjBuf
, pcjBuf
));
ASSERTGDI(pffv->cRefCount < 100, "cRefCount >= 100\n");
bRet = TRUE;
bMapIt = TRUE;
AcquireFastMutex(pgfmMemory);
if( pffv->fv.pvView )
{
bMapIt = FALSE;
pffv->cRefCount += 1;
}
else if ( !pffv->pwszPath )
{
RIP("fv.pvView==0 && pwszPath==0\n");
}
ReleaseFastMutex(pgfmMemory);
if( bMapIt )
{
if(!bMapFileUNICODE( pffv->pwszPath, &fv, 0 ) )
{
WARNING("EngMapFontFile: error mapping file\n");
bRet = FALSE;
}
else
{
BOOL bKeepIt;
AcquireFastMutex(pgfmMemory);
pffv->cRefCount += 1; // ref count is altered
if( pffv->fv.pvView )
{
// Looks like someone beat us to mapping a view. We'll unmap what
// we've mapped and just increment the count
bKeepIt = FALSE;
}
else
{
bKeepIt = TRUE;
pffv->fv.pvView = fv.pvView; // view ptr is altered
if
(
(pffv->fv.LastWriteTime.QuadPart == 0)
||
((pffv->fv.cjView == fv.cjView) &&
(pffv->fv.TimeZoneBias.QuadPart != fv.TimeZoneBias.QuadPart))
)
{
// This is the first time that this file has been mapped
// OR
// the file has not really changed since it was mapped last time,
// however, because the time zone changed and because of the bug in the
// FAT file system, LastWriteTime is now reported different.
// Record the size and the LastWriteTime of the file and new TimeZoneBias
pffv->fv.cjView = fv.cjView;
pffv->fv.LastWriteTime = fv.LastWriteTime;
pffv->fv.TimeZoneBias = fv.TimeZoneBias;
}
else
if
(
(pffv->fv.LastWriteTime.QuadPart != 0) &&
((pffv->fv.cjView != fv.cjView ) ||
((pffv->fv.TimeZoneBias.QuadPart == fv.TimeZoneBias.QuadPart) &&
(pffv->fv.LastWriteTime.QuadPart != fv.LastWriteTime.QuadPart)))
)
{
// if the size or the time of the last write has changed
// then someone has switched the file or tampered with it
// while we had it unlocked. We will fail the call.
// Suggestion for the future
//
// When we fail to map the file because it had been
// switched like this. We should purge all the
// information associated with the original and
// then load this new file. This could be done
// by adding to the FONTFILEVIEW structure a pointer
// back to the associated PFF. When a call to the
// font driver fails we check to see if it was because
// of this switching problem. We could then deal
// with it by refreshing the font table.
KdPrint(("EngMapFontFile -- \"%ws\" has changed"
", failing request to map file\n", pffv->pwszPath));
pffv->cRefCount -= 1; // Restore FONTFILEVIEW
pffv->fv.pvView = 0; // to original state
bRet = FALSE;
bKeepIt = FALSE;
}
}
ReleaseFastMutex(pgfmMemory);
if( !bKeepIt )
{
vUnmapFile( &fv );
}
}
}
if (bRet)
{
// it's okay to access these without grabbing the MUTEX since we've
// incremented the reference count;
if (ppjBuf)
*ppjBuf = (ULONG*) pffv->fv.pvView;
if (pcjBuf)
*pcjBuf = pffv->fv.cjView;
}
return(bRet);
}
/******************************Public*Routine******************************\
*
* VOID EngUnmapFontFile
*
* This is called by font drivers to unmap a file mapped by a previous
* call to EngMapFontFile.
* Warnings:
*
* History:
* 20-Jan-1995 -by- Gerrit van Wingerden
*
\**************************************************************************/
void EngUnmapFontFile( ULONG iFile )
{
PFONTFILEVIEW pffv = (PFONTFILEVIEW) iFile;
void *pvView = 0;
PWSZ pwszPath = 0;
TRACE_FONT((
"EngUnmapFontFile((FONTFILEVIEW*) %-#x)\n"
" fv.pvView = %-#x\n"
" fv.cjView = %-#x\n"
" *pwszPath = \"%ws\"\n"
" cRefCount = %d\n"
, iFile
, ((FONTFILEVIEW*) iFile)->fv.pvView
, ((FONTFILEVIEW*) iFile)->fv.cjView
, ((FONTFILEVIEW*) iFile)->pwszPath
, ((FONTFILEVIEW*) iFile)->cRefCount
));
ASSERTGDI(
((FONTFILEVIEW*) iFile)->cRefCount < 100
, "unusually high cRefCount\n"
);
if (pffv->cRefCount)
{
AcquireFastMutex(pgfmMemory);
pffv->cRefCount -= 1;
if( pffv->cRefCount == 0 )
{
pvView = pffv->fv.pvView;
pwszPath = pffv->pwszPath;
if(pwszPath)
{
pffv->fv.pvView = NULL;
}
}
ReleaseFastMutex(pgfmMemory);
if( pvView )
{
if ( pwszPath ) // pvView points to Pool Allocated memory?
{
FILEVIEW fv;
fv.pvView = pvView;
vUnmapFile( &fv );
}
else
{
// do nothing this is a remote font
}
}
}
#if DBG
else
{
RIP("EngUnmapFontFile called with zero cRefCount\n");
}
#endif
}
/****************************************************************************
* 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.
*
****************************************************************************/
ULONG
cParseFontResources(
HANDLE hFontFile,
PVOID **ppvResourceBases)
{
PIMAGE_DOS_HEADER pDosHeader;
NTSTATUS Status;
ULONG 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.pvView;
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) ((PFONTFILEVIEW) hFontFile)->fv.pvView)|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 *) PALLOCNOZ(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 = EngFindResource(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);
}
/*******************************************************************************
* EngLoadModuleForWrite
*
* History:
* 4/24/1995 by Gerrit van Wingerden [gerritv]
* Wrote it.
*******************************************************************************/
HANDLE EngLoadModuleForWrite(
PWSZ pwsz,
ULONG cjSizeOfModule)
{
HANDLE hRet = 0;
UNICODE_STRING usPath;
PFILEVIEW pfv;
if (MakeSystemRelativePath(pwsz,&usPath, FALSE))
{
pfv = (PFILEVIEW) PALLOCMEM(sizeof(FILEVIEW), 'lifG');
if (pfv)
{
if (bMapFileUNICODE(usPath.Buffer,
(PFILEVIEW)pfv ,cjSizeOfModule ? cjSizeOfModule : -1))
{
hRet = (HANDLE) pfv;
}
else
{
VFREEMEM(pfv);
WARNING1("EngLoadModule unable to mapfile\n");
}
}
VFREEMEM(usPath.Buffer);
}
return(hRet);
}
LPWSTR EngGetFilePath(
HANDLE h)
{
return(((PFONTFILEVIEW) h)->pwszPath);
}
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)
{
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);
}
/*******************************************************************************
* EngLoadModule
*
* History:
* 4/24/1995 by Gerrit van Wingerden [gerritv]
* Wrote it.
*******************************************************************************/
HANDLE EngLoadModule(
PWSZ pwsz)
{
HANDLE hRet = 0;
UNICODE_STRING usPath;
PFILEVIEW pfv;
if (MakeSystemRelativePath(pwsz,&usPath, FALSE))
{
pfv = (PFILEVIEW) PALLOCMEM(sizeof(FILEVIEW), 'lifG');
if (pfv)
{
if (bMapFileUNICODE(usPath.Buffer, pfv, 0))
{
hRet = (HANDLE) pfv;
}
else
{
VFREEMEM(pfv);
WARNING1("EngLoadModule unable to mapfile\n");
}
}
VFREEMEM(usPath.Buffer);
}
return(hRet);
}
/*******************************************************************************
* 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 EngFindResource(
HANDLE h,
int iName,
int iType,
PULONG pulSize)
{
NTSTATUS Status;
PVOID p,pRet,pView,pViewEnd;
ULONG IdPath[ 3 ];
IdPath[0] = (ULONG) iType;
IdPath[1] = (ULONG) iName;
IdPath[2] = (ULONG) 0;
// add one to pvView to let LdrFindResource know that this has been mapped as a
// datafile
pView = (PVOID) (((ULONG) ((PFILEVIEW) h)->pvView)+1);
pViewEnd = (PVOID) ((PBYTE)((PFILEVIEW) h)->pvView + ((PFILEVIEW) h)->cjView);
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 );
}
/****************************************************************************
* EngFreeModule()
*
* History:
* 4/27/1995 by Gerrit van Wingerden [gerritv]
* Wrote it.
*****************************************************************************/
VOID EngFreeModule(
HANDLE h)
{
if (h)
{
vUnmapFile( (PFILEVIEW) h );
VFREEMEM((PVOID)h);
}
}
/****************************************************************************
* PVOID EngMapModule( HANDLE, PULONG )
*
* History:
* 5/25/1995 by Gerrit van Wingerden [gerritv]
* Wrote it.
*****************************************************************************/
PVOID EngMapModule(
HANDLE h,
PULONG pSize
)
{
*pSize=((PFILEVIEW)h)->cjView;
return(((PFILEVIEW)h)->pvView);
}
/******************************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, WCHAR * pwsz)
{
UINT i;
UNICODE_STRING String;
ULONG ulCharSet = DEFAULT_CHARSET;
pfcs->jCharSet = DEFAULT_CHARSET;
pfcs->fjFlags = 0;
String.Buffer = 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;
}
FD_GLYPHSET *
EngComputeGlyphSet(
INT nCodePage,
INT nFirstChar,
INT cChars
)
/*++
Routine Description:
Compute the glyph set supported on a device
Arguments:
nCodePage Code page supported
nFirstChar Char code of the first ANSI character supported
cChars Number of ANSI characters supported
Return Value:
Pointer to a FD_GLYPHSET structure if successful.
NULL if an error occured.
The caller must call EngFreeMem() to free the memory
after it's done using the FD_GLYPHSET structure.
--*/
{
FD_GLYPHSET *pGlyphSet = NULL;
WCHAR *wcbuf;
BYTE *cbuf;
INT cRuns;
// Allocate temporary buffers
wcbuf = (WCHAR *) PALLOCMEM(cChars * sizeof(WCHAR),'slgG');
cbuf = (BYTE *) PALLOCMEM(cChars,'slgG');
if (wcbuf != NULL && cbuf != NULL) {
// Figure out supported Unicode ranges
cRuns = cUnicodeRangesSupported(
nCodePage,
nFirstChar,
cChars,
wcbuf,
cbuf);
// Allocate memory and fill out the FD_GLYPHSET structure
if ((pGlyphSet = (FD_GLYPHSET *)
PALLOCMEM(SZ_GLYPHSET(cRuns, cChars),'slgG')) != NULL)
{
cComputeGlyphSet(
wcbuf,
cbuf,
cChars,
cRuns,
pGlyphSet);
}
}
// Free up temporary buffers
if (wcbuf != NULL) {
VFREEMEM(wcbuf);
}
if (cbuf != NULL) {
VFREEMEM(cbuf);
}
return pGlyphSet;
}
#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",
&(KeyValueInformation->Data[0]));
Result = TRUE;
}
else
{
WARNING("GetNlsTablePath failed to get NLS table\n");
}
VFREEMEM(ResultBuffer);
}
else
{
WARNING("GetNlsTablePath out of memory\n");
}
ZwClose(RegistryKeyHandle);
}
else
{
WARNING("GetNlsTablePath failed to open NLS key\n");
}
return(Result);
}
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);
}
}
AcquireFastMutex(pgfmMemory);
if(CodePage == LastCodePageTranslated)
{
// we can use the cached code page information
TableInfo = &LastCPTableInfo;
NlsTableUseCount += 1;
}
ReleaseFastMutex(pgfmMemory);
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,
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))
{
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
AcquireFastMutex(pgfmMemory);
NlsTableUseCount -= 1;
ReleaseFastMutex(pgfmMemory);
}
else
{
PVOID FreeTable;
// we must have just allocated a new CPTABLE structure so cache it
// unless another thread is using current cached entry
AcquireFastMutex(pgfmMemory);
if(!NlsTableUseCount)
{
LastCodePageTranslated = CodePage;
RtlMoveMemory(&LastCPTableInfo, TableInfo, sizeof(CPTABLEINFO));
FreeTable = LastNlsTableBuffer;
LastNlsTableBuffer = LocalTableBase;
}
else
{
FreeTable = LocalTableBase;
}
ReleaseFastMutex(pgfmMemory);
// 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));
}