diff --git a/HexCtrl/HexCtrl.h b/HexCtrl/HexCtrl.h index 6bac421b..d291ef0e 100644 --- a/HexCtrl/HexCtrl.h +++ b/HexCtrl/HexCtrl.h @@ -54,9 +54,12 @@ namespace HEXCTRL virtual bool CreateDialogCtrl(UINT uCtrlID, HWND hParent) = 0; //Сreates custom dialog control. virtual void Destroy() = 0; //Deleter. virtual void ExecuteCmd(EHexCmd enCmd) = 0; //Execute a command within the control. + [[nodiscard]] virtual auto GetCacheSize()const->DWORD = 0; //Returns Virtual/Message mode cache size. [[nodiscard]] virtual DWORD GetCapacity()const = 0; //Current capacity. [[nodiscard]] virtual ULONGLONG GetCaretPos()const = 0; //Cursor position. [[nodiscard]] virtual auto GetColors()const->HEXCOLORSSTRUCT = 0; //Current colors. + [[nodiscard]] virtual auto GetData(HEXSPANSTRUCT hss)const->std::byte* = 0; //Get pointer to data offset, no matter what mode the control works in. + [[nodiscard]] virtual auto GetDataMode()const->EHexDataMode = 0; //Get current Data mode. [[nodiscard]] virtual auto GetDataSize()const->ULONGLONG = 0; //Get currently set data size. [[nodiscard]] virtual int GetEncoding()const = 0; //Get current code page ID. [[nodiscard]] virtual long GetFontSize()const = 0; //Current font size. @@ -75,6 +78,7 @@ namespace HEXCTRL [[nodiscard]] virtual bool IsMutable()const = 0; //Is edit mode enabled or not. [[nodiscard]] virtual bool IsOffsetAsHex()const = 0; //Is "Offset" currently represented (shown) as Hex or as Decimal. [[nodiscard]] virtual HEXVISSTRUCT IsOffsetVisible(ULONGLONG ullOffset)const = 0; //Ensures that the given offset is visible. + virtual void ModifyData(const HEXMODIFY& hms) = 0; //Main routine to modify data in IsMutable()==true mode. virtual void Redraw() = 0; //Redraw the control's window. virtual void SetCapacity(DWORD dwCapacity) = 0; //Set the control's current capacity. virtual void SetCaretPos(ULONGLONG ullOffset, bool fHighLow = true, bool fRedraw = true) = 0; //Set the caret position. diff --git a/HexCtrl/HexCtrlDefs.h b/HexCtrl/HexCtrlDefs.h index 06cacdbf..7156dd38 100644 --- a/HexCtrl/HexCtrlDefs.h +++ b/HexCtrl/HexCtrlDefs.h @@ -229,4 +229,44 @@ namespace HEXCTRL std::int8_t i8Horz { }; //Horizontal offset. operator bool()const { return i8Vert == 0 && i8Horz == 0; }; //For test simplicity: if(IsOffsetVisible()). }; + + /******************************************************************************************** + * EHexModifyMode - Enum of the data modification mode, used in HEXMODIFY. * + ********************************************************************************************/ + enum class EHexModifyMode : WORD + { + MODIFY_DEFAULT, MODIFY_REPEAT, MODIFY_OPERATION + }; + + /******************************************************************************************** + * EHexOperMode - Enum of the data operation mode, used in HEXMODIFY when * + * HEXMODIFY::enModifyMode is set to MODIFY_OPERATION. * + ********************************************************************************************/ + enum class EHexOperMode : WORD + { + OPER_OR = 0x01, OPER_XOR, OPER_AND, OPER_NOT, OPER_SHL, OPER_SHR, + OPER_ADD, OPER_SUBTRACT, OPER_MULTIPLY, OPER_DIVIDE + }; + + /******************************************************************************************** + * HEXMODIFY - used to represent data modification parameters. * + * When enModifyMode is set to EHexModifyMode::MODIFY_DEFAULT, bytes from pData just replace * + * corresponding data bytes as is. If enModifyMode is equal to EHexModifyMode::MODIFY_REPEAT * + * then block by block replacement takes place few times. * + * For example : if SUM(vecSpan.ullSize) = 9, ullDataSize = 3 and enModifyMode is set to * + * EHexModifyMode::MODIFY_REPEAT, bytes in memory at vecSpan.ullOffset position are * + * 123456789, and bytes pointed to by pData are 345, then, after modification, bytes at * + * vecSpan.ullOffset will be 345345345. If enModifyMode is equal to * + * EHexModifyMode::MODIFY_OPERATION then enOperMode comes into play, showing what kind of * + * operation must be performed on data. * + ********************************************************************************************/ + struct HEXMODIFY + { + EHexModifyMode enModifyMode { EHexModifyMode::MODIFY_DEFAULT }; //Modify mode. + EHexOperMode enOperMode { }; //Operation mode, used only if enModifyMode == MODIFY_OPERATION. + std::byte* pData { }; //Pointer to a data to be set. + ULONGLONG ullDataSize { }; //Size of the data pData is pointing to. + std::vector vecSpan { }; //Vector of data offsets and sizes. + bool fRedraw { true }; //Redraw HexCtrl's window after data changes? + }; }; \ No newline at end of file diff --git a/HexCtrl/src/CHexCtrl.cpp b/HexCtrl/src/CHexCtrl.cpp index f5d11145..d86241d8 100644 --- a/HexCtrl/src/CHexCtrl.cpp +++ b/HexCtrl/src/CHexCtrl.cpp @@ -393,10 +393,10 @@ bool CHexCtrl::Create(const HEXCREATESTRUCT& hcs) //All dialogs are created after the main window, to set the parent window correctly. m_pDlgBkmMgr->Create(IDD_HEXCTRL_BKMMGR, this, &*m_pBookmarks); m_pDlgEncoding->Create(IDD_HEXCTRL_ENCODING, this, this); - m_pDlgDataInterp->Create(IDD_HEXCTRL_DATAINTERP, this); - m_pDlgFillData->Create(IDD_HEXCTRL_FILLDATA, this); - m_pDlgOpers->Create(IDD_HEXCTRL_OPERATIONS, this); - m_pDlgSearch->Create(IDD_HEXCTRL_SEARCH, this); + m_pDlgDataInterp->Create(IDD_HEXCTRL_DATAINTERP, this, this); + m_pDlgFillData->Create(IDD_HEXCTRL_FILLDATA, this, this); + m_pDlgOpers->Create(IDD_HEXCTRL_OPERATIONS, this, this); + m_pDlgSearch->Create(IDD_HEXCTRL_SEARCH, this, this); m_pDlgGoTo->Create(IDD_HEXCTRL_GOTO, this, this); m_pBookmarks->Attach(this); m_fCreated = true; @@ -410,7 +410,7 @@ bool CHexCtrl::Create(const HEXCREATESTRUCT& hcs) bool CHexCtrl::CreateDialogCtrl(UINT uCtrlID, HWND hParent) { - assert(!IsCreated()); //Already created. + assert(!IsCreated()); if (IsCreated()) return false; @@ -619,11 +619,19 @@ void CHexCtrl::ExecuteCmd(EHexCmd eCmd) } } +auto CHexCtrl::GetCacheSize()const->DWORD +{ + assert(IsCreated()); + assert(IsDataSet()); + if (!IsCreated() || !IsDataSet()) + return { }; + + return m_dwCacheSize; +} + DWORD CHexCtrl::GetCapacity()const { assert(IsCreated()); - if (!IsCreated()) - return 1; //Capacity can't be less than one. return m_dwCapacity; } @@ -647,6 +655,52 @@ auto CHexCtrl::GetColors()const->HEXCOLORSSTRUCT return m_stColor; } +auto CHexCtrl::GetData(HEXSPANSTRUCT hss)const->std::byte* +{ + assert(IsCreated()); + assert(IsDataSet()); + if (!IsCreated() || !IsDataSet()) + return { }; + + if (hss.ullOffset + hss.ullSize > m_ullDataSize) + return nullptr; + + std::byte* pData { }; + switch (m_enDataMode) + { + case EHexDataMode::DATA_MEMORY: + pData = m_pData + hss.ullOffset; + break; + case EHexDataMode::DATA_MSG: + { + HEXNOTIFYSTRUCT hns { { m_hWnd, static_cast(GetDlgCtrlID()), HEXCTRL_MSG_GETDATA } }; + if (hss.ullSize == 0) + hss.ullSize = m_dwCacheSize; + hns.stSpan = hss; + MsgWindowNotify(hns); + pData = hns.pData; + } + break; + case EHexDataMode::DATA_VIRTUAL: + if (hss.ullSize == 0) + hss.ullSize = m_dwCacheSize; + pData = m_pHexVirtData->GetData(hss); + break; + } + + return pData; +} + +auto CHexCtrl::GetDataMode()const->EHexDataMode +{ + assert(IsCreated()); + assert(IsDataSet()); + if (!IsCreated() || !IsDataSet()) + return { }; + + return m_enDataMode; +} + auto CHexCtrl::GetDataSize()const->ULONGLONG { assert(IsCreated()); @@ -1540,6 +1594,9 @@ void CHexCtrl::AsciiChunkPoint(ULONGLONG ullOffset, int& iCx, int& iCy)const auto CHexCtrl::BuildDataToDraw(ULONGLONG ullStartLine, int iLines)const->std::tuple { + if (!IsDataSet()) + return { }; + const auto ullOffsetStart = ullStartLine * m_dwCapacity; //Offset of the visible data to print. size_t sSizeData = static_cast(iLines) * static_cast(m_dwCapacity); //Size of the visible data to print. if (ullOffsetStart + sSizeData > m_ullDataSize) @@ -1830,7 +1887,7 @@ void CHexCtrl::ClipboardPaste(EClipboard enType) ULONGLONG ullSize = strlen(pszClipboardData); ULONGLONG ullSizeToModify { }; - SMODIFY hmd; + HEXMODIFY hmd; std::string strData; switch (enType) @@ -1881,7 +1938,7 @@ void CHexCtrl::ClipboardPaste(EClipboard enType) } hmd.vecSpan.emplace_back(HEXSPANSTRUCT { m_ullCaretPos, ullSizeToModify }); - Modify(hmd); + ModifyData(hmd); GlobalUnlock(hClipboard); CloseClipboard(); @@ -1899,7 +1956,7 @@ auto CHexCtrl::CopyBase64()const->std::wstring int iValB = -6; for (unsigned i = 0; i < ullSelSize; ++i) { - uValA = (uValA << 8) + GetData(m_pSelection->GetOffsetByIndex(i)); + uValA = (uValA << 8) + GetIHexTData(*this, m_pSelection->GetOffsetByIndex(i)); iValB += 8; while (iValB >= 0) { @@ -1931,7 +1988,7 @@ auto CHexCtrl::CopyCArr()const->std::wstring for (unsigned i = 0; i < ullSelSize; ++i) { wstrData += L"0x"; - const auto chByte = GetData(m_pSelection->GetOffsetByIndex(i)); + const auto chByte = GetIHexTData(*this, m_pSelection->GetOffsetByIndex(i)); wstrData += g_pwszHexMap[(chByte & 0xF0) >> 4]; wstrData += g_pwszHexMap[(chByte & 0x0F)]; if (i < ullSelSize - 1) @@ -1957,7 +2014,7 @@ auto CHexCtrl::CopyGrepHex()const->std::wstring for (unsigned i = 0; i < ullSelSize; ++i) { wstrData += L"\\x"; - const auto chByte = GetData(m_pSelection->GetOffsetByIndex(i)); + const auto chByte = GetIHexTData(*this, m_pSelection->GetOffsetByIndex(i)); wstrData += g_pwszHexMap[(chByte & 0xF0) >> 4]; wstrData += g_pwszHexMap[(chByte & 0x0F)]; } @@ -1973,7 +2030,7 @@ auto CHexCtrl::CopyHex()const->std::wstring wstrData.reserve(static_cast(ullSelSize) * 2); for (unsigned i = 0; i < ullSelSize; ++i) { - const auto chByte = GetData(m_pSelection->GetOffsetByIndex(i)); + const auto chByte = GetIHexTData(*this, m_pSelection->GetOffsetByIndex(i)); wstrData += g_pwszHexMap[(chByte & 0xF0) >> 4]; wstrData += g_pwszHexMap[(chByte & 0x0F)]; } @@ -1993,7 +2050,7 @@ auto CHexCtrl::CopyHexFormatted()const->std::wstring auto dwTail = m_pSelection->GetLineLength(); for (unsigned i = 0; i < ullSelSize; ++i) { - const auto chByte = GetData(m_pSelection->GetOffsetByIndex(i)); + const auto chByte = GetIHexTData(*this, m_pSelection->GetOffsetByIndex(i)); wstrData += g_pwszHexMap[(chByte & 0xF0) >> 4]; wstrData += g_pwszHexMap[(chByte & 0x0F)]; @@ -2027,7 +2084,7 @@ auto CHexCtrl::CopyHexFormatted()const->std::wstring for (unsigned i = 0; i < ullSelSize; ++i) { - const auto chByte = GetData(m_pSelection->GetOffsetByIndex(i)); + const auto chByte = GetIHexTData(*this, m_pSelection->GetOffsetByIndex(i)); wstrData += g_pwszHexMap[(chByte & 0xF0) >> 4]; wstrData += g_pwszHexMap[(chByte & 0x0F)]; @@ -2057,7 +2114,7 @@ auto CHexCtrl::CopyHexLE()const->std::wstring wstrData.reserve(static_cast(ullSelSize) * 2); for (int i = static_cast(ullSelSize); i > 0; --i) { - const auto chByte = GetData(m_pSelection->GetOffsetByIndex(i - 1)); + const auto chByte = GetIHexTData(*this, m_pSelection->GetOffsetByIndex(i - 1)); wstrData += g_pwszHexMap[(chByte & 0xF0) >> 4]; wstrData += g_pwszHexMap[(chByte & 0x0F)]; } @@ -2151,7 +2208,7 @@ auto CHexCtrl::CopyText()const->std::wstring strData.reserve(static_cast(ullSelSize)); for (auto i = 0; i < ullSelSize; ++i) - strData.push_back(GetData(m_pSelection->GetOffsetByIndex(i))); + strData.push_back(GetIHexTData(*this, m_pSelection->GetOffsetByIndex(i))); auto wstrData = str2wstr(strData, m_iCodePage == -1 ? HEXCTRL_CODEPAGE_DEFAULT : m_iCodePage); ReplaceUnprintable(wstrData, m_iCodePage == -1, false); @@ -2962,13 +3019,13 @@ void CHexCtrl::FillWithZeros() if (!IsDataSet()) return; - SMODIFY hms; + HEXMODIFY hms; hms.vecSpan = m_pSelection->GetData(); hms.ullDataSize = 1; - hms.enModifyMode = EModifyMode::MODIFY_REPEAT; + hms.enModifyMode = EHexModifyMode::MODIFY_REPEAT; std::byte byteZero { 0 }; hms.pData = &byteZero; - Modify(hms); + ModifyData(hms); } auto CHexCtrl::GetBottomLine()const->ULONGLONG @@ -2986,11 +3043,6 @@ auto CHexCtrl::GetBottomLine()const->ULONGLONG return ullEndLine; } -auto CHexCtrl::GetCacheSize()const->DWORD -{ - return m_dwCacheSize; -} - auto CHexCtrl::GetCommand(UCHAR uChar, bool fCtrl, bool fShift, bool fAlt)const->std::optional { std::optional optRet { }; @@ -3002,42 +3054,6 @@ auto CHexCtrl::GetCommand(UCHAR uChar, bool fCtrl, bool fShift, bool fAlt)const- return optRet; } -auto CHexCtrl::GetData(HEXSPANSTRUCT hss)const->std::byte* -{ - if (hss.ullOffset >= m_ullDataSize || hss.ullSize > m_ullDataSize) - return nullptr; - - std::byte* pData { }; - switch (m_enDataMode) - { - case EHexDataMode::DATA_MEMORY: - pData = m_pData + hss.ullOffset; - break; - case EHexDataMode::DATA_MSG: - { - HEXNOTIFYSTRUCT hns { { m_hWnd, static_cast(GetDlgCtrlID()), HEXCTRL_MSG_GETDATA } }; - if (hss.ullSize == 0) - hss.ullSize = m_dwCacheSize; - hns.stSpan = hss; - MsgWindowNotify(hns); - pData = hns.pData; - } - break; - case EHexDataMode::DATA_VIRTUAL: - if (hss.ullSize == 0) - hss.ullSize = m_dwCacheSize; - pData = m_pHexVirtData->GetData(hss); - break; - } - - return pData; -} - -auto CHexCtrl::GetDataMode()const->EHexDataMode -{ - return m_enDataMode; -} - auto CHexCtrl::GetMsgWindow()const->HWND { return m_hwndMsg; @@ -3127,7 +3143,7 @@ bool CHexCtrl::IsPageVisible()const return m_dwPageSize > 0 && (m_dwPageSize % m_dwCapacity == 0) && m_dwPageSize >= m_dwCapacity; } -void CHexCtrl::Modify(const SMODIFY& hms) +void CHexCtrl::ModifyData(const HEXMODIFY& hms) { if (!IsMutable()) return; @@ -3137,13 +3153,13 @@ void CHexCtrl::Modify(const SMODIFY& hms) switch (hms.enModifyMode) { - case EModifyMode::MODIFY_DEFAULT: + case EHexModifyMode::MODIFY_DEFAULT: ModifyDefault(hms); break; - case EModifyMode::MODIFY_REPEAT: + case EHexModifyMode::MODIFY_REPEAT: ModifyRepeat(hms); break; - case EModifyMode::MODIFY_OPERATION: + case EHexModifyMode::MODIFY_OPERATION: ModifyOperation(hms); break; } @@ -3154,7 +3170,7 @@ void CHexCtrl::Modify(const SMODIFY& hms) RedrawWindow(); } -void CHexCtrl::ModifyDefault(const SMODIFY& hms) +void CHexCtrl::ModifyDefault(const HEXMODIFY& hms) { const auto& vecSelRef = hms.vecSpan; const auto pData = GetData(vecSelRef[0]); @@ -3162,7 +3178,7 @@ void CHexCtrl::ModifyDefault(const SMODIFY& hms) SetDataVirtual(pData, vecSelRef[0]); } -void CHexCtrl::ModifyOperation(const SMODIFY& hms) +void CHexCtrl::ModifyOperation(const HEXMODIFY& hms) { if (hms.ullDataSize > sizeof(QWORD)) return; @@ -3195,7 +3211,7 @@ void CHexCtrl::ModifyOperation(const SMODIFY& hms) case (sizeof(BYTE)): { BYTE bDataOper { }; - if (hms.pData) //pDataOper might be null for, say, EOperMode::OPER_NOT. + if (hms.pData) //pDataOper might be null for, say, EHexOperMode::OPER_NOT. bDataOper = *reinterpret_cast(hms.pData); auto pOper = reinterpret_cast(pData); OperData(pOper, hms.enOperMode, bDataOper, ullSizeChunk); @@ -3246,7 +3262,7 @@ void CHexCtrl::ModifyOperation(const SMODIFY& hms) thrd.join(); } -void CHexCtrl::ModifyRepeat(const SMODIFY& hms) +void CHexCtrl::ModifyRepeat(const HEXMODIFY& hms) { const auto& vecSelRef = hms.vecSpan; constexpr auto sizeQuick { 1024 * 256 }; //256KB. @@ -3381,6 +3397,60 @@ void CHexCtrl::OnCaretPosChange(ULONGLONG ullOffset) MsgWindowNotify(HEXCTRL_MSG_CARETCHANGE); } +template +void CHexCtrl::OperData(T* pData, EHexOperMode eMode, T tDataOper, ULONGLONG ullSizeData) +{ + /************************************************************ + * OperData - function for Modify/Operations + * pData - Starting address of the data to operate on. + * eMode - Operation mode. + * tDataOper - The data to apply the operation with. + * ullSizeData - Size of the data (selection) to operate on. + ************************************************************/ + + if (pData == nullptr) + return; + + auto nChunks = ullSizeData / sizeof(T); + for (const auto pDataEnd = pData + nChunks; pData < pDataEnd; ++pData) + { + switch (eMode) + { + case EHexOperMode::OPER_OR: + *pData |= tDataOper; + break; + case EHexOperMode::OPER_XOR: + *pData ^= tDataOper; + break; + case EHexOperMode::OPER_AND: + *pData &= tDataOper; + break; + case EHexOperMode::OPER_NOT: + *pData = ~*pData; + break; + case EHexOperMode::OPER_SHL: + *pData <<= tDataOper; + break; + case EHexOperMode::OPER_SHR: + *pData >>= tDataOper; + break; + case EHexOperMode::OPER_ADD: + *pData += tDataOper; + break; + case EHexOperMode::OPER_SUBTRACT: + *pData -= tDataOper; + break; + case EHexOperMode::OPER_MULTIPLY: + *pData *= tDataOper; + break; + case EHexOperMode::OPER_DIVIDE: + if (tDataOper > 0) //Division by Zero check. + *pData /= tDataOper; + break; + } + } +} + void CHexCtrl::ParentNotify(const HEXNOTIFYSTRUCT& hns)const { ::SendMessageW(GetParent()->GetSafeHwnd(), WM_NOTIFY, GetDlgCtrlID(), reinterpret_cast(&hns)); @@ -3705,6 +3775,7 @@ void CHexCtrl::Redo() } m_deqRedo.pop_back(); + ParentNotify(HEXCTRL_MSG_SETDATA); RedrawWindow(); } @@ -4144,6 +4215,7 @@ void CHexCtrl::Undo() ++ullIndex; } m_deqUndo.pop_back(); + ParentNotify(HEXCTRL_MSG_SETDATA); RedrawWindow(); } @@ -4225,11 +4297,11 @@ void CHexCtrl::OnChar(UINT nChar, UINT /*nRepCnt*/, UINT /*nFlags*/) } } - SMODIFY hms; + HEXMODIFY hms; hms.vecSpan.emplace_back(HEXSPANSTRUCT { m_ullCaretPos, 1 }); hms.ullDataSize = 1; hms.pData = reinterpret_cast(&chByte); - Modify(hms); + ModifyData(hms); CaretMoveRight(); } @@ -4405,17 +4477,17 @@ void CHexCtrl::OnKeyDown(UINT nChar, UINT /*nRepCnt*/, UINT nFlags) else return; - auto chByteCurr = GetData(m_ullCaretPos); + auto chByteCurr = GetIHexTData(*this, m_ullCaretPos); if (m_fCaretHigh) chByte = (chByte << 4) | (chByteCurr & 0x0F); else chByte = (chByte & 0x0F) | (chByteCurr & 0xF0); - SMODIFY hms; + HEXMODIFY hms; hms.vecSpan.emplace_back(HEXSPANSTRUCT { m_ullCaretPos, 1 }); hms.ullDataSize = 1; hms.pData = reinterpret_cast(&chByte); - Modify(hms); + ModifyData(hms); CaretMoveRight(); } diff --git a/HexCtrl/src/CHexCtrl.h b/HexCtrl/src/CHexCtrl.h index 5878ff49..83c5225a 100644 --- a/HexCtrl/src/CHexCtrl.h +++ b/HexCtrl/src/CHexCtrl.h @@ -30,46 +30,6 @@ namespace HEXCTRL::INTERNAL class CHexSelection; namespace SCROLLEX { class CScrollEx; }; - /******************************************************************************************** - * EModifyMode - Enum of the data modification mode, used in SMODIFY. * - ********************************************************************************************/ - enum class EModifyMode : WORD - { - MODIFY_DEFAULT, MODIFY_REPEAT, MODIFY_OPERATION - }; - - /******************************************************************************************** - * EOperMode - Enum of the data operation mode, used in SMODIFY, * - * when SMODIFY::enModifyMode is MODIFY_OPERATION. * - ********************************************************************************************/ - enum class EOperMode : WORD - { - OPER_OR = 0x01, OPER_XOR, OPER_AND, OPER_NOT, OPER_SHL, OPER_SHR, - OPER_ADD, OPER_SUBTRACT, OPER_MULTIPLY, OPER_DIVIDE - }; - - /******************************************************************************************** - * SMODIFY - used to represent data modification parameters. * - * When enModifyMode is set to EModifyMode::MODIFY_DEFAULT, bytes from pData just replace * - * corresponding data bytes as is. If enModifyMode is equal to EModifyMode::MODIFY_REPEAT * - * then block by block replacement takes place few times. * - * For example : if SUM(vecSpan.ullSize) = 9, ullDataSize = 3 and enModifyMode is set to * - * EModifyMode::MODIFY_REPEAT, bytes in memory at vecSpan.ullOffset position are * - * 123456789, and bytes pointed to by pData are 345, then, after modification, bytes at * - * vecSpan.ullOffset will be 345345345. If enModifyMode is equal to * - * EModifyMode::MODIFY_OPERATION then enOperMode comes into play, showing what kind of * - * operation must be performed on data. * - ********************************************************************************************/ - struct SMODIFY - { - EModifyMode enModifyMode { EModifyMode::MODIFY_DEFAULT }; //Modify mode. - EOperMode enOperMode { }; //Operation mode enum. Used only if enModifyMode == MODIFY_OPERATION. - std::byte* pData { }; //Pointer to a data to be set. - ULONGLONG ullDataSize { }; //Size of the data pData is pointing to. - std::vector vecSpan { }; //Vector of data offsets and sizes. - bool fRedraw { true }; //Redraw HexCtrl's window after data changes? - }; - /******************************************************************************************** * CHexCtrl class is an implementation of the IHexCtrl interface. * ********************************************************************************************/ @@ -90,9 +50,12 @@ namespace HEXCTRL::INTERNAL bool CreateDialogCtrl(UINT uCtrlID, HWND hParent)override; //Сreates custom dialog control. void Destroy()override; //Deleter. void ExecuteCmd(EHexCmd eCmd)override; //Execute a command within the control. + [[nodiscard]] auto GetCacheSize()const->DWORD override; //Returns Virtual/Message mode cache size. [[nodiscard]] DWORD GetCapacity()const override; //Current capacity. [[nodiscard]] ULONGLONG GetCaretPos()const override; //Cursor position. [[nodiscard]] auto GetColors()const->HEXCOLORSSTRUCT override; //Current colors. + [[nodiscard]] auto GetData(HEXSPANSTRUCT hss)const->std::byte* override; //Get pointer to data offset, no matter what mode the control works in. + [[nodiscard]] auto GetDataMode()const->EHexDataMode override; //Get current Data mode. [[nodiscard]] auto GetDataSize()const->ULONGLONG override; //Get currently set data size. [[nodiscard]] int GetEncoding()const override; //Get current code page ID. [[nodiscard]] long GetFontSize()const override; //Current font size. @@ -111,6 +74,7 @@ namespace HEXCTRL::INTERNAL [[nodiscard]] bool IsMutable()const override; //Is edit mode enabled or not. [[nodiscard]] bool IsOffsetAsHex()const override; //Is "Offset" printed as Hex or as Decimal. [[nodiscard]] HEXVISSTRUCT IsOffsetVisible(ULONGLONG ullOffset)const override; //Ensures that the given offset is visible. + void ModifyData(const HEXMODIFY& hms)override; //Main routine to modify data in IsMutable()==true mode. void Redraw()override; //Redraw the control's window. void SetCapacity(DWORD dwCapacity)override; //Set the control's current capacity. void SetCaretPos(ULONGLONG ullOffset, bool fHighLow = true, bool fRedraw = true)override; //Set the caret position. @@ -127,10 +91,6 @@ namespace HEXCTRL::INTERNAL void SetSelection(const std::vector& vecSel, bool fRedraw = true, bool fHighlight = false)override; //Set current selection. void SetWheelRatio(double dbRatio)override; //Set the ratio for how much to scroll with mouse-wheel. private: - friend class CHexDlgDataInterp; - friend class CHexDlgFillData; - friend class CHexDlgOpers; - friend class CHexDlgSearch; struct SHBITMAP; struct SUNDO; struct SKEYBIND; @@ -170,27 +130,21 @@ namespace HEXCTRL::INTERNAL void DrawPageLines(CDC* pDC, ULONGLONG ullStartLine, int iLines); void FillWithZeros(); //Fill selection with zeros. [[nodiscard]] auto GetBottomLine()const->ULONGLONG; //Returns current bottom line number in view. - [[nodiscard]] auto GetCacheSize()const->DWORD; //Returns Virtual/Message mode cache size. [[nodiscard]] auto GetCommand(UCHAR uChar, bool fCtrl, bool fShift, bool fAlt)const->std::optional; //Get command from keybinding. - template - [[nodiscard]] auto GetData(ULONGLONG ullOffset)const->T; //Get T sized data from ullOffset. - [[nodiscard]] auto GetData(HEXSPANSTRUCT hss)const->std::byte*; //Gets pointer to exact data offset, no matter what mode the control works in. - [[nodiscard]] auto GetDataMode()const->EHexDataMode; //Current Data mode. [[nodiscard]] auto GetMsgWindow()const->HWND; //Returns pointer to the "Message" window. See HEXDATASTRUCT::pwndMessage. [[nodiscard]] auto GetTopLine()const->ULONGLONG; //Returns current top line number in view. void HexChunkPoint(ULONGLONG ullOffset, int& iCx, int& iCy)const; //Point of Hex chunk. [[nodiscard]] auto HitTest(POINT pt)const->std::optional; //Is any hex chunk withing given point? [[nodiscard]] bool IsCurTextArea()const; //Whether last focus was set at Text or Hex chunks area. [[nodiscard]] bool IsPageVisible()const; //Returns m_fSectorVisible. - void Modify(const SMODIFY& hms); //Main routine to modify data, in m_fMutable==true mode. - void ModifyDefault(const SMODIFY& hms); //EModifyMode::MODIFY_DEFAULT - void ModifyOperation(const SMODIFY& hms); //EModifyMode::MODIFY_OPERATION - void ModifyRepeat(const SMODIFY& hms); //EModifyMode::MODIFY_REPEAT + void ModifyDefault(const HEXMODIFY& hms); //EHexModifyMode::MODIFY_DEFAULT + void ModifyOperation(const HEXMODIFY& hms); //EHexModifyMode::MODIFY_OPERATION + void ModifyRepeat(const HEXMODIFY& hms); //EHexModifyMode::MODIFY_REPEAT void MsgWindowNotify(const HEXNOTIFYSTRUCT& hns)const; //Notify routine used to send messages to Msg window. void MsgWindowNotify(UINT uCode)const; //Same as above, but only for notification code. void OnCaretPosChange(ULONGLONG ullOffset); //On changing caret position. template - void OperData(T* pData, EOperMode eMode, T tDataOper, ULONGLONG ullSizeData); //Immediate operations on pData. + void OperData(T* pData, EHexOperMode eMode, T tDataOper, ULONGLONG ullSizeData); //Immediate operations on pData. void ParentNotify(const HEXNOTIFYSTRUCT& hns)const; //Notify routine used to send messages to Parent window. void ParentNotify(UINT uCode)const; //Same as above, but only for notification code. void Print(); //Printing routine. @@ -205,8 +159,6 @@ namespace HEXCTRL::INTERNAL void SelAddLeft(); //Left Key pressed with the Shift. void SelAddRight(); //Right Key pressed with the Shift. void SelAddUp(); //Up Key pressed with the Shift. - template - void SetData(ULONGLONG ullOffset, T tData); //Set T sized data tData at ullOffset. void SetDataVirtual(std::byte* pData, const HEXSPANSTRUCT& hss); //Sets data (notifies back) in DATA_MSG and DATA_VIRTUAL. void SnapshotUndo(const std::vector& vecSpan); //Takes currently modifiable data snapshot. void TtBkmShow(bool fShow, POINT pt = { }); //Tooltip bookmark show/hide. @@ -329,81 +281,4 @@ namespace HEXCTRL::INTERNAL bool m_fKeyDownAtm { false }; //Whether some key is down/pressed at the moment. bool m_fMenuCMD { false }; //Command to be executed through menu, not through key-shortcut. }; - - template - inline auto CHexCtrl::GetData(ULONGLONG ullOffset)const->T - { - if (ullOffset >= m_ullDataSize) - return T { }; - - if (auto pData = GetData({ ullOffset, sizeof(T) }); pData != nullptr) - return *reinterpret_cast(pData); - - return T { }; - } - - template - inline void CHexCtrl::SetData(ULONGLONG ullOffset, T tData) - { - //Data overflow check. - if (ullOffset + sizeof(T) > m_ullDataSize) - return; - - const auto pData = GetData({ ullOffset, sizeof(T) }); - std::copy_n(&tData, 1, reinterpret_cast(pData)); - SetDataVirtual(pData, { ullOffset, sizeof(T) }); - } - - /************************************************************ - * OperData - function for Modify/Operations - * pData - Starting address of the data to operate on. - * eMode - Operation mode. - * tDataOper - The data to apply the operation with. - * ullSizeData - Size of the data (selection) to operate on. - ************************************************************/ - template - inline void CHexCtrl::OperData(T* pData, EOperMode eMode, T tDataOper, ULONGLONG ullSizeData) - { - if (pData == nullptr) - return; - - auto nChunks = ullSizeData / sizeof(T); - for (const auto pDataEnd = pData + nChunks; pData < pDataEnd; ++pData) - { - switch (eMode) - { - case EOperMode::OPER_OR: - *pData |= tDataOper; - break; - case EOperMode::OPER_XOR: - *pData ^= tDataOper; - break; - case EOperMode::OPER_AND: - *pData &= tDataOper; - break; - case EOperMode::OPER_NOT: - *pData = ~*pData; - break; - case EOperMode::OPER_SHL: - *pData <<= tDataOper; - break; - case EOperMode::OPER_SHR: - *pData >>= tDataOper; - break; - case EOperMode::OPER_ADD: - *pData += tDataOper; - break; - case EOperMode::OPER_SUBTRACT: - *pData -= tDataOper; - break; - case EOperMode::OPER_MULTIPLY: - *pData *= tDataOper; - break; - case EOperMode::OPER_DIVIDE: - if (tDataOper > 0) //Division by Zero check. - *pData /= tDataOper; - break; - } - } - } } \ No newline at end of file diff --git a/HexCtrl/src/Dialogs/CHexDlgDataInterp.cpp b/HexCtrl/src/Dialogs/CHexDlgDataInterp.cpp index f462835a..c4b2567a 100644 --- a/HexCtrl/src/Dialogs/CHexDlgDataInterp.cpp +++ b/HexCtrl/src/Dialogs/CHexDlgDataInterp.cpp @@ -34,7 +34,7 @@ void CHexDlgDataInterp::DoDataExchange(CDataExchange* pDX) DDX_Control(pDX, IDC_HEXCTRL_DATAINTERP_PROPDATA, m_stCtrlGrid); } -BOOL CHexDlgDataInterp::Create(UINT nIDTemplate, CHexCtrl* pHexCtrl) +BOOL CHexDlgDataInterp::Create(UINT nIDTemplate, CWnd* pParent, IHexCtrl* pHexCtrl) { assert(pHexCtrl); if (pHexCtrl == nullptr) @@ -42,7 +42,7 @@ BOOL CHexDlgDataInterp::Create(UINT nIDTemplate, CHexCtrl* pHexCtrl) m_pHexCtrl = pHexCtrl; - return CDialogEx::Create(nIDTemplate, pHexCtrl); + return CDialogEx::Create(nIDTemplate, pParent); } BOOL CHexDlgDataInterp::OnInitDialog() @@ -257,7 +257,7 @@ void CHexDlgDataInterp::InspectOffset(ULONGLONG ullOffset) iter.pProp->AllowEdit(m_pHexCtrl->IsMutable()); m_ullOffset = ullOffset; - const auto byte = m_pHexCtrl->GetData(ullOffset); + const auto byte = GetIHexTData(*m_pHexCtrl, ullOffset); ShowNAME_BINARY(byte); ShowNAME_CHAR(byte); @@ -281,7 +281,7 @@ void CHexDlgDataInterp::InspectOffset(ULONGLONG ullOffset) if (iter.eSize == ESize::SIZE_WORD) iter.pProp->Enable(TRUE); - auto word = m_pHexCtrl->GetData(ullOffset); + auto word = GetIHexTData(*m_pHexCtrl, ullOffset); if (m_fBigEndian) word = _byteswap_ushort(word); @@ -306,7 +306,7 @@ void CHexDlgDataInterp::InspectOffset(ULONGLONG ullOffset) if (iter.eSize == ESize::SIZE_DWORD) iter.pProp->Enable(TRUE); - auto dword = m_pHexCtrl->GetData(ullOffset); + auto dword = GetIHexTData(*m_pHexCtrl, ullOffset); if (m_fBigEndian) dword = _byteswap_ulong(dword); @@ -335,7 +335,7 @@ void CHexDlgDataInterp::InspectOffset(ULONGLONG ullOffset) if (iter.eSize == ESize::SIZE_QWORD) iter.pProp->Enable(TRUE); - auto qword = m_pHexCtrl->GetData(ullOffset); + auto qword = GetIHexTData(*m_pHexCtrl, ullOffset); if (m_fBigEndian) qword = _byteswap_uint64(qword); @@ -365,7 +365,7 @@ void CHexDlgDataInterp::InspectOffset(ULONGLONG ullOffset) if (iter.eSize == ESize::SIZE_DQWORD) iter.pProp->Enable(TRUE); - auto dqword = m_pHexCtrl->GetData(ullOffset); + auto dqword = GetIHexTData(*m_pHexCtrl, ullOffset); if (m_fBigEndian) { //TODO: Test this thoroughly @@ -459,7 +459,8 @@ ULONGLONG CHexDlgDataInterp::GetSize()const return m_ullSize; } -templatevoid CHexDlgDataInterp::SetDigitData(T tData)const +template +void CHexDlgDataInterp::SetTData(T tData)const { if (m_fBigEndian) { @@ -478,7 +479,8 @@ templatevoid CHexDlgDataInterp::SetDigitData(T tData)const break; } } - m_pHexCtrl->SetData(m_ullOffset, tData); + + SetIHexTData(*m_pHexCtrl, m_ullOffset, tData); } void CHexDlgDataInterp::UpdateHexCtrl()const @@ -960,7 +962,7 @@ bool CHexDlgDataInterp::SetDataNAME_BINARY(const std::wstring& wstr)const bool fSuccess; UCHAR uchData; if (fSuccess = wstr2num(wstr, uchData, 2); fSuccess) - SetDigitData(uchData); + SetTData(uchData); return fSuccess; } @@ -970,7 +972,7 @@ bool CHexDlgDataInterp::SetDataNAME_CHAR(const std::wstring& wstr)const bool fSuccess; CHAR chData; if (fSuccess = wstr2num(wstr, chData); fSuccess) - SetDigitData(chData); + SetTData(chData); return fSuccess; } @@ -980,7 +982,7 @@ bool CHexDlgDataInterp::SetDataNAME_UCHAR(const std::wstring& wstr)const bool fSuccess; UCHAR uchData; if (fSuccess = wstr2num(wstr, uchData); fSuccess) - SetDigitData(uchData); + SetTData(uchData); return fSuccess; } @@ -990,7 +992,7 @@ bool CHexDlgDataInterp::SetDataNAME_SHORT(const std::wstring& wstr)const bool fSuccess; SHORT shData; if (fSuccess = wstr2num(wstr, shData); fSuccess) - SetDigitData(shData); + SetTData(shData); return fSuccess; } @@ -1000,7 +1002,7 @@ bool CHexDlgDataInterp::SetDataNAME_USHORT(const std::wstring& wstr)const bool fSuccess; USHORT ushData; if (fSuccess = wstr2num(wstr, ushData); fSuccess) - SetDigitData(ushData); + SetTData(ushData); return fSuccess; } @@ -1010,7 +1012,7 @@ bool CHexDlgDataInterp::SetDataNAME_LONG(const std::wstring& wstr)const bool fSuccess; LONG lData; if (fSuccess = wstr2num(wstr, lData); fSuccess) - SetDigitData(lData); + SetTData(lData); return fSuccess; } @@ -1020,7 +1022,7 @@ bool CHexDlgDataInterp::SetDataNAME_ULONG(const std::wstring& wstr)const bool fSuccess; ULONG ulData; if (fSuccess = wstr2num(wstr, ulData); fSuccess) - SetDigitData(ulData); + SetTData(ulData); return fSuccess; } @@ -1030,7 +1032,7 @@ bool CHexDlgDataInterp::SetDataNAME_LONGLONG(const std::wstring& wstr)const bool fSuccess; LONGLONG llData; if (fSuccess = wstr2num(wstr, llData); fSuccess) - SetDigitData(llData); + SetTData(llData); return fSuccess; } @@ -1040,7 +1042,7 @@ bool CHexDlgDataInterp::SetDataNAME_ULONGLONG(const std::wstring& wstr)const bool fSuccess; ULONGLONG ullData; if (fSuccess = wstr2num(wstr, ullData); fSuccess) - SetDigitData(ullData); + SetTData(ullData); return fSuccess; } @@ -1050,7 +1052,7 @@ bool CHexDlgDataInterp::SetDataNAME_FLOAT(const std::wstring& wstr)const bool fSuccess; float fl; if (fSuccess = wstr2num(wstr, fl); fSuccess) - SetDigitData(fl); + SetTData(fl); return fSuccess; } @@ -1060,7 +1062,7 @@ bool CHexDlgDataInterp::SetDataNAME_DOUBLE(const std::wstring& wstr)const bool fSuccess; double dd; if (fSuccess = wstr2num(wstr, dd); fSuccess) - SetDigitData(dd); + SetTData(dd); return fSuccess; } @@ -1095,7 +1097,7 @@ bool CHexDlgDataInterp::SetDataNAME_TIME32T(std::wstring_view wstr)const if (m_fBigEndian) lTime32 = _byteswap_ulong(lTime32); - m_pHexCtrl->SetData(m_ullOffset, lTime32); + SetIHexTData(*m_pHexCtrl, m_ullOffset, lTime32); } return true; @@ -1128,7 +1130,7 @@ bool CHexDlgDataInterp::SetDataNAME_TIME64T(std::wstring_view wstr)const if (m_fBigEndian) llTime64 = _byteswap_uint64(llTime64); - m_pHexCtrl->SetData(m_ullOffset, llTime64); + SetIHexTData(*m_pHexCtrl, m_ullOffset, llTime64); return true; } @@ -1150,7 +1152,7 @@ bool CHexDlgDataInterp::SetDataNAME_FILETIME(std::wstring_view wstr)const if (m_fBigEndian) stLITime.QuadPart = _byteswap_uint64(stLITime.QuadPart); - m_pHexCtrl->SetData(m_ullOffset, stLITime.QuadPart); + SetIHexTData(*m_pHexCtrl, m_ullOffset, stLITime.QuadPart); return true; } @@ -1171,7 +1173,7 @@ bool CHexDlgDataInterp::SetDataNAME_OLEDATETIME(std::wstring_view wstr)const if (m_fBigEndian) ullValue = _byteswap_uint64(ullValue); - m_pHexCtrl->SetData(m_ullOffset, ullValue); + SetIHexTData(*m_pHexCtrl, m_ullOffset, ullValue); return true; } @@ -1206,7 +1208,7 @@ bool CHexDlgDataInterp::SetDataNAME_JAVATIME(std::wstring_view wstr)const if (m_fBigEndian) llDiffMillis = _byteswap_uint64(llDiffMillis); - m_pHexCtrl->SetData(m_ullOffset, llDiffMillis); + SetIHexTData(*m_pHexCtrl, m_ullOffset, llDiffMillis); return true; } @@ -1227,7 +1229,7 @@ bool CHexDlgDataInterp::SetDataNAME_MSDOSTIME(std::wstring_view wstr)const //Note: Big-endian is not currently supported. This has never existed in the "wild". - m_pHexCtrl->SetData(m_ullOffset, msdosDateTime.dwTimeDate); + SetIHexTData(*m_pHexCtrl, m_ullOffset, msdosDateTime.dwTimeDate); return true; } @@ -1249,7 +1251,7 @@ bool CHexDlgDataInterp::SetDataNAME_MSDTTMTIME(std::wstring_view wstr)const //Note: Big-endian is not currently supported. This has never existed in the "wild". - m_pHexCtrl->SetData(m_ullOffset, dttm.dwValue); + SetIHexTData(*m_pHexCtrl, m_ullOffset, dttm.dwValue); return true; } @@ -1262,7 +1264,7 @@ bool CHexDlgDataInterp::SetDataNAME_SYSTEMTIME(std::wstring_view wstr)const //Note: Big-endian is not currently supported. This has never existed in the "wild". - m_pHexCtrl->SetData(m_ullOffset, stTime); + SetIHexTData(*m_pHexCtrl, m_ullOffset, stTime); return true; } @@ -1273,7 +1275,7 @@ bool CHexDlgDataInterp::SetDataNAME_GUIDTIME(std::wstring_view wstr)const //We can not just set a NAME_GUIDTIME for data range if it's not //a valid NAME_GUID range, so checking first. - auto dqword = m_pHexCtrl->GetData(m_ullOffset); + auto dqword = GetIHexTData(*m_pHexCtrl, m_ullOffset); const unsigned short unGuidVersion = (dqword.gGUID.Data3 & 0xf000) >> 12; if (unGuidVersion != 1) return false; @@ -1305,7 +1307,7 @@ bool CHexDlgDataInterp::SetDataNAME_GUIDTIME(std::wstring_view wstr)const dqword.gGUID.Data2 = qwGUIDTime.HighPart & 0xffff; dqword.gGUID.Data3 = ((qwGUIDTime.HighPart >> 16) & 0x0fff) | 0x1000; //Including Type 1 flag (0x1000) - m_pHexCtrl->SetData(m_ullOffset, dqword); + SetIHexTData(*m_pHexCtrl, m_ullOffset, dqword); return true; } @@ -1316,7 +1318,7 @@ bool CHexDlgDataInterp::SetDataNAME_GUID(const std::wstring& wstr)const if (IIDFromString(wstr.data(), &guid) != S_OK) return false; - m_pHexCtrl->SetData(m_ullOffset, guid); + SetIHexTData(*m_pHexCtrl, m_ullOffset, guid); return true; } \ No newline at end of file diff --git a/HexCtrl/src/Dialogs/CHexDlgDataInterp.h b/HexCtrl/src/Dialogs/CHexDlgDataInterp.h index 2221c04f..44ac828b 100644 --- a/HexCtrl/src/Dialogs/CHexDlgDataInterp.h +++ b/HexCtrl/src/Dialogs/CHexDlgDataInterp.h @@ -6,7 +6,7 @@ * https://github.com/jovibor/HexCtrl/blob/master/LICENSE * ****************************************************************************************/ #pragma once -#include "../CHexCtrl.h" +#include "../../HexCtrl.h" #include "CHexPropGridCtrl.h" #include #include @@ -73,7 +73,7 @@ namespace HEXCTRL::INTERNAL static constexpr auto m_ulFileTime1970_HIGH = 0x019db1deUL; //Used for Unix and Java times static constexpr auto m_ullUnixEpochDiff = 11644473600ULL; //Number of ticks from FILETIME epoch of 1st Jan 1601 to Unix epoch of 1st Jan 1970 public: - BOOL Create(UINT nIDTemplate, CHexCtrl* pHexCtrl); + BOOL Create(UINT nIDTemplate, CWnd* pParent, IHexCtrl* pHexCtrl); [[nodiscard]] ULONGLONG GetSize()const; void InspectOffset(ULONGLONG ullOffset); private: @@ -91,7 +91,7 @@ namespace HEXCTRL::INTERNAL afx_msg void OnClickRadioDec(); afx_msg void OnClickRadioHex(); afx_msg void OnDestroy(); - template void SetDigitData(T tData)const; + template void SetTData(T tData)const; void UpdateHexCtrl()const; [[nodiscard]] std::wstring GetCurrentUserDateFormatString()const; [[nodiscard]] std::wstring SystemTimeToString(const SYSTEMTIME* pSysTime, bool bIncludeDate, bool bIncludeTime)const; @@ -161,7 +161,7 @@ namespace HEXCTRL::INTERNAL ESize eSize { }; bool fChild { false }; }; - CHexCtrl* m_pHexCtrl { }; + IHexCtrl* m_pHexCtrl { }; bool m_fBigEndian { false }; bool m_fShowAsHex { true }; CHexPropGridCtrl m_stCtrlGrid; diff --git a/HexCtrl/src/Dialogs/CHexDlgFillData.cpp b/HexCtrl/src/Dialogs/CHexDlgFillData.cpp index 89c332df..6341fedd 100644 --- a/HexCtrl/src/Dialogs/CHexDlgFillData.cpp +++ b/HexCtrl/src/Dialogs/CHexDlgFillData.cpp @@ -16,7 +16,7 @@ using namespace HEXCTRL::INTERNAL; BEGIN_MESSAGE_MAP(CHexDlgFillData, CDialogEx) END_MESSAGE_MAP() -BOOL CHexDlgFillData::Create(UINT nIDTemplate, CHexCtrl* pHexCtrl) +BOOL CHexDlgFillData::Create(UINT nIDTemplate, CWnd* pParent, IHexCtrl* pHexCtrl) { assert(pHexCtrl); if (pHexCtrl == nullptr) @@ -24,7 +24,7 @@ BOOL CHexDlgFillData::Create(UINT nIDTemplate, CHexCtrl* pHexCtrl) m_pHexCtrl = pHexCtrl; - return CDialogEx::Create(nIDTemplate, pHexCtrl); + return CDialogEx::Create(nIDTemplate, pParent); } BOOL CHexDlgFillData::OnInitDialog() @@ -47,8 +47,8 @@ void CHexDlgFillData::OnOK() { const auto iRadioType = GetCheckedRadioButton(IDC_HEXCTRL_FILLDATA_RADIO_HEX, IDC_HEXCTRL_FILLDATA_RADIO_UTF16); - SMODIFY hms; - hms.enModifyMode = EModifyMode::MODIFY_REPEAT; + HEXMODIFY hms; + hms.enModifyMode = EHexModifyMode::MODIFY_REPEAT; hms.vecSpan = m_pHexCtrl->GetSelection(); if (hms.vecSpan.empty()) return; @@ -95,7 +95,7 @@ void CHexDlgFillData::OnOK() pCombo->InsertString(0, wstrComboText.data()); } - m_pHexCtrl->Modify(hms); + m_pHexCtrl->ModifyData(hms); ::SetFocus(m_pHexCtrl->GetWindowHandle(EHexWnd::WND_MAIN)); CDialogEx::OnOK(); diff --git a/HexCtrl/src/Dialogs/CHexDlgFillData.h b/HexCtrl/src/Dialogs/CHexDlgFillData.h index 8365e443..1fe5578b 100644 --- a/HexCtrl/src/Dialogs/CHexDlgFillData.h +++ b/HexCtrl/src/Dialogs/CHexDlgFillData.h @@ -6,7 +6,7 @@ * https://github.com/jovibor/HexCtrl/blob/master/LICENSE * ****************************************************************************************/ #pragma once -#include "../CHexCtrl.h" +#include "../../HexCtrl.h" #include namespace HEXCTRL::INTERNAL @@ -14,13 +14,13 @@ namespace HEXCTRL::INTERNAL class CHexDlgFillData final : public CDialogEx { public: - BOOL Create(UINT nIDTemplate, CHexCtrl* pHexCtrl); + BOOL Create(UINT nIDTemplate, CWnd* pParent, IHexCtrl* pHexCtrl); private: void DoDataExchange(CDataExchange* pDX)override; BOOL OnInitDialog()override; void OnOK()override; DECLARE_MESSAGE_MAP() private: - CHexCtrl* m_pHexCtrl { }; + IHexCtrl* m_pHexCtrl { }; }; } \ No newline at end of file diff --git a/HexCtrl/src/Dialogs/CHexDlgOpers.cpp b/HexCtrl/src/Dialogs/CHexDlgOpers.cpp index 7d7f274c..fe009c93 100644 --- a/HexCtrl/src/Dialogs/CHexDlgOpers.cpp +++ b/HexCtrl/src/Dialogs/CHexDlgOpers.cpp @@ -16,7 +16,7 @@ using namespace HEXCTRL::INTERNAL; BEGIN_MESSAGE_MAP(CHexDlgOpers, CDialogEx) END_MESSAGE_MAP() -BOOL CHexDlgOpers::Create(UINT nIDTemplate, CHexCtrl* pHexCtrl) +BOOL CHexDlgOpers::Create(UINT nIDTemplate, CWnd* pParent, IHexCtrl* pHexCtrl) { assert(pHexCtrl); if (pHexCtrl == nullptr) @@ -24,7 +24,7 @@ BOOL CHexDlgOpers::Create(UINT nIDTemplate, CHexCtrl* pHexCtrl) m_pHexCtrl = pHexCtrl; - return CDialogEx::Create(nIDTemplate, pHexCtrl); + return CDialogEx::Create(nIDTemplate, pParent); } BOOL CHexDlgOpers::OnInitDialog() @@ -101,8 +101,8 @@ void CHexDlgOpers::OnOK() const auto iRadioOperation = GetCheckedRadioButton(IDC_HEXCTRL_OPERS_RADIO_OR, IDC_HEXCTRL_OPERS_RADIO_DIV); const auto iRadioDataSize = GetCheckedRadioButton(IDC_HEXCTRL_OPERS_RADIO_BYTE, IDC_HEXCTRL_OPERS_RADIO_QWORD); - SMODIFY hms; - hms.enModifyMode = EModifyMode::MODIFY_OPERATION; + HEXMODIFY hms; + hms.enModifyMode = EHexModifyMode::MODIFY_OPERATION; hms.vecSpan = m_pHexCtrl->GetSelection(); if (hms.vecSpan.empty()) return; @@ -111,42 +111,42 @@ void CHexDlgOpers::OnOK() switch (iRadioOperation) { case IDC_HEXCTRL_OPERS_RADIO_OR: - hms.enOperMode = EOperMode::OPER_OR; + hms.enOperMode = EHexOperMode::OPER_OR; iEditID = IDC_HEXCTRL_OPERS_EDIT_OR; break; case IDC_HEXCTRL_OPERS_RADIO_XOR: - hms.enOperMode = EOperMode::OPER_XOR; + hms.enOperMode = EHexOperMode::OPER_XOR; iEditID = IDC_HEXCTRL_OPERS_EDIT_XOR; break; case IDC_HEXCTRL_OPERS_RADIO_AND: - hms.enOperMode = EOperMode::OPER_AND; + hms.enOperMode = EHexOperMode::OPER_AND; iEditID = IDC_HEXCTRL_OPERS_EDIT_AND; break; case IDC_HEXCTRL_OPERS_RADIO_NOT: - hms.enOperMode = EOperMode::OPER_NOT; + hms.enOperMode = EHexOperMode::OPER_NOT; break; case IDC_HEXCTRL_OPERS_RADIO_SHL: - hms.enOperMode = EOperMode::OPER_SHL; + hms.enOperMode = EHexOperMode::OPER_SHL; iEditID = IDC_HEXCTRL_OPERS_EDIT_SHL; break; case IDC_HEXCTRL_OPERS_RADIO_SHR: - hms.enOperMode = EOperMode::OPER_SHR; + hms.enOperMode = EHexOperMode::OPER_SHR; iEditID = IDC_HEXCTRL_OPERS_EDIT_SHR; break; case IDC_HEXCTRL_OPERS_RADIO_ADD: - hms.enOperMode = EOperMode::OPER_ADD; + hms.enOperMode = EHexOperMode::OPER_ADD; iEditID = IDC_HEXCTRL_OPERS_EDIT_ADD; break; case IDC_HEXCTRL_OPERS_RADIO_SUB: - hms.enOperMode = EOperMode::OPER_SUBTRACT; + hms.enOperMode = EHexOperMode::OPER_SUBTRACT; iEditID = IDC_HEXCTRL_OPERS_EDIT_SUB; break; case IDC_HEXCTRL_OPERS_RADIO_MUL: - hms.enOperMode = EOperMode::OPER_MULTIPLY; + hms.enOperMode = EHexOperMode::OPER_MULTIPLY; iEditID = IDC_HEXCTRL_OPERS_EDIT_MUL; break; case IDC_HEXCTRL_OPERS_RADIO_DIV: - hms.enOperMode = EOperMode::OPER_DIVIDE; + hms.enOperMode = EHexOperMode::OPER_DIVIDE; iEditID = IDC_HEXCTRL_OPERS_EDIT_DIV; break; default: @@ -164,7 +164,7 @@ void CHexDlgOpers::OnOK() MessageBoxW(L"Wrong number format!", L"Format Error", MB_ICONERROR); return; } - if (hms.enOperMode == EOperMode::OPER_DIVIDE && llData == 0) //Division by zero check. + if (hms.enOperMode == EHexOperMode::OPER_DIVIDE && llData == 0) //Division by zero check. { MessageBoxW(L"Wrong number format!\r\nCan not divide by zero.", L"Format Error", MB_ICONERROR); return; @@ -191,7 +191,7 @@ void CHexDlgOpers::OnOK() break; } - m_pHexCtrl->Modify(hms); + m_pHexCtrl->ModifyData(hms); ::SetFocus(m_pHexCtrl->GetWindowHandle(EHexWnd::WND_MAIN)); CDialogEx::OnOK(); diff --git a/HexCtrl/src/Dialogs/CHexDlgOpers.h b/HexCtrl/src/Dialogs/CHexDlgOpers.h index 81aa9356..5a548bf5 100644 --- a/HexCtrl/src/Dialogs/CHexDlgOpers.h +++ b/HexCtrl/src/Dialogs/CHexDlgOpers.h @@ -6,7 +6,7 @@ * https://github.com/jovibor/HexCtrl/blob/master/LICENSE * ****************************************************************************************/ #pragma once -#include "../CHexCtrl.h" +#include "../../HexCtrl.h" #include namespace HEXCTRL::INTERNAL @@ -14,7 +14,7 @@ namespace HEXCTRL::INTERNAL class CHexDlgOpers final : public CDialogEx { public: - BOOL Create(UINT nIDTemplate, CHexCtrl* pHexCtrl); + BOOL Create(UINT nIDTemplate, CWnd* pParent, IHexCtrl* pHexCtrl); protected: void DoDataExchange(CDataExchange* pDX)override; BOOL OnInitDialog()override; @@ -23,6 +23,6 @@ namespace HEXCTRL::INTERNAL void OnOK()override; DECLARE_MESSAGE_MAP() private: - CHexCtrl* m_pHexCtrl { }; + IHexCtrl* m_pHexCtrl { }; }; } \ No newline at end of file diff --git a/HexCtrl/src/Dialogs/CHexDlgSearch.cpp b/HexCtrl/src/Dialogs/CHexDlgSearch.cpp index 08ceafb3..c3ca1e59 100644 --- a/HexCtrl/src/Dialogs/CHexDlgSearch.cpp +++ b/HexCtrl/src/Dialogs/CHexDlgSearch.cpp @@ -10,6 +10,7 @@ #include "../Helper.h" #include "CHexDlgCallback.h" #include "CHexDlgSearch.h" +#include #include #include #include @@ -73,7 +74,7 @@ void CHexDlgSearch::DoDataExchange(CDataExchange* pDX) DDX_Control(pDX, IDC_HEXCTRL_SEARCH_EDIT_LIMIT, m_stEditLimit); } -BOOL CHexDlgSearch::Create(UINT nIDTemplate, CHexCtrl* pHexCtrl) +BOOL CHexDlgSearch::Create(UINT nIDTemplate, CWnd* pParent, IHexCtrl* pHexCtrl) { assert(pHexCtrl); if (pHexCtrl == nullptr) @@ -81,7 +82,7 @@ BOOL CHexDlgSearch::Create(UINT nIDTemplate, CHexCtrl* pHexCtrl) m_pHexCtrl = pHexCtrl; - return CDialogEx::Create(nIDTemplate, pHexCtrl); + return CDialogEx::Create(nIDTemplate, pParent); } BOOL CHexDlgSearch::OnInitDialog() @@ -1131,15 +1132,15 @@ CHexDlgSearch::SFIND CHexDlgSearch::Find(ULONGLONG& ullStart, ULONGLONG ullEnd, void CHexDlgSearch::Replace(ULONGLONG ullIndex, std::byte* pData, size_t nSizeData, size_t nSizeReplace, bool fRedraw)const { - SMODIFY hms; + HEXMODIFY hms; hms.vecSpan.emplace_back(HEXSPANSTRUCT { ullIndex, nSizeData }); hms.ullDataSize = nSizeReplace; hms.pData = pData; hms.fRedraw = fRedraw; - GetHexCtrl()->Modify(hms); + GetHexCtrl()->ModifyData(hms); } -CHexCtrl* CHexDlgSearch::GetHexCtrl()const +IHexCtrl* CHexDlgSearch::GetHexCtrl()const { return m_pHexCtrl; } diff --git a/HexCtrl/src/Dialogs/CHexDlgSearch.h b/HexCtrl/src/Dialogs/CHexDlgSearch.h index e98926db..7a97f9c9 100644 --- a/HexCtrl/src/Dialogs/CHexDlgSearch.h +++ b/HexCtrl/src/Dialogs/CHexDlgSearch.h @@ -6,7 +6,7 @@ * https://github.com/jovibor/HexCtrl/blob/master/LICENSE * ****************************************************************************************/ #pragma once -#include "../CHexCtrl.h" +#include "../../HexCtrl.h" #include "../../dep/ListEx/ListEx.h" #include @@ -19,7 +19,7 @@ namespace HEXCTRL::INTERNAL enum class EMode : WORD; enum class EMenuID : WORD; public: - BOOL Create(UINT nIDTemplate, CHexCtrl* pHexCtrl); + BOOL Create(UINT nIDTemplate, CWnd* pParent, IHexCtrl* pHexCtrl); void Search(bool fForward); [[nodiscard]] bool IsSearchAvail()const; //Can we do search next/prev? BOOL ShowWindow(int nCmdShow); @@ -45,7 +45,7 @@ namespace HEXCTRL::INTERNAL void AddToList(ULONGLONG ullOffset); void ClearList(); void HexCtrlHighlight(const std::vector& vecSel); //Highlight found occurence in HexCtrl. - [[nodiscard]] CHexCtrl* GetHexCtrl()const; + [[nodiscard]] IHexCtrl* GetHexCtrl()const; void PrepareSearch(); [[nodiscard]] bool PrepareHex(); [[nodiscard]] bool PrepareASCII(); @@ -69,7 +69,7 @@ namespace HEXCTRL::INTERNAL [[nodiscard]] bool MemCmp(const std::byte* pBuf1, const std::byte* pBuf2, size_t nSize)const; DECLARE_MESSAGE_MAP() private: - CHexCtrl* m_pHexCtrl { }; + IHexCtrl* m_pHexCtrl { }; EMode m_eSearchMode { }; IListExPtr m_pListMain { CreateListEx() }; std::vector m_vecSearchRes { }; diff --git a/HexCtrl/src/Helper.h b/HexCtrl/src/Helper.h index fbc4e4cd..952e086a 100644 --- a/HexCtrl/src/Helper.h +++ b/HexCtrl/src/Helper.h @@ -9,14 +9,15 @@ * Here dwells some useful helper stuff for HexCtrl. * ****************************************************************************************/ #pragma once +#include "../HexCtrl.h" #include #include #define HEXCTRL_PRODUCT_NAME "Hex Control for MFC/Win32" #define HEXCTRL_COPYRIGHT_NAME "(C) 2018-2021 Jovibor" #define HEXCTRL_VERSION_MAJOR 2 -#define HEXCTRL_VERSION_MINOR 19 -#define HEXCTRL_VERSION_MAINTENANCE 3 +#define HEXCTRL_VERSION_MINOR 20 +#define HEXCTRL_VERSION_MAINTENANCE 0 namespace HEXCTRL::INTERNAL { @@ -52,6 +53,35 @@ namespace HEXCTRL::INTERNAL //Substitute all unprintable wchar symbols with dot. void ReplaceUnprintable(std::wstring& wstr, bool fASCII, bool fCRLFRepl = true); + //Get data from IHexCtrl's given offset converted to necessary type. + template + T GetIHexTData(const IHexCtrl& refHexCtrl, ULONGLONG ullOffset) + { + T tData { }; + if (const auto pData = refHexCtrl.GetData({ ullOffset, sizeof(T) }); + ullOffset >= refHexCtrl.GetDataSize() && pData != nullptr) + tData = *reinterpret_cast(pData); + + return tData; + } + + //Set data to IHexCtrl's given offset converted to necessary type. + template + void SetIHexTData(IHexCtrl& refHexCtrl, ULONGLONG ullOffset, T tData) + { + //Data overflow check. + if (ullOffset + sizeof(T) > refHexCtrl.GetDataSize()) + return; + + HEXMODIFY hms; + hms.enModifyMode = EHexModifyMode::MODIFY_DEFAULT; + hms.fRedraw = false; + hms.pData = reinterpret_cast(&tData); + hms.ullDataSize = sizeof(T); + hms.vecSpan.emplace_back(HEXSPANSTRUCT { ullOffset, sizeof(T) }); + refHexCtrl.ModifyData(hms); + } + #define TO_STR_HELPER(x) #x #define TO_STR(x) TO_STR_HELPER(x) #ifdef _WIN64 diff --git a/README.md b/README.md index 3ff6caa3..18c8c59d 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,12 @@ * [CreateDialogCtrl](#createdialogctrl) * [Destroy](#destroy) * [ExecuteCmd](#executecmd) + * [GetCacheSize](#getcachesize) * [GetCapacity](#getcapacity) * [GetCaretPos](#getcaretpos) * [GetColors](#getcolors) + * [GetData](#getdata) + * [GetDataMode](#getdatamode) * [GetDataSize](#getdatasize) * [GetEncoding](#getencoding) * [GetFontSize](#getfontsize) @@ -52,6 +55,7 @@ * [IsMutable](#ismutable) * [IsOffsetAsHex](#isoffsetashex) * [IsOffsetVisible](#isoffsetvisible) + * [ModifyData](#modifydata) * [Redraw](#redraw) * [SetCapacity](#setcapacity) * [SetCaretPos](#setcaretpos) @@ -75,13 +79,18 @@ * [HEXCREATESTRUCT](#hexcreatestruct) * [HEXDATASTRUCT](#hexdatastruct) * [HEXHITTESTSTRUCT](#hexhitteststruct) + * [HEXMODIFY](#hexmodify) * [HEXNOTIFYSTRUCT](#hexnotifystruct) * [HEXSPANSTRUCT](#hexspanstruct) * [HEXVISSTRUCT](#hexvisstruct) + +* [Enums](#enums)
_Expand_ * [EHexCmd](#ehexcmd) * [EHexCreateMode](#ehexcreatemode) * [EHexDataMode](#ehexdatamode) * [EHexGroupMode](#ehexgroupmode) + * [EHexModifyMode](#ehexmodifymode) + * [EHexOperMode](#ehexopermode) * [EHexWnd](#ehexwnd)
* [Notification Messages](#notification-messages)
_Expand_ @@ -444,9 +453,15 @@ void ExecuteCmd(EHexCmd enCmd)const; ``` Executes one of the predefined commands of [`EHexCmd`](#ehexcmd) enum. All these commands are basically replicating control's inner menu. +### [](#)GetCacheSize +```cpp +auto GetCacheSize()const->DWORD; +``` +Returns current cache size set in [`HEXDATASTRUCT`](#hexdatastruct). + ### [](#)GetCapacity ```cpp -DWORD GetCapacity()const +DWORD GetCapacity()const; ``` Returns current capacity. @@ -458,10 +473,22 @@ Retrieves current caret position offset. ### [](#)GetColors ```cpp -auto GetColors()const->HEXCOLORSSTRUCT +auto GetColors()const->HEXCOLORSSTRUCT; ``` Returns current [`HEXCOLORSSTRUCT`](#hexcolorsstruct). +### [](#)GetData +```cpp +auto GetData(HEXSPANSTRUCT hss)const->std::byte*; +``` +Returns a pointer to data offset, no matter what mode the control works in. + +### [](#)GetDataMode +```cpp +auto GetDataMode()const->EHexDataMode; +``` +Returns current [data mode](#ehexdatamode). + ### [](#)GetDataSize ```cpp auto GetDataSize()const->ULONGLONG; @@ -578,6 +605,12 @@ HEXVISSTRUCT IsOffsetVisible(ULONGLONG ullOffset)const; ``` Checks for offset visibility and returns [`HEXVISSTRUCT`](#hexvisstruct) as a result. +### [](#)ModifyData +```cpp +void ModifyData(const HEXMODIFY& hms); +``` +Modify data in set **HexCtrl**. See [`HEXMODIFY`](#hexmodify) struct for details. + ### [](#)Redraw ```cpp void Redraw(); @@ -776,6 +809,25 @@ struct HEXHITTESTSTRUCT }; ``` +### [](#)HEXMODIFY +This struct is used to represent data modification parameters. +When `enModifyMode` is set to `EHexModifyMode::MODIFY_DEFAULT`, bytes from `pData` just replace corresponding data bytes as is. + +If `enModifyMode` is equal to `EHexModifyMode::MODIFY_REPEAT` then block by block replacement takes place few times. For example : if SUM(`vecSpan.ullSize`) = 9, `ullDataSize` = 3 and `enModifyMode` is set to `EHexModifyMode::MODIFY_REPEAT`, bytes in memory at `vecSpan.ullOffset` position are 123456789, and bytes pointed to by pData are 345, then, after modification, bytes at vecSpan.ullOffset will be 345345345. + +If `enModifyMode` is equal to `EHexModifyMode::MODIFY_OPERATION` then `enOperMode` comes into play, showing what kind of operation must be performed on data. +```cpp +struct HEXMODIFY +{ + EHexModifyMode enModifyMode { EHexModifyMode::MODIFY_DEFAULT }; //Modify mode. + EHexOperMode enOperMode { }; //Operation mode, used only if enModifyMode == MODIFY_OPERATION. + std::byte* pData { }; //Pointer to a data to be set. + ULONGLONG ullDataSize { }; //Size of the data pData is pointing to. + std::vector vecSpan { }; //Vector of data offsets and sizes. + bool fRedraw { true }; //Redraw HexCtrl's window after data changes? +}; +``` + ### [](#)HEXNOTIFYSTRUCT This struct is used in notification purposes, to notify parent window about **HexCtrl**'s states. ```cpp @@ -815,6 +867,8 @@ struct HEXVISSTRUCT }; ``` +## [](#)Enums + ### [](#)EHexCmd Enum of commands that can be executed within **HexCtrl**. ```cpp @@ -863,6 +917,25 @@ enum class EHexGroupMode : WORD }; ``` +### [](#)EHexModifyMode +Enum of the data modification mode, used in [`HEXMODIFY`](#hexmodify). +```cpp +enum class EHexModifyMode : WORD +{ + MODIFY_DEFAULT, MODIFY_REPEAT, MODIFY_OPERATION +}; +``` + +### [](#)EHexOperMode +Enum of the data operation mode, used in [`HEXMODIFY`](#hexmodify) when `HEXMODIFY::enModifyMode` is set to `MODIFY_OPERATION`. +```cpp +enum class EHexOperMode : WORD +{ + OPER_OR = 0x01, OPER_XOR, OPER_AND, OPER_NOT, OPER_SHL, OPER_SHR, + OPER_ADD, OPER_SUBTRACT, OPER_MULTIPLY, OPER_DIVIDE +}; +``` + ### [](#)EHexWnd Enum of all **HexCtrl**'s internal windows. This enum is used as an arg in [`GetWindowHandle`](#getwindowhandle) method to retrieve window's handle. ```cpp