Notepad enhancements:
1. Added line ending handling, so that Notepad can handle line endings
other than CR/LF. This is specified in a dropdown menu similar to the
text encoding. Consequently, I've moved text handling to a new file,
text.c
2. Implemented the Find command
3. Changed some dialog titles to be 'Notepad' instead of 'ERROR', in
line with how Windows notepad works.
4. The edit control now has the style ES_NOHIDESEL specified
Modified: trunk/reactos/subsys/system/notepad/En.rc
Modified: trunk/reactos/subsys/system/notepad/dialog.c
Modified: trunk/reactos/subsys/system/notepad/main.c
Modified: trunk/reactos/subsys/system/notepad/main.h
Modified: trunk/reactos/subsys/system/notepad/notepad.xml
Modified: trunk/reactos/subsys/system/notepad/notepad_res.h
Added: trunk/reactos/subsys/system/notepad/text.c
_____
Modified: trunk/reactos/subsys/system/notepad/En.rc
--- trunk/reactos/subsys/system/notepad/En.rc 2005-09-24 20:37:53 UTC
(rev 18036)
+++ trunk/reactos/subsys/system/notepad/En.rc 2005-09-24 23:45:05 UTC
(rev 18037)
@@ -95,7 +95,7 @@
}
/* Dialog `Encoding' */
-DIALOG_ENCODING DIALOG 0, 0, 256, 26
+DIALOG_ENCODING DIALOG 0, 0, 256, 44
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD |
WS_CLIPSIBLINGS |
WS_CAPTION | WS_SYSMENU
FONT 8, "MS Shell Dlg"
@@ -103,6 +103,8 @@
{
COMBOBOX ID_ENCODING,54,0,156,80,CBS_DROPDOWNLIST | CBS_SORT |
WS_VSCROLL | WS_TABSTOP
LTEXT "Encoding:",0x155,5,2,41,12
+COMBOBOX ID_EOLN,54,18,156,80,CBS_DROPDOWNLIST | WS_VSCROLL |
WS_TABSTOP
+LTEXT "Endlines:",0x156,5,20,41,12
}
STRINGTABLE DISCARDABLE
@@ -140,4 +142,7 @@
STRING_UNICODE, "Unicode"
STRING_UNICODE_BE, "Unicode (big endian)"
STRING_UTF8, "UTF-8"
+STRING_CRLF, "Windows"
+STRING_LF, "Unix"
+STRING_CR, "Mac"
}
_____
Modified: trunk/reactos/subsys/system/notepad/dialog.c
--- trunk/reactos/subsys/system/notepad/dialog.c 2005-09-24
20:37:53 UTC (rev 18036)
+++ trunk/reactos/subsys/system/notepad/dialog.c 2005-09-24
23:45:05 UTC (rev 18037)
@@ -93,7 +93,7 @@
wsprintf(szMessage, szResource, szFileName);
/* Load szCaption */
- LoadString(Globals.hInstance, STRING_ERROR, szResource,
SIZEOF(szResource));
+ LoadString(Globals.hInstance, STRING_NOTEPAD, szResource,
SIZEOF(szResource));
/* Display Modal Dialog */
MessageBox(Globals.hMainWnd, szMessage, szResource,
MB_ICONEXCLAMATION);
@@ -112,7 +112,7 @@
wsprintf(szMessage, szResource, szFileName[0] ? szFileName :
szUntitled);
/* Load Caption */
- LoadString(Globals.hInstance, STRING_ERROR, szResource,
SIZEOF(szResource));
+ LoadString(Globals.hInstance, STRING_NOTEPAD, szResource,
SIZEOF(szResource));
/* Display modal */
return MessageBox(Globals.hMainWnd, szMessage, szResource,
MB_ICONEXCLAMATION|MB_YESNOCANCEL);
@@ -138,15 +138,8 @@
static VOID DoSaveFile(VOID)
{
HANDLE hFile;
- DWORD dwNumWrite;
LPWSTR pTemp;
- LPVOID pConverted = NULL;
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);
@@ -166,72 +159,13 @@
}
size = GetWindowTextW(Globals.hEdit, pTemp, size);
- 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))
+ if (!WriteText(hFile, pTemp, size, Globals.iEncoding,
Globals.iEoln))
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);
}
/**
@@ -273,15 +207,9 @@
{
static const WCHAR dotlog[] = { '.','L','O','G',0 };
HANDLE hFile;
- LPSTR pTemp;
- LPWSTR pTemp2 = NULL;
- DWORD size;
- DWORD dwNumRead;
+ LPWSTR pszText;
+ DWORD dwTextLen;
WCHAR log[5];
- LPWSTR p;
- LPBYTE p2;
- int iCodePage;
- int iNewSize;
/* Close any files and prompt to save changes */
if (!DoCloseFile())
@@ -289,91 +217,20 @@
hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- if(hFile == INVALID_HANDLE_VALUE)
+ if (hFile == INVALID_HANDLE_VALUE)
{
ShowLastError();
- return;
+ goto done;
}
- size = GetFileSize(hFile, NULL);
- if (size == INVALID_FILE_SIZE)
+ if (!ReadText(hFile, &pszText, &dwTextLen, &Globals.iEncoding,
&Globals.iEoln))
{
- CloseHandle(hFile);
ShowLastError();
- return;
+ goto done;
}
- pTemp = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR));
- if (!pTemp)
- {
- CloseHandle(hFile);
- ShowLastError();
- return;
- }
+ SetWindowTextW(Globals.hEdit, pszText);
- if (!ReadFile(hFile, pTemp, size, &dwNumRead, NULL))
- {
- CloseHandle(hFile);
- HeapFree(GetProcessHeap(), 0, pTemp);
- ShowLastError();
- return;
- }
-
- CloseHandle(hFile);
- pTemp[dwNumRead] = 0;
-
- if (IsTextUnicode(pTemp, dwNumRead, NULL))
- {
- 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
- {
- p2 = (LPBYTE)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, (LPCSTR)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, (LPCSTR)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);
SetFocus(Globals.hEdit);
@@ -392,6 +249,12 @@
SetFileName(szFileName);
UpdateWindowCaption();
+
+done:
+ if (hFile != INVALID_HANDLE_VALUE)
+ CloseHandle(hFile);
+ if (pszText)
+ HeapFree(GetProcessHeap(), 0, pszText);
}
VOID DIALOG_FileNew(VOID)
@@ -475,14 +338,33 @@
SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
SendMessage(hCombo, CB_SETCURSEL, Globals.iEncoding, 0);
+
+ hCombo = GetDlgItem(hDlg, ID_EOLN);
+
+ LoadString(Globals.hInstance, STRING_CRLF, szText,
SIZEOF(szText));
+ SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
+
+ LoadString(Globals.hInstance, STRING_LF, szText,
SIZEOF(szText));
+ SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
+
+ LoadString(Globals.hInstance, STRING_CR, szText,
SIZEOF(szText));
+ SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
+
+ SendMessage(hCombo, CB_SETCURSEL, Globals.iEoln, 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);
+ if (hCombo)
+ Globals.iEncoding = SendMessage(hCombo,
CB_GETCURSEL, 0, 0);
+
+ hCombo = GetDlgItem(hDlg, ID_EOLN);
+ if (hCombo)
+ Globals.iEoln = SendMessage(hCombo,
CB_GETCURSEL, 0, 0);
}
break;
}
@@ -736,7 +618,7 @@
{
static const WCHAR editW[] = { 'e','d','i','t',0 };
DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL |
- ES_AUTOVSCROLL | ES_MULTILINE;
+ ES_AUTOVSCROLL | ES_MULTILINE | ES_NOHIDESEL;
RECT rc;
DWORD size;
LPWSTR pTemp;
_____
Modified: trunk/reactos/subsys/system/notepad/main.c
--- trunk/reactos/subsys/system/notepad/main.c 2005-09-24 20:37:53 UTC
(rev 18036)
+++ trunk/reactos/subsys/system/notepad/main.c 2005-09-24 23:45:05 UTC
(rev 18037)
@@ -23,9 +23,11 @@
*/
#define UNICODE
+#define _UNICODE
#include <windows.h>
#include <stdio.h>
+#include <tchar.h>
#include "main.h"
#include "dialog.h"
@@ -94,6 +96,78 @@
}
/***********************************************************************
+ *
+ * NOTEPAD_FindNext
+ */
+
+static VOID NOTEPAD_FindNext(FINDREPLACE *pFindReplace)
+{
+ int iTextLength, iTargetLength;
+ LPTSTR pszText = NULL;
+ DWORD dwPosition, dwDummy;
+ BOOL bMatches = FALSE;
+
+ iTargetLength = _tcslen(pFindReplace->lpstrFindWhat);
+
+ iTextLength = GetWindowTextLength(Globals.hEdit);
+
+ if (iTextLength > 0)
+ {
+ pszText = (LPTSTR) HeapAlloc(GetProcessHeap(), 0, (iTextLength
+ 1) * sizeof(TCHAR));
+ if (!pszText)
+ return;
+
+ GetWindowText(Globals.hEdit, pszText, iTextLength + 1);
+ }
+
+ SendMessage(Globals.hEdit, EM_GETSEL, (WPARAM) &dwDummy, (LPARAM)
&dwPosition);
+
+ while(dwPosition < iTextLength)
+ {
+ /* Make proper comparison */
+ if (pFindReplace->Flags & FR_MATCHCASE)
+ bMatches = !_tcsncmp(&pszText[dwPosition],
pFindReplace->lpstrFindWhat, iTargetLength);
+ else
+ bMatches = !_tcsnicmp(&pszText[dwPosition],
pFindReplace->lpstrFindWhat, iTargetLength);
+
+ if (bMatches && pFindReplace->Flags & FR_WHOLEWORD)
+ {
+ if ((dwPosition > 0) && !_istspace(pszText[dwPosition-1]))
+ bMatches = FALSE;
+ if ((dwPosition < iTextLength - 1) &&
!_istspace(pszText[dwPosition+1]))
+ bMatches = FALSE;
+ }
+
+ if (bMatches)
+ break;
+
+ if (pFindReplace->Flags & FR_DOWN)
+ dwPosition++;
+ else
+ dwPosition--;
+ }
+
+ if (bMatches)
+ {
+ SendMessage(Globals.hEdit, EM_SETSEL, dwPosition, dwPosition +
iTargetLength);
+ SendMessage(Globals.hEdit, EM_SCROLLCARET, 0, 0);
+ }
+
+ if (pszText)
+ HeapFree(GetProcessHeap(), 0, pszText);
+}
+
+/**********************************************************************
*
+ *
+ * NOTEPAD_FindTerm
+ */
+
+static VOID NOTEPAD_FindTerm(VOID)
+{
+ Globals.hFindReplaceDlg = NULL;
+}
+
+/**********************************************************************
*
* Data Initialization
*/
static VOID NOTEPAD_InitData(VOID)
@@ -150,7 +224,7 @@
GetClientRect(hWnd, &rc);
Globals.hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, editW, NULL,
WS_CHILD | WS_VISIBLE | WS_BORDER |
WS_VSCROLL | WS_HSCROLL |
- ES_AUTOVSCROLL | ES_MULTILINE,
+ ES_AUTOVSCROLL | ES_MULTILINE |
ES_NOHIDESEL,
0, 0, rc.right, rc.bottom, hWnd,
NULL, Globals.hInstance, NULL);
break;
@@ -205,6 +279,17 @@
break;
default:
+ if (msg == aFINDMSGSTRING)
+ {
+ FINDREPLACE *pFindReplace = (FINDREPLACE *) lParam;
+
+ if (pFindReplace->Flags & FR_FINDNEXT)
+ NOTEPAD_FindNext(pFindReplace);
+ else if (pFindReplace->Flags & FR_DIALOGTERM)
+ NOTEPAD_FindTerm();
+ break;
+ }
+
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
@@ -219,7 +304,7 @@
LoadString(Globals.hInstance, STRING_DOESNOTEXIST, szResource,
SIZEOF(szResource));
wsprintf(szMessage, szResource, szFileName);
- LoadString(Globals.hInstance, STRING_ERROR, szResource,
SIZEOF(szResource));
+ LoadString(Globals.hInstance, STRING_NOTEPAD, szResource,
SIZEOF(szResource));
nResult = MessageBox(Globals.hMainWnd, szMessage, szResource,
MB_ICONEXCLAMATION | MB_YESNO);
_____
Modified: trunk/reactos/subsys/system/notepad/main.h
--- trunk/reactos/subsys/system/notepad/main.h 2005-09-24 20:37:53 UTC
(rev 18036)
+++ trunk/reactos/subsys/system/notepad/main.h 2005-09-24 23:45:05 UTC
(rev 18037)
@@ -30,6 +30,10 @@
#define ENCODING_UNICODE_BE 2
#define ENCODING_UTF8 3
+#define EOLN_CRLF 0
+#define EOLN_LF 1
+#define EOLN_CR 2
+
typedef struct
{
HANDLE hInstance;
@@ -50,6 +54,7 @@
WCHAR szHeader[MAX_PATH];
WCHAR szFooter[MAX_PATH];
int iEncoding;
+ int iEoln;
FINDREPLACE find;
} NOTEPAD_GLOBALS;
@@ -57,3 +62,9 @@
extern NOTEPAD_GLOBALS Globals;
VOID SetFileName(LPCWSTR szFileName);
+
+/* from text.c */
+BOOL ReadText(HANDLE hFile, LPWSTR *ppszText, DWORD *pdwTextLen, int
*piEncoding, int *piEoln);
+BOOL WriteText(HANDLE hFile, LPCWSTR pszText, DWORD dwTextLen, int
iEncoding, int iEoln);
+
+
_____
Modified: trunk/reactos/subsys/system/notepad/notepad.xml
--- trunk/reactos/subsys/system/notepad/notepad.xml 2005-09-24
20:37:53 UTC (rev 18036)
+++ trunk/reactos/subsys/system/notepad/notepad.xml 2005-09-24
23:45:05 UTC (rev 18037)
@@ -10,5 +10,6 @@
<file>dialog.c</file>
<file>license.c</file>
<file>main.c</file>
+ <file>text.c</file>
<file>rsrc.rc</file>
</module>
_____
Modified: trunk/reactos/subsys/system/notepad/notepad_res.h
--- trunk/reactos/subsys/system/notepad/notepad_res.h 2005-09-24
20:37:53 UTC (rev 18036)
+++ trunk/reactos/subsys/system/notepad/notepad_res.h 2005-09-24
23:45:05 UTC (rev 18037)
@@ -24,6 +24,7 @@
#define ID_ACCEL 0x203
#define DIALOG_ENCODING 0x204
#define ID_ENCODING 0x205
+#define ID_EOLN 0x206
/* Commands */
#define CMD_NEW 0x100
@@ -84,3 +85,6 @@
#define STRING_UNICODE_BE 0x17F
#define STRING_UTF8 0x180
+#define STRING_CRLF 0x181
+#define STRING_LF 0x182
+#define STRING_CR 0x183
_____
Added: trunk/reactos/subsys/system/notepad/text.c
--- trunk/reactos/subsys/system/notepad/text.c 2005-09-24 20:37:53 UTC
(rev 18036)
+++ trunk/reactos/subsys/system/notepad/text.c 2005-09-24 23:45:05 UTC
(rev 18037)
@@ -0,0 +1,389 @@
+/*
+ * Notepad (text.c)
+ *
+ * Copyright 1998,99 Marcel Baur <mbaur(a)g26.ethz.ch>
+ * Copyright 2002 Sylvain Petreolle <spetreolle(a)yahoo.fr>
+ * Copyright 2002 Andriy Palamarchuk
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA
+ */
+
+#define UNICODE
+
+#include <assert.h>
+#include <stdio.h>
+#include <windows.h>
+#include <commdlg.h>
+
+#include "main.h"
+
+static BOOL Append(LPWSTR *ppszText, DWORD *pdwTextLen, LPCWSTR
pszAppendText, DWORD dwAppendLen)
+{
+ LPWSTR pszNewText;
+
+ if (dwAppendLen > 0)
+ {
+ if (*ppszText)
+ {
+ pszNewText = (LPWSTR)
HeapReAlloc(GetProcessHeap(), 0, *ppszText, (*pdwTextLen + dwAppendLen)
* sizeof(WCHAR));
+ }
+ else
+ {
+ pszNewText = (LPWSTR)
HeapAlloc(GetProcessHeap(), 0, dwAppendLen * sizeof(WCHAR));
+ }
+
+ if (!pszNewText)
+ return FALSE;
+
+ memcpy(pszNewText + *pdwTextLen, pszAppendText,
dwAppendLen * sizeof(WCHAR));
+ *ppszText = pszNewText;
+ *pdwTextLen += dwAppendLen;
+ }
+ return TRUE;
+}
+
+BOOL ReadText(HANDLE hFile, LPWSTR *ppszText, DWORD *pdwTextLen, int
*piEncoding, int *piEoln)
+{
+ DWORD dwSize;
+ LPBYTE pBytes = NULL;
+ LPCWSTR pszText;
+ LPWSTR pszAllocText = NULL;
+ DWORD dwPos, i;
+ DWORD dwCharCount;
+ BOOL bSuccess = FALSE;
+ BYTE b;
+ int iEncoding = ENCODING_ANSI;
+ int iCodePage;
+ WCHAR szCrlf[2] = { '\r', '\n' };
+ DWORD adwEolnCount[3] = { 0, 0, 0 };
+
+ *ppszText = NULL;
+ *pdwTextLen = 0;
+
+ dwSize = GetFileSize(hFile, NULL);
+ if (dwSize == INVALID_FILE_SIZE)
+ goto done;
+
+ pBytes = HeapAlloc(GetProcessHeap(), 0, dwSize + 2);
+ if (!pBytes)
+ goto done;
+
+ if (!ReadFile(hFile, pBytes, dwSize, &dwSize, NULL))
+ goto done;
+ dwPos = 0;
+
+ /* Make sure that there is a NUL character at the end, in any
encoding */
+ pBytes[dwSize + 0] = '\0';
+ pBytes[dwSize + 1] = '\0';
+
+ /* Look for Byte Order Marks */
+ if ((dwSize >= 2) && (pBytes[0] == 0xFF) && (pBytes[1] == 0xFE))
+ {
+ iEncoding = ENCODING_UNICODE;
+ dwPos += 2;
+ }
+ else if ((dwSize >= 2) && (pBytes[0] == 0xFE) && (pBytes[1] ==
0xFF))
+ {
+ iEncoding = ENCODING_UNICODE_BE;
+ dwPos += 2;
+ }
+ else if ((dwSize >= 3) && (pBytes[0] == 0xEF) && (pBytes[1] ==
0xBB) && (pBytes[2] == 0xBF))
+ {
+ iEncoding = ENCODING_UTF8;
+ dwPos += 3;
+ }
+
+ switch(iEncoding)
+ {
+ case ENCODING_UNICODE_BE:
+ for (i = dwPos; i < dwSize-1; i += 2)
+ {
+ b = pBytes[i+0];
+ pBytes[i+0] = pBytes[i+1];
+ pBytes[i+1] = b;
+ }
+ /* fall through */
+
+ case ENCODING_UNICODE:
+ pszText = (LPCWSTR) &pBytes[dwPos];
+ dwCharCount = (dwSize - dwPos) / sizeof(WCHAR);
+ break;
+
+ case ENCODING_ANSI:
+ case ENCODING_UTF8:
+ if (iEncoding == ENCODING_ANSI)
+ iCodePage = CP_ACP;
+ else if (iEncoding == ENCODING_UTF8)
+ iCodePage = CP_UTF8;
+ else
+ goto done;
+
+ dwCharCount = MultiByteToWideChar(iCodePage, 0,
&pBytes[dwPos], dwSize - dwPos, NULL, 0);
+ if (dwCharCount == 0)
+ goto done;
+
+ pszAllocText = (LPWSTR) HeapAlloc(GetProcessHeap(), 0,
(dwCharCount + 1) * sizeof(WCHAR));
+ if (!pszAllocText)
+ goto done;
+
+ if (!MultiByteToWideChar(iCodePage, 0, &pBytes[dwPos],
dwSize - dwPos, pszAllocText, dwCharCount))
+ goto done;
+
+ pszAllocText[dwCharCount] = '\0';
+ pszText = pszAllocText;
+ break;
+ }
+
+ dwPos = 0;
+ for (i = 0; i < dwCharCount; i++)
+ {
+ switch(pszText[i])
+ {
+ case '\r':
+ if ((i < dwCharCount-1) && (pszText[i+1] ==
'\n'))
+ {
+ i++;
+ adwEolnCount[EOLN_CRLF]++;
+ break;
+ }
+ /* fall through */
+
+ case '\n':
+ if (!Append(ppszText, pdwTextLen,
&pszText[dwPos], i - dwPos))
+ return FALSE;
+ if (!Append(ppszText, pdwTextLen, szCrlf,
sizeof(szCrlf) / sizeof(szCrlf[0])))
+ return FALSE;
+ dwPos = i + 1;
+
+ if (pszText[i] == '\r')
+ adwEolnCount[EOLN_CR]++;
+ else
+ adwEolnCount[EOLN_LF]++;
+ break;
+ }
+ }
+
+ if (!*ppszText && (pszText == pszAllocText))
+ {
+ /* special case; don't need to reallocate */
+ *ppszText = pszAllocText;
+ *pdwTextLen = dwCharCount;
+ pszAllocText = NULL;
+ }
+ else
+ {
+ /* append last remaining text */
+ if (!Append(ppszText, pdwTextLen, &pszText[dwPos], i -
dwPos + 1))
+ return FALSE;
+ }
+
+ /* chose which eoln to use */
+ *piEoln = EOLN_CRLF;
+ if (adwEolnCount[EOLN_LF] > adwEolnCount[*piEoln])
+ *piEoln = EOLN_LF;
+ if (adwEolnCount[EOLN_CR] > adwEolnCount[*piEoln])
+ *piEoln = EOLN_CR;
+ *piEncoding = iEncoding;
+
+ bSuccess = TRUE;
+
+done:
+ if (pBytes)
+ HeapFree(GetProcessHeap(), 0, pBytes);
+ if (pszAllocText)
+ HeapFree(GetProcessHeap(), 0, pszAllocText);
+
+ if (!bSuccess && *ppszText)
+ {
+ HeapFree(GetProcessHeap(), 0, *ppszText);
+ *ppszText = NULL;
+ *pdwTextLen = 0;
+ }
+ return bSuccess;
+}
+
+static BOOL WriteEncodedText(HANDLE hFile, LPCWSTR pszText, DWORD
dwTextLen, int iEncoding)
+{
+ LPBYTE pBytes;
+ LPBYTE pAllocBuffer = NULL;
+ DWORD dwPos = 0;
+ DWORD dwByteCount;
+ BYTE buffer[1024];
+ UINT iCodePage;
+ DWORD dwDummy, i;
+ BOOL bSuccess;
+ int iBufferSize, iRequiredBytes;
+ BYTE b;
+
+ while(dwPos < dwTextLen)
+ {
+ switch(iEncoding)
+ {
+ case ENCODING_UNICODE:
+ pBytes = (LPBYTE) &pszText[dwPos];
+ dwByteCount = (dwTextLen - dwPos) *
sizeof(WCHAR);
+ dwPos = dwTextLen;
+ break;
+
+ case ENCODING_UNICODE_BE:
+ dwByteCount = (dwTextLen - dwPos) *
sizeof(WCHAR);
+ if (dwByteCount > sizeof(buffer))
+ dwByteCount = sizeof(buffer);
+
+ memcpy(buffer, &pszText[dwPos],
dwByteCount);
+ for (i = 0; i < dwByteCount; i += 2)
+ {
+ b = buffer[i+0];
+ buffer[i+0] = buffer[i+1];
+ buffer[i+1] = b;
+ }
+ dwPos += dwByteCount / sizeof(WCHAR);
+ break;
+
+ case ENCODING_ANSI:
+ case ENCODING_UTF8:
+ if (iEncoding == ENCODING_ANSI)
+ iCodePage = CP_ACP;
+ else if (iEncoding == ENCODING_UTF8)
+ iCodePage = CP_UTF8;
+ else
+ goto done;
+
+ iRequiredBytes =
WideCharToMultiByte(iCodePage, 0, &pszText[dwPos], dwTextLen - dwPos,
NULL, 0, NULL, NULL);
+ if (iRequiredBytes <= 0)
+ {
+ goto done;
+ }
+ else if (iRequiredBytes <
sizeof(buffer))
+ {
+ pBytes = buffer;
+ iBufferSize = sizeof(buffer);
+ }
+ else
+ {
+ pAllocBuffer = (LPBYTE)
HeapAlloc(GetProcessHeap(), 0, iRequiredBytes);
+ if (!pAllocBuffer)
+ return FALSE;
+ pBytes = pAllocBuffer;
+ iBufferSize = iRequiredBytes;
+ }
+
+ dwByteCount =
WideCharToMultiByte(iCodePage, 0, &pszText[dwPos], dwTextLen - dwPos,
(LPSTR) pBytes, iBufferSize, NULL, NULL);
+ if (!dwByteCount)
+ goto done;
+
+ dwPos = dwTextLen;
+ break;
+
+ default:
+ goto done;
+ }
+
+ if (!WriteFile(hFile, pBytes, dwByteCount, &dwDummy,
NULL))
+ goto done;
+
+ /* free the buffer, if we have allocated one */
+ if (pAllocBuffer)
+ {
+ HeapFree(GetProcessHeap(), 0, pAllocBuffer);
+ pAllocBuffer = NULL;
+ }
+ }
+ bSuccess = TRUE;
+
+done:
+ if (pAllocBuffer)
+ HeapFree(GetProcessHeap(), 0, pAllocBuffer);
+ return bSuccess;
+}
+
+BOOL WriteText(HANDLE hFile, LPCWSTR pszText, DWORD dwTextLen, int
iEncoding, int iEoln)
+{
+ WCHAR wcBom;
+ WCHAR wcEoln;
+ BYTE bEoln;
+ LPBYTE pbEoln = NULL;
+ DWORD dwDummy, dwPos, dwNext, dwEolnSize = 0;
+
+ /* Write the proper byte order marks if not ANSI */
+ if (iEncoding != ENCODING_ANSI)
+ {
+ wcBom = 0xFEFF;
+ if (!WriteEncodedText(hFile, &wcBom, 1, iEncoding))
+ return FALSE;
+ }
+
+ /* Identify the proper eoln to use */
+ switch(iEoln)
+ {
+ case EOLN_LF:
+ bEoln = '\n';
+ pbEoln = &bEoln;
+ dwEolnSize = sizeof(bEoln);
+ break;
+ case EOLN_CR:
+ bEoln = '\r';
+ pbEoln = &bEoln;
+ dwEolnSize = sizeof(bEoln);
+ break;
+ }
+
+ /* If we have an eoln, make sure it is of the proper encoding */
+ if (pbEoln && ((iEncoding == ENCODING_UNICODE) || (iEncoding ==
ENCODING_UNICODE_BE)))
+ {
+ wcEoln = bEoln;
+ pbEoln = (LPBYTE) &wcEoln;
+ dwEolnSize = sizeof(wcEoln);
+ }
+
+ dwPos = 0;
+
+ while(dwPos < dwTextLen)
+ {
+ if (pbEoln)
+ {
+ /* Find the next eoln */
+ dwNext = dwPos;
+ while(dwNext < dwTextLen-1)
+ {
+ if ((pszText[dwNext] == '\r') &&
(pszText[dwNext+1] == '\n'))
+ break;
+ dwNext++;
+ }
+ }
+ else
+ {
+ /* No eoln conversion is necessary */
+ dwNext = dwTextLen;
+ }
+
+ if (!WriteEncodedText(hFile, &pszText[dwPos], dwNext -
dwPos, iEncoding))
+ return FALSE;
+ dwPos = dwNext;
+
+ /* are we at an eoln? */
+ while ((dwPos < dwTextLen-1) &&
+ ((pszText[dwPos] == '\r') && (pszText[dwPos+1]
== '\n')))
+ {
+ if (!WriteFile(hFile, pbEoln, dwEolnSize,
&dwDummy, NULL))
+ return FALSE;
+ dwPos += 2;
+ }
+ }
+ while(dwPos < dwTextLen);
+
+ return TRUE;
+}
+