#include <algorithm>
class CNotePadDlg : public CDialogEx
{
private:
void AddMainMenu();
void MoveEditContrl(int cx, int cy);
CString GetDragFileName(HDROP hDrop);
BOOL IsTextUnchanged();
CString GetTitle() const;
void ReadText(const CString& strFileName);
private:
void BEToLE(char* pStr, int nLength);
int GetCodePage(unsigned char* pStr);
BOOL CheckUtf8WithoutBom(unsigned char* pStr);
BOOL CheckUnicode(unsigned char* pStr, int nBytes);
LPWSTR ToUnicode(const char* pStr, DWORD nCode);
private:
enum class CodeType { ANSI = 0x01, UTF_BE, UTF_LE, UTF8, UTF8_BOM };
static TCHAR BASED_CODE m_szFilter[];
CString m_sFile = _T("");
DWORD m_nCode = 0;
};
TCHAR BASED_CODE CNotePadDlg::m_szFilter[] =
_T("Char Files (*.txt; *.ini; *.inf)\0*.txt; *.ini; *.inf\0")
_T("All Files (*.*)\0*.*\0\0");
void CNotePadDlg::BEToLE(char* pStr, int nLength)
{
for (char* p = pStr + nLength - 2; p >= pStr; p -= 2)
std::swap(*p, *(p + 1));
}
LPWSTR CNotePadDlg::ToUnicode(const char* pStr, DWORD nCode)
{
int nBytes = MultiByteToWideChar(nCode, 0, pStr, -1, NULL, 0);
auto p = new WCHAR[nBytes + 1];
MultiByteToWideChar(nCode, 0, pStr, -1, p, nBytes);
p[nBytes] = '\0';
return p;
}
BOOL CNotePadDlg::CheckUnicode(unsigned char* pStr, int nBytes)
{
if (pStr[0] == 0xFE && pStr[1] == 0xFF)
{
BEToLE((char*)pStr, nBytes);
m_nCode = (DWORD)CodeType::UTF_BE;
return TRUE;
}
else if (pStr[0] == 0xFF && pStr[1] == 0xFE)
{
m_nCode = (DWORD)CodeType::UTF_LE;
return TRUE;
}
return FALSE;
}
int CNotePadDlg::GetCodePage(unsigned char* pStr)
{
if ((pStr[0] == 0xEF && pStr[1] == 0xBB && pStr[2] == 0xBF) || CheckUtf8WithoutBom(pStr))
{
(pStr[0] == 0xEF && pStr[1] == 0xBB && pStr[2] == 0xBF)
? m_nCode = (DWORD)CodeType::UTF8_BOM
: m_nCode = (DWORD)CodeType::UTF8;
return CP_UTF8;
}
m_nCode = (DWORD)CodeType::ANSI;
return CP_ACP;
}
BOOL CNotePadDlg::CheckUtf8WithoutBom(unsigned char* pStr)
{
auto p = pStr;
int nCount = 0;
int nLength = strlen((LPCSTR)pStr);
while (*p)
{
auto c = *p++;
if ((c & 0x80) == 0)
if (++nCount == nLength)
return FALSE;
else continue;
int nBytes = 0;
do nBytes++; while ((c = c << 1) & 0x80);
if (nBytes == 1) return FALSE;
for (int i = 1; i < nBytes; i++)
if ((*p++ & 0xC0) != 0x80)
return FALSE;
}
return TRUE;
}
void CNotePadDlg::ReadText(const CString& strFileName)
{
CFile file;
int nReadMask = CFile::modeRead | OF_SHARE_DENY_WRITE;
if (!file.Open(strFileName, nReadMask, NULL))
{
MessageBox(_T("打开文件失败"));
return;
}
int nBytes = 0;
if ((nBytes = (int)file.GetLength()) <= 0)
{
MessageBox(_T("打开空文件"));
SetDlgItemText(IDC_TEXT, _T(""));
return;
}
unsigned char* p = new unsigned char[nBytes + 2];
nBytes = file.Read(p, nBytes);
p[nBytes] = p[nBytes + 1] = 0;
if (CheckUnicode(p, nBytes))
SetDlgItemText(IDC_TEXT, (LPTSTR)p);
else
{
int nCodePage = GetCodePage(p);
if (nCodePage != CP_ACP && nCodePage != CP_UTF8) return;
LPWSTR pText = ToUnicode((const char*)p, nCodePage);
if (!pText) return;
SetDlgItemText(IDC_TEXT, (LPCTSTR)pText);
}
if (!p) delete[]p;
}