notepad: Detect if saving will lose information.
This commit is contained in:
parent
67766392bf
commit
84fd1c84f8
|
@ -131,4 +131,11 @@ memory."
|
||||||
|
|
||||||
STRING_UNICODE_LE, "Unicode (UTF-16)"
|
STRING_UNICODE_LE, "Unicode (UTF-16)"
|
||||||
STRING_UNICODE_BE, "Unicode (UTF-16 big-endian)"
|
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);
|
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:
|
* Returns:
|
||||||
* TRUE - if file exists
|
* TRUE - if file exists
|
||||||
|
@ -158,8 +175,30 @@ BOOL FileExists(LPCWSTR szFilename)
|
||||||
return (hFile != INVALID_HANDLE_VALUE);
|
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;
|
int lenW;
|
||||||
WCHAR* textW;
|
WCHAR* textW;
|
||||||
|
@ -174,12 +213,12 @@ static VOID DoSaveFile(VOID)
|
||||||
if (!textW)
|
if (!textW)
|
||||||
{
|
{
|
||||||
ShowLastError();
|
ShowLastError();
|
||||||
return;
|
return SAVE_FAILED;
|
||||||
}
|
}
|
||||||
textW[0] = (WCHAR) 0xfeff;
|
textW[0] = (WCHAR) 0xfeff;
|
||||||
lenW = GetWindowTextW(Globals.hEdit, textW+1, lenW) + 1;
|
lenW = GetWindowTextW(Globals.hEdit, textW+1, lenW) + 1;
|
||||||
|
|
||||||
switch (Globals.encFile)
|
switch (enc)
|
||||||
{
|
{
|
||||||
case ENCODING_UTF16BE:
|
case ENCODING_UTF16BE:
|
||||||
byteswap_wide_string(textW, lenW);
|
byteswap_wide_string(textW, lenW);
|
||||||
|
@ -197,46 +236,54 @@ static VOID DoSaveFile(VOID)
|
||||||
{
|
{
|
||||||
ShowLastError();
|
ShowLastError();
|
||||||
HeapFree(GetProcessHeap(), 0, textW);
|
HeapFree(GetProcessHeap(), 0, textW);
|
||||||
return;
|
return SAVE_FAILED;
|
||||||
}
|
}
|
||||||
WideCharToMultiByte(CP_UTF8, 0, textW, lenW, pBytes, size, NULL, NULL);
|
WideCharToMultiByte(CP_UTF8, 0, textW, lenW, pBytes, size, NULL, NULL);
|
||||||
HeapFree(GetProcessHeap(), 0, textW);
|
HeapFree(GetProcessHeap(), 0, textW);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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);
|
size = WideCharToMultiByte(CP_ACP, 0, textW+1, lenW-1, NULL, 0, NULL, NULL);
|
||||||
pBytes = HeapAlloc(GetProcessHeap(), 0, size);
|
pBytes = HeapAlloc(GetProcessHeap(), 0, size);
|
||||||
if (!pBytes)
|
if (!pBytes)
|
||||||
{
|
{
|
||||||
ShowLastError();
|
ShowLastError();
|
||||||
HeapFree(GetProcessHeap(), 0, textW);
|
HeapFree(GetProcessHeap(), 0, textW);
|
||||||
return;
|
return SAVE_FAILED;
|
||||||
}
|
}
|
||||||
WideCharToMultiByte(CP_ACP, 0, textW+1, lenW-1, pBytes, size, NULL, NULL);
|
WideCharToMultiByte(CP_ACP, 0, textW+1, lenW-1, pBytes, size, NULL, NULL);
|
||||||
HeapFree(GetProcessHeap(), 0, textW);
|
HeapFree(GetProcessHeap(), 0, textW);
|
||||||
break;
|
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);
|
NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
if(hFile == INVALID_HANDLE_VALUE)
|
if(hFile == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
ShowLastError();
|
ShowLastError();
|
||||||
HeapFree(GetProcessHeap(), 0, pBytes);
|
HeapFree(GetProcessHeap(), 0, pBytes);
|
||||||
return;
|
return SAVE_FAILED;
|
||||||
}
|
}
|
||||||
if (!WriteFile(hFile, pBytes, size, &dwNumWrite, NULL))
|
if (!WriteFile(hFile, pBytes, size, &dwNumWrite, NULL))
|
||||||
{
|
{
|
||||||
ShowLastError();
|
ShowLastError();
|
||||||
CloseHandle(hFile);
|
CloseHandle(hFile);
|
||||||
HeapFree(GetProcessHeap(), 0, pBytes);
|
HeapFree(GetProcessHeap(), 0, pBytes);
|
||||||
return;
|
return SAVE_FAILED;
|
||||||
}
|
}
|
||||||
SetEndOfFile(hFile);
|
SetEndOfFile(hFile);
|
||||||
CloseHandle(hFile);
|
CloseHandle(hFile);
|
||||||
HeapFree(GetProcessHeap(), 0, pBytes);
|
HeapFree(GetProcessHeap(), 0, pBytes);
|
||||||
|
|
||||||
SendMessageW(Globals.hEdit, EM_SETMODIFY, FALSE, 0);
|
SendMessageW(Globals.hEdit, EM_SETMODIFY, FALSE, 0);
|
||||||
|
return SAVED_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -570,14 +617,20 @@ VOID DIALOG_FileOpen(VOID)
|
||||||
DoOpenFile(openfilename.lpstrFile, Globals.encOfnCombo);
|
DoOpenFile(openfilename.lpstrFile, Globals.encOfnCombo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return FALSE to cancel close */
|
||||||
BOOL DIALOG_FileSave(VOID)
|
BOOL DIALOG_FileSave(VOID)
|
||||||
{
|
{
|
||||||
if (Globals.szFileName[0] == '\0')
|
if (Globals.szFileName[0] == '\0')
|
||||||
return DIALOG_FileSaveAs();
|
return DIALOG_FileSaveAs();
|
||||||
else
|
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)
|
BOOL DIALOG_FileSaveAs(VOID)
|
||||||
|
@ -611,13 +664,23 @@ BOOL DIALOG_FileSaveAs(VOID)
|
||||||
Globals.encOfnCombo = Globals.encFile;
|
Globals.encOfnCombo = Globals.encFile;
|
||||||
Globals.bOfnIsOpenDialog = FALSE;
|
Globals.bOfnIsOpenDialog = FALSE;
|
||||||
|
|
||||||
if (GetSaveFileNameW(&saveas)) {
|
retry:
|
||||||
SetFileNameAndEncoding(szPath, Globals.encOfnCombo);
|
if (!GetSaveFileNameW(&saveas))
|
||||||
UpdateWindowCaption();
|
return FALSE;
|
||||||
DoSaveFile();
|
|
||||||
return TRUE;
|
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 {
|
typedef struct {
|
||||||
|
|
|
@ -88,6 +88,8 @@
|
||||||
#define STRING_UNICODE_LE 0x180
|
#define STRING_UNICODE_LE 0x180
|
||||||
#define STRING_UNICODE_BE 0x181
|
#define STRING_UNICODE_BE 0x181
|
||||||
|
|
||||||
|
#define STRING_LOSS_OF_UNICODE_CHARACTERS 0x182
|
||||||
|
|
||||||
/* Open/Save As dialog template */
|
/* Open/Save As dialog template */
|
||||||
#define IDD_OFN_TEMPLATE 0x190
|
#define IDD_OFN_TEMPLATE 0x190
|
||||||
#define IDC_OFN_ENCCOMBO 0x191
|
#define IDC_OFN_ENCCOMBO 0x191
|
||||||
|
|
Loading…
Reference in New Issue