Commit 84fd1c84 authored by Alexander Scott-Johns's avatar Alexander Scott-Johns Committed by Alexandre Julliard

notepad: Detect if saving will lose information.

parent 67766392
......@@ -131,4 +131,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?"
}
......@@ -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,30 @@ 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);
return ret;
}
static VOID DoSaveFile(VOID)
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,12 +213,12 @@ static VOID DoSaveFile(VOID)
if (!textW)
{
ShowLastError();
return;
return SAVE_FAILED;
}
textW[0] = (WCHAR) 0xfeff;
lenW = GetWindowTextW(Globals.hEdit, textW+1, lenW) + 1;
switch (Globals.encFile)
switch (enc)
{
case ENCODING_UTF16BE:
byteswap_wide_string(textW, lenW);
......@@ -197,46 +236,54 @@ static VOID DoSaveFile(VOID)
{
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);
break;
}
hFile = CreateFileW(Globals.szFileName, GENERIC_WRITE, FILE_SHARE_WRITE,
hFile = CreateFileW(szFileName, GENERIC_WRITE, FILE_SHARE_WRITE,
NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
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;
}
/**
......@@ -570,14 +617,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();
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)
......@@ -611,13 +664,23 @@ BOOL DIALOG_FileSaveAs(VOID)
Globals.encOfnCombo = Globals.encFile;
Globals.bOfnIsOpenDialog = FALSE;
if (GetSaveFileNameW(&saveas)) {
retry:
if (!GetSaveFileNameW(&saveas))
return FALSE;
switch (DoSaveFile(szPath, Globals.encOfnCombo))
{
case SAVED_OK:
SetFileNameAndEncoding(szPath, Globals.encOfnCombo);
UpdateWindowCaption();
DoSaveFile();
return TRUE;
}
case SHOW_SAVEAS_DIALOG:
goto retry;
default:
return FALSE;
}
}
typedef struct {
......
......@@ -88,6 +88,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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment