// XTPSyntaxEditBufferManager.cpp /** * @file XTPSyntaxEditBufferManager.cpp * * @copyright * (c) 1998-2025 Codejock Software, All Rights Reserved. * * This source file is the property of Codejock Software and must not be * redistributed by any means without the explicit written permission of * Codejock Software. * * The use of this source code is governed by the terms and conditions specified * in the Toolkit Pro license agreement. Codejock Software grants you, as a * single software developer, the limited right to use this software on one * computer only. * * Contact Information: * support@codejock.com * http://www.codejock.com * */ #include "stdafx.h" // common includes #include "Common/XTPTypeId.h" #include "Common/XTPCasting.h" #include "Common/XTPFramework.h" #include "Common/XTPSystemHelpers.h" #include "Common/XTPSynchro.h" #include "Common/XTPApplication.h" #include "Common/XTPSingleton.h" #include "Common/XTPColorManager.h" #include "Common/XTPGdiObjects.h" #include "Common/XTPDrawHelpers.h" #include "Common/XTPNotifyConnection.h" #include "Common/XTPSmartPtrInternalT.h" #include "Common/XTPVC80Helpers.h" // syntax editor includes #include "SyntaxEdit/XTPSyntaxEditDefines.h" #include "SyntaxEdit/XTPSyntaxEditStruct.h" #include "SyntaxEdit/XTPSyntaxEditUndoManager.h" #include "SyntaxEdit/XTPSyntaxEditLineMarksManager.h" #include "SyntaxEdit/XTPSyntaxEditLexPtrs.h" #include "SyntaxEdit/XTPSyntaxEditTextIterator.h" #include "SyntaxEdit/XTPSyntaxEditLexParser.h" #include "SyntaxEdit/XTPSyntaxEditLexColorFileReader.h" #include "SyntaxEdit/XTPSyntaxEditBufferManager.h" #include "SyntaxEdit/XTPSyntaxEditIIDs.h" using namespace XTPSyntaxEditLexAnalyser; #include "Common/Base/Diagnostic/XTPDisableNoisyWarnings.h" #ifdef _DEBUG # define new DEBUG_NEW # undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif IMPLEMENT_DYNCREATE(CXTPSyntaxEditBufferManager, CXTPCmdTarget) //=========================================================================== // CRLF styles static const char* g_pcszCRLFStyles[] = { "\x0D\x0A", // DOS/Windows style "\x0A\x0D", // UNIX style "\x0A" // Macintosh style }; static const WCHAR* g_pcszCRLFStylesW[] = { L"\x0D\x0A", // DOS/Windows style L"\x0A\x0D", // UNIX style L"\x0A" // Macintosh style }; //=========================================================================== // CXTPSyntaxEditBufferManager //=========================================================================== template inline _TFileChar* _T_GetCRLF(int nCRLFLenStyle, _TFileChar c = 0) { UNREFERENCED_PARAMETER(c); _TFileChar** ppStyles = NULL; #pragma warning(push) #pragma warning(disable : 4127) // C4127: conditional expression is constant if (sizeof(_TFileChar) == 1) #pragma warning(pop) { ppStyles = (_TFileChar**)g_pcszCRLFStyles; } else { _ASSERTE(sizeof(_TFileChar) == 2); ppStyles = (_TFileChar**)g_pcszCRLFStylesW; } if (nCRLFLenStyle < 0 || nCRLFLenStyle >= _countof(g_pcszCRLFStyles)) { _ASSERTE(FALSE); nCRLFLenStyle = 0; } return ppStyles[nCRLFLenStyle]; } template inline int _T_StrLen(_TFileChar* pStr) { #pragma warning(push) #pragma warning(disable : 4127) // C4127: conditional expression is constant if (sizeof(_TFileChar) == 1) #pragma warning(pop) { return (int)strlen((CHAR*)pStr); } _ASSERTE(sizeof(_TFileChar) == 2); return (int)wcslen((WCHAR*)pStr); } CString GetFileExtention(CFile* pFile) { TCHAR szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szFileName[_MAX_FNAME], szExt[_MAX_EXT]; szDrive[0] = _T('\0'); szDir[0] = _T('\0'); szFileName[0] = _T('\0'); szExt[0] = _T('\0'); SPLITPATH_S(pFile->GetFileName(), szDrive, szDir, szFileName, szExt); return szExt; } //--------------------------------------------------------------------------- int AFX_CDECL _Compare_BYTE(const void* pb1, const void* pb2) { if (*((BYTE*)pb1) > *((BYTE*)pb2)) return 1; if (*((BYTE*)pb2) > *((BYTE*)pb1)) return -1; return 0; } BOOL _IsUnicodeFile_heuristic(CFile* pFile) { pFile->SeekToBegin(); const int cnBufferSize = 1024; BYTE arData[cnBufferSize]; BYTE arData0[cnBufferSize / 2]; BYTE arData1[cnBufferSize / 2]; UINT uDataSize = pFile->Read(arData, cnBufferSize); pFile->SeekToBegin(); UINT uDataXcount = uDataSize / 2; UINT i; for (i = 0; i < uDataXcount; i++) { arData0[i] = arData[i * 2]; arData1[i] = arData[i * 2 + 1]; if ((arData0[i] == 0xA || arData0[i] == 0xD) && arData1[i] == 0) return TRUE; } qsort(arData0, uDataXcount, sizeof(BYTE), _Compare_BYTE); qsort(arData1, uDataXcount, sizeof(BYTE), _Compare_BYTE); int nVariation0 = 0; int nVariation1 = 0; int nSmallNumbers1 = 0; for (i = 1; i < uDataXcount; i++) { if (arData0[i] != arData0[i - 1]) nVariation0++; } for (i = 1; i < uDataXcount; i++) { if (arData1[i] != arData1[i - 1]) nVariation1++; if (arData1[i] < 9) nSmallNumbers1++; } if (uDataXcount < 10) return nVariation0 > nVariation1 || nSmallNumbers1; int nVariationDiff = nVariation0 * 100 / max(1, nVariation1); int nSmallNumbersPc = XTPToIntChecked(nSmallNumbers1 * 100 / max(1, uDataXcount)); return nVariationDiff > 150 || nSmallNumbersPc > 3; } BOOL IsUnicodeFile(CFile* pFile) { pFile->SeekToBegin(); WORD wPrefix; UINT uReaded = pFile->Read(&wPrefix, 2); if (uReaded == 2 && wPrefix == 0xFEFF) { return TRUE; } #ifdef XTP_FIXED // fail it with multi byte text. // disable this method. #else DWORD_PTR dwFileSize = (DWORD_PTR)pFile->GetLength(); if (dwFileSize % 2 == 0) { return _IsUnicodeFile_heuristic(pFile); } #endif pFile->SeekToBegin(); return FALSE; } //=========================================================================== template inline int _T_GetCRLFStyle(_TFileChar chEOL1, _TFileChar chEOL2, int* pnCRLFLen) { int nCRLFLen = 1; int nCRLFStyle = xtpEditCRLFStyleUnknown; if (chEOL1 == 13) { // _ASSERTE(chEOL2 == 10); // incorrect text - reversed DOS CRLF style nCRLFLen = chEOL2 == 10 ? 2 : 1; nCRLFStyle = xtpEditCRLFStyleDos; } else if (chEOL1 == 10) { if (chEOL2 == 13) { nCRLFLen = 2; nCRLFStyle = xtpEditCRLFStyleUnix; } else { nCRLFLen = 1; nCRLFStyle = xtpEditCRLFStyleMac; } } if (pnCRLFLen) { *pnCRLFLen = nCRLFLen; } return nCRLFStyle; } template inline void _T_StrAdd(CString& rStr, _TFileChar* pStr2, UINT uCodePage) { #pragma warning(push) #pragma warning(disable : 4127) // C4127: conditional expression is constant if (sizeof(TCHAR) == 2 && sizeof(_TFileChar) == 1) #pragma warning(pop) { const int cnBuf2Size = _cnMaxStr2_chars + 1; WCHAR szBuf2[cnBuf2Size]; ::ZeroMemory(szBuf2, sizeof(szBuf2)); int nLen = MultiByteToWideChar(uCodePage, 0, (LPCSTR)pStr2, -1, szBuf2, cnBuf2Size - 1); _ASSERTE(nLen <= cnBuf2Size - 1); UNUSED(nLen); rStr += szBuf2; } else { // _ASSERTE(sizeof(TCHAR) == sizeof(_TFileChar)); UNREFERENCED_PARAMETER(uCodePage); rStr += pStr2; } } //=========================================================================== template BOOL _T_ReadStringFromFile(CFile* pFile, CString& rstrString, int& rnCRLFStyle, UINT uCodePage, _TFileChar c = 0) { UNREFERENCED_PARAMETER(c); _ASSERTE(pFile); if (!pFile) return FALSE; rstrString.Empty(); rnCRLFStyle = -1; const int cnBuffSize = 128; // 512; _TFileChar pBuff[cnBuffSize + 10]; UINT uFileSize = (UINT)pFile->GetLength(); while ((UINT)pFile->GetPosition() < uFileSize) { UINT uReadSizeB = (cnBuffSize) * sizeof(_TFileChar); UINT uBufDataCountB = pFile->Read(pBuff, uReadSizeB); if (!uBufDataCountB) { _ASSERTE(FALSE); break; } _ASSERTE(uBufDataCountB % sizeof(_TFileChar) == 0); int nBufDataLen = XTPToIntChecked(uBufDataCountB / sizeof(_TFileChar)); pBuff[nBufDataLen] = _T('\0'); int nBufStrLen = _T_StrLen(pBuff); _ASSERTE(nBufStrLen <= nBufDataLen); _TFileChar* pEOL = NULL; #pragma warning(push) #pragma warning(disable : 4127) // C4127: conditional expression is constant if (sizeof(_TFileChar) == 1) #pragma warning(pop) { #ifdef _MBCS pEOL = (_TFileChar*)_mbspbrk((BYTE*)pBuff, (BYTE*)"\x0A\x0D"); #else pEOL = (_TFileChar*)strpbrk((char*)pBuff, "\x0A\x0D"); #endif } else { pEOL = (_TFileChar*)wcspbrk((wchar_t*)pBuff, L"\x0A\x0D"); } BOOL bEOL_badFormat = FALSE; // check bad case: when zero char is rather then readed buffer end if (!pEOL && nBufStrLen < nBufDataLen) { pEOL = pBuff + nBufStrLen; bEOL_badFormat = TRUE; } //--------------------------------- if (!pEOL) { _T_StrAdd<_TFileChar, cnBuffSize>(rstrString, pBuff, uCodePage); continue; } _TFileChar chEOL1 = pEOL[0]; _TFileChar chEOL2 = pEOL[1]; *pEOL = 0; _T_StrAdd<_TFileChar, cnBuffSize>(rstrString, pBuff, uCodePage); if (!bEOL_badFormat && chEOL2 == 0 && (chEOL1 == 10 || chEOL1 == 13)) { // buffer ended on the middle of CRLF ? // read one more char to be sure in CRLF style. if (uReadSizeB == uBufDataCountB && (UINT)pFile->GetPosition() < uFileSize) { _TFileChar* pBufTail = pBuff + uBufDataCountB / sizeof(_TFileChar); UINT uReadedB = pFile->Read(pBufTail, sizeof(_TFileChar)); pBufTail[1] = 0; chEOL2 = pBufTail[0]; uReadSizeB += uReadedB; uBufDataCountB += uReadedB; } } int nCRLFLen = 1; if (!bEOL_badFormat) { rnCRLFStyle = _T_GetCRLFStyle<_TFileChar>(chEOL1, chEOL2, &nCRLFLen); _ASSERTE(rnCRLFStyle != xtpEditCRLFStyleUnknown); } INT_PTR nEolPos = INT_PTR(pEOL - pBuff); LONG nSeekBack = XTPToLong((nEolPos + nCRLFLen) * sizeof(_TFileChar) - XTPToIntChecked(uBufDataCountB)); pFile->Seek(nSeekBack, CFile::current); return TRUE; } return rstrString.GetLength() > 0; } //=========================================================================== template int _T_WriteStringToFile(_TFile* pFile, LPCTSTR pszString, int nCRLFStyle, UINT uCodePage, CByteArray* parBuffer = NULL, _TFileChar c = 0) { UNREFERENCED_PARAMETER(c); CByteArray arBufferInt; if (!parBuffer) { parBuffer = &arBufferInt; } int nStrLen = (int)_tcslen(pszString); BYTE* pFileBuffer = NULL; int nFileBufferLenB = 0; #pragma warning(push) #pragma warning(disable : 4127) // C4127: conditional expression is constant if (sizeof(TCHAR) == sizeof(_TFileChar)) #pragma warning(pop) { pFileBuffer = (BYTE*)pszString; nFileBufferLenB = XTPToIntChecked(nStrLen * sizeof(_TFileChar)); } else { int nNeedBufSizeB = nStrLen * 2 + 30; if (parBuffer->GetSize() < nNeedBufSizeB) { parBuffer->SetSize(nNeedBufSizeB + 256); } pFileBuffer = parBuffer->GetData(); _ASSERTE(parBuffer->GetSize() >= nNeedBufSizeB); ZeroMemory(pFileBuffer, XTPToSizeTChecked(nNeedBufSizeB)); #pragma warning(push) #pragma warning(disable : 4127) // C4127: conditional expression is constant if (sizeof(TCHAR) == 2 && sizeof(_TFileChar) == 1) #pragma warning(pop) { int nMBCStextLen = WideCharToMultiByte(uCodePage, 0, (LPCWSTR)pszString, -1, (LPSTR)pFileBuffer, nNeedBufSizeB, NULL, NULL); nFileBufferLenB = max(nMBCStextLen - 1, 0); } #pragma warning(push) #pragma warning(disable : 4127) // C4127: conditional expression is constant else if (sizeof(TCHAR) == 1 && sizeof(_TFileChar) == 2) #pragma warning(pop) { int nWtextLen = MultiByteToWideChar(uCodePage, 0, (LPCSTR)pszString, -1, (LPWSTR)pFileBuffer, nNeedBufSizeB / 2); nFileBufferLenB = max(nWtextLen - 1, 0) * 2; } else { _ASSERTE(FALSE); return 0; } } //------------------------------------------------------------------------ if (nFileBufferLenB > 0) { pFile->Write(pFileBuffer, XTPToUIntChecked(nFileBufferLenB)); } if (nCRLFStyle >= 0) { _TFileChar* tszCRLF = _T_GetCRLF<_TFileChar>(nCRLFStyle); int nCRLFlenB = XTPToIntChecked(_T_StrLen(tszCRLF) * sizeof(_TFileChar)); pFile->Write(tszCRLF, XTPToUIntChecked(nCRLFlenB)); nFileBufferLenB += nCRLFlenB; } return nFileBufferLenB; } //=========================================================================== AFX_INLINE BOOL ReadStringFromFileEx(CFile* pFile, CString& rstrString, int& rnCRLFStyle, UINT uCodePage, BOOL bUnicode) { if (bUnicode) { return _T_ReadStringFromFile(pFile, rstrString, rnCRLFStyle, uCodePage); } return _T_ReadStringFromFile(pFile, rstrString, rnCRLFStyle, uCodePage); } template AFX_INLINE int _T_WriteStringToFileEx(_TFile* pFile, LPCTSTR pszString, int nCRLFStyle, UINT uCodePage, CByteArray* parBuffer, BOOL bUnicode) { if (bUnicode) { return _T_WriteStringToFile(pFile, pszString, nCRLFStyle, uCodePage, parBuffer); } return _T_WriteStringToFile(pFile, pszString, nCRLFStyle, uCodePage, parBuffer); } //=========================================================================== CXTPSyntaxEditBufferManager::CXTPSyntaxEditBufferManager() { m_pConnection = new CXTPNotifyConnection(); m_pLexParser = new CXTPSyntaxEditLexParser(); m_bOverwrite = FALSE; m_nCodePage = CP_ACP; m_bUnicodeFileFormat = FALSE; m_nTabSize = XTP_DPI_X(4); m_iCRLFStyle = xtpEditCRLFStyleDos; m_nAverageLineLen = XTP_EDIT_AVELINELEN; m_pLexConfigManSinkMT = new CXTPNotifySinkMT(); m_pLineMarksManager = new CXTPSyntaxEditLineMarksManager(); m_pUndoRedoManager = new CXTPSyntaxEditUndoRedoManager(); m_bIsParserEnabled = TRUE; m_ptrDefaultLexConfigurationManager = new CXTPSyntaxEditConfigurationManager(); SetLexConfigurationManager(m_ptrDefaultLexConfigurationManager); CWinApp* pWinApp = AfxGetApp(); if (pWinApp) { m_nTabSize = XTPToIntChecked( pWinApp->GetProfileInt(XTP_EDIT_REG_SETTINGS, XTP_EDIT_REG_TABSIZE, m_nTabSize)); } m_nFileEncoding = XTP_SYNTAXEDIT_FILE_UTF_8; #ifdef _XTP_ACTIVEX EnableAutomation(); EnableTypeLib(); #endif } CXTPSyntaxEditBufferManager::~CXTPSyntaxEditBufferManager() { Close(); if (!!m_ptrDefaultLexConfigurationManager) { m_ptrDefaultLexConfigurationManager->Close(); m_ptrDefaultLexConfigurationManager = NULL; } CMDTARGET_RELEASE(m_pLexParser); CMDTARGET_RELEASE(m_pConnection); SAFE_DELETE(m_pLineMarksManager); SAFE_DELETE(m_pUndoRedoManager); m_pLexConfigManSinkMT->Delete(); } void CXTPSyntaxEditBufferManager::Close() { m_pLexConfigManSinkMT->UnadviseAll(); m_pLexParser->Close(); CleanUp(); } void CXTPSyntaxEditBufferManager::CleanUp() { m_Strings.RemoveAllStrs(); m_pUndoRedoManager->Clear(); // m_strFileExt.Empty(); } void CXTPSyntaxEditBufferManager::Load(CFile* pFile, LPCTSTR pcszFileExt) { CArchive ar(pFile, CArchive::load); SerializeEx(ar, -1, FALSE, m_nCodePage, pcszFileExt); } void CXTPSyntaxEditBufferManager::Serialize(CArchive& ar) { BOOL bUnicode = ar.IsStoring() ? m_bUnicodeFileFormat : -1; SerializeEx(ar, bUnicode, TRUE, m_nCodePage, NULL); if (ar.IsStoring()) m_pUndoRedoManager->MarkSaved(); } void CXTPSyntaxEditBufferManager::SerializeEx(CArchive& ar, BOOL bUnicode, BOOL bWriteUnicodeFilePrefix, UINT nCodePage, LPCTSTR pcszFileExt, int nDataSizeLimit) { if (m_bIsParserEnabled) { m_pLexParser->StopParseInThread(); } if (nCodePage != (UINT)-1) m_nCodePage = nCodePage; CFile* pFile = ar.GetFile(); if (ar.IsLoading()) { CleanUp(); if (bUnicode < 0) { m_bUnicodeFileFormat = FALSE; SetFileEncoding(XTP_SYNTAXEDIT_FILE_UTF_8); BYTE buff[3]; pFile->SeekToBegin(); UINT uRead = pFile->Read(buff, 3); if (uRead == 3 && buff[0] == 0xEF && buff[1] == 0xBB && buff[2] == 0xBF) { SetFileEncoding(XTP_SYNTAXEDIT_FILE_UTF_8_BOM); } else { pFile->SeekToBegin(); uRead = pFile->Read(buff, 2); if (uRead == 2 && buff[0] == 0xFE && buff[1] == 0xFF) { m_bUnicodeFileFormat = TRUE; SetFileEncoding(XTP_SYNTAXEDIT_FILE_UTF_16_BE); } if (uRead == 2 && buff[0] == 0xFF && buff[1] == 0xFE) { m_bUnicodeFileFormat = TRUE; SetFileEncoding(XTP_SYNTAXEDIT_FILE_UTF_16_LE); } } if (GetFileEncoding() == XTP_SYNTAXEDIT_FILE_UTF_8) pFile->SeekToBegin(); } else m_bUnicodeFileFormat = (bUnicode > 0); CString strString; int nCRLFStyle = -1; int nCRLFLastLineStyle = -1; BOOL bSETeol = TRUE; int nRow = 1; while ( ReadStringFromFileEx(pFile, strString, nCRLFStyle, m_nCodePage, m_bUnicodeFileFormat)) { if (GetFileEncoding() == XTP_SYNTAXEDIT_FILE_UTF_16_BE) { BYTE* arr = (BYTE*)strString.GetBuffer(strString.GetLength()); for (int n = 0; n < strString.GetLength() * 2; n += 2) { BYTE b = arr[n]; arr[n] = arr[n + 1]; arr[n + 1] = b; }; } m_Strings.SetAtGrowStr(nRow, strString); if (bSETeol && nCRLFStyle >= 0) { SetCRLFStyle(nCRLFStyle); bSETeol = FALSE; } nCRLFLastLineStyle = nCRLFStyle; nRow++; } if (nCRLFLastLineStyle >= 0) { m_Strings.SetAtGrowStr(nRow, _T("")); } CString strExt = (NULL != pcszFileExt ? CString(pcszFileExt) : GetFileExtention(pFile)); if (!strExt.IsEmpty()) SetFileExt(strExt); } else if (ar.IsStoring()) { if (bUnicode == -1) bUnicode = m_bUnicodeFileFormat; if (bWriteUnicodeFilePrefix) { if (bUnicode) { if (GetFileEncoding() == XTP_SYNTAXEDIT_FILE_UTF_16_BE) { ar << (BYTE)0xFE; ar << (BYTE)0xFF; } if (GetFileEncoding() == XTP_SYNTAXEDIT_FILE_UTF_16_LE) { ar << (BYTE)0xFF; ar << (BYTE)0xFE; } } else { if (GetFileEncoding() == XTP_SYNTAXEDIT_FILE_UTF_8) { // } if (GetFileEncoding() == XTP_SYNTAXEDIT_FILE_UTF_8_BOM) { ar << (BYTE)0xEF; ar << (BYTE)0xBB; ar << (BYTE)0xBF; } } } CByteArray arBuffer; int nCRLFStyle = GetCurCRLFType(); int nDataSize = 0; int nRowsCount = m_Strings.GetCount(); for (int i = 1; i < nRowsCount; i++) { CString strLine = m_Strings.GetStr(i); if (i == nRowsCount - 1) { // last line nCRLFStyle = -1; // do not write CRLF } if (GetFileEncoding() == XTP_SYNTAXEDIT_FILE_UTF_16_BE) { BYTE* arr = (BYTE*)strLine.GetBuffer(strLine.GetLength()); for (int n = 0; n < strLine.GetLength() * 2; n += 2) { BYTE b = arr[n]; arr[n] = arr[n + 1]; arr[n + 1] = b; }; } int nWrittenBytes = _T_WriteStringToFileEx(&ar, strLine, nCRLFStyle, m_nCodePage, &arBuffer, bUnicode); nDataSize += nWrittenBytes; if (nDataSizeLimit > 0 && nDataSize > nDataSizeLimit) break; } CString strExt = (NULL != pcszFileExt ? CString(pcszFileExt) : GetFileExtention(pFile)); if (!strExt.IsEmpty()) SetFileExt(strExt); } } void CXTPSyntaxEditBufferManager::SetFileEncoding(int val) { m_nFileEncoding = (XTP_SYNTAXEDIT_FILE_ENCODING)val; } int CXTPSyntaxEditBufferManager::GetFileEncoding() { return m_nFileEncoding; } void CXTPSyntaxEditBufferManager::SetLexConfigurationManager( CXTPSyntaxEditConfigurationManager* pMan) { m_pLexConfigManSinkMT->UnadviseAll(); if (m_ptrDefaultLexConfigurationManager.operator!=(pMan)) { m_ptrDefaultLexConfigurationManager->Close(); m_ptrDefaultLexConfigurationManager = NULL; } m_ptrLexConfigurationManager.SetPtr(pMan, TRUE); if (pMan) { CXTPNotifyConnection* ptrConn = pMan->GetConnection(); _ASSERTE(ptrConn); if (ptrConn) { m_pLexConfigManSinkMT->Advise( ptrConn, xtpEditClassSchWasChanged, CreateNotfySinkClassDelegate( this, &CXTPSyntaxEditBufferManager::OnLexConfigManEventHandler)); m_pLexConfigManSinkMT->Advise( ptrConn, xtpEditThemeWasChanged, CreateNotfySinkClassDelegate( this, &CXTPSyntaxEditBufferManager::OnLexConfigManEventHandler)); m_pLexConfigManSinkMT->Advise( ptrConn, xtpEditAllConfigWasChanged, CreateNotfySinkClassDelegate( this, &CXTPSyntaxEditBufferManager::OnLexConfigManEventHandler)); } } } void CXTPSyntaxEditBufferManager::OnLexConfigManEventHandler(XTP_NOTIFY_CODE Event, WPARAM wParam, LPARAM lParam) { if (!m_bIsParserEnabled) { return; } if (Event == xtpEditClassSchWasChanged || Event == xtpEditAllConfigWasChanged) { CXTPSyntaxEditTextSchema* ptrNewTxtSch = NULL; BOOL bSetTxtSch = FALSE; if (Event == xtpEditClassSchWasChanged) { // wParam = LPCTSTR - Schema name; // lParam = CXTPSyntaxEditLexTextSchema* New text schema pointer // or NULL if schema was removed. CXTPSyntaxEditLexTextSchema* pTxtSch = (CXTPSyntaxEditLexTextSchema*)lParam; if (pTxtSch) { if (pTxtSch->IsFileExtSupported(m_strFileExt)) { ptrNewTxtSch = pTxtSch; bSetTxtSch = TRUE; } else { CXTPSyntaxEditLexTextSchema* ptrTxtSch_current = m_pLexParser->GetTextSchema(); CString strName_current = ptrTxtSch_current ? ptrTxtSch_current->GetSchName() : CString(); CString strName_New = pTxtSch->GetSchName(); if (strName_current.CompareNoCase(strName_New) == 0) { // such file ext is no longer supported by this schema ptrNewTxtSch = NULL; bSetTxtSch = TRUE; } } } else { ptrNewTxtSch = GetMasterTextSchema(m_strFileExt); bSetTxtSch = !ptrNewTxtSch; } } if (Event == xtpEditAllConfigWasChanged) { ptrNewTxtSch = GetMasterTextSchema(m_strFileExt); bSetTxtSch = TRUE; } //==================================================================== if (bSetTxtSch) { m_pLexParser->SetTextSchema(ptrNewTxtSch); if (ptrNewTxtSch) { XTP_EDIT_LINECOL pos1_0 = { 1, 0 }; BOOL bParseInThread = m_pLexParser->GetSchemaOptions(GetFileExt()) ->m_bConfigChangedReparceInSeparateThread; if (bParseInThread) { m_pLexParser->StartParseInThread(this, &pos1_0, NULL, 0, TRUE); } else { CXTPSyntaxEditLexTextSchema* ptrTextSch = m_pLexParser->GetTextSchema(); if (ptrTextSch) { CXTPSyntaxEditTextIterator txtIter(this); ptrTextSch->RunParseUpdate(TRUE, &txtIter, &pos1_0, NULL); } } } m_pConnection->SendEvent(Event, wParam, lParam); } } if (Event == xtpEditThemeWasChanged) { // wParam = LPCTSTR - Theme name; // lParam = CXTPSyntaxEditColorTheme* New theme pointer // or NULL if theme was removed. CXTPSyntaxEditColorTheme* pNewTheme = (CXTPSyntaxEditColorTheme*)lParam; CXTPSyntaxEditLexTextSchema* ptrTxtSch = m_pLexParser->GetTextSchema(); if (ptrTxtSch) { ptrTxtSch->ApplyTheme(pNewTheme); m_pConnection->SendEvent(Event, wParam, lParam); } } } BOOL CXTPSyntaxEditBufferManager::InsertText(LPCTSTR szText, int nRow, int nCol, BOOL bCanUndo, XTP_EDIT_LINECOL* pFinalLC) { int nStrLenB = XTPToIntChecked(_tcslen(szText) * sizeof(TCHAR)); CMemFile memFile((BYTE*)szText, XTPToUIntChecked(nStrLenB)); CString strString; CString strReplased; int nLastLineEOLstyle = -1; CString strRow1, strRow2; memFile.SeekToBegin(); // process first row (cut and concatenate) if (_T_ReadStringFromFile(&memFile, strString, nLastLineEOLstyle, m_nCodePage)) { strRow1 = m_Strings.GetStr(nRow); // int nLen = strRow1.GetLength(); int nLenC = (int)_tcsclen(strRow1); if (nCol - 1 < nLenC) { int nPosX = XTPToIntChecked(_tcsnbcnt(strRow1, XTPToSizeTChecked(nCol - 1))); strRow2 = strRow1.Mid(nPosX); strRow1 = strRow1.Left(nPosX); strRow1 += strString; if (m_bOverwrite) { int nReplaceLen = min(strString.GetLength(), strRow2.GetLength()); strReplased = strRow2.Left(nReplaceLen); strRow2.Delete(0, nReplaceLen); } m_Strings.SetAtGrowStr(nRow, strRow1); } else { m_Strings.InsertText(nRow, nCol - 1, strString, TRUE); } } // process middle rows (insert them) int nCRLFStyleX = -1; int r = nRow + 1; while (_T_ReadStringFromFile(&memFile, strString, nCRLFStyleX, m_nCodePage)) { m_Strings.InsertStr(r, strString); r++; nLastLineEOLstyle = nCRLFStyleX; } // process last row (concatenate) int nRowTo = nRow; int nColTo = nCol + 1; if (nLastLineEOLstyle >= 0) { m_Strings.InsertStr(r, strRow2); nRowTo = r; nColTo = (int)_tcsclen(strString) + 1; } else { strString = m_Strings.GetStr(r - 1); nRowTo = r - 1; nColTo = (int)_tcsclen(strString) + 1; strString += strRow2; m_Strings.SetAtGrowStr(r - 1, strString); } //=========================================================================== if (pFinalLC) { pFinalLC->nLine = nRowTo; pFinalLC->nCol = nColTo; } if (bCanUndo) { if (!m_bOverwrite || strReplased == "") // By Leva: added 2nd condition to eliminate undo bug { m_pUndoRedoManager->AddCommand(new CXTPSyntaxEditInsertStringCommand( this, szText, XTP_EDIT_LINECOL::MakeLineCol(nRow, nCol), XTP_EDIT_LINECOL::MakeLineCol(nRowTo, nColTo))); } else { m_pUndoRedoManager->SetGroupInsertMode(FALSE); m_pUndoRedoManager->AddCommand(new CXTPSyntaxEditReplaceStringCommand( this, szText, strReplased, XTP_EDIT_LINECOL::MakeLineCol(nRow, nCol), XTP_EDIT_LINECOL::MakeLineCol(nRowTo, nColTo))); } } return TRUE; } BOOL CXTPSyntaxEditBufferManager::InsertTextBlock(LPCTSTR szText, int nRow, int nCol, BOOL bCanUndo, XTP_EDIT_LINECOL* pFinalLC) { int nStrLenB = XTPToIntChecked(_tcslen(szText) * sizeof(TCHAR)); CMemFile memFile((BYTE*)szText, XTPToUIntChecked(nStrLenB)); memFile.SeekToBegin(); CString strString; int nEndPos = 0; int nCRLFStyleX = -1; int r = nRow; int nDispCol = StrPosToCol(nRow, nCol - 1); if (bCanUndo) { m_pUndoRedoManager->SetGroupInsertMode(TRUE); } while (_T_ReadStringFromFile(&memFile, strString, nCRLFStyleX, m_nCodePage)) { CString strRow = m_Strings.GetStr(r); int nRowLen = (int)_tcsclen(strRow); int nRowCols = StrPosToCol(r, nRowLen); int nPos = ColToStrPos(r, nDispCol); if (nRowCols < nDispCol) { nPos = nRowLen + (nDispCol - nRowCols); } m_Strings.InsertText(r, nPos, strString, TRUE); //-------------------------------------------------------------------- nEndPos = nPos + strString.GetLength(); if (bCanUndo) { XTP_EDIT_LINECOL posFrom = { r, nPos + 1 }; XTP_EDIT_LINECOL posTo = { r, nEndPos + 1 }; m_pUndoRedoManager->AddCommand( new CXTPSyntaxEditInsertStringCommand(this, strString, posFrom, posTo)); } //-------------------------------------------------------------------- r++; } if (bCanUndo) { m_pUndoRedoManager->SetGroupInsertMode(FALSE); } //=========================================================================== if (pFinalLC) { pFinalLC->nLine = r - 1; pFinalLC->nCol = nEndPos + 1; } return TRUE; } void CXTPSyntaxEditBufferManager::GetLineText(int nLine, CString& strText, BOOL bAddCRLF, int nCRLFStyle) { strText = GetLineText(nLine, bAddCRLF, nCRLFStyle); } CString CXTPSyntaxEditBufferManager::GetLineText(int nLine, BOOL bAddCRLF, int nCRLFStyle) const { CString strText = m_Strings.GetStr(nLine); if (bAddCRLF) { strText += GetCRLF(nCRLFStyle); } return strText; } int CXTPSyntaxEditBufferManager::GetLineTextLength(int nLine, BOOL bAddCRLF, int nCRLFStyle) const { int nLen = m_Strings.GetStrLen(nLine); if (bAddCRLF) { int nEOLlen = (int)_tcslen(GetCRLF(nCRLFStyle)); nLen += nEOLlen; } return nLen; } int CXTPSyntaxEditBufferManager::GetLineTextLengthC(int nLine, BOOL bAddCRLF, int nCRLFStyle) const { int nLen = m_Strings.GetStrLenC(nLine); if (bAddCRLF) { int nEOLlen = (int)_tcsclen(GetCRLF(nCRLFStyle)); nLen += nEOLlen; } return nLen; } int CXTPSyntaxEditBufferManager::GetMaxLineTextLength() const { return CalcMaxLineTextLength(); } int CXTPSyntaxEditBufferManager::CalcMaxLineTextLength(int nLineFrom, int nLineTo, BOOL bExpandTabs) const { nLineFrom = min(max(1, nLineFrom), GetRowCount()); nLineTo = nLineTo < 0 ? GetRowCount() : min(nLineTo, GetRowCount()); if (nLineFrom >= m_Strings.GetCount() || nLineTo >= m_Strings.GetCount()) { return 0; } int nTabSize = GetTabSize(); int nMAXlen = 0; for (int i = nLineFrom; i <= nLineTo; i++) { CString* pCStrData = m_Strings.GetStrDataC(i); if (!pCStrData) continue; int nLen = pCStrData->GetLength(); if (bExpandTabs) { LPCTSTR pcszString = (LPCTSTR)(*pCStrData); int nOffset = 0; for (int k = 0; k < nLen; k++) { if (pcszString[k] == _T('\t')) nOffset += (nTabSize - nOffset % nTabSize); else nOffset++; } nLen = nOffset; } if (nLen > nMAXlen) nMAXlen = nLen; } return nMAXlen; } BOOL CXTPSyntaxEditBufferManager::DeleteText(int nRowFrom, int nColFrom, int nRowTo, int nColTo, BOOL bCanUndo, BOOL bDispCol) { _ASSERTE(nColFrom >= 1 && nColTo >= 1); if (bCanUndo) { int nPos1 = bDispCol ? nColFrom : StrPosToCol(nRowFrom, nColFrom - 1); // By Leva: moved -1 into brackets int nPos2 = bDispCol ? nColTo : StrPosToCol(nRowTo, nColTo - 1); // By Leva: moved -1 into brackets CMemFile file(CalcAveDataSize(nRowFrom, nRowTo)); if (GetBuffer(nRowFrom, nPos1, nRowTo, nPos2, file)) { TCHAR szNull = NULL; file.SeekToEnd(); file.Write((const BYTE*)&szNull, sizeof(TCHAR)); BYTE* pBytes = file.Detach(); m_pUndoRedoManager->AddCommand(new CXTPSyntaxEditDeleteStringCommand( this, (LPCTSTR)pBytes, XTP_EDIT_LINECOL::MakeLineCol(nRowFrom, bDispCol ? ColToStrPos(nRowFrom, nColFrom) + 1 : nColFrom), XTP_EDIT_LINECOL::MakeLineCol(nRowTo, bDispCol ? ColToStrPos(nRowTo, nColTo) + 1 : nColTo))); free(pBytes); } } BOOL bResult = FALSE; if (nRowFrom < nRowTo) { // Process nRowFrom int nStrLenR1 = m_Strings.GetStrLenC(nRowFrom); int nStrPos = bDispCol ? ColToStrPos(nRowFrom, nColFrom) : nColFrom - 1; int nCount = nStrLenR1 - nStrPos; if (nStrLenR1 && nCount > 0) { _ASSERTE(nStrPos >= 0); bResult = m_Strings.DeleteText(nRowFrom, nStrPos, nCount); _ASSERTE(bResult); } // Process nRowTo int nStrLenR2 = m_Strings.GetStrLenC(nRowTo); nStrPos = 0; nCount = bDispCol ? ColToStrPos(nRowTo, nColTo) : nColTo - 1; if (nStrLenR2 && nCount > 0) { _ASSERTE(nStrPos >= 0); bResult = m_Strings.DeleteText(nRowTo, nStrPos, nCount); _ASSERTE(bResult); } // Concatenate row and row CString strRowNew = m_Strings.GetStr(nRowFrom); CString strRow2 = m_Strings.GetStr(nRowTo); strRowNew += strRow2; m_Strings.SetAtGrowStr(nRowFrom, strRowNew); for (int r = nRowTo; r > nRowFrom; r--) { bResult = m_Strings.RemoveStr(r); // _ASSERTE(bResult); } } else { _ASSERTE(nRowFrom == nRowTo); int nPos1 = bDispCol ? ColToStrPos(nRowFrom, nColFrom) : nColFrom - 1; int nPos2 = bDispCol ? ColToStrPos(nRowTo, nColTo) : nColTo - 1; int nCount = abs(nPos2 - nPos1); // abs(nColTo - nColFrom); if (nCount) { bResult = m_Strings.DeleteText(nRowFrom, min(nPos1, nPos2), nCount); } } return bResult; } BOOL CXTPSyntaxEditBufferManager::RemoveLine(int nRow, BOOL bCanUndo, int nRowsCount) { int nRowEnd = min(GetRowCount() + 1, nRow + nRowsCount); if (bCanUndo) { CMemFile file(CalcAveDataSize(nRow, nRowEnd)); if (GetBuffer(nRow, 1, nRowEnd, 1, file)) { TCHAR szNull = _T('\0'); file.SeekToEnd(); file.Write((const BYTE*)&szNull, sizeof(TCHAR)); BYTE* pBytes = file.Detach(); m_pUndoRedoManager->AddCommand( new CXTPSyntaxEditDeleteStringCommand(this, (LPCTSTR)pBytes, XTP_EDIT_LINECOL::MakeLineCol(nRow, 1), XTP_EDIT_LINECOL::MakeLineCol(nRowEnd, 1))); free(pBytes); } } BOOL bResult = FALSE; for (int r = nRowEnd - 1; r >= nRow; r--) { BOOL b = m_Strings.RemoveStr(r); bResult |= b; } return bResult; } BOOL CXTPSyntaxEditBufferManager::GetBuffer(int row1, int col1, int row2, int col2, CMemFile& file, BOOL bColumnSelection, BOOL bForceDOSStyleCRLF) { int nTempRow1 = row1, nTempRow2 = row2; int nTempCol1 = col1, nTempCol2 = col2; if (nTempRow2 < nTempRow1) { row1 = nTempRow2; col1 = nTempCol2; row2 = nTempRow1; col2 = nTempCol1; } if (nTempRow1 == nTempRow2 || bColumnSelection) { col1 = min(nTempCol1, nTempCol2); col2 = max(nTempCol1, nTempCol2); } BOOL bStart = TRUE; BOOL bEnd = FALSE; int nStartPos = 0, nEndPos = 0; int nSizeCopy = 0; int nNewCRLFStyle = (bForceDOSStyleCRLF) ? xtpEditCRLFStyleDos : m_iCRLFStyle; const CString strCRLF(GetCRLF(nNewCRLFStyle)); for (int i = row1; i <= row2; i++) { if (i == row2) bEnd = TRUE; CString strBuffer; GetLineText(i, strBuffer); const int nLineLen = (int)_tcslen(strBuffer); nStartPos = min(bStart || bColumnSelection ? ColToStrPos(i, col1) : 0, nLineLen); nEndPos = min(bEnd || bColumnSelection ? ColToStrPos(i, col2) : nLineLen, nLineLen); if (bStart || bColumnSelection) nStartPos = XTPToIntChecked(_tcsnbcnt(strBuffer, XTPToSizeTChecked(nStartPos))); if (bEnd || bColumnSelection) nEndPos = XTPToIntChecked(_tcsnbcnt(strBuffer, XTPToSizeTChecked(nEndPos))); nSizeCopy = XTPToIntChecked(abs(nEndPos - nStartPos) * sizeof(TCHAR)); if (nSizeCopy > 0) file.Write((LPVOID)((LPCTSTR)strBuffer + nStartPos), XTPToUIntChecked(nSizeCopy)); if (bColumnSelection) { // add spaces for the free size of the column block int nAddSpaces = abs(col2 - col1) - (int)_tcsnccnt((LPCTSTR)strBuffer + nStartPos, XTPToSizeTChecked(abs(nEndPos - nStartPos))); if (nAddSpaces > 0) { const CString strSpaces(_T(' '), nAddSpaces); file.Write((LPVOID)(LPCTSTR)strSpaces, nAddSpaces * sizeof(TCHAR)); } } if (row1 != row2 && i != row2 || bColumnSelection) { // add end of the line file.Write((LPVOID)(LPCTSTR)strCRLF, strCRLF.GetLength() * sizeof(TCHAR)); } bStart = FALSE; } return TRUE; } void CXTPSyntaxEditBufferManager::SetOverwriteFlag(BOOL bOverwrite) { m_bOverwrite = bOverwrite; } BOOL CXTPSyntaxEditBufferManager::IsTextCRLF(LPCTSTR szCompText, BOOL bMatchReverse) const { CString strCRLF(g_pcszCRLFStyles[m_iCRLFStyle]); LPCTSTR szCurCRLF = (LPCTSTR)strCRLF; LPCTSTR szTextToCompare = szCompText; int nCRLFSize = lstrlen(szCurCRLF); if (bMatchReverse) szTextToCompare = (szCompText - (nCRLFSize - 1)); BOOL bIsCRLF = (_tcsncmp(szTextToCompare, szCurCRLF, XTPToSizeTChecked(nCRLFSize)) == 0); return bIsCRLF; } #ifdef _UNICODE BOOL CXTPSyntaxEditBufferManager::IsTextCRLF(LPCSTR szCompText, BOOL bMatchReverse) const { LPCSTR szCurCRLF = (LPCSTR)g_pcszCRLFStyles[m_iCRLFStyle]; LPCSTR szTextToCompare = szCompText; int nCRLFSize = (int)strlen(szCurCRLF); if (bMatchReverse) szTextToCompare = (szCompText - (nCRLFSize - 1)); BOOL bIsCRLF = (strncmp(szTextToCompare, szCurCRLF, XTPToSizeTChecked(nCRLFSize)) == 0); return bIsCRLF; } #endif CString CXTPSyntaxEditBufferManager::GetCurCRLF() const { return GetCRLF(); } LPCTSTR CXTPSyntaxEditBufferManager::GetCRLF(int nCRLFStyle) const { _ASSERTE(m_iCRLFStyle >= 0 && m_iCRLFStyle < _countof(g_pcszCRLFStyles)); int nCRLFidx = m_iCRLFStyle; if (nCRLFStyle >= 0 && nCRLFStyle < _countof(g_pcszCRLFStyles)) { nCRLFidx = nCRLFStyle; } return _T_GetCRLF(nCRLFidx); } void CXTPSyntaxEditBufferManager::SetCRLFStyle(int nCRLFStyle) { if (nCRLFStyle >= 0 && nCRLFStyle < _countof(g_pcszCRLFStyles)) { m_iCRLFStyle = nCRLFStyle; } else { _ASSERTE(FALSE); } } BOOL CXTPSyntaxEditBufferManager::SetTabSize(int nTabSize, BOOL bUpdateReg /*=FALSE*/) { m_nTabSize = nTabSize; if (bUpdateReg) { CWinApp* pWinApp = AfxGetApp(); if (pWinApp != NULL) { if (pWinApp->WriteProfileInt(XTP_EDIT_REG_SETTINGS, XTP_EDIT_REG_TABSIZE, nTabSize)) return TRUE; } return FALSE; } return TRUE; } int CXTPSyntaxEditBufferManager::GetRowCount() const { return m_Strings.GetCount() ? ((int)m_Strings.GetCount() - 1) : 0; } BOOL CXTPSyntaxEditBufferManager::IsModified() const { return m_pUndoRedoManager->IsModified(); } void CXTPSyntaxEditBufferManager::SetFileExt(const CString& strExt) { if (!m_strFileExt.IsEmpty() && m_strFileExt.CompareNoCase(strExt) == 0) return; m_strFileExt = strExt; if (m_bIsParserEnabled) { CXTPSyntaxEditTextSchema* ptrMasterTxtSch = GetMasterTextSchema(strExt); m_pLexParser->SetTextSchema(ptrMasterTxtSch); } } CString CXTPSyntaxEditBufferManager::GetConfigFile() const { if (!m_ptrLexConfigurationManager) return _T(""); return m_ptrLexConfigurationManager->GetConfigFile(); } BOOL CXTPSyntaxEditBufferManager::SetConfigFile(LPCTSTR szPath) { if (!m_ptrLexConfigurationManager) return FALSE; if (m_ptrLexConfigurationManager->m_bConfigFileMode && CString(szPath).IsEmpty()) return FALSE; CString strCfgFile0 = m_ptrLexConfigurationManager->GetConfigFile(); if (!m_ptrLexConfigurationManager->m_bConfigFileMode) m_ptrLexConfigurationManager->ReloadConfig(_T("")); else if (strCfgFile0.CompareNoCase(szPath) != 0) m_ptrLexConfigurationManager->ReloadConfig(szPath); return TRUE; } void CXTPSyntaxEditBufferManager::SetCodePage(UINT uCodePage) { m_nCodePage = uCodePage; } CXTPSyntaxEditTextSchema* CXTPSyntaxEditBufferManager::GetMasterTextSchema(const CString& strExt) const { if (!m_ptrLexConfigurationManager) return NULL; CXTPSyntaxEditTextSchemaPtr ptrMasterSch; ptrMasterSch = m_ptrLexConfigurationManager->GetTextSchemesManager().FindSchema(strExt); return ptrMasterSch; } UINT CXTPSyntaxEditBufferManager::CalcAveDataSize(int nRowStart, int nRowEnd) { UINT uSize = XTPToUIntChecked(m_nAverageLineLen * abs(nRowStart - nRowEnd)); uSize = (uSize / 1024 + 1) * 1024; return uSize; } void CXTPSyntaxEditBufferManager::EnableParser(BOOL bEnable) { if (m_bIsParserEnabled == bEnable) return; m_bIsParserEnabled = bEnable; if (m_bIsParserEnabled) { CXTPSyntaxEditTextSchema* ptrMasterTxtSch = GetMasterTextSchema(m_strFileExt); m_pLexParser->SetTextSchema(ptrMasterTxtSch); XTP_EDIT_LINECOL pos1_0 = { 1, 0 }; BOOL bParseInThread = m_pLexParser->GetSchemaOptions(GetFileExt())->m_bConfigChangedReparceInSeparateThread; if (bParseInThread) { m_pLexParser->StartParseInThread(this, &pos1_0, NULL, 0, TRUE); } else { CXTPSyntaxEditLexTextSchema* ptrTextSch = m_pLexParser->GetTextSchema(); if (ptrTextSch) { CXTPSyntaxEditTextIterator txtIter(this); ptrTextSch->RunParseUpdate(TRUE, &txtIter, &pos1_0, NULL); } } } else { m_pLexParser->SetTextSchema(NULL); } } int CXTPSyntaxEditBufferManager::ColToStrPos(int nLine, int nDispCol) const { int nStrPos = 0; int nCol = 0; const CString strText = m_Strings.GetStr(nLine); #ifdef XTP_FIXED // use ByteLength insted of Text length. int nChars = (int)_tcslen(strText); #else int nChars = (int)_tcsclen(strText); #endif LPCTSTR pChar = strText; int nTabSize = GetTabSize(); for (int i = 0; *pChar != 0 && i < nChars && (nCol + 1) < nDispCol; i++) { if (*pChar == _T('\t')) { nCol += nTabSize - (nCol % nTabSize); } else { nCol++; } if (isleadbyte(*pChar)) { i++; #ifdef XTP_FIXED nCol++; #endif } pChar = _tcsinc(pChar); nStrPos++; } // support VirtualSpace by default // m_bVirtualSpace if (nCol + 1 < nDispCol) nStrPos += nDispCol - nCol - 1; return nStrPos; } int CXTPSyntaxEditBufferManager::StrPosToCol(int nLine, int nStrPos) const { int nDispCol = 1; const CString strText = m_Strings.GetStr(nLine); LPCTSTR pChar = strText; int nTabSize = GetTabSize(); int i; for (i = 0; *pChar != 0 && i < nStrPos;) { if (*pChar == _T('\t')) { nDispCol += nTabSize - ((nDispCol - 1) % nTabSize); } else { nDispCol++; } #ifdef XTP_FIXED // multi byte character : DisplayLength 2 if (isleadbyte(*pChar)) nDispCol++; #endif pChar = _tcsinc(pChar); i++; } // support VirtualSpace by default // m_bVirtualSpace if (i < nStrPos) nDispCol += nStrPos - i; return nDispCol; } void CXTPSyntaxEditBufferManager::ChangeCase(int nRow, int nDispFrom, int nDispTo, BOOL bUpper, BOOL bCanUndo) { CString strText(m_Strings.GetStr(nRow)); int nFrom = XTPToIntChecked( _tcsnbcnt(strText, XTPToSizeTChecked(ColToStrPos(nRow, nDispFrom)))); int nTo = strText.GetLength(); if (nDispTo <= strText.GetLength() * GetTabSize()) nTo = XTPToIntChecked(_tcsnbcnt(strText, XTPToSizeTChecked(ColToStrPos(nRow, nDispTo)))); CString strOriginal = strText.Mid(nFrom, nTo - nFrom); CString strChanged(strOriginal); // upper/lower text at row nRow from nFrom to nTo if (bUpper) strChanged.MakeUpper(); else strChanged.MakeLower(); for (int i = nFrom; i < nTo; ++i) strText.SetAt(i, strChanged[i - nFrom]); m_Strings.SetAtGrowStr(nRow, strText); if (bCanUndo) { m_pUndoRedoManager->AddCommand( new CXTPSyntaxEditReplaceStringCommand(this, strChanged, strOriginal, XTP_EDIT_LINECOL::MakeLineCol(nRow, nFrom + 1), XTP_EDIT_LINECOL::MakeLineCol(nRow, nTo + 1))); } } void CXTPSyntaxEditBufferManager::ChangeTabification(int nRow, int nDispFrom, int nDispTo, BOOL bTabify, BOOL bCanUndo) { CString strText(m_Strings.GetStr(nRow)); const int nTextLen = (int)_tcsclen(strText); int nFrom = ColToStrPos(nRow, nDispFrom); int nTo = ColToStrPos(nRow, nDispTo); const int nTabSize = GetTabSize(); const CString strTab(_T(' '), nTabSize); CString strOriginal = strText.Mid(nFrom, nTo - nFrom); CString strChanged(strOriginal); // upper/lower text at row nRow from nFrom to nTo if (bTabify) { strChanged.Replace(strTab, _T("\x09")); } else { strChanged.Replace(_T("\x09"), strTab); } strText = strText.Left(nFrom) + strChanged + strText.Right(nTextLen - nTo); m_Strings.SetAtGrowStr(nRow, strText); if (bCanUndo) { m_pUndoRedoManager->AddCommand( new CXTPSyntaxEditDeleteStringCommand(this, strOriginal, XTP_EDIT_LINECOL::MakeLineCol(nRow, nFrom + 1), XTP_EDIT_LINECOL::MakeLineCol(nRow, nTo + 1))); m_pUndoRedoManager->AddCommand(new CXTPSyntaxEditInsertStringCommand( this, strChanged, XTP_EDIT_LINECOL::MakeLineCol(nRow, nFrom + 1), XTP_EDIT_LINECOL::MakeLineCol(nRow, nFrom + (int)_tcsclen(strChanged) + 1))); } } //////////////////////////////////////////////////////////////////////////// // class CXTPSyntaxEditStringsManager CXTPSyntaxEditBufferManager::CXTPSyntaxEditStringsManager::CXTPSyntaxEditStringsManager() { } CXTPSyntaxEditBufferManager::CXTPSyntaxEditStringsManager::~CXTPSyntaxEditStringsManager() { } int CXTPSyntaxEditBufferManager::CXTPSyntaxEditStringsManager::GetCount() const { return (int)m_arStrings.GetSize(); } CString CXTPSyntaxEditBufferManager::CXTPSyntaxEditStringsManager::GetStr(int nRow) const { CString* pCStr = GetStrDataC(nRow); if (pCStr) return *pCStr; return _T(""); } int CXTPSyntaxEditBufferManager::CXTPSyntaxEditStringsManager::GetStrLen(int nRow) const { CString* pCStr = GetStrDataC(nRow); if (!pCStr) return 0; int nLen = pCStr->GetLength(); return nLen; } int CXTPSyntaxEditBufferManager::CXTPSyntaxEditStringsManager::GetStrLenC(int nRow) const { CString* pCStr = GetStrDataC(nRow); if (!pCStr) return 0; int nLenC = (int)_tcsclen(*pCStr); return nLenC; } void CXTPSyntaxEditBufferManager::CXTPSyntaxEditStringsManager::SetAtGrowStr(int nRow, LPCTSTR pcszText) { CString* pCStr = GetStrData(nRow, TRUE); if (!pCStr) return; *pCStr = pcszText; } void CXTPSyntaxEditBufferManager::CXTPSyntaxEditStringsManager::SetAtGrowStr(int nRow, const CString& strText) { CString* pCStr = GetStrData(nRow, TRUE); if (!pCStr) return; *pCStr = strText; } void CXTPSyntaxEditBufferManager::CXTPSyntaxEditStringsManager::InsertStr(int nRow, const CString& strText) { if (nRow >= 0 && nRow < m_arStrings.GetSize()) { CString* pCStr = new CString(strText); m_arStrings.InsertAt(nRow, pCStr); } else { SetAtGrowStr(nRow, strText); } } BOOL CXTPSyntaxEditBufferManager::CXTPSyntaxEditStringsManager::RemoveStr(int nRow) { if (nRow >= 0 && nRow < m_arStrings.GetSize()) { CString* pCStr = m_arStrings[nRow]; m_arStrings.RemoveAt(nRow); if (pCStr) delete pCStr; return TRUE; } return FALSE; } CString* CXTPSyntaxEditBufferManager::CXTPSyntaxEditStringsManager::GetStrDataC(int nRow) const { CString* pCStr = NULL; if (nRow >= 0 && nRow < m_arStrings.GetSize()) pCStr = m_arStrings[nRow]; return pCStr; } CString* CXTPSyntaxEditBufferManager::CXTPSyntaxEditStringsManager::GetStrData( int nRow, BOOL bGrowArrayIfNeed) { CString* pCStr = NULL; if (nRow >= 0 && nRow < m_arStrings.GetSize()) pCStr = m_arStrings[nRow]; else if (bGrowArrayIfNeed) m_arStrings.SetSize(nRow + 1); else return NULL; if (!pCStr) { pCStr = new CString(); m_arStrings[nRow] = pCStr; } return pCStr; } BOOL CXTPSyntaxEditBufferManager::CXTPSyntaxEditStringsManager::InsertText(int nRow, int nPos, LPCTSTR pcszText, BOOL bGrowArrayIfNeed, TCHAR chLeftSpaceFiller) { _ASSERTE(nPos >= 0 && pcszText); CString* pCStr = GetStrData(nRow, bGrowArrayIfNeed); if (!pCStr || !pcszText && nPos < 0) return FALSE; int nStrLenC = (int)_tcsclen(*pCStr); int nFillCount = nPos > nStrLenC ? nPos - nStrLenC : 0; int nInsPos = XTPToIntChecked(_tcsnbcnt(*pCStr, XTPToSizeTChecked(nPos))); if (nFillCount) { if (chLeftSpaceFiller != _T('\0')) { CString strFill(chLeftSpaceFiller, nFillCount); *pCStr += strFill; nInsPos = XTPToIntChecked(_tcsnbcnt(*pCStr, XTPToSizeTChecked(nPos))); } else { nInsPos = pCStr->GetLength(); } } pCStr->Insert(nInsPos, pcszText); return TRUE; } BOOL CXTPSyntaxEditBufferManager::CXTPSyntaxEditStringsManager::DeleteText(int nRow, int nPos, int nCount) { _ASSERTE(nPos >= 0 && nCount > 0); CString* pCStr = GetStrData(nRow, FALSE); if (!pCStr || nPos < 0 || nCount <= 0) return FALSE; int nStrLen0 = pCStr->GetLength(); int nPosX = XTPToIntChecked(_tcsnbcnt(*pCStr, XTPToSizeTChecked(nPos))); if (nPosX >= nStrLen0) return FALSE; int nStrLenC = (int)_tcsclen(*pCStr); if (nCount > nStrLenC - nPos) nCount = nStrLenC - nPos; int nCountX = XTPToIntChecked(_tcsnbcnt(((LPCTSTR)*pCStr) + nPosX, XTPToSizeTChecked(nCount))); pCStr->Delete(nPosX, nCountX); return TRUE; } void CXTPSyntaxEditBufferManager::CXTPSyntaxEditStringsManager::RemoveAllStrs() { m_arStrings.RemoveAll(); } //////////////////////////////////////////////////////////////////////////// // class CStringPtrArray : public CArray CXTPSyntaxEditBufferManager::CXTPSyntaxEditStringsManager::CStringPtrArray::CStringPtrArray() { } CXTPSyntaxEditBufferManager::CXTPSyntaxEditStringsManager::CStringPtrArray::~CStringPtrArray() { RemoveAll(); } void CXTPSyntaxEditBufferManager::CXTPSyntaxEditStringsManager::CStringPtrArray::RemoveAll() { int nCount = (int)GetSize(); for (int i = 0; i < nCount; i++) { CString* pCStr = GetAt(i); if (pCStr) { SetAt(i, NULL); delete pCStr; } } TBase::RemoveAll(); } #ifdef _XTP_ACTIVEX BEGIN_INTERFACE_MAP(CXTPSyntaxEditBufferManager, CXTPCmdTarget) INTERFACE_PART(CXTPSyntaxEditBufferManager, XTPDIID_SyntaxEditDataManager, Dispatch) END_INTERFACE_MAP() IMPLEMENT_OLETYPELIB_EX(CXTPSyntaxEditBufferManager, XTPDIID_SyntaxEditDataManager) BEGIN_DISPATCH_MAP(CXTPSyntaxEditBufferManager, CXTPCmdTarget) DISP_PROPERTY_EX_ID(CXTPSyntaxEditBufferManager, "FileExt", 1, OleGetFileExt, OleSetFileExt, VT_BSTR) END_DISPATCH_MAP() BSTR CXTPSyntaxEditBufferManager::OleGetFileExt() { return GetFileExt().AllocSysString(); } void CXTPSyntaxEditBufferManager::OleSetFileExt(LPCTSTR pcszFileExt) { if (GetFileExt().CompareNoCase(pcszFileExt) != 0) { SetFileExt(pcszFileExt); } } #endif