You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
587 lines
16 KiB
587 lines
16 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: fon16.c
|
|
*
|
|
* routines for accessing font resources within *.fon files
|
|
* (win 3.0 16 bit dlls)
|
|
*
|
|
* Created: 08-May-1991 12:55:14
|
|
* Author: Bodin Dresevic [BodinD]
|
|
*
|
|
* Copyright (c) 1990 Microsoft Corporation
|
|
*
|
|
\**************************************************************************/
|
|
|
|
/*
|
|
local Hungarian
|
|
|
|
j byte
|
|
cj count of bytes
|
|
pj pointer to byte
|
|
off offset
|
|
rt resource type
|
|
rn resource name
|
|
dp offset (ptrdiff_t)
|
|
ne new exe, Win16 format, see windows\core\ntgdi\inc\exehdr.h
|
|
*/
|
|
|
|
#include "fd.h"
|
|
#include "exehdr.h"
|
|
|
|
// GETS ushort at (PBYTE)pv + off. both pv and off must be even
|
|
|
|
#define US_GET(pv,off) ( *(UNALIGNED PUSHORT)((PBYTE)(pv) + (off)) )
|
|
|
|
#if DBG
|
|
DWORD g_BreakAboutBadFonts;
|
|
DWORD g_PrintAboutBadFonts = TRUE;
|
|
#endif
|
|
|
|
VOID
|
|
__cdecl
|
|
NotifyBadFont(
|
|
PCSTR Format,
|
|
...
|
|
)
|
|
{
|
|
#if DBG
|
|
if (g_PrintAboutBadFonts
|
|
|| g_BreakAboutBadFonts
|
|
)
|
|
{
|
|
va_list Args;
|
|
|
|
va_start(Args, Format);
|
|
vDbgPrintEx(DPFLTR_SYSTEM_ID, DPFLTR_ERROR_LEVEL, (PSTR)Format, Args);
|
|
va_end(Args);
|
|
}
|
|
if (g_BreakAboutBadFonts)
|
|
{
|
|
DbgBreakPoint();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
BOOL
|
|
bMappedViewStrlen(
|
|
PVOID pvViewBase,
|
|
SIZE_T cjViewSize,
|
|
PVOID pvString,
|
|
OUT PSIZE_T pcjOutLength OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a mapped view and size and starting address, verify that the 8bit string
|
|
starting at the address is nul terminated within the mapped view, optionally
|
|
returning the length of the string.
|
|
|
|
Arguments:
|
|
|
|
pvViewBase -
|
|
cjViewSize -
|
|
pvString -
|
|
pcjOutLength -
|
|
|
|
Return Value:
|
|
|
|
TRUE: the string is nul terminated within the view
|
|
FALSE: the string is not nul terminated within the view
|
|
--*/
|
|
{
|
|
BOOL bSuccess;
|
|
PBYTE pjViewBase;
|
|
PBYTE pjViewEnd;
|
|
PBYTE pjString;
|
|
PBYTE pjStringEnd;
|
|
|
|
bSuccess = FALSE;
|
|
if (pcjOutLength != NULL)
|
|
{
|
|
*pcjOutLength = 0;
|
|
}
|
|
pjViewBase = (PBYTE)pvViewBase;
|
|
pjViewEnd = cjViewSize + pjViewBase;
|
|
pjString = (PBYTE)pvString;
|
|
|
|
if (!(pjString >= pjViewBase && pjString < pjViewEnd))
|
|
{
|
|
goto Exit;
|
|
}
|
|
for (pjStringEnd = pjString ; pjStringEnd != pjViewEnd && *pjStringEnd != 0 ; ++pjStringEnd)
|
|
{
|
|
// nothing
|
|
}
|
|
if (pjStringEnd == pjViewEnd)
|
|
{
|
|
goto Exit;
|
|
}
|
|
if (pcjOutLength != NULL)
|
|
{
|
|
*pcjOutLength = (SIZE_T)(pjStringEnd - pjString);
|
|
}
|
|
bSuccess = TRUE;
|
|
Exit:
|
|
#if DBG
|
|
if (!bSuccess)
|
|
{
|
|
NotifyBadFont(
|
|
"WIN32K: bMappedViewStrlen(%p,0x%Ix,%p) returning false\n",
|
|
pvViewBase,
|
|
cjViewSize,
|
|
pvString
|
|
);
|
|
}
|
|
#endif
|
|
return bSuccess;
|
|
}
|
|
|
|
BOOL
|
|
bMappedViewRangeCheck(
|
|
PVOID ViewBase,
|
|
SIZE_T ViewSize,
|
|
PVOID DataAddress,
|
|
SIZE_T DataSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a mapped view and size, range check a data address and size.
|
|
|
|
Arguments:
|
|
|
|
ViewBase -
|
|
ViewSize -
|
|
DataAddress -
|
|
DataSize -
|
|
|
|
Return Value:
|
|
|
|
TRUE: all of the data is within the view
|
|
FALSE: some of the data is outside the view
|
|
--*/
|
|
{
|
|
ULONG_PTR iViewBegin;
|
|
ULONG_PTR iViewEnd;
|
|
ULONG_PTR iDataBegin;
|
|
ULONG_PTR iDataEnd;
|
|
BOOL fResult;
|
|
|
|
//
|
|
// iDataBegin is a valid address.
|
|
// iDataEnd is one past a valid address.
|
|
// We must not allow iDataBegin == iViewEnd.
|
|
// We must allow iDataEnd == iViewEnd.
|
|
// Therefore, we must not allow iDataBegin == iDataEnd.
|
|
// This can be achieved by not allowing DataSize == 0.
|
|
//
|
|
if (DataSize == 0)
|
|
{
|
|
DataSize = 1;
|
|
}
|
|
|
|
iViewBegin = (ULONG_PTR)ViewBase;
|
|
iViewEnd = iViewBegin + ViewSize;
|
|
iDataBegin = (ULONG_PTR)DataAddress;
|
|
iDataEnd = iDataBegin + DataSize;
|
|
|
|
fResult =
|
|
( iDataBegin >= iViewBegin
|
|
&& iDataBegin < iDataEnd
|
|
&& iDataEnd <= iViewEnd
|
|
&& DataSize <= ViewSize
|
|
);
|
|
|
|
#if DBG
|
|
if (!fResult)
|
|
{
|
|
NotifyBadFont(
|
|
"WIN32K: bMappedViewRangeCheck(%p,0x%Ix,%p,0x%Ix) returning false\n",
|
|
ViewBase,
|
|
ViewSize,
|
|
DataAddress,
|
|
DataSize
|
|
);
|
|
}
|
|
#endif
|
|
|
|
return fResult;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bInitWinResData
|
|
*
|
|
* Initializes the fields of the WINRESDATA structure so as to make it
|
|
* possible for the user to access *.fnt resources within the
|
|
* corresponding *.fon file
|
|
*
|
|
* The function returns True if *.fnt resources found in the *.fon
|
|
* file, otherwise false (if not an *.fon file or if it contains no
|
|
* *.fnt resources
|
|
*
|
|
*
|
|
* History:
|
|
* January 2002 -by- Jay Krell [JayKrell]
|
|
* range check memory mapped i/o
|
|
* 09-May-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bInitWinResData(
|
|
PVOID pvView,
|
|
COUNT cjView,
|
|
PWINRESDATA pwrd
|
|
)
|
|
{
|
|
PBYTE pjNewExe; // ptr to the beginning of the new exe hdr
|
|
PBYTE pjResType; // ptr to the beginning of TYPEINFO struct
|
|
PBYTE pjResName; // ptr to the beginning of NAMEINFO struct
|
|
ULONG iResID; // resource type id
|
|
COUNT cFdirEntries;
|
|
BOOL bZeroUponFailure;
|
|
BOOL bSuccess;
|
|
ULONG crn;
|
|
PBYTE pjView;
|
|
PBYTE pjResType_FNT;
|
|
PBYTE pjResType_FDIR;
|
|
BOOL bBreakWhile;
|
|
|
|
#ifdef DUMPCALL
|
|
DbgPrint("\nbInitWinResData(");
|
|
DbgPrint("\n PFILEVIEW pfvw = %-#8lx", pfvw);
|
|
DbgPrint("\n PWINRESDATA pwrd = %-#8lx", pwrd);
|
|
DbgPrint("\n )\n");
|
|
#endif
|
|
|
|
bSuccess = FALSE;
|
|
bZeroUponFailure = FALSE;
|
|
|
|
pwrd->pvView = pvView;
|
|
pwrd->cjView = cjView;
|
|
pjView = (PBYTE)pvView;
|
|
|
|
// check the magic # at the beginning of the old header
|
|
{ C_ASSERT(OFF_e_lfanew > OFF_e_magic); }
|
|
|
|
if (!bMappedViewRangeCheck(pjView, cjView, pjView + OFF_e_lfanew, sizeof(DWORD)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (US_GET(pjView, OFF_e_magic) != EMAGIC)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pwrd->dpNewExe = (PTRDIFF)READ_DWORD(pjView + OFF_e_lfanew);
|
|
|
|
pjNewExe = pjView + pwrd->dpNewExe;
|
|
|
|
// make sure that offset is consistent
|
|
{ C_ASSERT(OFF_ne_magic < CJ_NEW_EXE);
|
|
C_ASSERT(OFF_ne_restab < CJ_NEW_EXE);
|
|
C_ASSERT(OFF_ne_rsrctab < CJ_NEW_EXE);
|
|
}
|
|
if (!bMappedViewRangeCheck(pjView, cjView, pjNewExe, CJ_NEW_EXE))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (US_GET(pjNewExe, OFF_ne_magic) != NEMAGIC)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pwrd->cjResTab = (ULONG)(US_GET(pjNewExe, OFF_ne_restab) -
|
|
US_GET(pjNewExe, OFF_ne_rsrctab));
|
|
|
|
if (pwrd->cjResTab == 0L)
|
|
{
|
|
//
|
|
// The following test is applied by DOS, so I presume that it is
|
|
// legitimate. The assumption is that the resident name table
|
|
// FOLLOWS the resource table directly, and that if it points to
|
|
// the same location as the resource table, then there are no
|
|
// resources.
|
|
|
|
WARNING("No resources in *.fon file\n");
|
|
goto Exit;
|
|
}
|
|
|
|
// want offset from pvView, not from pjNewExe => must add dpNewExe
|
|
|
|
pwrd->dpResTab = (PTRDIFF)US_GET(pjNewExe, OFF_ne_rsrctab) + pwrd->dpNewExe;
|
|
|
|
// make sure that offset is consistent
|
|
|
|
if (!bMappedViewRangeCheck(pjView, cjView, pjView + pwrd->dpResTab, sizeof(USHORT) + CJ_TYPEINFO))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// what really lies at the offset OFF_ne_rsrctab is a NEW_RSRC.rs_align field
|
|
// that is used in computing resource data offsets and sizes as a shift factor.
|
|
// This field occupies two bytes on the disk and the first TYPEINFO structure
|
|
// follows right after. We want pwrd->dpResTab to point to the first
|
|
// TYPEINFO structure, so we must add 2 to get there and subtract 2 from
|
|
// the length
|
|
|
|
pwrd->ulShift = (ULONG) US_GET(pjView, pwrd->dpResTab);
|
|
pwrd->dpResTab += 2;
|
|
pwrd->cjResTab -= 2;
|
|
|
|
// Now we want to determine where the resource data is located.
|
|
// The data consists of a RSRC_TYPEINFO structure, followed by
|
|
// an array of RSRC_NAMEINFO structures, which are then followed
|
|
// by a RSRC_TYPEINFO structure, again followed by an array of
|
|
// RSRC_NAMEINFO structures. This continues until an RSRC_TYPEINFO
|
|
// structure which has a 0 in the rt_id field.
|
|
|
|
pjResType = pjView + pwrd->dpResTab;
|
|
pjResType_FNT = NULL;
|
|
pjResType_FDIR = NULL;
|
|
bBreakWhile = FALSE;
|
|
while (TRUE)
|
|
{
|
|
iResID = (ULONG) US_GET(pjResType,OFF_rt_id);
|
|
switch (iResID)
|
|
{
|
|
default:
|
|
break;
|
|
case 0:
|
|
bBreakWhile = TRUE;
|
|
break;
|
|
case RT_FNT:
|
|
pjResType_FNT = pjResType;
|
|
if (pjResType_FDIR != NULL)
|
|
bBreakWhile = TRUE;
|
|
break;
|
|
case RT_FDIR:
|
|
pjResType_FDIR = pjResType;
|
|
if (pjResType_FNT != NULL)
|
|
bBreakWhile = TRUE;
|
|
break;
|
|
}
|
|
if (bBreakWhile)
|
|
break;
|
|
|
|
// # of NAMEINFO structures that follow = resources of this type
|
|
crn = (ULONG)US_GET(pjResType, OFF_rt_nres);
|
|
|
|
// get ptr to the new TYPEINFO struc and the new resource id
|
|
pjResType = pjResType + CJ_TYPEINFO + crn * CJ_NAMEINFO;
|
|
|
|
if (!bMappedViewRangeCheck(pjView, cjView, pjResType, CJ_TYPEINFO))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
bZeroUponFailure = TRUE;
|
|
|
|
ASSERT((iResID == 0) == (pjResType_FNT == NULL || pjResType_FDIR == NULL));
|
|
if (iResID == 0)
|
|
{ // we did not find one or both of them
|
|
goto Exit;
|
|
}
|
|
|
|
pjResType = pjResType_FNT;
|
|
|
|
// # of NAMEINFO structures that follow == # of font resources
|
|
pwrd->cFntRes = (ULONG)US_GET(pjResType, OFF_rt_nres);
|
|
|
|
// this is ptr to the first NAMEINFO struct that follows
|
|
// an RT_FNT TYPEINFO structure
|
|
|
|
pjResName = pjResType + CJ_TYPEINFO;
|
|
pwrd->dpFntTab = (PTRDIFF)(pjResName - pjView);
|
|
|
|
// make sure that offset is consistent
|
|
|
|
if ((ULONG)pwrd->dpFntTab > pwrd->cjView)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Now we search for the FONDIR resource. Windows actually grabs facenames
|
|
// from the FONDIR entries and not the FNT entries. For some wierd fonts this
|
|
// makes a difference. [gerritv]
|
|
|
|
pjResType = pjResType_FDIR;
|
|
|
|
// this is ptr to the first NAMEINFO struct that follows
|
|
// an RT_FDIR TYPEINFO structure
|
|
|
|
pjResName = pjResType + CJ_TYPEINFO;
|
|
if (!bMappedViewRangeCheck(pjView, cjView, pjResName, CJ_NAMEINFO))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Get the offset to res data computed from the top of the new header
|
|
|
|
pwrd->dpFdirRes = (PTRDIFF)((ULONG)US_GET(pjResName,OFF_rn_offset) <<
|
|
pwrd->ulShift);
|
|
|
|
// Now pwrd->dpFdirRes is an offset to the FONTDIR resource, the first
|
|
// byte [ushort?] will be the number of entries in the font dir. Lets make sure it
|
|
// matches the number of FNT resources in the file.
|
|
|
|
if (!bMappedViewRangeCheck(pjView, cjView, pjView + pwrd->dpFdirRes, sizeof(USHORT)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
cFdirEntries = (ULONG)US_GET(pjView,pwrd->dpFdirRes);
|
|
|
|
if( cFdirEntries != pwrd->cFntRes )
|
|
{
|
|
WARNING( "bInitWinResData: # of FONTDIR entries != # of FNT entries.\n");
|
|
goto Exit;
|
|
}
|
|
|
|
// now increment dpFdirRes so it points passed the count of entries and
|
|
// to the first entry.
|
|
|
|
pwrd->dpFdirRes += 2;
|
|
|
|
bSuccess = TRUE;
|
|
Exit:
|
|
if (!bSuccess)
|
|
{
|
|
#if DBG
|
|
NotifyBadFont("WIN32K: %s failing\n", __FUNCTION__);
|
|
#endif
|
|
if (bZeroUponFailure && pwrd != NULL)
|
|
{
|
|
pwrd->cFntRes = (ULONG)0;
|
|
pwrd->dpFntTab = (PTRDIFF)0;
|
|
}
|
|
}
|
|
return bSuccess;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bGetFntResource
|
|
*
|
|
* Writes the pointer to and the size of the iFntRes-th *.fnt resource
|
|
* of the *.fon file identified by pwrd. The info is written into RES_ELEM
|
|
* structure if successful. The function returns FALSE if it is not possible
|
|
* to locate iFntRes-th *.fnt resource in the file.
|
|
*
|
|
*
|
|
* History:
|
|
* January 2002 -by- Jay Krell [JayKrell]
|
|
* range check memory mapped i/o
|
|
* 09-May-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bGetFntResource(
|
|
PWINRESDATA pwrd ,
|
|
ULONG iFntRes,
|
|
PRES_ELEM pre
|
|
)
|
|
{
|
|
//
|
|
// This function is called in a loop for iFntRes in [0..pwrd->cFntRes),
|
|
// and therefore has quadratic perf.
|
|
//
|
|
PBYTE pjResName;
|
|
PBYTE pjFaceName;
|
|
PTRDIFF dpResData;
|
|
BOOL bSuccess;
|
|
PBYTE pjView;
|
|
PBYTE pjViewEnd;
|
|
SIZE_T cjView;
|
|
SIZE_T cjFaceNameLength;
|
|
|
|
#ifdef DUMPCALL
|
|
DbgPrint("\nbGetFntResource(");
|
|
DbgPrint("\n PWINRESDATA pwrd = %-#8lx", pwrd);
|
|
DbgPrint("\n ULONG iFntRes = %-#8lx", iFntRes);
|
|
DbgPrint("\n PRES_ELEM pre = %-#8lx", pre);
|
|
DbgPrint("\n )\n");
|
|
#endif
|
|
|
|
ASSERTGDI((pwrd->cFntRes != 0L) && (iFntRes < pwrd->cFntRes),
|
|
"bGetFntResource\n");
|
|
|
|
bSuccess = FALSE;
|
|
pjView = (PBYTE)pwrd->pvView;
|
|
cjView = pwrd->cjView;
|
|
|
|
// get to the Beginning of the NAMEINFO struct that correspoonds to
|
|
// the iFntRes-th *.fnt resource. (Note: iFntRes is zero based)
|
|
|
|
pjResName = pjView + pwrd->dpFntTab + iFntRes * CJ_NAMEINFO;
|
|
|
|
// Get the offset to res data computed from the top of the new header
|
|
|
|
if (!bMappedViewRangeCheck(pjView, cjView, pjResName, CJ_NAMEINFO))
|
|
{
|
|
goto Exit;
|
|
}
|
|
dpResData = (PTRDIFF)((ULONG)US_GET(pjResName,OFF_rn_offset) <<
|
|
pwrd->ulShift);
|
|
|
|
pre->pvResData = (PVOID)(pjView + dpResData);
|
|
pre->dpResData = dpResData;
|
|
|
|
pre->cjResData = (ULONG)US_GET(pjResName,OFF_rn_length) << pwrd->ulShift;
|
|
|
|
if (!bMappedViewRangeCheck(pjView, cjView, pre->pvResData, pre->cjResData))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Get the face name from the FONTDIR
|
|
|
|
pjFaceName = pjView + pwrd->dpFdirRes;
|
|
pjViewEnd = pjView + cjView;
|
|
do
|
|
{
|
|
// The first two bytes of the entry are the resource index so we will skip
|
|
// past that. After that add in the size of the font header. This will
|
|
// point us to the string for the device_name
|
|
|
|
pjFaceName += 2 + OFF_BitsOffset;
|
|
|
|
if (!bMappedViewStrlen(pjView, cjView, pjFaceName, &cjFaceNameLength))
|
|
{
|
|
goto Exit;
|
|
}
|
|
pjFaceName += cjFaceNameLength + 1;
|
|
|
|
// pjFaceName now really points to the facename
|
|
if( iFntRes )
|
|
{
|
|
if (!bMappedViewStrlen(pjView, cjView, pjFaceName, &cjFaceNameLength))
|
|
{
|
|
goto Exit;
|
|
}
|
|
pjFaceName += cjFaceNameLength + 1;
|
|
}
|
|
}
|
|
while( iFntRes-- );
|
|
|
|
//
|
|
// Later on strlen is going to be called on pjFaceName.
|
|
// Let's do a range checked version first.
|
|
//
|
|
if (!bMappedViewStrlen(pjView, cjView, pjFaceName, NULL))
|
|
{
|
|
goto Exit;
|
|
}
|
|
pre->pjFaceName = pjFaceName;
|
|
|
|
#ifdef FOOGOO
|
|
KdPrint(("%s: offset= 0x%lx, charset = %ld\n", pjFaceName, dpResData + OFF_CharSet, *((BYTE *)pjView + dpResData + OFF_CharSet)));
|
|
#endif
|
|
|
|
bSuccess = TRUE;
|
|
Exit:
|
|
return bSuccess;
|
|
}
|