From: Fabian Maurer Subject: [=PATCH v5 2/2] gdiplus: In GdipPrivateAddMemoryFont allow loading fonts with long names Message-Id: <20171119194426.9003-2-dark.shadow4@web.de> Date: Sun, 19 Nov 2017 20:44:26 +0100 In-Reply-To: <20171119194426.9003-1-dark.shadow4@web.de> References: <20171119194426.9003-1-dark.shadow4@web.de> Fixes Bug 43956. v3 Removed stray return Properly cleanup font v4 Cleanup family v5 Don't cleanup family, since GdipDeletePrivateFontCollection already seems to do that Signed-off-by: Fabian Maurer --- dlls/gdiplus/font.c | 38 +++++++++-------- dlls/gdiplus/tests/Makefile.in | 2 + dlls/gdiplus/tests/font.c | 77 +++++++++++++++++++++++++++++++++++ dlls/gdiplus/tests/resource.rc | 22 ++++++++++ dlls/gdiplus/tests/wine_longname.sfd | 66 ++++++++++++++++++++++++++++++ dlls/gdiplus/tests/wine_longname.ttf | Bin 0 -> 2252 bytes 6 files changed, 189 insertions(+), 16 deletions(-) create mode 100644 dlls/gdiplus/tests/resource.rc create mode 100644 dlls/gdiplus/tests/wine_longname.sfd create mode 100644 dlls/gdiplus/tests/wine_longname.ttf diff --git a/dlls/gdiplus/font.c b/dlls/gdiplus/font.c index ccf93ed395..f99b026b25 100644 --- a/dlls/gdiplus/font.c +++ b/dlls/gdiplus/font.c @@ -1393,33 +1393,36 @@ static int match_name_table_language( const tt_name_record *name, LANGID lang ) return 0; } -static WCHAR *copy_name_table_string( const tt_name_record *name, const BYTE *data, WCHAR *ret, DWORD len ) +static WCHAR *copy_name_table_string( const tt_name_record *name, const BYTE *data ) { WORD name_len = GET_BE_WORD(name->length); WORD codepage; + WCHAR *ret; + int len; switch (GET_BE_WORD(name->platform_id)) { case TT_PLATFORM_APPLE_UNICODE: case TT_PLATFORM_MICROSOFT: - if (name_len >= len*sizeof(WCHAR)) - return NULL; + ret = heap_alloc((name_len / 2 + 1) * sizeof(WCHAR)); for (len = 0; len < name_len / 2; len++) ret[len] = (data[len * 2] << 8) | data[len * 2 + 1]; ret[len] = 0; return ret; case TT_PLATFORM_MACINTOSH: codepage = get_mac_code_page( name ); - len = MultiByteToWideChar( codepage, 0, (char *)data, name_len, ret, len-1 ); + len = MultiByteToWideChar( codepage, 0, (char *)data, name_len, NULL, 0 ) + 1; if (!len) return NULL; + ret = heap_alloc(len * sizeof(WCHAR)); + len = MultiByteToWideChar( codepage, 0, (char *)data, name_len, ret, len - 1 ); ret[len] = 0; return ret; } return NULL; } -static WCHAR *load_ttf_name_id( const BYTE *mem, DWORD_PTR size, DWORD id, WCHAR *ret, DWORD len ) +static WCHAR *load_ttf_name_id( const BYTE *mem, DWORD_PTR size, DWORD id ) { LANGID lang = GetSystemDefaultLangID(); const tt_header *header; @@ -1480,8 +1483,9 @@ static WCHAR *load_ttf_name_id( const BYTE *mem, DWORD_PTR size, DWORD id, WCHAR if (best_lang) { + WCHAR *ret; name_record = (const tt_name_record*)(name_table + 1) + best_index; - ret = copy_name_table_string( name_record, mem+ofs+GET_BE_WORD(name_record->offset), ret, len ); + ret = copy_name_table_string( name_record, mem+ofs+GET_BE_WORD(name_record->offset) ); TRACE( "name %u found platform %u lang %04x %s\n", GET_BE_WORD(name_record->name_id), GET_BE_WORD(name_record->platform_id), GET_BE_WORD(name_record->language_id), debugstr_w( ret )); return ret; @@ -1497,43 +1501,45 @@ static INT CALLBACK add_font_proc(const LOGFONTW *lfw, const TEXTMETRICW *ntm, D GpStatus WINGDIPAPI GdipPrivateAddMemoryFont(GpFontCollection* fontCollection, GDIPCONST void* memory, INT length) { - WCHAR buf[32], *name; + WCHAR *name; DWORD count = 0; HANDLE font; + GpStatus ret = Ok; TRACE("%p, %p, %d\n", fontCollection, memory, length); if (!fontCollection || !memory || !length) return InvalidParameter; - name = load_ttf_name_id(memory, length, NAME_ID_FULL_FONT_NAME, buf, sizeof(buf)/sizeof(*buf)); + name = load_ttf_name_id(memory, length, NAME_ID_FULL_FONT_NAME); if (!name) return OutOfMemory; font = AddFontMemResourceEx((void*)memory, length, NULL, &count); TRACE("%s: %p/%u\n", debugstr_w(name), font, count); if (!font || !count) - return InvalidParameter; - - if (count) + ret = InvalidParameter; + else { HDC hdc; LOGFONTW lfw; hdc = CreateCompatibleDC(0); + /* Truncate name if necessary, GDI32 can't deal with long names */ + if(lstrlenW(name) > LF_FACESIZE - 1) + name[LF_FACESIZE - 1] = 0; + lfw.lfCharSet = DEFAULT_CHARSET; lstrcpyW(lfw.lfFaceName, name); lfw.lfPitchAndFamily = 0; if (!EnumFontFamiliesExW(hdc, &lfw, add_font_proc, (LPARAM)fontCollection, 0)) - { - DeleteDC(hdc); - return OutOfMemory; - } + ret = OutOfMemory; DeleteDC(hdc); } - return Ok; + heap_free(name); + return ret; } /***************************************************************************** diff --git a/dlls/gdiplus/tests/Makefile.in b/dlls/gdiplus/tests/Makefile.in index f427b02b13..3e1a037889 100644 --- a/dlls/gdiplus/tests/Makefile.in +++ b/dlls/gdiplus/tests/Makefile.in @@ -14,3 +14,5 @@ C_SRCS = \ pen.c \ region.c \ stringformat.c + +RC_SRCS = resource.rc diff --git a/dlls/gdiplus/tests/font.c b/dlls/gdiplus/tests/font.c index 2cae48192e..8fe40c2de1 100644 --- a/dlls/gdiplus/tests/font.c +++ b/dlls/gdiplus/tests/font.c @@ -43,6 +43,82 @@ static void set_rect_empty(RectF *rc) rc->Height = 0.0; } +static WCHAR *create_testfontfile(const WCHAR *filename, int resource) +{ + static WCHAR pathW[MAX_PATH]; + DWORD written; + HANDLE file; + HRSRC res; + void *ptr; + + GetTempPathW(sizeof(pathW)/sizeof(WCHAR), pathW); + lstrcatW(pathW, filename); + + file = CreateFileW(pathW, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %d\n", wine_dbgstr_w(pathW), + GetLastError()); + + res = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(resource), (LPCSTR)RT_RCDATA); + ok( res != 0, "couldn't find resource\n" ); + ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res )); + WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL ); + ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" ); + CloseHandle( file ); + + return pathW; +} + +#define DELETE_FONTFILE(filename) _delete_testfontfile(filename, __LINE__) +static void _delete_testfontfile(const WCHAR *filename, int line) +{ + BOOL ret = DeleteFileW(filename); + ok_(__FILE__,line)(ret, "failed to delete file %s, error %d\n", wine_dbgstr_w(filename), GetLastError()); +} + +static void test_long_name(void) +{ + WCHAR* path; + static const WCHAR path_longname[] = {'w','i','n','e','_','l','o','n','g','n','a','m','e','.','t','t','f',0}; + GpStatus stat; + GpFontCollection *fonts; + INT num_families; + GpFontFamily *family; + WCHAR family_name[LF_FACESIZE]; + GpFont *font; + + stat = GdipNewPrivateFontCollection(&fonts); + ok(stat == Ok, "GdipNewPrivateFontCollection failed: %d\n", stat); + + path = create_testfontfile(path_longname, 1); + + stat = GdipPrivateAddFontFile(fonts, path); + ok(stat == Ok, "GdipPrivateAddFontFile failed: %d\n", stat); + + stat = GdipGetFontCollectionFamilyCount(fonts, &num_families); + ok(stat == Ok, "GdipGetFontCollectionFamilyCount failed: %d\n", stat); + + ok(num_families == 1, "expected num_families to be 1, got %d\n", num_families); + + stat = GdipGetFontCollectionFamilyList(fonts, num_families, &family, &num_families); + ok(stat == Ok, "GdipGetFontCollectionFamilyList failed: %d\n", stat); + + stat = GdipGetFamilyName(family, family_name, LANG_NEUTRAL); + ok(stat == Ok, "GdipGetFamilyName failed: %d\n", stat); + + stat = GdipCreateFont(family, 256.0, FontStyleRegular, UnitPixel, &font); + ok(stat == Ok, "GdipCreateFont failed: %d\n", stat); + + /* Cleanup */ + + stat = GdipDeleteFont(font); + ok(stat == Ok, "GdipDeleteFont failed: %d\n", stat); + + stat = GdipDeletePrivateFontCollection(&fonts); + ok(stat == Ok, "GdipDeletePrivateFontCollection failed: %d\n", stat); + + DELETE_FONTFILE(path); +} + static void test_createfont(void) { GpFontFamily* fontfamily = NULL, *fontfamily2; @@ -1129,6 +1205,7 @@ START_TEST(font) GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); + test_long_name(); test_font_transform(); test_font_substitution(); test_font_metrics(); diff --git a/dlls/gdiplus/tests/resource.rc b/dlls/gdiplus/tests/resource.rc new file mode 100644 index 0000000000..d7d915ce00 --- /dev/null +++ b/dlls/gdiplus/tests/resource.rc @@ -0,0 +1,22 @@ +/* + * Resources for gdiplus test suite. + * + * Copyright 2017 Fabian Maurer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* @makedep: wine_longname.ttf */ +1 RCDATA wine_longname.ttf diff --git a/dlls/gdiplus/tests/wine_longname.sfd b/dlls/gdiplus/tests/wine_longname.sfd new file mode 100644 index 0000000000..998d7cc01f --- /dev/null +++ b/dlls/gdiplus/tests/wine_longname.sfd @@ -0,0 +1,66 @@ +SplineFontDB: 3.0 +FontName: wine_1_this_is_a_very_long_name_that_might_be_too_long_for_gdi32 +FullName: wine_2_this_is_a_very_long_name_that_might_be_too_long_for_gdi32 +FamilyName: wine_3_this_is_a_very_long_name_that_might_be_too_long_for_gdi32 +Weight: Regular +Copyright: Copyright (c) 2017, Fabian Maurer +UComments: "2017-11-17: Created with FontForge (http://fontforge.org)" +Version: 001.000 +ItalicAngle: 0 +UnderlinePosition: -102.4 +UnderlineWidth: 51.2 +Ascent: 819 +Descent: 205 +InvalidEm: 0 +LayerCount: 2 +Layer: 0 0 "Back" 1 +Layer: 1 0 "Fore" 0 +XUID: [1021 48 28337276 3092883] +OS2Version: 0 +OS2_WeightWidthSlopeOnly: 0 +OS2_UseTypoMetrics: 1 +CreationTime: 1510948643 +ModificationTime: 1510949092 +OS2TypoAscent: 0 +OS2TypoAOffset: 1 +OS2TypoDescent: 0 +OS2TypoDOffset: 1 +OS2TypoLinegap: 0 +OS2WinAscent: 0 +OS2WinAOffset: 1 +OS2WinDescent: 0 +OS2WinDOffset: 1 +HheadAscent: 0 +HheadAOffset: 1 +HheadDescent: 0 +HheadDOffset: 1 +OS2Vendor: 'PfEd' +MarkAttachClasses: 1 +DEI: 91125 +Encoding: ISO8859-1 +UnicodeInterp: none +NameList: AGL For New Fonts +DisplaySize: -48 +AntiAlias: 1 +FitToEm: 0 +WinInfo: 64 16 4 +BeginPrivate: 0 +EndPrivate +BeginChars: 256 1 + +StartChar: at +Encoding: 64 64 0 +Width: 1024 +VWidth: 0 +Flags: HW +LayerCount: 2 +Fore +SplineSet +259 332 m 29 + 468 664 l 29 + 514 332 l 29 + 259 332 l 29 +EndSplineSet +EndChar +EndChars +EndSplineFont diff --git a/dlls/gdiplus/tests/wine_longname.ttf b/dlls/gdiplus/tests/wine_longname.ttf new file mode 100644 index 0000000000000000000000000000000000000000..59d9517560592e9578f1510f99f4fb65065c1195 GIT binary patch literal 2252 zcmdT`J!~6Q9RIz$vy(ze6NyY%=$Z!6pv1io)Gv83{V*L80j0`9(dA;F&nMYF>wHP- zEn;Fof`I`fHnvbz#A0FuAu(hCArJ#BOqEKh7`jo+@4dUk$yy{T-ueID|MR{7*WEJ& zfGKQ4$6Bp+W96OM-;M#3pOag9^~%*6X7McP4<-HDn`fNWg1-fb7U{Km$M4}p@gC`) z376`dsfju5T|h5UZiIfnHyUwgOuk2YGHef;-|P-8$`?uZT7lnq=Jxy@;=dElw#X

c#zZw1cxedX4gzAY&y=efL?(J5hOvrwuZIpI(0OX}12^z#O1y+79VSXp+l88^yVq z>1&$WDU)Thp*Y5YjkFYsS4CN=7*zQHj7|Gkqlb7uTg5%Nf*IFP;G7TX=fQZrd9}g% zR8iI4k&Bzk6Xnx^iU~o_=sBZSAeeKRcLk-~+X^YUbBRhOSA&nFtE`clM_=cf5XJEU zLdGKD@Hpb(VZj)e$N$fV>Sgwge9ki#P3BlQtbmRQly?QrRE84ob6S`Pt$9*JoES@9zeOWAv z<-fm>$(zER{hHt;uH?8t6?b!7!-Tky<2v3Jk8<2VRr@u^3z*icIbLKR{UAHRko|Uv zkl}(o*35AYQ(_^M;WZO%!2M!ng$wZzN{a?fbtg@U5J2g^8Hd$2pM#$pI$D~4# z^rN_IT9#e5EQ_3Rz3nGb?<{Kj@vF#>%l^$V+UDEC51eEj8S=ss)H