From d6b5f53a0e3013932b71d7d527638d9ce473ce64 Mon Sep 17 00:00:00 2001 From: Don Ho Date: Tue, 27 Jun 2023 04:00:59 +0200 Subject: [PATCH] Fix Clipboard History panel shows corrupted data issue Fix #13817, fix #13844, close #13833 --- .../clipboardHistoryPanel.cpp | 139 +++++++++++------- .../ClipboardHistory/clipboardHistoryPanel.h | 19 ++- PowerEditor/src/clipboardFormats.h | 2 +- 3 files changed, 97 insertions(+), 63 deletions(-) diff --git a/PowerEditor/src/WinControls/ClipboardHistory/clipboardHistoryPanel.cpp b/PowerEditor/src/WinControls/ClipboardHistory/clipboardHistoryPanel.cpp index 4a3d9c62f..d8973b6fa 100644 --- a/PowerEditor/src/WinControls/ClipboardHistory/clipboardHistoryPanel.cpp +++ b/PowerEditor/src/WinControls/ClipboardHistory/clipboardHistoryPanel.cpp @@ -20,62 +20,71 @@ #include "clipboardFormats.h" -#define CLIPBOARD_TEXTFORMAT CF_UNICODETEXT #define MAX_DISPLAY_LENGTH 64 -ClipboardData ClipboardHistoryPanel::getClipboadData() +ClipboardDataInfo ClipboardHistoryPanel::getClipboadData() { - ClipboardData clipboardData; - if (!IsClipboardFormatAvailable(CLIPBOARD_TEXTFORMAT)) + ClipboardDataInfo clipboardData; + if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) return clipboardData; if (!OpenClipboard(NULL)) return clipboardData; - HGLOBAL hglb = GetClipboardData(CLIPBOARD_TEXTFORMAT); + HGLOBAL hglb = GetClipboardData(CF_UNICODETEXT); if (hglb != NULL) { - char *lpchar = (char *)GlobalLock(hglb); - wchar_t *lpWchar = (wchar_t *)GlobalLock(hglb); - - if (lpchar != NULL) + unsigned char* pData = static_cast(GlobalLock(hglb)); + if (pData != NULL) { UINT cf_nppTextLen = RegisterClipboardFormat(CF_NPPTEXTLEN); if (IsClipboardFormatAvailable(cf_nppTextLen)) { HGLOBAL hglbLen = GetClipboardData(cf_nppTextLen); if (hglbLen != NULL) - { - unsigned long *lpLen = (unsigned long *)GlobalLock(hglbLen); - if (lpLen != NULL) + { + HGLOBAL hglb_binText = GetClipboardData(CF_TEXT); + if (hglb_binText != NULL) { - for (size_t i = 0 ; i < (*lpLen) ; ++i) + unsigned char* pData_bin = static_cast(GlobalLock(hglb_binText)); + if (pData_bin != NULL) { - clipboardData.push_back(static_cast(lpchar[i])); + unsigned long* lpLen = (unsigned long*)GlobalLock(hglbLen); + if (lpLen != NULL) // Special copy-paste: Binary data + { + size_t nbBytes = (*lpLen); + for (size_t i = 0; i < nbBytes; ++i) + { + clipboardData._data.push_back(static_cast(pData_bin[i])); + } + clipboardData._isBinaryContained = true; + GlobalUnlock(hglbLen); + } + } - GlobalUnlock(hglbLen); + GlobalUnlock(hglb_binText); } } } - else if (lpWchar != nullptr) + else // Not internal binary clipboard data { - int nbBytes = (lstrlenW(lpWchar) + 1) * sizeof(wchar_t); - for (int i = 0 ; i < nbBytes ; ++i) + wchar_t* lpwchar = (wchar_t*)pData; + size_t nbBytes = (lstrlenW(lpwchar) + 1) * sizeof(wchar_t); + for (size_t i = 0 ; i < nbBytes ; ++i) { - clipboardData.push_back(static_cast(lpchar[i])); + clipboardData._data.push_back(static_cast(pData[i])); } } GlobalUnlock(hglb); - GlobalUnlock(hglb); } } CloseClipboard(); return clipboardData; } -ByteArray::ByteArray(ClipboardData cd) +ByteArray::ByteArray(ClipboardDataInfo cd) { - _length = cd.size(); + _length = cd._data.size(); if (!_length) { _pBytes = NULL; @@ -84,20 +93,22 @@ ByteArray::ByteArray(ClipboardData cd) _pBytes = new unsigned char[_length]; for (size_t i = 0 ; i < _length ; ++i) { - _pBytes[i] = cd[i]; + _pBytes[i] = cd._data[i]; } } -StringArray::StringArray(ClipboardData cd, size_t maxLen) +StringArray::StringArray(ClipboardDataInfo cd, size_t maxLen) { - if (!cd.size()) + size_t len = cd._data.size(); + + if (!len) { _pBytes = NULL; return; } - bool isCompleted = (cd.size() <= maxLen); - _length = isCompleted?cd.size():maxLen; + bool isCompleted = (len <= maxLen); + _length = isCompleted?len:maxLen; _pBytes = new unsigned char[_length+(isCompleted?0:2)]; @@ -109,7 +120,7 @@ StringArray::StringArray(ClipboardData cd, size_t maxLen) else if (!isCompleted && (i == _length-6 || i == _length-4 || i == _length-2)) _pBytes[i] = '.'; else - _pBytes[i] = cd[i]; + _pBytes[i] = cd._data[i]; } if (!isCompleted) @@ -121,17 +132,17 @@ StringArray::StringArray(ClipboardData cd, size_t maxLen) // Search clipboard data in internal storage // return -1 if not found, else return the index of internal array -int ClipboardHistoryPanel::getClipboardDataIndex(ClipboardData cbd) +int ClipboardHistoryPanel::getClipboardDataIndex(ClipboardDataInfo cbd) { int iFound = -1; bool found = false; - for (size_t i = 0, len = _clipboardDataVector.size() ; i < len ; ++i) + for (size_t i = 0, len = _clipboardDataInfos.size() ; i < len ; ++i) { - if (cbd.size() == _clipboardDataVector[i].size()) + if (cbd._data.size() == _clipboardDataInfos[i]._data.size()) { - for (size_t j = 0, len2 = cbd.size(); j < len2 ; ++j) + for (size_t j = 0, len2 = cbd._data.size(); j < len2 ; ++j) { - if (cbd[j] == _clipboardDataVector[i][j]) + if (cbd._data[j] == _clipboardDataInfos[i]._data[j]) found = true; else { @@ -150,40 +161,49 @@ int ClipboardHistoryPanel::getClipboardDataIndex(ClipboardData cbd) return iFound; } -void ClipboardHistoryPanel::addToClipboadHistory(ClipboardData cbd) +void ClipboardHistoryPanel::addToClipboadHistory(ClipboardDataInfo cbd) { int i = getClipboardDataIndex(cbd); if (i == 0) return; if (i != -1) { - _clipboardDataVector.erase(_clipboardDataVector.begin() + i); + _clipboardDataInfos.erase(_clipboardDataInfos.begin() + i); ::SendDlgItemMessage(_hSelf, IDC_LIST_CLIPBOARD, LB_DELETESTRING, i, 0); } - _clipboardDataVector.insert(_clipboardDataVector.begin(), cbd); + _clipboardDataInfos.insert(_clipboardDataInfos.begin(), cbd); - StringArray sa(cbd, MAX_DISPLAY_LENGTH); - TCHAR *displayStr = (TCHAR *)sa.getPointer(); - ::SendDlgItemMessage(_hSelf, IDC_LIST_CLIPBOARD, LB_INSERTSTRING, 0, reinterpret_cast(displayStr)); + ::SendDlgItemMessage(_hSelf, IDC_LIST_CLIPBOARD, LB_INSERTSTRING, 0, reinterpret_cast(L"")); // String will be added in drawItem() } void ClipboardHistoryPanel::drawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { - if (lpDrawItemStruct->itemID >= _clipboardDataVector.size()) + UINT i = lpDrawItemStruct->itemID; + if (i >= _clipboardDataInfos.size()) return; //printStr(TEXT("OK")); COLORREF fgColor = _lbFgColor == -1?black:_lbFgColor; // fg black by default COLORREF bgColor = _lbBgColor == -1?white:_lbBgColor; // bg white by default - StringArray sa(_clipboardDataVector[lpDrawItemStruct->itemID], MAX_DISPLAY_LENGTH); - TCHAR *ptStr = (TCHAR *)sa.getPointer(); + ClipboardDataInfo& cbd = _clipboardDataInfos[i]; + StringArray sa(cbd, MAX_DISPLAY_LENGTH); + TCHAR* displayStr = nullptr; + WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance(); + if (cbd._isBinaryContained) + { + char* displayStrA = (char*)sa.getPointer(); + displayStr = (TCHAR*)wmc.char2wchar(displayStrA, SC_CP_UTF8); + } + else + { + displayStr = (TCHAR*)sa.getPointer(); + } - //printStr(ptStr); ::SetTextColor(lpDrawItemStruct->hDC, fgColor); ::SetBkColor(lpDrawItemStruct->hDC, bgColor); - ::DrawText(lpDrawItemStruct->hDC, ptStr, lstrlen(ptStr), &(lpDrawItemStruct->rcItem), DT_SINGLELINE | DT_VCENTER | DT_LEFT); + ::DrawText(lpDrawItemStruct->hDC, displayStr, lstrlen(displayStr), &(lpDrawItemStruct->rcItem), DT_SINGLELINE | DT_VCENTER | DT_LEFT); } intptr_t CALLBACK ClipboardHistoryPanel::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam) @@ -212,9 +232,11 @@ intptr_t CALLBACK ClipboardHistoryPanel::run_dlgProc(UINT message, WPARAM wParam case WM_DRAWCLIPBOARD : { - ClipboardData clipboardData = getClipboadData(); - if (clipboardData.size()) + ClipboardDataInfo clipboardData = getClipboadData(); + if (clipboardData._data.size()) + { addToClipboadHistory(clipboardData); + } if (_hwndNextCbViewer) ::SendMessage(_hwndNextCbViewer, message, wParam, lParam); return TRUE; @@ -244,18 +266,27 @@ intptr_t CALLBACK ClipboardHistoryPanel::run_dlgProc(UINT message, WPARAM wParam else codepage = SC_CP_UTF8; - ByteArray ba(_clipboardDataVector[i]); + char* c = nullptr; try { - int nbChar = WideCharToMultiByte(codepage, 0, (wchar_t *)ba.getPointer(), static_cast(ba.getLength()), NULL, 0, NULL, NULL); + if (_clipboardDataInfos[i]._isBinaryContained) + { + (*_ppEditView)->execute(SCI_REPLACESEL, 0, reinterpret_cast("")); + (*_ppEditView)->execute(SCI_ADDTEXT, _clipboardDataInfos[i]._data.size(), reinterpret_cast(&(_clipboardDataInfos[i]._data[0]))); + } + else + { + ByteArray ba(_clipboardDataInfos[i]); + int nbChar = WideCharToMultiByte(codepage, 0, (wchar_t*)ba.getPointer(), static_cast(ba.getLength()), NULL, 0, NULL, NULL); - c = new char[nbChar + 1]; - WideCharToMultiByte(codepage, 0, (wchar_t *)ba.getPointer(), static_cast(ba.getLength()), c, nbChar + 1, NULL, NULL); + c = new char[nbChar + 1]; + WideCharToMultiByte(codepage, 0, (wchar_t*)ba.getPointer(), static_cast(ba.getLength()), c, nbChar + 1, NULL, NULL); - (*_ppEditView)->execute(SCI_REPLACESEL, 0, reinterpret_cast("")); - (*_ppEditView)->execute(SCI_ADDTEXT, strlen(c), reinterpret_cast(c)); - (*_ppEditView)->getFocus(); - delete[] c; + (*_ppEditView)->execute(SCI_REPLACESEL, 0, reinterpret_cast("")); + (*_ppEditView)->execute(SCI_ADDTEXT, strlen(c), reinterpret_cast(c)); + (*_ppEditView)->getFocus(); + delete[] c; + } } catch (...) { diff --git a/PowerEditor/src/WinControls/ClipboardHistory/clipboardHistoryPanel.h b/PowerEditor/src/WinControls/ClipboardHistory/clipboardHistoryPanel.h index 639f390b0..4108501fb 100644 --- a/PowerEditor/src/WinControls/ClipboardHistory/clipboardHistoryPanel.h +++ b/PowerEditor/src/WinControls/ClipboardHistory/clipboardHistoryPanel.h @@ -23,14 +23,17 @@ #define CH_PROJECTPANELTITLE TEXT("Clipboard History") -typedef std::vector ClipboardData; - class ScintillaEditView; +struct ClipboardDataInfo { + std::vector _data; + bool _isBinaryContained = false; +}; + class ByteArray { public: ByteArray() = default; - explicit ByteArray(ClipboardData cd); + explicit ByteArray(ClipboardDataInfo cd); ~ByteArray() { if (_pBytes) @@ -45,7 +48,7 @@ protected: class StringArray : public ByteArray { public: - StringArray(ClipboardData cd, size_t maxLen); + StringArray(ClipboardDataInfo cd, size_t maxLen); }; class ClipboardHistoryPanel : public DockingDlgInterface { @@ -61,9 +64,9 @@ public: _hParent = parent2set; }; - ClipboardData getClipboadData(); - void addToClipboadHistory(ClipboardData cbd); - int getClipboardDataIndex(ClipboardData cbd); + ClipboardDataInfo getClipboadData(); + void addToClipboadHistory(ClipboardDataInfo cbd); + int getClipboardDataIndex(ClipboardDataInfo cbd); virtual void setBackgroundColor(COLORREF bgColour) { _lbBgColor = bgColour; @@ -79,7 +82,7 @@ protected: private: ScintillaEditView **_ppEditView = nullptr; - std::vector _clipboardDataVector; + std::vector _clipboardDataInfos; HWND _hwndNextCbViewer = nullptr; int _lbBgColor = -1; int _lbFgColor= -1; diff --git a/PowerEditor/src/clipboardFormats.h b/PowerEditor/src/clipboardFormats.h index 9b9a084ff..1113fccc6 100644 --- a/PowerEditor/src/clipboardFormats.h +++ b/PowerEditor/src/clipboardFormats.h @@ -20,6 +20,6 @@ #define CF_HTML TEXT("HTML Format") #define CF_RTF TEXT("Rich Text Format") -#define CF_NPPTEXTLEN TEXT("Notepad++ Binary Text Length") +#define CF_NPPTEXTLEN TEXT("Notepad++ Binary Length") #endif //CLIPBOARDFORMATS_H