From 78bdfe9e281f8276660a7b8bfbde5f46144cc3d0 Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Tue, 14 Jul 2015 21:24:07 +0000
Subject: [PATCH] Mac GUI crashes if an invalid UTF8 string is added to the
 recent files menu

---
 Fltk/graphicWindow.cpp | 32 ++++++++++++++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)

diff --git a/Fltk/graphicWindow.cpp b/Fltk/graphicWindow.cpp
index 76738b55f4..02dfc8b853 100644
--- a/Fltk/graphicWindow.cpp
+++ b/Fltk/graphicWindow.cpp
@@ -3514,6 +3514,28 @@ void graphicWindow::changeMessageFontSize(int incr)
   setMessageFontSize(_browser->textsize() + incr);
 }
 
+static bool check_utf8(const std::string &string)
+{
+  for (int i = 0, ix = string.length(); i < ix; i++){
+    int n;
+    int c = (unsigned char) string[i];
+    if (0x00 <= c && c <= 0x7f) n = 0; // 0bbbbbbb
+    else if ((c & 0xE0) == 0xC0) n = 1; // 110bbbbb
+    else if (c==0xed && i < (ix-1) && ((unsigned char)string[i+1] & 0xa0) == 0xa0)
+      return false; //U+d800 to U+dfff
+    else if ((c & 0xF0) == 0xE0) n = 2; // 1110bbbb
+    else if ((c & 0xF8) == 0xF0) n = 3; // 11110bbb
+    //else if (($c & 0xFC) == 0xF8) n=4; // 111110bb //byte 5, unnecessary in 4 byte UTF-8
+    //else if (($c & 0xFE) == 0xFC) n=5; // 1111110b //byte 6, unnecessary in 4 byte UTF-8
+    else return false;
+    for (int j = 0; j < n && i < ix; j++) { // n bytes matching 10bbbbbb follow ?
+      if ((++i == ix) || (((unsigned char)string[i] & 0xC0) != 0x80))
+        return false;
+    }
+  }
+  return true;
+}
+
 void graphicWindow::fillRecentHistoryMenu()
 {
 #if defined(__APPLE__)
@@ -3529,8 +3551,14 @@ void graphicWindow::fillRecentHistoryMenu()
 
   static char recent[10][256];
   for(int i = 0; i < 10; i++){
-    if(i < (int)CTX::instance()->recentFiles.size())
-      strcpy(recent[i], CTX::instance()->recentFiles[i].c_str());
+    if(i < (int)CTX::instance()->recentFiles.size()){
+      if(check_utf8(CTX::instance()->recentFiles[i]))
+         strcpy(recent[i], CTX::instance()->recentFiles[i].c_str());
+      else{
+        Msg::Info("Ignoring invalid General.RecentFile%d", i);
+        strcpy(recent[i], "");
+      }
+    }
     else
       strcpy(recent[i], "");
     table[4 + i].text = recent[i];
-- 
GitLab