[NTGDI][GDI32] AddFontResource: Support multiple files (#7833)

JIRA issue: CORE-17684
- Add HEAP_strdupA2W_buf and HEAP_strdupA2W_buf_free
  helper functions for quick string conversion.
- Optimize HEAP_... functions.
- Add IntConvertFontPaths helper function.
- Support multiple files in AddFontResource function.
- Add cFiles parameter to some internal font addition/
  removal functions.
- Half-implement NtGdiRemoveFontResourceW and
  RemoveFontResourceExW functions.
This commit is contained in:
Katayama Hirofumi MZ 2025-04-04 19:30:18 +09:00 committed by GitHub
parent 72bd9ef29a
commit 1890ad20f8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 506 additions and 232 deletions

View file

@ -1179,23 +1179,6 @@ NtGdiGetStringBitmapW(
return 0; return 0;
} }
/*
* @unimplemented
*/
BOOL
APIENTRY
NtGdiRemoveFontResourceW(
IN WCHAR *pwszFiles,
IN ULONG cwc,
IN ULONG cFiles,
IN ULONG fl,
IN DWORD dwPidTid,
IN OPTIONAL DESIGNVECTOR *pdv)
{
UNIMPLEMENTED;
return FALSE;
}
/* /*
* @unimplemented * @unimplemented
*/ */

View file

@ -208,20 +208,46 @@ typedef DWORD (WINAPI *QUERYREMOTEFONTS) (DWORD,DWORD,DWORD);
extern CLOSEPRINTER fpClosePrinter; extern CLOSEPRINTER fpClosePrinter;
extern OPENPRINTERW fpOpenPrinterW; extern OPENPRINTERW fpOpenPrinterW;
extern HANDLE hProcessHeap;
/* FUNCTIONS *****************************************************************/ /* FUNCTIONS *****************************************************************/
PVOID static inline
HEAP_alloc(DWORD len); _Ret_maybenull_
__drv_allocatesMem(Mem)
PVOID FASTCALL
HEAP_alloc(_In_ SIZE_T len)
{
ASSERT(hProcessHeap);
return RtlAllocateHeap(hProcessHeap, 0, len);
}
NTSTATUS static inline VOID FASTCALL
HEAP_strdupA2W( HEAP_free(_In_ __drv_freesMem(Mem) PVOID memory)
LPWSTR* ppszW, {
LPCSTR lpszA ASSERT(hProcessHeap);
); RtlFreeHeap(hProcessHeap, 0, memory);
}
VOID NTSTATUS FASTCALL
HEAP_free(LPVOID memory); HEAP_strdupA2W(_Outptr_ PWSTR* ppszW, _In_ PCSTR lpszA);
/* Buffered string conversion (quicker) */
PWSTR FASTCALL
HEAP_strdupA2W_buf(
_In_ PCSTR lpszA,
_In_ PWSTR pszStaticBuff,
_In_ SIZE_T cchStaticBuff);
/* Free memory allocated by HEAP_strdupA2W_buf */
static inline VOID FASTCALL
HEAP_strdupA2W_buf_free(
_In_opt_ PWSTR pszDynamicBuff,
_In_ PWSTR pszStaticBuff)
{
if (pszDynamicBuff && pszDynamicBuff != pszStaticBuff)
HEAP_free(pszDynamicBuff);
}
VOID VOID
FASTCALL FASTCALL

View file

@ -30,17 +30,8 @@
// global variables in a dll are process-global // global variables in a dll are process-global
HANDLE hProcessHeap = NULL; HANDLE hProcessHeap = NULL;
NTSTATUS FASTCALL
PVOID HEAP_strdupA2W(_Outptr_ PWSTR* ppszW, _In_ PCSTR lpszA)
HEAP_alloc ( DWORD len )
{
/* make sure hProcessHeap gets initialized by GdiProcessSetup before we get here */
assert(hProcessHeap);
return RtlAllocateHeap ( hProcessHeap, 0, len );
}
NTSTATUS
HEAP_strdupA2W ( LPWSTR* ppszW, LPCSTR lpszA )
{ {
ULONG len; ULONG len;
NTSTATUS Status; NTSTATUS Status;
@ -54,16 +45,24 @@ HEAP_strdupA2W ( LPWSTR* ppszW, LPCSTR lpszA )
if ( !*ppszW ) if ( !*ppszW )
return STATUS_NO_MEMORY; return STATUS_NO_MEMORY;
Status = RtlMultiByteToUnicodeN ( *ppszW, len*sizeof(WCHAR), NULL, (PCHAR)lpszA, len ); Status = RtlMultiByteToUnicodeN ( *ppszW, len*sizeof(WCHAR), NULL, (PCHAR)lpszA, len );
(*ppszW)[len] = L'\0'; (*ppszW)[len] = UNICODE_NULL;
return Status; return Status;
} }
PWSTR FASTCALL
VOID HEAP_strdupA2W_buf(
HEAP_free ( LPVOID memory ) _In_ PCSTR lpszA,
_In_ PWSTR pszStaticBuff,
_In_ SIZE_T cchStaticBuff)
{ {
/* make sure hProcessHeap gets initialized by GdiProcessSetup before we get here */ if (!lpszA)
assert(hProcessHeap); return NULL;
RtlFreeHeap ( hProcessHeap, 0, memory ); SIZE_T size = strlen(lpszA) + 1;
PWSTR pszW = (size < cchStaticBuff) ? pszStaticBuff : HEAP_alloc(size * sizeof(WCHAR));
if (!pszW)
return NULL;
RtlMultiByteToUnicodeN(pszW, size * sizeof(WCHAR), NULL, lpszA, size);
return pszW;
} }

View file

@ -1,10 +1,12 @@
/* /*
* COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS GDI32
* PROJECT: ReactOS system libraries * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
* FILE: win32ss/gdi/gdi32/objects/font.c * PURPOSE: Font manipulation API
* PURPOSE: * COPYRIGHT: Copyright 2019 James Tabor
* PROGRAMMER: * Copyright 2019 Pierre Schweitzer (heis_spiter@hotmail.com)
* * Copyright 2019-2021 Hermes Belusca-Maito (hermes.belusca-maito@reactos.org)
* Copyright 2018 Baruch Rutman (peterooch@gmail.com)
* Copyright 2025 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
*/ */
#include <precomp.h> #include <precomp.h>
@ -1939,6 +1941,144 @@ CreateFontW(
return CreateFontIndirectW(&logfont); return CreateFontIndirectW(&logfont);
} }
// Convert single or multiple font path(s)
PWSTR
FASTCALL
IntConvertFontPaths(
_In_ PCWSTR pszFiles,
_Out_ PDWORD pcFiles,
_Out_ PDWORD pcwc,
_Inout_ PDWORD pfl,
_In_ BOOL bFlag)
{
// FIXME: pfl
// FIXME: bFlag
*pcwc = *pcFiles = 0;
if (!*pszFiles)
{
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
// Build "Fonts" path
WCHAR szFontsDir[MAX_PATH];
GetWindowsDirectoryW(szFontsDir, _countof(szFontsDir));
StringCchCatW(szFontsDir, _countof(szFontsDir), L"\\Fonts");
// Count the number of paths separated by '|'.
ULONG pathCount = 1;
for (PCWSTR pch1 = pszFiles; *pch1; ++pch1)
{
if (*pch1 == L'|')
pathCount++;
}
// Allocate memory for the paths.
SIZE_T cchBuff = pathCount * MAX_PATH;
PWSTR pszBuff = HEAP_alloc(cchBuff * sizeof(WCHAR));
if (!pszBuff)
return NULL;
pszBuff[0] = UNICODE_NULL;
*pcFiles = pathCount;
// Convert paths
DWORD dwError = ERROR_SUCCESS;
PCWSTR pch1, pch1Prev;
BOOL bFirst = TRUE;
for (pch1 = pch1Prev = pszFiles;; ++pch1)
{
if (*pch1 && *pch1 != L'|')
continue;
UINT_PTR spanLen = pch1 - pch1Prev;
if (spanLen < _countof(L".ttf") || spanLen >= MAX_PATH)
{
dwError = ERROR_INVALID_FUNCTION;
break;
}
WCHAR szFileName[MAX_PATH], szFullPath[MAX_PATH];
StringCchCopyNW(szFileName, _countof(szFileName), pch1Prev, spanLen);
// Search file
if (!SearchPathW(L".", szFileName, NULL, _countof(szFullPath), szFullPath, NULL) &&
!SearchPathW(szFontsDir, szFileName, NULL, _countof(szFullPath), szFullPath, NULL))
{
dwError = ERROR_FILE_NOT_FOUND;
break;
}
if (bFirst)
{
bFirst = FALSE;
}
else
{
SIZE_T cch = wcslen(szFullPath);
if (cch < _countof(L".pfb"))
{
dwError = ERROR_INVALID_FUNCTION;
break;
}
// Check filename extension
PCWSTR pchDotExt = &szFullPath[cch - 4];
if (_wcsicmp(pchDotExt, L".pfb") != 0 &&
_wcsicmp(pchDotExt, L".mmm") != 0)
{
dwError = ERROR_INVALID_FUNCTION;
break;
}
}
// Convert to an NT path
UNICODE_STRING NtAbsPath;
if (!RtlDosPathNameToNtPathName_U(szFullPath, &NtAbsPath, NULL, NULL))
{
dwError = ERROR_OUTOFMEMORY;
break;
}
// Append a path and '|' to pszBuff
if (StringCchCatW(pszBuff, cchBuff, NtAbsPath.Buffer) != S_OK ||
StringCchCatW(pszBuff, cchBuff, L"|") != S_OK)
{
RtlFreeUnicodeString(&NtAbsPath);
dwError = ERROR_INVALID_FUNCTION;
break;
}
RtlFreeUnicodeString(&NtAbsPath);
if (!*pch1)
break;
pch1Prev = pch1 + 1;
}
if (dwError != ERROR_SUCCESS)
{
HEAP_free(pszBuff);
*pcwc = *pcFiles = 0;
if (dwError != ERROR_INVALID_FUNCTION)
SetLastError(dwError);
return NULL;
}
*pcwc = (DWORD)wcslen(pszBuff);
// Convert '|' to '\0'
for (PWSTR pch2 = pszBuff; *pch2; ++pch2)
{
if (*pch2 == L'|')
*pch2 = UNICODE_NULL;
}
return pszBuff;
}
/* /*
* @unimplemented * @unimplemented
@ -1955,124 +2095,146 @@ CreateScalableFontResourceA(
return FALSE; return FALSE;
} }
/* @implemented */
/* INT
* @implemented
*/
int
WINAPI WINAPI
AddFontResourceExW ( LPCWSTR lpszFilename, DWORD fl, PVOID pvReserved ) AddFontResourceExW(
_In_ LPCWSTR lpszFilename,
_In_ DWORD fl,
_In_opt_ PVOID pvReserved)
{ {
if (fl & ~(FR_PRIVATE | FR_NOT_ENUM)) if (fl & ~(FR_PRIVATE | FR_NOT_ENUM))
{ {
SetLastError( ERROR_INVALID_PARAMETER ); SetLastError(ERROR_INVALID_PARAMETER);
return 0; return 0;
} }
return GdiAddFontResourceW(lpszFilename, fl,0); return GdiAddFontResourceW(lpszFilename, fl, NULL);
} }
/* @implemented */
/* INT
* @implemented
*/
int
WINAPI WINAPI
AddFontResourceExA ( LPCSTR lpszFilename, DWORD fl, PVOID pvReserved ) AddFontResourceExA(
_In_ LPCSTR lpszFilename,
_In_ DWORD fl,
_In_opt_ PVOID pvReserved)
{ {
NTSTATUS Status;
PWSTR FilenameW;
int rc;
if (fl & ~(FR_PRIVATE | FR_NOT_ENUM)) if (fl & ~(FR_PRIVATE | FR_NOT_ENUM))
{ {
SetLastError( ERROR_INVALID_PARAMETER ); SetLastError(ERROR_INVALID_PARAMETER);
return 0; return 0;
} }
Status = HEAP_strdupA2W ( &FilenameW, lpszFilename ); if (!lpszFilename)
if ( !NT_SUCCESS (Status) )
{
SetLastError (RtlNtStatusToDosError(Status));
return 0; return 0;
}
rc = GdiAddFontResourceW ( FilenameW, fl, 0 );
HEAP_free ( FilenameW );
return rc;
}
/*
* @implemented
*/
int
WINAPI
AddFontResourceA ( LPCSTR lpszFilename )
{
NTSTATUS Status;
PWSTR FilenameW; PWSTR FilenameW;
int rc = 0; WCHAR szBuff[MAX_PATH];
Status = HEAP_strdupA2W ( &FilenameW, lpszFilename ); _SEH2_TRY
if ( !NT_SUCCESS (Status) )
{ {
SetLastError (RtlNtStatusToDosError(Status)); FilenameW = HEAP_strdupA2W_buf(lpszFilename, szBuff, _countof(szBuff));
} }
else _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{ {
rc = GdiAddFontResourceW ( FilenameW, 0, 0); _SEH2_YIELD(return 0);
HEAP_free ( FilenameW );
} }
return rc; _SEH2_END;
if (!FilenameW)
{
SetLastError(ERROR_OUTOFMEMORY);
return 0;
}
INT ret = GdiAddFontResourceW(FilenameW, fl, NULL);
HEAP_strdupA2W_buf_free(FilenameW, szBuff);
return ret;
} }
/* @implemented */
/* INT
* @implemented
*/
int
WINAPI WINAPI
AddFontResourceW ( LPCWSTR lpszFilename ) AddFontResourceA(_In_ LPCSTR lpszFilename)
{ {
return GdiAddFontResourceW ( lpszFilename, 0, 0 ); return AddFontResourceExA(lpszFilename, 0, NULL);
} }
/* @implemented */
INT
WINAPI
AddFontResourceW(_In_ LPCWSTR lpszFilename)
{
return GdiAddFontResourceW(lpszFilename, 0, NULL);
}
/* /* @implemented */
* @implemented
*/
BOOL BOOL
WINAPI WINAPI
RemoveFontResourceW(LPCWSTR lpFileName) RemoveFontResourceW(_In_ LPCWSTR lpFileName)
{ {
return RemoveFontResourceExW(lpFileName,0,0); return RemoveFontResourceExW(lpFileName, 0, NULL);
} }
/* @implemented */
/*
* @implemented
*/
BOOL BOOL
WINAPI WINAPI
RemoveFontResourceA(LPCSTR lpFileName) RemoveFontResourceA(_In_ LPCSTR lpFileName)
{ {
return RemoveFontResourceExA(lpFileName,0,0); return RemoveFontResourceExA(lpFileName, 0, NULL);
} }
/* /* @implemented */
* @implemented
*/
BOOL BOOL
WINAPI WINAPI
RemoveFontResourceExA(LPCSTR lpFileName, RemoveFontResourceExA(
DWORD fl, _In_ LPCSTR lpFileName,
PVOID pdv) _In_ DWORD fl,
_In_opt_ PVOID pdv)
{ {
NTSTATUS Status; if (fl & ~(FR_PRIVATE | FR_NOT_ENUM))
LPWSTR lpFileNameW; {
BOOL result; SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!lpFileName)
return FALSE;
WCHAR szBuff[MAX_PATH];
PWSTR FilenameW;
_SEH2_TRY
{
FilenameW = HEAP_strdupA2W_buf(lpFileName, szBuff, _countof(szBuff));
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
FilenameW = NULL;
}
_SEH2_END;
if (!FilenameW)
{
SetLastError(ERROR_OUTOFMEMORY);
return FALSE;
}
BOOL result = RemoveFontResourceExW(FilenameW, fl, pdv);
HEAP_strdupA2W_buf_free(FilenameW, szBuff);
return result;
}
/* @implemented */
BOOL
WINAPI
RemoveFontResourceExW(
_In_ LPCWSTR lpFileName,
_In_ DWORD fl,
_In_opt_ PVOID pdv)
{
DPRINT("RemoveFontResourceExW\n");
if (fl & ~(FR_PRIVATE | FR_NOT_ENUM)) if (fl & ~(FR_PRIVATE | FR_NOT_ENUM))
{ {
@ -2080,44 +2242,19 @@ RemoveFontResourceExA(LPCSTR lpFileName,
return FALSE; return FALSE;
} }
_SEH2_TRY if (!lpFileName)
{
Status = HEAP_strdupA2W(&lpFileNameW, lpFileName);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
if (!NT_SUCCESS(Status))
{
SetLastError(RtlNtStatusToDosError(Status));
return FALSE; return FALSE;
}
result = RemoveFontResourceExW(lpFileNameW, fl, pdv); ULONG cFiles, cwc;
HEAP_free(lpFileNameW); PWSTR pszConverted = IntConvertFontPaths(lpFileName, &cFiles, &cwc, &fl, TRUE);
return result; if (!pszConverted)
return FALSE;
BOOL ret = NtGdiRemoveFontResourceW(pszConverted, cwc, cFiles, fl, 0, NULL);
HEAP_free(pszConverted);
return ret;
} }
/*
* @unimplemented
*/
BOOL
WINAPI
RemoveFontResourceExW(LPCWSTR lpFileName,
DWORD fl,
PVOID pdv)
{
/* FIXME the flags */
/* FIXME the pdv */
/* FIXME NtGdiRemoveFontResource handle flags and pdv */
DPRINT("RemoveFontResourceExW\n");
return 0;
}
/*********************************************************************** /***********************************************************************
* GdiGetCharDimensions * GdiGetCharDimensions
* *
@ -2407,55 +2544,33 @@ NewEnumFontFamiliesExW(
return ret; return ret;
} }
/* /* @implemented */
* @implemented INT
*/
int
WINAPI WINAPI
GdiAddFontResourceW( GdiAddFontResourceW(
LPCWSTR lpszFilename, LPCWSTR lpszFilename,
FLONG fl, FLONG fl,
DESIGNVECTOR *pdv) DESIGNVECTOR *pdv)
{ {
INT Ret; ULONG cFiles, cwc;
WCHAR lpszBuffer[MAX_PATH]; PWSTR pszConverted = IntConvertFontPaths(lpszFilename, &cFiles, &cwc, &fl, FALSE);
WCHAR lpszAbsPath[MAX_PATH]; if (!pszConverted)
UNICODE_STRING NtAbsPath;
/* FIXME: We don't support multiple files passed in lpszFilename
* as L"abcxxxxx.pfm|abcxxxxx.pfb"
*/
/* Does the file exist in CurrentDirectory or in the Absolute Path passed? */
GetCurrentDirectoryW(MAX_PATH, lpszBuffer);
if (!SearchPathW(lpszBuffer, lpszFilename, NULL, MAX_PATH, lpszAbsPath, NULL))
{
/* Nope. Then let's check Fonts folder */
GetWindowsDirectoryW(lpszBuffer, MAX_PATH);
StringCbCatW(lpszBuffer, sizeof(lpszBuffer), L"\\Fonts");
if (!SearchPathW(lpszBuffer, lpszFilename, NULL, MAX_PATH, lpszAbsPath, NULL))
{
DPRINT1("Font not found. The Buffer is: %ls, the FileName is: %S\n", lpszBuffer, lpszFilename);
return 0;
}
}
/* We found the font file so: */
if (!RtlDosPathNameToNtPathName_U(lpszAbsPath, &NtAbsPath, NULL, NULL))
{
DPRINT1("Can't convert Path! Path: %ls\n", lpszAbsPath);
return 0; return 0;
}
/* The Nt call expects a null-terminator included in cwc param. */ INT ret = NtGdiAddFontResourceW(pszConverted, cwc, cFiles, fl, 0, pdv);
ASSERT(NtAbsPath.Buffer[NtAbsPath.Length / sizeof(WCHAR)] == UNICODE_NULL); HEAP_free(pszConverted);
Ret = NtGdiAddFontResourceW(NtAbsPath.Buffer, NtAbsPath.Length / sizeof(WCHAR) + 1, 1, fl, 0, pdv); if (ret)
return ret;
RtlFreeUnicodeString(&NtAbsPath); pszConverted = IntConvertFontPaths(lpszFilename, &cFiles, &cwc, &fl, TRUE);
if (!pszConverted)
return 0;
return Ret; ret = NtGdiAddFontResourceW(pszConverted, cwc, cFiles, fl, 0, pdv);
HEAP_free(pszConverted);
if (!ret)
SetLastError(ERROR_INVALID_PARAMETER);
return ret;
} }
/* /*
@ -2683,4 +2798,3 @@ cGetTTFFromFOT(DWORD x1 ,DWORD x2 ,DWORD x3, DWORD x4, DWORD x5, DWORD x6, DWORD
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0; return 0;
} }

View file

@ -438,23 +438,41 @@ RealizeFontInit(HFONT hFont)
return pTextObj; return pTextObj;
} }
static BOOL
IntCheckFontPathNames(
_In_reads_(cwc) WCHAR *pwcFiles,
_In_ ULONG cFiles,
_In_ ULONG cwc)
{
ULONG ich, cRealFiles;
if (pwcFiles[cwc - 1] != UNICODE_NULL)
return FALSE;
for (ich = cRealFiles = 0; ich < cwc; ++ich)
{
if (!pwcFiles[ich])
++cRealFiles;
}
return cRealFiles >= cFiles;
}
/** Functions ******************************************************************/ /** Functions ******************************************************************/
INT INT
APIENTRY APIENTRY
NtGdiAddFontResourceW( NtGdiAddFontResourceW(
IN WCHAR *pwcFiles, _In_reads_(cwc) WCHAR *pwcFiles,
IN ULONG cwc, _In_ ULONG cwc,
IN ULONG cFiles, _In_ ULONG cFiles,
IN FLONG fl, _In_ FLONG fl,
IN DWORD dwPidTid, _In_ DWORD dwPidTid,
IN OPTIONAL DESIGNVECTOR *pdv) _In_opt_ DESIGNVECTOR *pdv)
{ {
UNICODE_STRING SafeFileName; UNICODE_STRING SafeFileName;
INT Ret; INT Ret;
DBG_UNREFERENCED_PARAMETER(cFiles);
DBG_UNREFERENCED_PARAMETER(dwPidTid); DBG_UNREFERENCED_PARAMETER(dwPidTid);
DBG_UNREFERENCED_PARAMETER(pdv); DBG_UNREFERENCED_PARAMETER(pdv);
@ -464,19 +482,21 @@ NtGdiAddFontResourceW(
if ((cwc <= 1) || (cwc > UNICODE_STRING_MAX_CHARS)) if ((cwc <= 1) || (cwc > UNICODE_STRING_MAX_CHARS))
return 0; return 0;
SafeFileName.MaximumLength = (USHORT)(cwc * sizeof(WCHAR)); SafeFileName.Length = (USHORT)((cwc - 1) * sizeof(WCHAR));
SafeFileName.Length = SafeFileName.MaximumLength - sizeof(UNICODE_NULL); SafeFileName.MaximumLength = SafeFileName.Length + sizeof(UNICODE_NULL);
SafeFileName.Buffer = ExAllocatePoolWithTag(PagedPool, SafeFileName.Buffer = ExAllocatePoolWithTag(PagedPool,
SafeFileName.MaximumLength, SafeFileName.MaximumLength,
TAG_STRING); TAG_STRING);
if (!SafeFileName.Buffer) if (!SafeFileName.Buffer)
{
return 0; return 0;
}
_SEH2_TRY _SEH2_TRY
{ {
ProbeForRead(pwcFiles, cwc * sizeof(WCHAR), sizeof(WCHAR)); ProbeForRead(pwcFiles, cwc * sizeof(WCHAR), sizeof(WCHAR));
if (!IntCheckFontPathNames(pwcFiles, cFiles, cwc))
return 0;
RtlCopyMemory(SafeFileName.Buffer, pwcFiles, SafeFileName.Length); RtlCopyMemory(SafeFileName.Buffer, pwcFiles, SafeFileName.Length);
} }
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
@ -487,7 +507,62 @@ NtGdiAddFontResourceW(
_SEH2_END; _SEH2_END;
SafeFileName.Buffer[SafeFileName.Length / sizeof(WCHAR)] = UNICODE_NULL; SafeFileName.Buffer[SafeFileName.Length / sizeof(WCHAR)] = UNICODE_NULL;
Ret = IntGdiAddFontResource(&SafeFileName, fl);
Ret = IntGdiAddFontResourceEx(&SafeFileName, cFiles, fl, 0);
ExFreePoolWithTag(SafeFileName.Buffer, TAG_STRING);
return Ret;
}
BOOL
APIENTRY
NtGdiRemoveFontResourceW(
_In_reads_(cwc) WCHAR *pwszFiles,
_In_ ULONG cwc,
_In_ ULONG cFiles,
_In_ ULONG fl,
_In_ DWORD dwPidTid,
_In_opt_ DESIGNVECTOR *pdv)
{
UNICODE_STRING SafeFileName;
BOOL Ret;
DBG_UNREFERENCED_PARAMETER(dwPidTid);
DBG_UNREFERENCED_PARAMETER(pdv);
DPRINT("NtGdiRemoveFontResourceW\n");
/* cwc = Length + trailing zero. */
if ((cwc <= 1) || (cwc > UNICODE_STRING_MAX_CHARS))
return FALSE;
SafeFileName.Length = (USHORT)((cwc - 1) * sizeof(WCHAR));
SafeFileName.MaximumLength = SafeFileName.Length + sizeof(UNICODE_NULL);
SafeFileName.Buffer = ExAllocatePoolWithTag(PagedPool,
SafeFileName.MaximumLength,
TAG_STRING);
if (!SafeFileName.Buffer)
return FALSE;
_SEH2_TRY
{
ProbeForRead(pwszFiles, cwc * sizeof(WCHAR), sizeof(WCHAR));
if (!IntCheckFontPathNames(pwszFiles, cFiles, cwc))
return FALSE;
RtlCopyMemory(SafeFileName.Buffer, pwszFiles, SafeFileName.Length);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ExFreePoolWithTag(SafeFileName.Buffer, TAG_STRING);
_SEH2_YIELD(return FALSE);
}
_SEH2_END;
SafeFileName.Buffer[SafeFileName.Length / sizeof(WCHAR)] = UNICODE_NULL;
Ret = IntGdiRemoveFontResource(&SafeFileName, cFiles, fl);
ExFreePoolWithTag(SafeFileName.Buffer, TAG_STRING); ExFreePoolWithTag(SafeFileName.Buffer, TAG_STRING);
return Ret; return Ret;

View file

@ -1233,7 +1233,9 @@ IntUnicodeStringToBuffer(LPWSTR pszBuffer, SIZE_T cbBuffer, const UNICODE_STRING
} }
static NTSTATUS static NTSTATUS
DuplicateUnicodeString(PUNICODE_STRING Source, PUNICODE_STRING Destination) DuplicateUnicodeString(
_In_ PCUNICODE_STRING Source,
_Out_ PUNICODE_STRING Destination)
{ {
NTSTATUS Status = STATUS_NO_MEMORY; NTSTATUS Status = STATUS_NO_MEMORY;
UNICODE_STRING Tmp; UNICODE_STRING Tmp;
@ -1664,10 +1666,8 @@ IntLoadSystemFonts(VOID)
{ {
RtlCopyUnicodeString(&FileName, &Directory); RtlCopyUnicodeString(&FileName, &Directory);
RtlAppendUnicodeStringToString(&FileName, &TempString); RtlAppendUnicodeStringToString(&FileName, &TempString);
if (!IntGdiAddFontResourceEx(&FileName, 0, AFRX_WRITE_REGISTRY)) if (!IntGdiAddFontResourceEx(&FileName, 1, 0, AFRX_WRITE_REGISTRY))
{
DPRINT1("ERR: Failed to load %wZ\n", &FileName); DPRINT1("ERR: Failed to load %wZ\n", &FileName);
}
} }
if (DirInfo->NextEntryOffset == 0) if (DirInfo->NextEntryOffset == 0)
@ -2086,15 +2086,12 @@ NameFromCharSet(BYTE CharSet)
} }
} }
/* /* Adds the font resource from the specified file to the system */
* IntGdiAddFontResource static INT FASTCALL
* IntGdiAddFontResourceSingle(
* Adds the font resource from the specified file to the system. _In_ PCUNICODE_STRING FileName,
*/ _In_ DWORD Characteristics,
_In_ DWORD dwFlags)
INT FASTCALL
IntGdiAddFontResourceEx(PUNICODE_STRING FileName, DWORD Characteristics,
DWORD dwFlags)
{ {
NTSTATUS Status; NTSTATUS Status;
HANDLE FileHandle; HANDLE FileHandle;
@ -2291,9 +2288,86 @@ IntGdiAddFontResourceEx(PUNICODE_STRING FileName, DWORD Characteristics,
} }
INT FASTCALL INT FASTCALL
IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics) IntGdiAddFontResourceEx(
_In_ PCUNICODE_STRING FileName,
_In_ DWORD cFiles,
_In_ DWORD Characteristics,
_In_ DWORD dwFlags)
{ {
return IntGdiAddFontResourceEx(FileName, Characteristics, 0); PWSTR pchFile = FileName->Buffer;
SIZE_T cchFile;
INT ret = 0;
while (cFiles--)
{
_SEH2_TRY
{
cchFile = wcslen(pchFile);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
_SEH2_YIELD(return FALSE);
}
_SEH2_END;
UNICODE_STRING ustrPathName;
ustrPathName.Length = (USHORT)(cchFile * sizeof(WCHAR));
ustrPathName.MaximumLength = ustrPathName.Length + sizeof(WCHAR);
ustrPathName.Buffer = pchFile;
INT count = IntGdiAddFontResourceSingle(&ustrPathName, Characteristics, dwFlags);
if (!count)
return 0;
ret += count;
pchFile += cchFile + 1;
}
return ret;
}
static BOOL FASTCALL
IntGdiRemoveFontResourceSingle(
_In_ PCUNICODE_STRING FileName,
_In_ DWORD dwFlags)
{
return FALSE; // FIXME
}
BOOL FASTCALL
IntGdiRemoveFontResource(
_In_ PCUNICODE_STRING FileName,
_In_ DWORD cFiles,
_In_ DWORD dwFlags)
{
PWSTR pchFile = FileName->Buffer;
SIZE_T cchFile;
while (cFiles--)
{
_SEH2_TRY
{
cchFile = wcslen(pchFile);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
_SEH2_YIELD(return FALSE);
}
_SEH2_END;
UNICODE_STRING ustrPathName;
ustrPathName.Length = (USHORT)(cchFile * sizeof(WCHAR));
ustrPathName.MaximumLength = ustrPathName.Length + sizeof(WCHAR);
ustrPathName.Buffer = pchFile;
BOOL ret = IntGdiRemoveFontResourceSingle(&ustrPathName, dwFlags);
if (!ret)
return FALSE;
pchFile += cchFile + 1;
}
return TRUE;
} }
/* Borrowed from shlwapi!PathIsRelativeW */ /* Borrowed from shlwapi!PathIsRelativeW */
@ -2439,7 +2513,7 @@ IntLoadFontsInRegistry(VOID)
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ {
RtlCreateUnicodeString(&FileNameW, szPath); RtlCreateUnicodeString(&FileNameW, szPath);
nFontCount += IntGdiAddFontResourceEx(&FileNameW, 0, dwFlags); nFontCount += IntGdiAddFontResourceEx(&FileNameW, 1, 0, dwFlags);
RtlFreeUnicodeString(&FileNameW); RtlFreeUnicodeString(&FileNameW);
} }
@ -2508,8 +2582,6 @@ IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded)
return Ret; return Ret;
} }
// FIXME: Add RemoveFontResource
VOID FASTCALL VOID FASTCALL
IntGdiCleanupMemEntry(PFONT_ENTRY_MEM Head) IntGdiCleanupMemEntry(PFONT_ENTRY_MEM Head)
{ {
@ -4131,7 +4203,6 @@ IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight)
if (error) if (error)
{ {
DPRINT1("%s: Failed to request font size.\n", face->family_name); DPRINT1("%s: Failed to request font size.\n", face->family_name);
ASSERT(FALSE);
return error; return error;
} }

View file

@ -118,9 +118,15 @@ ULONG FASTCALL FontGetObject(PTEXTOBJ TextObj, ULONG Count, PVOID Buffer);
VOID FASTCALL IntLoadSystemFonts(VOID); VOID FASTCALL IntLoadSystemFonts(VOID);
BOOL FASTCALL IntLoadFontsInRegistry(VOID); BOOL FASTCALL IntLoadFontsInRegistry(VOID);
VOID FASTCALL IntGdiCleanupPrivateFontsForProcess(VOID); VOID FASTCALL IntGdiCleanupPrivateFontsForProcess(VOID);
INT FASTCALL IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics); INT FASTCALL IntGdiAddFontResourceEx(
INT FASTCALL IntGdiAddFontResourceEx(PUNICODE_STRING FileName, DWORD Characteristics, _In_ PCUNICODE_STRING FileName,
DWORD dwFlags); _In_ DWORD cFiles,
_In_ DWORD Characteristics,
_In_ DWORD dwFlags);
BOOL FASTCALL IntGdiRemoveFontResource(
_In_ PCUNICODE_STRING FileName,
_In_ DWORD cFiles,
_In_ DWORD dwFlags);
HANDLE FASTCALL IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded); HANDLE FASTCALL IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded);
BOOL FASTCALL IntGdiRemoveFontMemResource(HANDLE hMMFont); BOOL FASTCALL IntGdiRemoveFontMemResource(HANDLE hMMFont);
ULONG FASTCALL ftGdiGetGlyphOutline(PDC,WCHAR,UINT,LPGLYPHMETRICS,ULONG,PVOID,LPMAT2,BOOL); ULONG FASTCALL ftGdiGetGlyphOutline(PDC,WCHAR,UINT,LPGLYPHMETRICS,ULONG,PVOID,LPMAT2,BOOL);