[4/4] notepad: Detect if saving will lose information.

Alexander Scott-Johns alexander.scott.johns at googlemail.com
Mon Jun 29 19:25:46 CDT 2009


This is a (rebased) resend of patch 4 of my first attempt.

Original: http://www.winehq.org/pipermail/wine-patches/2009-June/074917.html

---
 programs/notepad/En.rc         |    7 +++
 programs/notepad/dialog.c      |   95 +++++++++++++++++++++++++++++++++------
 programs/notepad/notepad_res.h |    2 +
 3 files changed, 89 insertions(+), 15 deletions(-)
-------------- next part --------------
From cc65701e608b36bd326b97260de6127670102d3f Mon Sep 17 00:00:00 2001
From: Alexander Scott-Johns <alexander.scott.johns at googlemail.com>
Date: Tue, 30 Jun 2009 00:24:18 +0100
Subject: notepad: Detect if saving will lose information.

---
 programs/notepad/En.rc         |    7 +++
 programs/notepad/dialog.c      |   95 +++++++++++++++++++++++++++++++++------
 programs/notepad/notepad_res.h |    2 +
 3 files changed, 89 insertions(+), 15 deletions(-)

diff --git a/programs/notepad/En.rc b/programs/notepad/En.rc
index 8a2ceb8..444bc74 100644
--- a/programs/notepad/En.rc
+++ b/programs/notepad/En.rc
@@ -129,4 +129,11 @@ memory."
 
 STRING_UNICODE_LE,     "Unicode (UTF-16)"
 STRING_UNICODE_BE,     "Unicode (UTF-16 big-endian)"
+
+STRING_LOSS_OF_UNICODE_CHARACTERS,         "%s\n\
+This file contains Unicode characters which will be lost if \n\
+you save this file in the %s encoding. \n\
+To keep these characters, click Cancel, and then select \n\
+one of the Unicode options in the Encoding drop down list. \n\
+Continue?"
 }
diff --git a/programs/notepad/dialog.c b/programs/notepad/dialog.c
index 51ad695..c1127cf 100644
--- a/programs/notepad/dialog.c
+++ b/programs/notepad/dialog.c
@@ -142,6 +142,23 @@ static int AlertFileNotSaved(LPCWSTR szFileName)
      MB_ICONQUESTION|MB_YESNOCANCEL);
 }
 
+static int AlertUnicodeCharactersLost(LPCWSTR szFileName)
+{
+    WCHAR szMsgFormat[MAX_STRING_LEN];
+    WCHAR szEnc[MAX_STRING_LEN];
+    WCHAR szMsg[ARRAY_SIZE(szMsgFormat) + MAX_PATH + ARRAY_SIZE(szEnc)];
+    WCHAR szCaption[MAX_STRING_LEN];
+
+    LoadStringW(Globals.hInstance, STRING_LOSS_OF_UNICODE_CHARACTERS,
+                szMsgFormat, ARRAY_SIZE(szMsgFormat));
+    load_encoding_name(ENCODING_ANSI, szEnc, ARRAY_SIZE(szEnc));
+    wnsprintfW(szMsg, ARRAY_SIZE(szMsg), szMsgFormat, szFileName, szEnc);
+    LoadStringW(Globals.hInstance, STRING_NOTEPAD, szCaption,
+                ARRAY_SIZE(szCaption));
+    return MessageBoxW(Globals.hMainWnd, szMsg, szCaption,
+                       MB_OKCANCEL|MB_ICONEXCLAMATION);
+}
+
 /**
  * Returns:
  *   TRUE  - if file exists
@@ -158,8 +175,32 @@ BOOL FileExists(LPCWSTR szFilename)
    return (hFile != INVALID_HANDLE_VALUE);
 }
 
+static inline BOOL is_conversion_to_ansi_lossy(LPCWSTR textW, int lenW)
+{
+    BOOL ret = FALSE;
+    WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, textW, lenW, NULL, 0,
+                        NULL, &ret);
+    /* WCtoMB doesn't like flags when used with certain code pages. */
+    SetLastError(0);
+    return ret;
+}
 
-static VOID DoSaveFile(LPCWSTR szFileName, ENCODING enc)
+typedef enum
+{
+    SAVED_OK,
+    SAVE_FAILED,
+    SHOW_SAVEAS_DIALOG
+} SAVE_STATUS;
+
+/* szFileName is the filename to save under; enc is the encoding to use.
+ *
+ * If the function succeeds, it returns SAVED_OK.
+ * If the function fails, it returns SAVE_FAILED.
+ * If Unicode data could be lost due to conversion to a non-Unicode character
+ * set, a warning is displayed. The user can continue (and the function carries
+ * on), or cancel (and the function returns SHOW_SAVEAS_DIALOG).
+ */
+static SAVE_STATUS DoSaveFile(LPCWSTR szFileName, ENCODING enc)
 {
     int lenW;
     WCHAR* textW;
@@ -174,7 +215,7 @@ static VOID DoSaveFile(LPCWSTR szFileName, ENCODING enc)
     if (!textW)
     {
         ShowLastError();
-        return;
+        return SAVE_FAILED;
     }
     textW[0] = (WCHAR) 0xfeff;
     lenW = GetWindowTextW(Globals.hEdit, textW+1, lenW) + 1;
@@ -197,20 +238,27 @@ static VOID DoSaveFile(LPCWSTR szFileName, ENCODING enc)
         {
             ShowLastError();
             HeapFree(GetProcessHeap(), 0, textW);
-            return;
+            return SAVE_FAILED;
         }
         WideCharToMultiByte(CP_UTF8, 0, textW, lenW, pBytes, size, NULL, NULL);
         HeapFree(GetProcessHeap(), 0, textW);
         break;
 
     default:
+        if (is_conversion_to_ansi_lossy(textW+1, lenW-1)
+            && AlertUnicodeCharactersLost(szFileName) == IDCANCEL)
+        {
+            HeapFree(GetProcessHeap(), 0, textW);
+            return SHOW_SAVEAS_DIALOG;
+        }
+
         size = WideCharToMultiByte(CP_ACP, 0, textW+1, lenW-1, NULL, 0, NULL, NULL);
         pBytes = HeapAlloc(GetProcessHeap(), 0, size);
         if (!pBytes)
         {
             ShowLastError();
             HeapFree(GetProcessHeap(), 0, textW);
-            return;
+            return SAVE_FAILED;
         }
         WideCharToMultiByte(CP_ACP, 0, textW+1, lenW-1, pBytes, size, NULL, NULL);
         HeapFree(GetProcessHeap(), 0, textW);
@@ -223,20 +271,21 @@ static VOID DoSaveFile(LPCWSTR szFileName, ENCODING enc)
     {
         ShowLastError();
         HeapFree(GetProcessHeap(), 0, pBytes);
-        return;
+        return SAVE_FAILED;
     }
     if (!WriteFile(hFile, pBytes, size, &dwNumWrite, NULL))
     {
         ShowLastError();
         CloseHandle(hFile);
         HeapFree(GetProcessHeap(), 0, pBytes);
-        return;
+        return SAVE_FAILED;
     }
     SetEndOfFile(hFile);
     CloseHandle(hFile);
     HeapFree(GetProcessHeap(), 0, pBytes);
 
     SendMessageW(Globals.hEdit, EM_SETMODIFY, FALSE, 0);
+    return SAVED_OK;
 }
 
 /**
@@ -569,14 +618,20 @@ VOID DIALOG_FileOpen(VOID)
         DoOpenFile(openfilename.lpstrFile, Globals.encOfnCombo);
 }
 
-
+/* Return FALSE to cancel close */
 BOOL DIALOG_FileSave(VOID)
 {
     if (Globals.szFileName[0] == '\0')
         return DIALOG_FileSaveAs();
     else
-        DoSaveFile(Globals.szFileName, Globals.encFile);
-    return TRUE;
+    {
+        switch (DoSaveFile(Globals.szFileName, Globals.encFile))
+        {
+            case SAVED_OK:           return TRUE;
+            case SHOW_SAVEAS_DIALOG: return DIALOG_FileSaveAs();
+            default:                 return FALSE;
+        }
+    }
 }
 
 BOOL DIALOG_FileSaveAs(VOID)
@@ -610,13 +665,23 @@ BOOL DIALOG_FileSaveAs(VOID)
     Globals.encOfnCombo = Globals.encFile;
     Globals.bOfnIsOpenDialog = FALSE;
 
-    if (GetSaveFileNameW(&saveas)) {
-        SetFileNameAndEncoding(szPath, Globals.encOfnCombo);
-        UpdateWindowCaption();
-        DoSaveFile(szPath, Globals.encFile);
-        return TRUE;
+retry:
+    if (!GetSaveFileNameW(&saveas))
+        return FALSE;
+
+    switch (DoSaveFile(szPath, Globals.encOfnCombo))
+    {
+        case SAVED_OK:
+            SetFileNameAndEncoding(szPath, Globals.encOfnCombo);
+            UpdateWindowCaption();
+            return TRUE;
+
+        case SHOW_SAVEAS_DIALOG:
+            goto retry;
+
+        default:
+            return FALSE;
     }
-    return FALSE;
 }
 
 typedef struct {
diff --git a/programs/notepad/notepad_res.h b/programs/notepad/notepad_res.h
index 3122d98..e102109 100644
--- a/programs/notepad/notepad_res.h
+++ b/programs/notepad/notepad_res.h
@@ -85,6 +85,8 @@
 #define STRING_UNICODE_LE      0x180
 #define STRING_UNICODE_BE      0x181
 
+#define STRING_LOSS_OF_UNICODE_CHARACTERS 0x182
+
 /* Open/Save As dialog template */
 #define IDD_OFN_TEMPLATE       0x190
 #define IDC_OFN_ENCCOMBO       0x191
-- 
1.5.6.3


More information about the wine-patches mailing list