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


svn path=/trunk/; revision=18037
This commit is contained in:
Nathan Woods 2005-09-24 23:45:05 +00:00
parent 5f28a5ed9f
commit 3c14414c1d
7 changed files with 535 additions and 158 deletions

View file

@ -95,7 +95,7 @@ PUSHBUTTON "&Help", 0x153, 180, 39, 40, 15, WS_TABSTOP
}
/* 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 @@ CAPTION "Encoding"
{
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_ANSI, "ANSI"
STRING_UNICODE, "Unicode"
STRING_UNICODE_BE, "Unicode (big endian)"
STRING_UTF8, "UTF-8"
STRING_CRLF, "Windows"
STRING_LF, "Unix"
STRING_CR, "Mac"
}

View file

@ -93,7 +93,7 @@ static void AlertFileNotFound(LPCWSTR szFileName)
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 @@ static int AlertFileNotSaved(LPCWSTR szFileName)
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 @@ BOOL FileExists(LPCWSTR szFilename)
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 @@ static VOID DoSaveFile(VOID)
}
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))
ShowLastError();
else if (!WriteFile(hFile, pConverted, iNewSize, &dwNumWrite, NULL))
if (!WriteText(hFile, pTemp, size, Globals.iEncoding, Globals.iEoln))
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 @@ void DoOpenFile(LPCWSTR szFileName)
{
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,90 +217,19 @@ void DoOpenFile(LPCWSTR szFileName)
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;
}
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);
SetWindowTextW(Globals.hEdit, pszText);
SendMessage(Globals.hEdit, EM_SETMODIFY, FALSE, 0);
SendMessage(Globals.hEdit, EM_EMPTYUNDOBUFFER, 0, 0);
@ -392,6 +249,12 @@ void DoOpenFile(LPCWSTR szFileName)
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 @@ static UINT_PTR CALLBACK DIALOG_FileSaveAs_Hook(HWND hDlg, UINT msg, WPARAM wPar
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 @@ VOID DIALOG_EditWrap(VOID)
{
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;

View file

@ -23,9 +23,11 @@
*/
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include "main.h"
#include "dialog.h"
@ -93,6 +95,78 @@ static int NOTEPAD_MenuCommand(WPARAM wParam)
return 0;
}
/***********************************************************************
*
* 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
*/
@ -150,7 +224,7 @@ static LRESULT WINAPI NOTEPAD_WndProc(HWND hWnd, UINT msg, WPARAM wParam,
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 @@ static LRESULT WINAPI NOTEPAD_WndProc(HWND hWnd, UINT msg, WPARAM wParam,
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 @@ static int AlertFileDoesNotExist(LPCWSTR szFileName)
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);

View file

@ -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 @@ typedef struct
WCHAR szHeader[MAX_PATH];
WCHAR szFooter[MAX_PATH];
int iEncoding;
int iEoln;
FINDREPLACE find;
} NOTEPAD_GLOBALS;
@ -57,3 +62,9 @@ typedef struct
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);

View file

@ -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>

View file

@ -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

View file

@ -0,0 +1,389 @@
/*
* Notepad (text.c)
*
* Copyright 1998,99 Marcel Baur <mbaur@g26.ethz.ch>
* Copyright 2002 Sylvain Petreolle <spetreolle@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;
}