Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package fontforge for openSUSE:Factory 
checked in at 2026-06-28 21:04:57
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/fontforge (Old)
 and      /work/SRC/openSUSE:Factory/.fontforge.new.11887 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "fontforge"

Sun Jun 28 21:04:57 2026 rev:68 rq:1361919 version:20251009

Changes:
--------
--- /work/SRC/openSUSE:Factory/fontforge/fontforge.changes      2026-04-09 
16:10:18.742917259 +0200
+++ /work/SRC/openSUSE:Factory/.fontforge.new.11887/fontforge.changes   
2026-06-28 21:05:46.988555872 +0200
@@ -1,0 +2,41 @@
+Tue Jun 16 08:51:27 UTC 2026 - Cliff Zhao <[email protected]>
+
+- Add fontforge-fix-buffer-overflow-in-SCDefWidthVal.patch:
+  Backport e5f110c9 from upstream, fix buffer overflow in
+  SCDefWidthVal() function.
+
+-------------------------------------------------------------------
+Tue Jun 16 07:04:09 UTC 2026 - Cliff Zhao <[email protected]>
+
+- Add fontforge-fix-crash-in-LoadPluginMetadata.patch:
+  Backport 763b8fc6 from upstream, fix crash in LoadPluginMetadata
+  when distribution not found.
+  * Don't DECREF borrowed reference from PyDict_GetItemString
+  * Fix memory leak: DECREF globals and locals dictionaries
+  * Handle Py_None return (not just NULL) when no distribution matches
+  * Print original Python exception if present, then set formatted error
+
+-------------------------------------------------------------------
+Tue Jun 16 06:55:18 UTC 2026 - Cliff Zhao <[email protected]>
+
+- Add fontforge-fix-crash-in-LoadPluginMetadata-shim01-fbc4114e.patch:
+  Backport fbc4114e from upstream, Use importlib in plugin manager.
+  This is for support the following patch to fix LoadPluginMetadata
+  crash.
+
+-------------------------------------------------------------------
+Tue Jun 16 06:15:22 UTC 2026 - Cliff Zhao <[email protected]>
+
+- Add fontforge-fix-memory-allocation-in-utf8toutf7-copy.patch:
+  Backport a4533e93 from upstream, fix memory allocation in
+  utf8toutf7_copy() function.
+
+-------------------------------------------------------------------
+Tue Jun 16 05:44:04 UTC 2026 - Cliff Zhao <[email protected]>
+
+- Add fontforge-fix-crashes-on-importing-dfontNFNT-fonts.patch:
+  Backport cb443433e from upstream, fix crashes on importing
+  Mac-style dfont/NFNT bitmap fonts with some legal (but unusual?)
+  values.
+
+-------------------------------------------------------------------

New:
----
  fontforge-fix-buffer-overflow-in-SCDefWidthVal.patch
  fontforge-fix-crash-in-LoadPluginMetadata-shim01-fbc4114e.patch
  fontforge-fix-crash-in-LoadPluginMetadata.patch
  fontforge-fix-crashes-on-importing-dfontNFNT-fonts.patch
  fontforge-fix-memory-allocation-in-utf8toutf7-copy.patch

----------(New B)----------
  New:
- Add fontforge-fix-buffer-overflow-in-SCDefWidthVal.patch:
  Backport e5f110c9 from upstream, fix buffer overflow in
  New:
- Add fontforge-fix-crash-in-LoadPluginMetadata-shim01-fbc4114e.patch:
  Backport fbc4114e from upstream, Use importlib in plugin manager.
  New:
- Add fontforge-fix-crash-in-LoadPluginMetadata.patch:
  Backport 763b8fc6 from upstream, fix crash in LoadPluginMetadata
  New:
- Add fontforge-fix-crashes-on-importing-dfontNFNT-fonts.patch:
  Backport cb443433e from upstream, fix crashes on importing
  New:
- Add fontforge-fix-memory-allocation-in-utf8toutf7-copy.patch:
  Backport a4533e93 from upstream, fix memory allocation in
----------(New E)----------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ fontforge.spec ++++++
--- /var/tmp/diff_new_pack.shpItz/_old  2026-06-28 21:05:48.048591590 +0200
+++ /var/tmp/diff_new_pack.shpItz/_new  2026-06-28 21:05:48.052591725 +0200
@@ -49,6 +49,16 @@
 Patch11:        fontforge-fix-multiple-crashes-in-Multiple-Masters.patch
 # PATCH-FIX-UPSTREAM fontforge-CVE-2025-15270.patch CVE-2025-15270 
ZDI-CAN-28563 ZDI-25-1194 bsc#1256031 -- Add validation to check for negative 
kern class name length values.
 Patch12:        fontforge-CVE-2025-15270.patch
+# PATCH-FIX-UPSTREAM fontforge-fix-crashes-on-importing-dfontNFNT-fonts.patch 
[email protected] -- Fix crashes on importing Mac-style dfont/NFNT bitmap fonts 
with some legal (but unusual?) values.
+Patch13:        fontforge-fix-crashes-on-importing-dfontNFNT-fonts.patch
+# PATCH-FIX-UPSTREAM fontforge-fix-memory-allocation-in-utf8toutf7-copy.patch 
[email protected] -- Fix memory allocation in utf8toutf7_copy().
+Patch14:        fontforge-fix-memory-allocation-in-utf8toutf7-copy.patch
+# PATCH-FIX-UPSTREAM 
fontforge-fix-crash-in-LoadPluginMetadata-shim01-fbc4114e.patch [email protected] 
-- Use importlib in plugin manager, support following fix LoadPluginMetadata 
crash.
+Patch15:        fontforge-fix-crash-in-LoadPluginMetadata-shim01-fbc4114e.patch
+# PATCH-FIX-UPSTREAM fontforge-fix-crash-in-LoadPluginMetadata.patch 
[email protected] -- Fix crash in LoadPluginMetadata when distribution not found, 
Fix memory leak: DECREF globals and locals dictionaries.
+Patch16:        fontforge-fix-crash-in-LoadPluginMetadata.patch
+# PATCH-FIX-UPSTREAM fontforge-fix-buffer-overflow-in-SCDefWidthVal.patch 
[email protected] -- Fix buffer overflow in SCDefWidthVal().
+Patch17:        fontforge-fix-buffer-overflow-in-SCDefWidthVal.patch
 BuildRequires:  cairo-devel
 BuildRequires:  cmake
 BuildRequires:  fdupes

++++++ fontforge-fix-buffer-overflow-in-SCDefWidthVal.patch ++++++
>From e5f110c9a99f7a640ca50b8cb137f85fd8872eab Mon Sep 17 00:00:00 2001
From: Maxim Iorsh <[email protected]>
Date: Wed, 6 May 2026 22:43:52 +0300
Subject: [PATCH] Fix buffer overflow in SCDefWidthVal() (#5798)

---
 fontforgeexe/fvmetricsdlg.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/fontforgeexe/fvmetricsdlg.c b/fontforgeexe/fvmetricsdlg.c
index 322bfd692..2be119681 100644
--- a/fontforgeexe/fvmetricsdlg.c
+++ b/fontforgeexe/fvmetricsdlg.c
@@ -293,7 +293,7 @@ static void FVCreateWidth( void *_fv,SplineChar* _sc,void 
(*doit)(CreateWidthDat
     GDrawSetVisible(cwd.gw,false);
 }
 
-static void BCDefWidthVal(char *buf,BDFChar *bc, FontView *fv, enum widthtype 
wtype) {
+static void BCDefWidthVal(char buf[12],BDFChar *bc, FontView *fv, enum 
widthtype wtype) {
     IBounds bb;
 
     if ( wtype==wt_width )
@@ -311,7 +311,7 @@ static void BCDefWidthVal(char *buf,BDFChar *bc, FontView 
*fv, enum widthtype wt
     }
 }
 
-static void SCDefWidthVal(char *buf,SplineChar *sc, enum widthtype wtype) {
+static void SCDefWidthVal(char buf[12],SplineChar *sc, enum widthtype wtype) {
     DBounds bb;
 
     if ( wtype==wt_width )
@@ -359,7 +359,7 @@ static void CVDoit(CreateWidthData *wd) {
 }
 
 void CVSetWidth(CharView *cv,enum widthtype wtype) {
-    char buf[10];
+    char buf[12];
 
     SCDefWidthVal(buf,cv->b.sc,wtype);
     FVCreateWidth(cv,cv->b.sc,CVDoit,wtype,buf);
@@ -367,7 +367,7 @@ void CVSetWidth(CharView *cv,enum widthtype wtype) {
 
 
 void GenericVSetWidth(FontView *fv,SplineChar* sc,enum widthtype wtype) {
-    char buf[10];
+    char buf[12];
 
     SCDefWidthVal(buf,sc,wtype);
     FVCreateWidth(fv,sc,GenericVDoit,wtype,buf);
-- 
2.49.0


++++++ fontforge-fix-crash-in-LoadPluginMetadata-shim01-fbc4114e.patch ++++++
>From fbc4114e1af657b0889f78d24f70c4d56937d189 Mon Sep 17 00:00:00 2001
From: Maxim Iorsh <[email protected]>
Date: Sat, 22 Nov 2025 20:19:10 +0200
Subject: [PATCH] Use importlib in plugin manager (#5643)

---
 fontforge/plugin.c      | 192 +++++++++++++++++++++++++++++-----------
 fontforgeexe/pluginui.c |   3 +-
 2 files changed, 140 insertions(+), 55 deletions(-)

diff --git a/fontforge/plugin.c b/fontforge/plugin.c
index 35ffb3016..54de15501 100644
--- a/fontforge/plugin.c
+++ b/fontforge/plugin.c
@@ -285,28 +285,144 @@ static void ReimportPlugins() {
     }
 }
 
-static bool DiscoverPlugins(int do_import) {
-    int do_ask = false;
-    PluginEntry *pe;
-    GList_Glib *i;
-    PyObject *str, *str2, *iter, *tmp, *tmp2, *entrypoint;
-    PyObject *pkgres = PyImport_ImportModule("pkg_resources");
-    if (pkgres == NULL || !PyObject_HasAttrString(pkgres, 
"iter_entry_points")) {
-        LogError(_("Core python package 'pkg_resources' not found: Cannot 
discover plugins"));
+static PyObject *GetPluginEntryPoints() {
+    PyObject *iter = NULL, *all_eps = NULL;
+    PyObject *entry_points = NULL;
+
+    PyObject *importlib = PyImport_ImportModule("importlib.metadata");
+    if (!importlib) {
+        PyErr_Clear();
+        LogError(_("Core python package 'importlib.metadata' not found: Cannot 
discover plugins"));
+        return NULL;
+    }
+    if (!PyObject_HasAttrString(importlib, "entry_points")) {
+        LogError(_("Method 'entry_points()' not found in module 
'importlib.metadata'"));
        PyErr_Clear();
-        return false;
+        Py_DECREF(importlib);
+        return NULL;
+    }
+    all_eps = PyObject_CallMethod(importlib, "entry_points", NULL);
+
+    /* The object returned from importlib.metadata.entry_points() varies 
between versions*/
+    if (PyDict_Check(all_eps)) {
+       /* entry_points is a dictionary of entry point groups */
+       entry_points = PyDict_GetItemString(all_eps, "fontforge_plugin");
+       if (!entry_points) {
+           /* No FontForge plugins found */
+           PyErr_Clear();
+            return NULL;
+       }
+    } else {
+        /* all_eps is an EntryPoints object. Call 
all_eps.select(group="fontforge_plugin") */
+        PyObject *select_method = PyObject_GetAttrString(all_eps, "select");
+        PyObject *kw_args = Py_BuildValue("{s,s}", "group", 
"fontforge_plugin");
+        entry_points = PyObject_Call(select_method, PyTuple_New(0), kw_args);
+        Py_DECREF(select_method);
+        Py_DECREF(kw_args);
+        if (!entry_points) {
+            LogError(_("Failed to retrieve plugin entry points"));
+           PyErr_Print();
+            return NULL;
+        }
     }
-    str = PyUnicode_FromString("iter_entry_points");
-    str2 = PyUnicode_FromString("fontforge_plugin");
-    iter = PyObject_CallMethodObjArgs(pkgres, str, str2, NULL);
-    if (!PyIter_Check(iter)) {
+
+    Py_DECREF(importlib);
+
+    iter = PyObject_GetIter(entry_points);
+    if (!iter || !PyIter_Check(iter)) {
+       PyErr_Clear();
         LogError(_("Could not iterate 'fontforge_plugin' entry points."));
-        return false;
+        Py_XDECREF(iter);
+        return NULL;
+    }
+
+    return iter;
+}
+
+static void RetrieveStringItem(PyObject* obj, const char* key, char** p_value) 
{
+    PyObject* str = PyUnicode_FromString(key);
+    PyObject* val = PyObject_GetItem(obj, str);
+    if (val) {
+        free(*p_value);
+        *p_value = copy(PyUnicode_AsUTF8(val));
+    }
+    Py_XDECREF(str);
+    Py_XDECREF(val);
+}
+
+/* Retrieve name, URL, and summary of the plugin */
+static void LoadPluginMetadata(PluginEntry* pe) {
+    PyObject *globals = PyDict_New(), *locals = PyDict_New();
+    PyObject *dist = NULL, *function_args = NULL;
+
+    /* The `EntryPoint.dist` attribute is available starting with Python 3.10.
+     * To support Python 3.8+ we resort to the ugly but more uniform method of
+     * retrieving all `Distribution` objects and traversing them until we find
+     * one which points to our `EntryPoint` object. */
+    const char* function_string =
+        "def load_plugin_metadata(entrypoint):\n"
+        "    import importlib.metadata\n"
+        "    all_dists = importlib.metadata.distributions()\n"
+        "    for dist in all_dists:\n"
+        "        dist_eps = dist.entry_points\n"
+        "        for ep in dist_eps:\n"
+        "            if ep == entrypoint:\n"
+        "                return dist\n"
+        "    return None\n";
+
+    /* Execute the function definition */
+    if (PyRun_String(function_string, Py_file_input, globals, locals) == NULL) 
{
+        Py_DECREF(globals);
+        Py_DECREF(locals);
+        return;
+    }
+
+    /* Retrieve the function object */
+    PyObject* func = PyDict_GetItemString(locals, "load_plugin_metadata");
+    if (func == NULL || !PyCallable_Check(func)) {
+        PyErr_SetString(PyExc_RuntimeError, "Could not find the function");
+        Py_DECREF(globals);
+        Py_DECREF(locals);
+        return;
+    }
+
+    /* Call the function */
+    function_args = PyTuple_Pack(1, pe->entrypoint);
+    if (function_args != NULL) {
+        dist = PyObject_Call(func, function_args, NULL);
+    }
+    Py_XDECREF(func);
+    Py_XDECREF(function_args);
+
+    if (dist == NULL) {
+        PyErr_Print();
+        PyErr_SetString(PyExc_RuntimeError, "Could not retrieve distribution");
+        return;
+    }
+
+    if (PyObject_HasAttrString(dist, "metadata")) {
+        PyObject* metadata = PyObject_GetAttrString(dist, "metadata");
+
+       RetrieveStringItem(metadata, "Home-page", &pe->package_url);
+       RetrieveStringItem(metadata, "Name", &pe->package_name);
+       RetrieveStringItem(metadata, "Summary", &pe->summary);
+        Py_XDECREF(metadata);
+    }
+
+    Py_XDECREF(dist);
+}
+
+static bool DiscoverPlugins(int do_import) {
+    int do_ask = false;
+    PluginEntry *pe = NULL;
+    GList_Glib *i;
+    PyObject *str, *str2, *iter, *entrypoint;
+
+    iter = GetPluginEntryPoints();
+    if (iter == NULL) {
+       return false;
     }
-    Py_DECREF(str);
-    Py_DECREF(str2);
 
-    PyObject *getmetastr = PyUnicode_FromString("get_metadata_lines");
     while ((entrypoint = PyIter_Next(iter))) {
         // Find name and module_name
         str = PyObject_GetAttrString(entrypoint, "name");
@@ -316,7 +432,7 @@ static bool DiscoverPlugins(int do_import) {
             PyErr_Clear();
             continue;
         }
-        str2 = PyObject_GetAttrString(entrypoint, "module_name");
+        str2 = PyObject_GetAttrString(entrypoint, "value");
         const char *modname = PyUnicode_AsUTF8(str2);
         if (modname == NULL) {
             Py_XDECREF(str);
@@ -341,8 +457,8 @@ static bool DiscoverPlugins(int do_import) {
         }
         Py_DECREF(str);
         Py_DECREF(str2);
-        str = PyObject_GetAttrString(entrypoint, "attrs");
-        if (str == NULL) {
+        str = PyObject_GetAttrString(entrypoint, "attr");
+        if (str == NULL || str == Py_None) {
             PyErr_Clear();
         } else {
             if (pe->attrs) {
@@ -355,43 +471,13 @@ static bool DiscoverPlugins(int do_import) {
         pe->is_present = true;
         Py_XDECREF(pe->entrypoint);
         pe->entrypoint = entrypoint;
-        // Extract project URL from package data
-        PyObject *dist = PyObject_GetAttrString(entrypoint, "dist");
-        if (dist != NULL) {
-            tmp = PyObject_GetAttrString(dist, "PKG_INFO");
-            tmp2 = PyObject_CallMethodObjArgs(dist, getmetastr, tmp, NULL);
-            Py_DECREF(tmp);
-            if (PyIter_Check(tmp2)) {
-                while ((str = PyIter_Next(tmp2))) {
-                    const char *metaline = PyUnicode_AsUTF8(str);
-                    // printf("%s\n", metaline);
-                    if (strncmp(metaline, "Home-page: ", 11) == 0) {
-                        if (pe->package_url != NULL) {
-                            free(pe->package_url);
-                        }
-                        pe->package_url = copy(metaline + 11);
-                    } else if (strncmp(metaline, "Name: ", 6) == 0) {
-                        if (pe->package_name != NULL) {
-                            free(pe->package_name);
-                        }
-                        pe->package_name = copy(metaline + 6);
-                    } else if (strncmp(metaline, "Summary: ", 9) == 0) {
-                        if (pe->summary != NULL) {
-                            free(pe->summary);
-                        }
-                        pe->summary = copy(metaline + 9);
-                    }
-                    Py_DECREF(str);
-                }
-            }
-            Py_DECREF(tmp2);
-        }
+
+       LoadPluginMetadata(pe);
         if (do_import && pe->startup_mode == sm_on) {
             LoadPlugin(pe);
         } else if (do_import && pe->startup_mode == sm_ask) {
             do_ask = true;
         }
-        Py_XDECREF(dist);
     }
     if (PyErr_Occurred()) {
         PyErr_Print();
@@ -403,8 +489,6 @@ static bool DiscoverPlugins(int do_import) {
         }
     }
     Py_DECREF(iter);
-    Py_DECREF(getmetastr);
-    Py_DECREF(pkgres);
     return do_ask;
 }
 
diff --git a/fontforgeexe/pluginui.c b/fontforgeexe/pluginui.c
index fa7f36665..dda25430d 100644
--- a/fontforgeexe/pluginui.c
+++ b/fontforgeexe/pluginui.c
@@ -164,7 +164,7 @@ static void PluginInfoDlg(PluginEntry *pe) {
     gcd[k++].creator = GLabelCreate;
     hvgrid[3][0] = &gcd[k - 1];
 
-    label[k].text = (unichar_t *) pe->attrs;
+    label[k].text = (unichar_t *)(pe->attrs == NULL ? "" : pe->attrs);
     label[k].text_is_1byte = true;
     gcd[k].gd.label = &label[k];
     gcd[k].gd.flags = gg_enabled | gg_visible;
@@ -522,6 +522,7 @@ static int PLUG_PluginOp(GGadget *g, GEvent *e) {
     } else if (cid == CID_Revert) {
         FigurePluginList(d);
     }
+    GGadgetRedraw(list);
     return true;
 }
 
-- 
2.49.0


++++++ fontforge-fix-crash-in-LoadPluginMetadata.patch ++++++
>From 763b8fc6d05815282b83f9668d23cd2fe58e310a Mon Sep 17 00:00:00 2001
From: skef <[email protected]>
Date: Sun, 15 Feb 2026 22:13:10 -0800
Subject: [PATCH] Fix crash in LoadPluginMetadata when distribution not found
 (#5755)

- Don't DECREF borrowed reference from PyDict_GetItemString
- Fix memory leak: DECREF globals and locals dictionaries
- Handle Py_None return (not just NULL) when no distribution matches
- Print original Python exception if present, then set formatted error

Fixes #5754

Co-authored-by: Claude Opus 4.5 <[email protected]>
---
 fontforge/plugin.c | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/fontforge/plugin.c b/fontforge/plugin.c
index 54de15501..34ec78679 100644
--- a/fontforge/plugin.c
+++ b/fontforge/plugin.c
@@ -390,13 +390,20 @@ static void LoadPluginMetadata(PluginEntry* pe) {
     function_args = PyTuple_Pack(1, pe->entrypoint);
     if (function_args != NULL) {
         dist = PyObject_Call(func, function_args, NULL);
+        Py_DECREF(function_args);
     }
-    Py_XDECREF(func);
-    Py_XDECREF(function_args);
+    /* Note: func is a borrowed reference from PyDict_GetItemString, don't 
DECREF */
 
-    if (dist == NULL) {
-        PyErr_Print();
-        PyErr_SetString(PyExc_RuntimeError, "Could not retrieve distribution");
+    Py_DECREF(globals);
+    Py_DECREF(locals);
+
+    if (dist == NULL || dist == Py_None) {
+        if (dist == NULL) {
+            PyErr_Print();
+        }
+        PyErr_Format(PyExc_RuntimeError,
+            "Could not retrieve distribution for plugin '%s'", pe->name);
+        Py_XDECREF(dist);
         return;
     }
 
@@ -409,7 +416,7 @@ static void LoadPluginMetadata(PluginEntry* pe) {
         Py_XDECREF(metadata);
     }
 
-    Py_XDECREF(dist);
+    Py_DECREF(dist);
 }
 
 static bool DiscoverPlugins(int do_import) {
-- 
2.49.0


++++++ fontforge-fix-crashes-on-importing-dfontNFNT-fonts.patch ++++++
>From cb443433e907588d2aa610172031b0c3899edb3c Mon Sep 17 00:00:00 2001
From: Rob Hagemans <[email protected]>
Date: Sun, 1 Feb 2026 21:20:30 +0000
Subject: [PATCH] Fix crashes on importing Mac-style dfont/NFNT bitmap fonts
 with some legal (but unusual?) values  (#5246)

---
 fontforge/macbinary.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/fontforge/macbinary.c b/fontforge/macbinary.c
index 964ed25fa..5532a4a7b 100644
--- a/fontforge/macbinary.c
+++ b/fontforge/macbinary.c
@@ -2348,7 +2348,7 @@ static FOND *BuildFondList(FILE *f,long rlistpos,int 
subcnt,long rdata_pos,
                cur->stylewidths[j].style = getushort(f);
                cur->stylewidths[j].widthtab = 
malloc((cur->last-cur->first+3)*sizeof(short));
                for ( k=cur->first; k<=cur->last+2; ++k )
-                   cur->stylewidths[j].widthtab[k] = getushort(f);
+                   cur->stylewidths[j].widthtab[k-cur->first] = getushort(f);
            }
        }
        if ( kernoff!=0 && (flags&ttf_onlykerns) ) {
@@ -2395,13 +2395,13 @@ static FOND *BuildFondList(FILE *f,long rlistpos,int 
subcnt,long rdata_pos,
            continue;           /* this style doesn't exist */
                format = stringoffsets[j]-1;
                stringlen = strings[0][0];
-               if ( format!=0 )
+               if ( format>0 )
                    for ( k=0; k<strings[format][0]; ++k )
                        stringlen += strings[ strings[format][k+1]-1 ][0];
                pt = cur->psnames[j] = malloc(stringlen+1);
                strcpy(pt,strings[ 0 ]+1);
                pt += strings[ 0 ][0];
-               if ( format!=0 )
+               if ( format>0 )
                    for ( k=0; k<strings[format][0]; ++k ) {
                        strcpy(pt,strings[ strings[format][k+1]-1 ]+1);
                        pt += strings[ strings[format][k+1]-1 ][0];
-- 
2.49.0


++++++ fontforge-fix-memory-allocation-in-utf8toutf7-copy.patch ++++++
>From a4533e9301910cc40640192fb5a2a36c31b52053 Mon Sep 17 00:00:00 2001
From: Maxim Iorsh <[email protected]>
Date: Sat, 14 Feb 2026 20:10:35 +0200
Subject: [PATCH] Fix memory allocation in utf8toutf7_copy() (#5745)

---
 fontforge/sfd.c | 81 ++++++++++++++-----------------------------------
 1 file changed, 23 insertions(+), 58 deletions(-)

diff --git a/fontforge/sfd.c b/fontforge/sfd.c
index fdbb0f3f4..270747274 100644
--- a/fontforge/sfd.c
+++ b/fontforge/sfd.c
@@ -213,54 +213,41 @@ void SFDDumpUTF7Str(FILE *sfd, const char *str) {
 char *utf8toutf7_copy(const char *_str) {
     uint16_t ch;
     int prev_cnt=0, prev=0, in=0;
-    int i, len;
+    int len = 0;
     char *ret=NULL, *ostr=NULL;
     uint16_t *utf16_str, *pt;
 
     if ( _str==NULL )
         return( NULL );
 
-    utf16_str = utf82utf16_copy(_str);
+    pt = utf16_str = utf82utf16_copy(_str);
+    while ( *pt++!='\0' )
+       ++len;
+    /* 5x buffer is guaranteed to suffice for UTF-7 encoded string. */
+    ostr = ret = malloc(5 * len+1);
 
-    for ( i=0; i<2; ++i ) {
         pt = utf16_str;
-       len= prev_cnt= prev= in=0;
+       prev_cnt= prev= in=0;
        while ( (ch = *pt++)!='\0' ) {
            if ( ch<127 && ch!='\n' && ch!='\r' && ch!='\\' && ch!='~' &&
                    ch!='+' && ch!='=' && ch!='"' ) {
                if ( prev_cnt!=0 ) {
-                   if ( i ) {
-                       prev<<= (prev_cnt==1?16:8);
-                       ostr = base64_encode(ostr,prev);
-                       prev_cnt=prev=0;
-                   } else
-                       len += 4;
+                   prev<<= (prev_cnt==1?16:8);
+                   ostr = base64_encode(ostr,prev);
+                   prev_cnt=prev=0;
                }
                if ( in ) {
-                   if ( inbase64[ch]!=-1 || ch=='-' ) {
-                       if ( i )
-                           *ostr++ = '-';
-                       else
-                           ++len;
-                   }
+                   if ( inbase64[ch]!=-1 || ch=='-' )
+                       *ostr++ = '-';
                    in = 0;
                }
-               if ( i )
-                   *ostr++ = ch;
-               else
-                   ++len;
+               *ostr++ = ch;
            } else if ( ch=='+' && !in ) {
-               if ( i ) {
-                   *ostr++ = '+';
-                   *ostr++ = '-';
-               } else
-                   len += 2;
+               *ostr++ = '+';
+               *ostr++ = '-';
            } else if ( prev_cnt== 0 ) {
                if ( !in ) {
-                   if ( i )
-                       *ostr++ = '+';
-                   else
-                       ++len;
+                   *ostr++ = '+';
                    in = 1;
                }
                prev = ch;
@@ -268,21 +255,13 @@ char *utf8toutf7_copy(const char *_str) {
            } else if ( prev_cnt==2 ) {
                prev<<=8;
                prev += (ch>>8)&0xff;
-               if ( i ) {
-                   ostr = base64_encode(ostr,prev);
-                   prev_cnt=prev=0;
-               } else
-                   len += 4;
+               ostr = base64_encode(ostr,prev);
                prev = (ch&0xff);
                prev_cnt=1;
            } else {
                prev<<=16;
                prev |= ch;
-               if ( i ) {
-                   ostr = base64_encode(ostr,prev);
-                   prev_cnt=prev=0;
-               } else
-                   len += 4;
+               ostr = base64_encode(ostr,prev);
                prev_cnt = prev = 0;
            }
        }
@@ -294,32 +273,18 @@ char *utf8toutf7_copy(const char *_str) {
            output 4 chars. */
        if ( prev_cnt==2 ) {
            prev<<=8;
-           if ( i ) {
-               ostr = base64_encode(ostr,prev);
-               prev_cnt=prev=0;
-           } else
-               len += 4;
+           ostr = base64_encode(ostr,prev);
        } else if ( prev_cnt==1 ) {
            prev<<=16;
-           if ( i ) {
-               ostr = base64_encode(ostr,prev);
-               prev_cnt=prev=0;
-           } else
-               len += 4;
+           ostr = base64_encode(ostr,prev);
        }
         /* Base64 block can optionally end with a hyphen '-'. We omit it at the
            end of the encoded string to preserve the existing SFD convention. 
*/
         /*
-       if ( in ) {
-           if ( i )
-               *ostr++ = '-';
-           else
-               ++len;
-       }
+       if ( in )
+           *ostr++ = '-';
         */
-       if ( i==0 )
-           ostr = ret = malloc(len+1);
-    }
+
     *ostr = '\0';
     free(utf16_str);
 return( ret );
-- 
2.49.0

Reply via email to