From 1890ad20f842e0ff58394422d6726d95eb34a247 Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Fri, 4 Apr 2025 19:30:18 +0900 Subject: [PATCH] [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. --- win32ss/gdi/eng/stubs.c | 17 -- win32ss/gdi/gdi32/include/gdi32p.h | 44 ++- win32ss/gdi/gdi32/misc/heap.c | 35 ++- win32ss/gdi/gdi32/objects/font.c | 422 ++++++++++++++++++----------- win32ss/gdi/ntgdi/font.c | 99 ++++++- win32ss/gdi/ntgdi/freetype.c | 109 ++++++-- win32ss/gdi/ntgdi/text.h | 12 +- 7 files changed, 506 insertions(+), 232 deletions(-) diff --git a/win32ss/gdi/eng/stubs.c b/win32ss/gdi/eng/stubs.c index e1b14af0448..f130347c8d8 100644 --- a/win32ss/gdi/eng/stubs.c +++ b/win32ss/gdi/eng/stubs.c @@ -1179,23 +1179,6 @@ NtGdiGetStringBitmapW( 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 */ diff --git a/win32ss/gdi/gdi32/include/gdi32p.h b/win32ss/gdi/gdi32/include/gdi32p.h index b2dab4ef879..1b269618179 100644 --- a/win32ss/gdi/gdi32/include/gdi32p.h +++ b/win32ss/gdi/gdi32/include/gdi32p.h @@ -208,20 +208,46 @@ typedef DWORD (WINAPI *QUERYREMOTEFONTS) (DWORD,DWORD,DWORD); extern CLOSEPRINTER fpClosePrinter; extern OPENPRINTERW fpOpenPrinterW; +extern HANDLE hProcessHeap; /* FUNCTIONS *****************************************************************/ -PVOID -HEAP_alloc(DWORD len); +static inline +_Ret_maybenull_ +__drv_allocatesMem(Mem) +PVOID FASTCALL +HEAP_alloc(_In_ SIZE_T len) +{ + ASSERT(hProcessHeap); + return RtlAllocateHeap(hProcessHeap, 0, len); +} -NTSTATUS -HEAP_strdupA2W( - LPWSTR* ppszW, - LPCSTR lpszA -); +static inline VOID FASTCALL +HEAP_free(_In_ __drv_freesMem(Mem) PVOID memory) +{ + ASSERT(hProcessHeap); + RtlFreeHeap(hProcessHeap, 0, memory); +} -VOID -HEAP_free(LPVOID memory); +NTSTATUS FASTCALL +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 FASTCALL diff --git a/win32ss/gdi/gdi32/misc/heap.c b/win32ss/gdi/gdi32/misc/heap.c index 5328c45a248..e2c003807bc 100644 --- a/win32ss/gdi/gdi32/misc/heap.c +++ b/win32ss/gdi/gdi32/misc/heap.c @@ -30,17 +30,8 @@ // global variables in a dll are process-global HANDLE hProcessHeap = NULL; - -PVOID -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 ) +NTSTATUS FASTCALL +HEAP_strdupA2W(_Outptr_ PWSTR* ppszW, _In_ PCSTR lpszA) { ULONG len; NTSTATUS Status; @@ -54,16 +45,24 @@ HEAP_strdupA2W ( LPWSTR* ppszW, LPCSTR lpszA ) if ( !*ppszW ) return STATUS_NO_MEMORY; Status = RtlMultiByteToUnicodeN ( *ppszW, len*sizeof(WCHAR), NULL, (PCHAR)lpszA, len ); - (*ppszW)[len] = L'\0'; + (*ppszW)[len] = UNICODE_NULL; return Status; } - -VOID -HEAP_free ( LPVOID memory ) +PWSTR FASTCALL +HEAP_strdupA2W_buf( + _In_ PCSTR lpszA, + _In_ PWSTR pszStaticBuff, + _In_ SIZE_T cchStaticBuff) { - /* make sure hProcessHeap gets initialized by GdiProcessSetup before we get here */ - assert(hProcessHeap); + if (!lpszA) + 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; } diff --git a/win32ss/gdi/gdi32/objects/font.c b/win32ss/gdi/gdi32/objects/font.c index 7d6ade035ce..f829d448a5f 100644 --- a/win32ss/gdi/gdi32/objects/font.c +++ b/win32ss/gdi/gdi32/objects/font.c @@ -1,10 +1,12 @@ /* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS system libraries - * FILE: win32ss/gdi/gdi32/objects/font.c - * PURPOSE: - * PROGRAMMER: - * + * PROJECT: ReactOS GDI32 + * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) + * PURPOSE: Font manipulation API + * COPYRIGHT: Copyright 2019 James Tabor + * 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 @@ -1939,6 +1941,144 @@ CreateFontW( 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 @@ -1955,124 +2095,146 @@ CreateScalableFontResourceA( return FALSE; } - -/* - * @implemented - */ -int +/* @implemented */ +INT 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)) { - SetLastError( ERROR_INVALID_PARAMETER ); + SetLastError(ERROR_INVALID_PARAMETER); return 0; } - return GdiAddFontResourceW(lpszFilename, fl,0); + return GdiAddFontResourceW(lpszFilename, fl, NULL); } - -/* - * @implemented - */ -int +/* @implemented */ +INT 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)) { - SetLastError( ERROR_INVALID_PARAMETER ); + SetLastError(ERROR_INVALID_PARAMETER); return 0; } - Status = HEAP_strdupA2W ( &FilenameW, lpszFilename ); - if ( !NT_SUCCESS (Status) ) - { - SetLastError (RtlNtStatusToDosError(Status)); + if (!lpszFilename) return 0; - } - rc = GdiAddFontResourceW ( FilenameW, fl, 0 ); - HEAP_free ( FilenameW ); - return rc; -} - - -/* - * @implemented - */ -int -WINAPI -AddFontResourceA ( LPCSTR lpszFilename ) -{ - NTSTATUS Status; PWSTR FilenameW; - int rc = 0; + WCHAR szBuff[MAX_PATH]; - Status = HEAP_strdupA2W ( &FilenameW, lpszFilename ); - if ( !NT_SUCCESS (Status) ) + _SEH2_TRY { - SetLastError (RtlNtStatusToDosError(Status)); + FilenameW = HEAP_strdupA2W_buf(lpszFilename, szBuff, _countof(szBuff)); } - else + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { - rc = GdiAddFontResourceW ( FilenameW, 0, 0); - - HEAP_free ( FilenameW ); + _SEH2_YIELD(return 0); } - 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 -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 WINAPI -RemoveFontResourceW(LPCWSTR lpFileName) +RemoveFontResourceW(_In_ LPCWSTR lpFileName) { - return RemoveFontResourceExW(lpFileName,0,0); + return RemoveFontResourceExW(lpFileName, 0, NULL); } - -/* - * @implemented - */ +/* @implemented */ BOOL WINAPI -RemoveFontResourceA(LPCSTR lpFileName) +RemoveFontResourceA(_In_ LPCSTR lpFileName) { - return RemoveFontResourceExA(lpFileName,0,0); + return RemoveFontResourceExA(lpFileName, 0, NULL); } -/* - * @implemented - */ +/* @implemented */ BOOL WINAPI -RemoveFontResourceExA(LPCSTR lpFileName, - DWORD fl, - PVOID pdv) +RemoveFontResourceExA( + _In_ LPCSTR lpFileName, + _In_ DWORD fl, + _In_opt_ PVOID pdv) { - NTSTATUS Status; - LPWSTR lpFileNameW; - BOOL result; + if (fl & ~(FR_PRIVATE | FR_NOT_ENUM)) + { + 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)) { @@ -2080,44 +2242,19 @@ RemoveFontResourceExA(LPCSTR lpFileName, return FALSE; } - _SEH2_TRY - { - Status = HEAP_strdupA2W(&lpFileNameW, lpFileName); - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - Status = _SEH2_GetExceptionCode(); - } - _SEH2_END; - - if (!NT_SUCCESS(Status)) - { - SetLastError(RtlNtStatusToDosError(Status)); + if (!lpFileName) return FALSE; - } - result = RemoveFontResourceExW(lpFileNameW, fl, pdv); - HEAP_free(lpFileNameW); - return result; + ULONG cFiles, cwc; + PWSTR pszConverted = IntConvertFontPaths(lpFileName, &cFiles, &cwc, &fl, TRUE); + 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 * @@ -2407,55 +2544,33 @@ NewEnumFontFamiliesExW( return ret; } -/* - * @implemented - */ -int +/* @implemented */ +INT WINAPI GdiAddFontResourceW( LPCWSTR lpszFilename, FLONG fl, DESIGNVECTOR *pdv) { - INT Ret; - WCHAR lpszBuffer[MAX_PATH]; - WCHAR lpszAbsPath[MAX_PATH]; - 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); + ULONG cFiles, cwc; + PWSTR pszConverted = IntConvertFontPaths(lpszFilename, &cFiles, &cwc, &fl, FALSE); + if (!pszConverted) return 0; - } - /* The Nt call expects a null-terminator included in cwc param. */ - ASSERT(NtAbsPath.Buffer[NtAbsPath.Length / sizeof(WCHAR)] == UNICODE_NULL); - Ret = NtGdiAddFontResourceW(NtAbsPath.Buffer, NtAbsPath.Length / sizeof(WCHAR) + 1, 1, fl, 0, pdv); + INT ret = NtGdiAddFontResourceW(pszConverted, cwc, cFiles, fl, 0, pdv); + HEAP_free(pszConverted); + 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); return 0; } - diff --git a/win32ss/gdi/ntgdi/font.c b/win32ss/gdi/ntgdi/font.c index cd1b080861f..bb0446b9173 100644 --- a/win32ss/gdi/ntgdi/font.c +++ b/win32ss/gdi/ntgdi/font.c @@ -438,23 +438,41 @@ RealizeFontInit(HFONT hFont) 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 ******************************************************************/ INT APIENTRY NtGdiAddFontResourceW( - IN WCHAR *pwcFiles, - IN ULONG cwc, - IN ULONG cFiles, - IN FLONG fl, - IN DWORD dwPidTid, - IN OPTIONAL DESIGNVECTOR *pdv) + _In_reads_(cwc) WCHAR *pwcFiles, + _In_ ULONG cwc, + _In_ ULONG cFiles, + _In_ FLONG fl, + _In_ DWORD dwPidTid, + _In_opt_ DESIGNVECTOR *pdv) { UNICODE_STRING SafeFileName; INT Ret; - DBG_UNREFERENCED_PARAMETER(cFiles); DBG_UNREFERENCED_PARAMETER(dwPidTid); DBG_UNREFERENCED_PARAMETER(pdv); @@ -464,19 +482,21 @@ NtGdiAddFontResourceW( if ((cwc <= 1) || (cwc > UNICODE_STRING_MAX_CHARS)) return 0; - SafeFileName.MaximumLength = (USHORT)(cwc * sizeof(WCHAR)); - SafeFileName.Length = SafeFileName.MaximumLength - sizeof(UNICODE_NULL); + 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 0; - } _SEH2_TRY { ProbeForRead(pwcFiles, cwc * sizeof(WCHAR), sizeof(WCHAR)); + + if (!IntCheckFontPathNames(pwcFiles, cFiles, cwc)) + return 0; + RtlCopyMemory(SafeFileName.Buffer, pwcFiles, SafeFileName.Length); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) @@ -487,7 +507,62 @@ NtGdiAddFontResourceW( _SEH2_END; 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); return Ret; diff --git a/win32ss/gdi/ntgdi/freetype.c b/win32ss/gdi/ntgdi/freetype.c index 4a98a6de7a5..267fdcd23b2 100644 --- a/win32ss/gdi/ntgdi/freetype.c +++ b/win32ss/gdi/ntgdi/freetype.c @@ -1233,7 +1233,9 @@ IntUnicodeStringToBuffer(LPWSTR pszBuffer, SIZE_T cbBuffer, const UNICODE_STRING } static NTSTATUS -DuplicateUnicodeString(PUNICODE_STRING Source, PUNICODE_STRING Destination) +DuplicateUnicodeString( + _In_ PCUNICODE_STRING Source, + _Out_ PUNICODE_STRING Destination) { NTSTATUS Status = STATUS_NO_MEMORY; UNICODE_STRING Tmp; @@ -1664,10 +1666,8 @@ IntLoadSystemFonts(VOID) { RtlCopyUnicodeString(&FileName, &Directory); 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); - } } if (DirInfo->NextEntryOffset == 0) @@ -2086,15 +2086,12 @@ NameFromCharSet(BYTE CharSet) } } -/* - * IntGdiAddFontResource - * - * Adds the font resource from the specified file to the system. - */ - -INT FASTCALL -IntGdiAddFontResourceEx(PUNICODE_STRING FileName, DWORD Characteristics, - DWORD dwFlags) +/* Adds the font resource from the specified file to the system */ +static INT FASTCALL +IntGdiAddFontResourceSingle( + _In_ PCUNICODE_STRING FileName, + _In_ DWORD Characteristics, + _In_ DWORD dwFlags) { NTSTATUS Status; HANDLE FileHandle; @@ -2291,9 +2288,86 @@ IntGdiAddFontResourceEx(PUNICODE_STRING FileName, DWORD Characteristics, } 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 */ @@ -2439,7 +2513,7 @@ IntLoadFontsInRegistry(VOID) if (NT_SUCCESS(Status)) { RtlCreateUnicodeString(&FileNameW, szPath); - nFontCount += IntGdiAddFontResourceEx(&FileNameW, 0, dwFlags); + nFontCount += IntGdiAddFontResourceEx(&FileNameW, 1, 0, dwFlags); RtlFreeUnicodeString(&FileNameW); } @@ -2508,8 +2582,6 @@ IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded) return Ret; } -// FIXME: Add RemoveFontResource - VOID FASTCALL IntGdiCleanupMemEntry(PFONT_ENTRY_MEM Head) { @@ -4131,7 +4203,6 @@ IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight) if (error) { DPRINT1("%s: Failed to request font size.\n", face->family_name); - ASSERT(FALSE); return error; } diff --git a/win32ss/gdi/ntgdi/text.h b/win32ss/gdi/ntgdi/text.h index 1a8ca9202fc..63860e0dd2c 100644 --- a/win32ss/gdi/ntgdi/text.h +++ b/win32ss/gdi/ntgdi/text.h @@ -118,9 +118,15 @@ ULONG FASTCALL FontGetObject(PTEXTOBJ TextObj, ULONG Count, PVOID Buffer); VOID FASTCALL IntLoadSystemFonts(VOID); BOOL FASTCALL IntLoadFontsInRegistry(VOID); VOID FASTCALL IntGdiCleanupPrivateFontsForProcess(VOID); -INT FASTCALL IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics); -INT FASTCALL IntGdiAddFontResourceEx(PUNICODE_STRING FileName, DWORD Characteristics, - DWORD dwFlags); +INT FASTCALL IntGdiAddFontResourceEx( + _In_ PCUNICODE_STRING FileName, + _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); BOOL FASTCALL IntGdiRemoveFontMemResource(HANDLE hMMFont); ULONG FASTCALL ftGdiGetGlyphOutline(PDC,WCHAR,UINT,LPGLYPHMETRICS,ULONG,PVOID,LPMAT2,BOOL);