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

Fabian Maurer dark.shadow4 at web.de
Sun Nov 26 07:33:18 CST 2017


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
v6
Avoid cast
Formatting

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            |  76 +++++++++++++++++++++++++++++++++++
 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, 188 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 6c7738cf90..53f30b4635 100644
--- a/dlls/gdiplus/tests/font.c
+++ b/dlls/gdiplus/tests/font.c
@@ -43,6 +43,81 @@ 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), MAKEINTRESOURCEA(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;
@@ -1183,6 +1258,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