Index: subsys/system/notepad/dialog.c =================================================================== --- subsys/system/notepad/dialog.c (revision 17811) +++ subsys/system/notepad/dialog.c (working copy) @@ -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); - if (!pTemp) - { - CloseHandle(hFile); - ShowLastError(); - return; + size = GetWindowTextLength(Globals.hEdit) + 1; + pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*pTemp)); + if (!pTemp) + { + CloseHandle(hFile); + ShowLastError(); + return; } - size = GetWindowTextA(Globals.hEdit, pTemp, size); + size = GetWindowText(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,8 +273,13 @@ { 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()) @@ -232,7 +302,7 @@ } size++; - pTemp = HeapAlloc(GetProcessHeap(), 0, size); + pTemp = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR)); if (!pTemp) { CloseHandle(hFile); @@ -253,15 +323,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 +396,18 @@ VOID DIALOG_FileOpen(VOID) { OPENFILENAME openfilename; - WCHAR szPath[MAX_PATH]; WCHAR szDir[MAX_PATH]; + WCHAR szPath[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 +438,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 szPath[MAX_PATH]; WCHAR szDir[MAX_PATH]; + WCHAR szPath[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 +500,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); Index: subsys/system/notepad/notepad_res.h =================================================================== --- subsys/system/notepad/notepad_res.h (revision 17811) +++ subsys/system/notepad/notepad_res.h (working copy) @@ -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 + Index: subsys/system/notepad/En.rc =================================================================== --- subsys/system/notepad/En.rc (revision 17811) +++ subsys/system/notepad/En.rc (working copy) @@ -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" } Index: subsys/system/notepad/main.h =================================================================== --- subsys/system/notepad/main.h (revision 17811) +++ subsys/system/notepad/main.h (working copy) @@ -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;