Bletch <npwoods@mess.org>
- Implements the Encoding field when you save, allowing the user to save as
  ANSI, Unicode or UTF-8
- Invoking 'Save As' after saving or loading a file will default to the
  earlier filename
(minor changes by GvG, so mistakes are mine).
Modified: trunk/reactos/subsys/system/notepad/En.rc
Modified: trunk/reactos/subsys/system/notepad/dialog.c
Modified: trunk/reactos/subsys/system/notepad/main.h
Modified: trunk/reactos/subsys/system/notepad/notepad_res.h

Modified: trunk/reactos/subsys/system/notepad/En.rc
--- trunk/reactos/subsys/system/notepad/En.rc	2005-09-12 16:06:53 UTC (rev 17819)
+++ trunk/reactos/subsys/system/notepad/En.rc	2005-09-12 17:10:00 UTC (rev 17820)
@@ -94,6 +94,17 @@
 PUSHBUTTON    "&Help",       0x153,                180, 39, 40, 15, WS_TABSTOP
 }
 
+/* Dialog `Encoding' */
+DIALOG_ENCODING DIALOG 0, 0, 256, 26
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | 
+    WS_CAPTION | WS_SYSMENU
+FONT 8, "MS Shell Dlg"
+CAPTION "Encoding"
+{
+COMBOBOX        ID_ENCODING,54,0,156,80,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+LTEXT           "Encoding:",0x155,5,2,41,12
+}
+
 STRINGTABLE DISCARDABLE
 {
 STRING_PAGESETUP_HEADERVALUE,   "&n"        /* FIXME */
@@ -125,5 +136,8 @@
 STRING_OUT_OF_MEMORY,                   "Not enough memory to complete this \
 task. \nClose one or more applications to increase the amount of \nfree \
 memory."
-
+STRING_ANSI,                                    "ANSI"
+STRING_UNICODE,                                 "Unicode"
+STRING_UNICODE_BE,                              "Unicode (big endian)"
+STRING_UTF8,                                    "UTF-8"
 }

Modified: trunk/reactos/subsys/system/notepad/dialog.c
--- trunk/reactos/subsys/system/notepad/dialog.c	2005-09-12 16:06:53 UTC (rev 17819)
+++ trunk/reactos/subsys/system/notepad/dialog.c	2005-09-12 17:10:00 UTC (rev 17820)
@@ -139,8 +139,14 @@
 {
     HANDLE hFile;
     DWORD dwNumWrite;
-    LPSTR pTemp;
+    LPWSTR pTemp;
+    LPVOID pConverted;
     DWORD size;
+    BYTE bom[3];
+    int iBomSize = 0;
+    int iCodePage = -1;
+    int iNewSize;
+    int i;
 
     hFile = CreateFile(Globals.szFileName, GENERIC_WRITE, FILE_SHARE_WRITE,
                        NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
@@ -150,23 +156,82 @@
         return;
     }
 
-    size = GetWindowTextLengthA(Globals.hEdit) + 1;
-    pTemp = HeapAlloc(GetProcessHeap(), 0, size);
+    size = GetWindowTextLengthW(Globals.hEdit) + 1;
+    pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*pTemp));
     if (!pTemp)
     {
-	CloseHandle(hFile);
+        CloseHandle(hFile);
         ShowLastError();
         return;
     }
-    size = GetWindowTextA(Globals.hEdit, pTemp, size);
+    size = GetWindowTextW(Globals.hEdit, pTemp, size);
 
-    if (!WriteFile(hFile, pTemp, size, &dwNumWrite, NULL))
+    switch(Globals.iEncoding)
+    {
+        case ENCODING_ANSI:
+            iCodePage = CP_ACP;
+            break;
+
+        case ENCODING_UNICODE:
+            pConverted = pTemp;
+            iBomSize = 2;
+            bom[0] = 0xFF;
+            bom[1] = 0xFE;
+            break;
+
+        case ENCODING_UNICODE_BE:
+            pConverted = pTemp;
+            iBomSize = 2;
+            bom[0] = 0xFE;
+            bom[1] = 0xFF;
+
+            /* flip the endianness */
+            for (i = 0; i < size; i++)
+            {
+                pTemp[i] = ((pTemp[i] & 0x00FF) << 8)
+                           | ((pTemp[i] & 0xFF00) >> 8);
+            }
+            break;
+
+        case ENCODING_UTF8:
+            iCodePage = CP_UTF8;
+            iBomSize = 3;
+            bom[0] = 0xEF;
+            bom[1] = 0xBB;
+            bom[2] = 0xBF;
+            break;
+    }
+
+    if (iCodePage >= 0)
+    {
+        iNewSize = WideCharToMultiByte(iCodePage, 0, pTemp, size, NULL, 0, NULL, NULL);
+        pConverted = HeapAlloc(GetProcessHeap(), 0, iNewSize);
+        if (!pConverted)
+        {
+            HeapFree(GetProcessHeap(), 0, pTemp);
+            CloseHandle(hFile);
+            ShowLastError();
+            return;
+        }
+        WideCharToMultiByte(iCodePage, 0, pTemp, size, pConverted, iNewSize, NULL, NULL);
+    }
+    else
+    {
+        iNewSize = size * sizeof(WCHAR);
+    }
+
+    if ((iBomSize > 0) && !WriteFile(hFile, bom, iBomSize, &dwNumWrite, NULL))
         ShowLastError();
+    else if (!WriteFile(hFile, pConverted, iNewSize, &dwNumWrite, NULL))
+        ShowLastError();
     else
         SendMessage(Globals.hEdit, EM_SETMODIFY, FALSE, 0);
 
     CloseHandle(hFile);
     HeapFree(GetProcessHeap(), 0, pTemp);
+
+    if (iCodePage >= 0)
+        HeapFree(GetProcessHeap(), 0, pConverted);
 }
 
 /**
@@ -208,44 +273,48 @@
 {
     HANDLE hFile;
     LPSTR pTemp;
+    LPWSTR pTemp2 = NULL;
     DWORD size;
     DWORD dwNumRead;
+    LPWSTR p;
+    LPBYTE p2;
+    int iCodePage;
+    int iNewSize;
 
     /* Close any files and prompt to save changes */
     if (!DoCloseFile())
-	return;
+        return;
 
     hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
-	OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+                       OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
     if(hFile == INVALID_HANDLE_VALUE)
     {
-	ShowLastError();
-	return;
+        ShowLastError();
+        return;
     }
 
     size = GetFileSize(hFile, NULL);
     if (size == INVALID_FILE_SIZE)
     {
-	CloseHandle(hFile);
-	ShowLastError();
-	return;
+        CloseHandle(hFile);
+        ShowLastError();
+        return;
     }
-    size++;
 
-    pTemp = HeapAlloc(GetProcessHeap(), 0, size);
+    pTemp = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR));
     if (!pTemp)
     {
-	CloseHandle(hFile);
-	ShowLastError();
-	return;
+        CloseHandle(hFile);
+        ShowLastError();
+        return;
     }
 
     if (!ReadFile(hFile, pTemp, size, &dwNumRead, NULL))
     {
-	CloseHandle(hFile);
-	HeapFree(GetProcessHeap(), 0, pTemp);
-	ShowLastError();
-	return;
+        CloseHandle(hFile);
+        HeapFree(GetProcessHeap(), 0, pTemp);
+        ShowLastError();
+        return;
     }
 
     CloseHandle(hFile);
@@ -253,15 +322,55 @@
 
     if (IsTextUnicode(pTemp, dwNumRead, NULL))
     {
-	LPWSTR p = (LPWSTR)pTemp;
-	/* We need to strip BOM Unicode character, SetWindowTextW won't do it for us. */
-	if (*p == 0xFEFF || *p == 0xFFFE) p++;
-	SetWindowTextW(Globals.hEdit, p);
+        p = (LPWSTR)pTemp;
+        p[dwNumRead / 2] = 0;
+
+        /* We need to strip BOM Unicode character, SetWindowTextW won't do it for us. */
+        if (*p == 0xFEFF)
+        {
+            Globals.iEncoding = ENCODING_UNICODE_BE;
+            p++;
+        }
+        else if (*p == 0xFFFE)
+        {
+            Globals.iEncoding = ENCODING_UNICODE;
+            p++;
+        }
     }
     else
-	SetWindowTextA(Globals.hEdit, pTemp);
+    {
+        p2 = pTemp;
+        if ((p2[0] == 0xEF) && (p2[1] == 0xBB) && (p2[2] == 0xBF))
+        {
+            iCodePage = CP_UTF8;
+            Globals.iEncoding = ENCODING_UTF8;
+            p2 += 3;
+            dwNumRead -= 3;
+        }
+        else
+        {
+            iCodePage = CP_ACP;
+            Globals.iEncoding = ENCODING_ANSI;
+        }
 
+        iNewSize = MultiByteToWideChar(iCodePage, 0, p2, dwNumRead, NULL, 0);
+        pTemp2 = HeapAlloc(GetProcessHeap(), 0, (iNewSize + 1) * sizeof(*pTemp2));
+        if (!pTemp2)
+        {
+            CloseHandle(hFile);
+            HeapFree(GetProcessHeap(), 0, pTemp);
+            ShowLastError();
+            return;
+        }
+        MultiByteToWideChar(iCodePage, 0, p2, dwNumRead, pTemp2, iNewSize);
+        pTemp2[iNewSize] = 0;
+        p = pTemp2;
+    }
+    SetWindowTextW(Globals.hEdit, p);
+
     HeapFree(GetProcessHeap(), 0, pTemp);
+    if (pTemp2)
+       HeapFree(GetProcessHeap(), 0, pTemp2);
 
     SendMessage(Globals.hEdit, EM_SETMODIFY, FALSE, 0);
     SendMessage(Globals.hEdit, EM_EMPTYUNDOBUFFER, 0, 0);
@@ -286,15 +395,18 @@
 VOID DIALOG_FileOpen(VOID)
 {
     OPENFILENAME openfilename;
+    WCHAR szDir[MAX_PATH];
     WCHAR szPath[MAX_PATH];
-    WCHAR szDir[MAX_PATH];
     static const WCHAR szDefaultExt[] = { 't','x','t',0 };
     static const WCHAR txt_files[] = { '*','.','t','x','t',0 };
 
     ZeroMemory(&openfilename, sizeof(openfilename));
 
     GetCurrentDirectory(SIZEOF(szDir), szDir);
-    lstrcpy(szPath, txt_files);
+    if (Globals.szFileName[0] == 0)
+        lstrcpy(szPath, txt_files);
+    else
+        lstrcpy(szPath, Globals.szFileName);
 
     openfilename.lStructSize       = sizeof(openfilename);
     openfilename.hwndOwner         = Globals.hMainWnd;
@@ -325,18 +437,59 @@
         DoSaveFile();
 }
 
+static UINT_PTR CALLBACK DIALOG_FileSaveAs_Hook(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    WCHAR szText[128];
+    HWND hCombo;
+    OFNOTIFY *pNotify;
+
+    switch(msg)
+    {
+        case WM_INITDIALOG:
+            hCombo = GetDlgItem(hDlg, ID_ENCODING);
+
+            LoadString(Globals.hInstance, STRING_ANSI, szText, SIZEOF(szText));
+            SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
+
+            LoadString(Globals.hInstance, STRING_UNICODE, szText, SIZEOF(szText));
+            SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
+
+            LoadString(Globals.hInstance, STRING_UNICODE_BE, szText, SIZEOF(szText));
+            SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
+
+            LoadString(Globals.hInstance, STRING_UTF8, szText, SIZEOF(szText));
+            SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
+
+            SendMessage(hCombo, CB_SETCURSEL, Globals.iEncoding, 0);
+            break;
+
+        case WM_NOTIFY:
+            if (((NMHDR *) lParam)->code == CDN_FILEOK)
+            {
+                pNotify = (OFNOTIFY *) lParam;
+                hCombo = GetDlgItem(hDlg, ID_ENCODING);
+                Globals.iEncoding = SendMessage(hCombo, CB_GETCURSEL, 0, 0);
+            }
+            break;
+    }
+    return 0;
+}
+
 VOID DIALOG_FileSaveAs(VOID)
 {
     OPENFILENAME saveas;
+    WCHAR szDir[MAX_PATH];
     WCHAR szPath[MAX_PATH];
-    WCHAR szDir[MAX_PATH];
     static const WCHAR szDefaultExt[] = { 't','x','t',0 };
     static const WCHAR txt_files[] = { '*','.','t','x','t',0 };
 
     ZeroMemory(&saveas, sizeof(saveas));
 
     GetCurrentDirectory(SIZEOF(szDir), szDir);
-    lstrcpy(szPath, txt_files);
+    if (Globals.szFileName[0] == 0)
+        lstrcpy(szPath, txt_files);
+    else
+        lstrcpy(szPath, Globals.szFileName);
 
     saveas.lStructSize       = sizeof(OPENFILENAME);
     saveas.hwndOwner         = Globals.hMainWnd;
@@ -346,8 +499,10 @@
     saveas.nMaxFile          = SIZEOF(szPath);
     saveas.lpstrInitialDir   = szDir;
     saveas.Flags             = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT |
-        OFN_HIDEREADONLY;
+        OFN_HIDEREADONLY | OFN_EXPLORER | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK;
     saveas.lpstrDefExt       = szDefaultExt;
+    saveas.lpTemplateName    = MAKEINTRESOURCE(DIALOG_ENCODING);
+    saveas.lpfnHook          = DIALOG_FileSaveAs_Hook;
 
     if (GetSaveFileName(&saveas)) {
         SetFileName(szPath);
@@ -423,14 +578,14 @@
     cHeightPels = GetDeviceCaps(printer.hDC, VERTRES);
 
     /* Get the file text */
-    size = GetWindowTextLength(Globals.hEdit) + 1;
+    size = GetWindowTextLengthW(Globals.hEdit) + 1;
     pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
     if (!pTemp)
     {
         ShowLastError();
         return;
     }
-    size = GetWindowText(Globals.hEdit, pTemp, size);
+    size = GetWindowTextW(Globals.hEdit, pTemp, size);
 
     border = 150;
     for (copycount=1; copycount <= printer.nCopies; copycount++) {
@@ -700,8 +855,8 @@
           return TRUE;
         }
 
-	default:
-	    break;
+        default:
+          break;
         }
       break;
 

Modified: trunk/reactos/subsys/system/notepad/main.h
--- trunk/reactos/subsys/system/notepad/main.h	2005-09-12 16:06:53 UTC (rev 17819)
+++ trunk/reactos/subsys/system/notepad/main.h	2005-09-12 17:10:00 UTC (rev 17820)
@@ -25,6 +25,11 @@
 
 #define MAX_STRING_LEN      255
 
+#define ENCODING_ANSI		0
+#define ENCODING_UNICODE	1
+#define ENCODING_UNICODE_BE	2
+#define ENCODING_UTF8		3
+
 typedef struct
 {
   HANDLE  hInstance;
@@ -44,6 +49,7 @@
   WCHAR   szMarginRight[MAX_PATH];
   WCHAR   szHeader[MAX_PATH];
   WCHAR   szFooter[MAX_PATH];
+  int     iEncoding;
 
   FINDREPLACE find;
 } NOTEPAD_GLOBALS;

Modified: trunk/reactos/subsys/system/notepad/notepad_res.h
--- trunk/reactos/subsys/system/notepad/notepad_res.h	2005-09-12 16:06:53 UTC (rev 17819)
+++ trunk/reactos/subsys/system/notepad/notepad_res.h	2005-09-12 17:10:00 UTC (rev 17820)
@@ -22,6 +22,8 @@
 #define MAIN_MENU               0x201
 #define DIALOG_PAGESETUP        0x202
 #define ID_ACCEL                0x203
+#define DIALOG_ENCODING         0x204
+#define ID_ENCODING             0x205
 
 /* Commands */
 #define CMD_NEW                 0x100
@@ -76,3 +78,9 @@
 
 #define STRING_NOTFOUND 0x17B
 #define STRING_OUT_OF_MEMORY 0x17C
+
+#define STRING_ANSI 0x17D
+#define STRING_UNICODE 0x17E
+#define STRING_UNICODE_BE 0x17F
+#define STRING_UTF8 0x180
+