gdi32[2/3]: implement AddFontMemResourceEx (based on a patch of Byeong-Sik Jeon, helps with bug #5865)

Mikolaj Zalewski mikolajz at google.com
Thu Sep 6 14:03:59 CDT 2007


  Byeong-Sik Jeon send only a first version of his patch to
wine-patches. Bugzilla bug #5865 contains a more advanced that have
some small problems (e.g. a buffer overflow) but generally seems
correct. I've tried to make the patch simpler but apart from relinking
the child fonts from file names to struct Face (what allowed to remove
a hack) it ended very similar to the original. There are many changes
needed because there are many places that assumes that a font resides
in a file.
-------------- next part --------------
From 9a59b8bff39f2f65aec4685d48eb6d1f300a2012 Mon Sep 17 00:00:00 2001
From: Mikolaj Zalewski <mikolaj at zalewski.pl>
Date: Thu, 6 Sep 2007 11:41:51 -0700
Subject: [PATCH] gdi32: implement AddFontMemResourceEx (based on a patch of Byeong-Sik Jeon, helps with bug #5865)
---
 dlls/gdi32/font.c        |   14 ++++-
 dlls/gdi32/freetype.c    |  123 ++++++++++++++++++++++++++++++++++++----------
 dlls/gdi32/gdi_private.h |    1 
 include/wingdi.h         |    1 
 4 files changed, 110 insertions(+), 29 deletions(-)

diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c
index c516736..efc044b 100644
--- a/dlls/gdi32/font.c
+++ b/dlls/gdi32/font.c
@@ -3214,8 +3214,18 @@ BOOL WINAPI RemoveFontResourceW( LPCWSTR
  */
 HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
 {
-    FIXME("(%p,%08x,%p,%p): stub\n", pbFont, cbFont, pdv, pcFonts);
-    return NULL;
+    PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
+    HANDLE ret;
+
+    TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
+    memcpy(pFontCopy, pbFont, cbFont);
+    ret = WineEngAddFontMemResourceEx(pFontCopy, cbFont, pdv, pcFonts);
+    if (ret == NULL)
+    {
+        TRACE("Font create failed - freeing %p\n", pFontCopy);
+        HeapFree(GetProcessHeap(), 0, pFontCopy);
+    }
+    return ret;
 }
 
 /***********************************************************************
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c
index 421a640..d223992 100644
--- a/dlls/gdi32/freetype.c
+++ b/dlls/gdi32/freetype.c
@@ -236,6 +236,8 @@ typedef struct tagFace {
     struct list entry;
     WCHAR *StyleName;
     char *file;
+    void *font_data_ptr;
+    DWORD font_data_size;
     FT_Long face_index;
     BOOL Italic;
     BOOL Bold;
@@ -708,6 +710,8 @@ static Face *find_face_from_filename(con
             continue;
         LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
         {
+            if (!face->file)
+                continue;
             file = strrchr(face->file, '/');
             if(!file)
                 file = face->file;
@@ -930,7 +934,7 @@ static WCHAR *get_familyname(FT_Face ft_
 
 #define ADDFONT_EXTERNAL_FONT 0x01
 #define ADDFONT_FORCE_BITMAP  0x02
-static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
+static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
 {
     FT_Face ft_face;
     TT_OS2 *pOS2;
@@ -948,8 +952,11 @@ #endif
     int i, bitmap_num, internal_leading;
     FONTSIGNATURE fs;
 
+    /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
+    assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
+
 #ifdef HAVE_CARBON_CARBON_H
-    if(!fake_family)
+    if(file && !fake_family)
     {
         char **mac_list = expand_mac_font(file);
         if(mac_list)
@@ -972,21 +979,30 @@ #endif /* HAVE_CARBON_CARBON_H */
     do {
         char *family_name = fake_family;
 
-        TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
-	if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
-	    WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
+        if (file)
+        {
+            TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
+            err = pFT_New_Face(library, file, face_index, &ft_face);
+        } else
+        {
+            TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
+            err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
+        }
+
+	if(err != 0) {
+	    WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
 	    return 0;
 	}
 
 	if(!FT_IS_SFNT(ft_face) && (FT_IS_SCALABLE(ft_face) || !(flags & ADDFONT_FORCE_BITMAP))) { /* for now we'll accept TT/OT or bitmap fonts*/
-	    WARN("Ignoring font %s\n", debugstr_a(file));
+	    WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
 	    pFT_Done_Face(ft_face);
 	    return 0;
 	}
 
         /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
         if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
-	    WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
+	    WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
 	    pFT_Done_Face(ft_face);
 	    return 0;
 	}
@@ -994,14 +1010,14 @@ #endif /* HAVE_CARBON_CARBON_H */
 	if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
 	   !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
            !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
-	    TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
-		  "Skipping this font.\n", debugstr_a(file));
+	    TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
+		  "Skipping this font.\n", debugstr_a(file), font_data_ptr);
 	    pFT_Done_Face(ft_face);
 	    return 0;
 	}
 
         if(!ft_face->family_name || !ft_face->style_name) {
-            TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
+            TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
             pFT_Done_Face(ft_face);
             return 0;
         }
@@ -1137,8 +1153,18 @@ #endif
             face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
             list_add_tail(&family->faces, &face->entry);
             face->StyleName = StyleW;
-            face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
-            strcpy(face->file, file);
+            if (file)
+            {
+                face->file = strdupA(file);
+                face->font_data_ptr = NULL;
+                face->font_data_size = 0;
+            }
+            else
+            {
+                face->file = NULL;
+                face->font_data_ptr = font_data_ptr;
+                face->font_data_size = font_data_size;
+            }
             face->face_index = face_index;
             face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
             face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
@@ -1198,6 +1224,11 @@ #endif
     return num_faces;
 }
 
+static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
+{
+    return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
+}
+
 static void DumpFontList(void)
 {
     Family *family;
@@ -1269,7 +1300,7 @@ static void LoadReplaceList(void)
                         TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
                               debugstr_w(face->StyleName), familyA);
                         /* Now add a new entry with the new family name */
-                        AddFontFileToList(face->file, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
+                        AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
                     }
                     break;
                 }
@@ -1713,6 +1744,26 @@ INT WineEngAddFontResourceEx(LPCWSTR fil
 }
 
 /*************************************************************
+ *    WineEngAddFontMemResourceEx
+ *
+ */
+HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
+{
+    if (ft_handle)  /* do it only if we have freetype up and running */
+    {
+        *pcFonts = AddFontToList(NULL, pbFont, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
+        /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
+         * For now return something unique but quite random
+         */
+        TRACE("Returning handle %lx\n", ((INT_PTR)pbFont)^0x87654321);
+        return (HANDLE)(((INT_PTR)pbFont)^0x87654321);
+    }
+
+    *pcFonts = 0;
+    return 0;
+}
+
+/*************************************************************
  *    WineEngRemoveFontResourceEx
  *
  */
@@ -2179,7 +2230,7 @@ static LONG calc_ppem_for_height(FT_Face
     return ppem;
 }
 
-static struct font_mapping *map_font( const char *name )
+static struct font_mapping *map_font_file( const char *name )
 {
     struct font_mapping *mapping;
     struct stat st;
@@ -2220,7 +2271,7 @@ error:
     return NULL;
 }
 
-static void unmap_font( struct font_mapping *mapping )
+static void unmap_font_file( struct font_mapping *mapping )
 {
     if (!--mapping->refcount)
     {
@@ -2232,20 +2283,32 @@ static void unmap_font( struct font_mapp
 
 static LONG load_VDMX(GdiFont*, LONG);
 
-static FT_Face OpenFontFile(GdiFont *font, char *file, FT_Long face_index, LONG width, LONG height)
+static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
 {
     FT_Error err;
     FT_Face ft_face;
+    void *data_ptr;
+    DWORD data_size;
 
-    TRACE("%s, %ld, %d x %d\n", debugstr_a(file), face_index, width, height);
+    TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
 
-    if (!(font->mapping = map_font( file )))
+    if (face->file)
     {
-        WARN("failed to map %s\n", debugstr_a(file));
-        return 0;
+        if (!(font->mapping = map_font_file( face->file )))
+        {
+            WARN("failed to map %s\n", debugstr_a(face->file));
+            return 0;
+        }
+        data_ptr = font->mapping->data;
+        data_size = font->mapping->size;
+    }
+    else
+    {
+        data_ptr = face->font_data_ptr;
+        data_size = face->font_data_size;
     }
 
-    err = pFT_New_Memory_Face(library, font->mapping->data, font->mapping->size, face_index, &ft_face);
+    err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
     if(err) {
         ERR("FT_New_Face rets %d\n", err);
 	return 0;
@@ -2343,7 +2406,7 @@ static void free_font(GdiFont *font)
     }
 
     if (font->ft_face) pFT_Done_Face(font->ft_face);
-    if (font->mapping) unmap_font( font->mapping );
+    if (font->mapping) unmap_font_file( font->mapping );
     HeapFree(GetProcessHeap(), 0, font->kern_pairs);
     HeapFree(GetProcessHeap(), 0, font->potm);
     HeapFree(GetProcessHeap(), 0, font->name);
@@ -2892,14 +2955,14 @@ found:
     else
         ret->charset = get_nearest_charset(face, &ret->codepage);
 
-    TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
-	  debugstr_w(face->StyleName), face->file, face->face_index);
+    TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
+	  debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
 
     if(!face->scalable) {
         width = face->size.x_ppem >> 6;
         height = face->size.y_ppem >> 6;
     }
-    ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
+    ret->ft_face = OpenFontFace(ret, face, width, height);
 
     if (!ret->ft_face)
     {
@@ -3034,7 +3097,7 @@ static void GetEnumStructs(Face *face, L
         width = face->size.x_ppem >> 6;
     }
     
-    if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
+    if (!(font->ft_face = OpenFontFace(font, face, width, height)))
     {
         free_font(font);
         return;
@@ -4133,7 +4196,7 @@ static BOOL load_child_font(GdiFont *fon
 {
     HFONTLIST *hfontlist;
     child->font = alloc_font();
-    child->font->ft_face = OpenFontFile(child->font, child->face->file, child->face->face_index, 0, -font->ppem);
+    child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
     if(!child->font->ft_face)
     {
         free_font(child->font);
@@ -4950,6 +5013,12 @@ INT WineEngRemoveFontResourceEx(LPCWSTR 
     return TRUE;
 }
 
+HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
+{
+    FIXME(":stub\n");
+    return NULL;
+}
+
 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
 {
     FIXME(":stub\n");
diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h
index 74cca26..c665373 100644
--- a/dlls/gdi32/gdi_private.h
+++ b/dlls/gdi32/gdi_private.h
@@ -421,6 +421,7 @@ extern HENHMETAFILE EMF_Create_HENHMETAF
 
 /* freetype.c */
 extern INT WineEngAddFontResourceEx(LPCWSTR, DWORD, PVOID);
+extern HANDLE WineEngAddFontMemResourceEx(PVOID, DWORD, PVOID, LPDWORD);
 extern GdiFont* WineEngCreateFontInstance(DC*, HFONT);
 extern BOOL WineEngDestroyFontInstance(HFONT handle);
 extern DWORD WineEngEnumFonts(LPLOGFONTW, FONTENUMPROCW, LPARAM);
diff --git a/include/wingdi.h b/include/wingdi.h
index 77d8d92..7d8c4a1 100644
--- a/include/wingdi.h
+++ b/include/wingdi.h
@@ -3274,6 +3274,7 @@ #define     AddFontResource WINELIB_NAME
 INT         WINAPI AddFontResourceExA(LPCSTR, DWORD, PVOID);
 INT         WINAPI AddFontResourceExW(LPCWSTR, DWORD, PVOID);
 #define     AddFontResourceEx WINELIB_NAME_AW(AddFontResourceEx)
+HANDLE      WINAPI AddFontMemResourceEx(PVOID, DWORD, PVOID, DWORD *);
 BOOL        WINAPI AlphaBlend(HDC,int,int,int,int,HDC,int,int,int,int,BLENDFUNCTION);
 BOOL        WINAPI AngleArc(HDC, INT, INT, DWORD, FLOAT, FLOAT);
 BOOL        WINAPI AnimatePalette(HPALETTE,UINT,UINT,const PALETTEENTRY*);
-- 
1.4.1


More information about the wine-patches mailing list