[PATCH v4 2/2] gdiplus: In GdipPrivateAddMemoryFont allow loading fonts with long names

Fabian Maurer dark.shadow4 at web.de
Sun Nov 19 11:09:20 CST 2017


Fixes Bug 43956.

v3
Removed stray return
Properly cleanup font
v4
Cleanup family

Signed-off-by: Fabian Maurer <dark.shadow4 at web.de>
---
 dlls/gdiplus/font.c                  |  38 ++++++++++-------
 dlls/gdiplus/tests/Makefile.in       |   2 +
 dlls/gdiplus/tests/font.c            |  80 +++++++++++++++++++++++++++++++++++
 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, 192 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..34bb223d48 100644
--- a/dlls/gdiplus/tests/font.c
+++ b/dlls/gdiplus/tests/font.c
@@ -43,6 +43,85 @@ 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 = GdipDeleteFontFamily(family);
+    ok(stat == Ok, "GdipDeleteFontFamily 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 +1208,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+ at 4dUk$yy{T-ueID|MR{7*WEJ&
zfGKQ4$6Bp+W96OM-;M#3pOag9^~%*6X7McP4<-HDn`fNWg1-fb7U{Km$M4}p at gC`)
z376`dsfju5T|h5UZiIfnHyUwgOuk2YGHef;-|P-8$`?uZT7lnq=Jxy@;=dElw#X<P
zGYZ^mp7eaHlioTG at dD{@Nl&-qx{r0-puI`@sg8fEhikY%`8CpJ*Y5=DvzvRAf5PLx
z>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 at Hpb(VZj)e$N$fV>Sgwge9ki#P3BlQtbmRQly?QrRE84<?mN51!Y`Gft`Wtq
zF4+ai9!?a+UzH(Kc;9hnPR_jO&YYSP(|_#kX*-Wr=d>ob6S`Pt$9*JoES at 9zeOWAv
z<-fm>$(zER{hHt;uH?8t6?b!7!-Tky<2v3Jk8<2VRr at u^3z*icIbLKR{UAHRko|Uv
zkl}(o*35AYQ(_^<b$lsa$#DbQ+FLnZfT=&9<3()iZ{RXw^e{kz2q9WX*=46u#{yRe
z7HpiuBJmpJTO4ujl3L-qL7RYp%W-dzL}4p6PuCYr$Fk2Ynl*nt^1J4WzmWt~*`j5a
z+8$g&%5x(0iDk1-Y*XzuAl9ZwUHam2_R&#R(!!^mM|$5+kN(IVQ|iY@?3$z#azZqy
z?J^E*Mcu%2y|fkeJ^p-eGe`zrJMM;_`~Xqlr(Q<};jNR3<4o3!6EAE;E_b-j!$Jn#
zrX!5#dJt~3eIhmGZmQOV8i7h&nW-~zkuVP3QO^F?p=Vy$d=-{hOq=t5Sy79-X)R8|
zz;w!%dC^o!avncP+`>M;WZO%!2M!ng$wZzN{a?fbtg at U5J2g^8Hd$2pM#$pI$D~4#
z^rN_IT9#e5EQ_3Rz3nGb?<{Kj at vF#>%l^$V+UDEC51eEj8S=ss)H<cOf_KsQc0JDj
V9#YOPqq5Ab)%@daq1MB9_dm8?dc^<$

literal 0
HcmV?d00001

-- 
2.15.0




More information about the wine-devel mailing list