Blog

  • HexCtrl

    Hex Control

    Table of Contents

    Introduction

    HexCtrl is the fully-featured Hex Control written in pure Win32 API.

    The main features of the HexCtrl:

    • View and edit data up to 16EB (exabyte)
    • Two working modes: Memory and Virtual Data Mode
    • Fully-featured Bookmarks Manager
    • Fully-featured Search and Replace
    • Fully-featured Data Interpreter
    • Grouping data with arbitrary group size
    • Changeable codepage for the text area
    • Many options to Copy/Paste to/from clipboard
    • Modify data with Filling and many predefined Operations options
    • Undo/Redo
    • Ability to visually divide data into pages
    • Print whole document/pages range/selection
    • Customizable colors for data with Custom Colors
    • Powerful system of Templates
    • Assignable keyboard shortcuts via external config file
    • Customizable look and appearance, font, colors
    • High-DPI compliant
    • Utilizes AVX/AVX2 instruction set for best performance
    • Supports compiling for the ARM64 architecture
    • Written with the /std:c++20 standard conformance

    How To Build

    git clone https://github.com/jovibor/HexCtrl.git

    Integrate Sources

    To build HexCtrl from the sources:

    1. Add all files from the HexCtrl folder into your project
    2. Make sure to disable Precompiled Header usage for all *.ixx files in the project
    3. Add #include "HexCtrl.h"
    4. Declare HexCtrl object: auto myHex { HEXCTRL::CreateHexCtrl() };
    5. Create control instance

    Note

    You can skip adding rapidjson-amalgam.h into your project, to avoid polluting project’s global namespace.

    Dynamic Link Library

    To build and use HexCtrl as a DLL:

    1. Build HexCtrl{x86/x64/ARM64}.dll and HexCtrl{x86/x64/ARM64}.lib with the HexCtrl DLL.vcxproj project
    2. Include HexCtrl.h into your project
    3. Add /DHEXCTRL_DYNAMIC_LIB compiler option, or alternatively #define it before including HexCtrl.h:
      #define HEXCTRL_DYNAMIC_LIB
      #include "HexCtrl.h"
    4. Declare IHexCtrlPtr object: auto myHex { HEXCTRL::CreateHexCtrl() };
    5. Create control instance

    Creating

    Classic Approach

    First you need to create HexCtrl object:

    auto myHex { HEXCTRL::CreateHexCtrl() };

    Then call the Create method, which takes the HEXCREATE struct with the all necessary information for the HexCtrl creation. The HEXCREATE::dwStyle and dwExStyle are window and extended window styles respectively, set these styles according to your needs. For all available options see the HEXCREATE struct description.

    In Dialog

    To use HexCtrl in a Dialog you can create it with the Classic Approach: call Create method and provide all the necessary information.
    But there is another option:

    1. Put the Custom Control from the Toolbox in Visual Studio dialog designer onto your dialog template.
    2. In the Properties of this control in the Class field within the Misc section write: HexCtrl_MainWnd.
    3. Declare IHexCtrlPtr member variable within your dialog class:
      HEXCTRL::IHexCtrlPtr m_myHex { CreateHexCtrl() };
    4. Call the CreateDialogCtrl method from dialog’s OnInitDialog method.
      BOOL CMyDialog::OnInitDialog() {
          CDialogEx::OnInitDialog();
          m_myHex->CreateDialogCtrl(IDC_MY_HEX, m_hWnd);
      }

    CreateHexCtrl

    [[nodiscard]] IHexCtrlPtr CreateHexCtrl();

    This is the main factory function for creating HexCtrl object. The IHexCtrlPtr class is a IHexCtrl interface pointer wrapped into a standard std::unique_ptr with custom deleter, so you don’t need to worry about its destruction.

    Setting Data

    To set a data for the HexCtrl the SetData method is used. The code below shows how to construct HexCtrl object and display first 0x1FF bytes of the current app’s memory:

    IHexCtrlPtr myHex { CreateHexCtrl() };
    
    HEXCREATE hcs;
    hcs.hWndParent = m_hWnd;
    hcs.rect = {0, 0, 600, 400}; //Window rect.
    myHex->Create(hcs);
    
    HEXDATA hds;
    hds.spnData = { reinterpret_cast<std::byte*>(GetModuleHandle(nullptr)), 0x1FF };
    myHex->SetData(hds);

    The next example shows how to display std::string‘s text as hex data:

    std::string str = "My string";
    HEXDATA hds;
    hds.spnData = { reinterpret_cast<std::byte*>(str.data()), str.size() };
    myHex->SetData(hds);

    Virtual Data Mode

    Besides the standard mode, when the HexCtrl just holds a pointer to a data in a memory, it can also work in the Virtual mode. This mode can be useful in cases where you need to display a very large amount of a data that can’t fit in the memory all at once.

    If HEXDATA::pHexVirtData pointer is set, then the whole data routine will be done through it. This pointer is of IHexVirtData class type, which is a pure abstract base class. You have to derive your own class from it and implement all its public methods. Then provide a pointer to the created object of this derived class through the HEXDATA::pHexVirtData member, prior to call the SetData method.

    Virtual Bookmarks

    HexCtrl has innate functional to work with any amount of bookmarked regions. These regions can be assigned with individual background and text colors and description.

    But if you have big and complicated data logic and want to handle all these bookmarks yourself, you can do it with the help of the Virtual Bookmarks mode. In this mode all bookmark’s burden is handled by yourself, by implementing the IHexBookmarks interface and providing pointer to this implementation to the HexCtrl by calling the SetVirtualBkm method.

    Custom Colors

    If you’d like to colorize data regions with your own custom colors, use the IHexVirtColors interface.

    To use it set the HEXDATA::pHexVirtColors member to a valid instance of your own class that implements this interface, prior to calling the SetData method.

    The OnHexGetColor method of this interface takes HEXCOLORINFO struct as an argument. The HEXCOLORINFO::ullOffset member indicates the offset for which the color is requested. This method should return true if it sets custom colors for the given offset or false for default colors.

    Templates


    HexCtrl‘s templates is a powerful system of a data structures’ description with a simple .json file. These files can be loaded through the HexControl‘s internal template manager, or through the API.

    {
        "$schema": "https://raw.githubusercontent.com/jovibor/HexCtrl/master/docs/HexCtrl.Templates.Schema.json",
        "TemplateName": "SampleTemplate",
        "Data": {
            "endianness": "little",
            "clrBk": "#999999",
            "clrText": "#FFFFFF",
            "Fields": [
                {
                    "name": "MyCustomDataSingle",
                    "type": "MyCustomType"
                },
                {
                    "name": "CustomComplexData",
                    "type": "MyCustomComplexType"
                },
                {
                    "name": "ArrayOfDWORDs",
                    "type": "DWORD",
                    "array": 10
                },
                {
                    "name": "MyCustomDataArray",
                    "type": "MyCustomType",
                    "array": 4
                }
            ]
        },
        "CustomTypes": [
            {
                "TypeName": "MyCustomType",
                "Fields": [
                    {
                        "name": "myCustomTypeField1",
                        "type": "DWORD"
                    },
                    {
                        "name": "myCustomTypeField2",
                        "type": "DWORD"
                    }
                ]
            },
            {
                "TypeName": "MyCustomComplexType",
                "Fields": [
                    {
                        "name": "MyCustomTypeData1",
                        "type": "MyCustomType"
                    },
                    {
                        "name": "MyCustomTypeData2",
                        "type": "MyCustomType"
                    }
                ]
            }
        ]
    }

    Every such file contains the following properties:

    • TemplateName [mandatory, string] – the name of the template
    • Data [mandatory, object] – main object that contains all template field’s information
    • CustomTypes [optional, array] – array of a user defined types, that can be then referenced in the type property of the Fields

    CustomTypes objects are the same as Fields objects, the only difference is the TypeName property which Fields objects don’t have.

    Every Data or CustomType object contains Fields property with actual struct members.

    Fields [array] – is an array of objects where every object represents a struct data member. Any such object can have its own Fields sub-objects, which will represent nested structs.
    The Fields‘s properties include:

    • name – [mandatory, string] – name of the field
    • description – [optional, string] – field description
    • type – [optional, string] – field type, such as:
      bool, char, unsigned char, byte, short, unsigned short, WORD, long, unsigned long, int, unsigned int, DWORD, long long, unsigned long long, QWORD, float, double, time32_t, time64_t, FILETIME, SYSTEMTIME, GUID, or any custom type defined in the CustomTypes section
    • size – [optional, int] – size of the field in bytes, if the type field is not provided
    • array – [optional, int] – size of the array, if the given field is an array of fields
    • endianness – [optional, string] – field endianness, “little” or “big”. By default all fields are little-endian.
    • clrBk – [optional, string] – field background color
    • clrText – [optional, string] – field text color

    The endianness, clrBk and clrText properties that locate at the same level as the Fields property, would mean the default properties for all the Fields objects of that level and below the line, unless they explicitly redefined in the field itself.

    For the available templates check the Templates directory.

    Methods

    The HexCtrl has plenty of methods that you can use to manage its behavior.

    ClearData

    void ClearData();

    Clears data from the HexCtrl view, not touching data itself.

    Create

    bool Create(const HEXCREATE& hcs);

    Main initialization method. Takes the HEXCREATE struct as argument. Returns true if created successfully, false otherwise.

    CreateDialogCtrl

    bool CreateDialogCtrl(UINT uCtrlID, HWND hwndDlg);

    Creates HexCtrl from a Custom Control dialog’s template. Takes control id, and dialog’s window handle as arguments. See Creating section for more info.

    Delete

    void Delete();

    Deletes the HexCtrl object. You only use this method if you want, for some reason, to manually delete the HexCtrl object, otherwise IHexCtrlPtr will invoke this method automatically.

    Important

    You usually don’t need to call this method unless you use the HexCtrl through a raw pointer. If you use HexCtrl in the standard way, through the IHexCtrlPtr pointer obtained by the CreateHexCtrl function, this method will be called automatically.

    DestroyWindow

    void DestroyWindow();

    Destroys the HexCtrl main window.

    ExecuteCmd

    void ExecuteCmd(EHexCmd eCmd)const;

    Executes one of the predefined commands of the EHexCmd enum. All these commands are basically replicating HexCtrl‘s inner menu.

    GetActualWidth

    [[nodiscard]] auto GetActualWidth()const->int;

    Returns the width of the HexCtrl bounding rectangle, i.e. the width of the drawn working area.

    GetBookmarks

    [[nodiscard]] auto GetBookmarks()->IHexBookmarks*;

    Returns pointer to the IHexBookmarks interface, which responds for the bookmarks machinery.

    GetCacheSize

    [[nodiscard]] auto GetCacheSize()const->DWORD;

    Returns current cache size set in HEXDATA.

    GetCapacity

    [[nodiscard]] auto GetCapacity()const->DWORD;

    Returns current capacity.

    GetCaretPos

    [[nodiscard]] auto GetCaretPos()const->ULONGLNG;

    Retrieves current caret position offset.

    GetCharsExtraSpace

    [[nodiscard]] auto GetCharsExtraSpace()const->DWORD;

    Get extra space between chars, in pixels. This extra space can be set with the SetCharsExtraSpace method.

    GetColors

    [[nodiscard]] auto GetColors()const->const HEXCOLORS&;

    Returns reference to the current HEXCOLORS struct.

    GetData

    [[nodiscard]] auto GetData(HEXSPAN hss)const->std::byte*;

    Returns a pointer to the data offset no matter what mode the control works in.

    Note

    In the Virtual mode returned data size can not exceed current cache size, and therefore may be less than the size acquired. In the default mode returned pointer is just an offset from the data pointer set in the SetData method.

    GetDataSize

    [[nodiscard]] auto GetDataSize()const->ULONGLONG;

    Returns currently set data size.

    GetDateInfo

    [[nodiscard]] auto GetDateInfo()const->std::tuple<DWORD, wchar_t>;

    Returns tuple of the current date format-ordering specifier, and date separator.

    GetDlgItemHandle

    [[nodiscard]] auto GetDlgItemHandle(EHexDlgItem eItem)const->HWND;

    Returns HWND of a dialog’s internal child control.

    GetCodepage

    [[nodiscard]] auto GetCodepage()const->int;

    Returns code page that is currently in use.

    GetFont

    [[nodiscard]] auto GetFont(bool fMain)const->LOGFONTW;

    Returns current main font if fMain is true, and infobar font if fMain is false.

    GetGroupSize

    [[nodiscard]] auto GetGroupSize()const->DWORD;

    Returns current data grouping size.

    GetMenuHandle

    [[nodiscard]] auto GetMenuHandle()const->HMENU;

    Returns the HMENU handle of the HexCtrl context menu. You can use this handle to customize menu for your needs.
    HexCtrl‘s internal menu uses IDs starting from 0x8001. So if you wish to add your own new menu, assign menu ID starting from 0x9000 to not interfere.
    When a user clicks custom menu, control sends WM_NOTIFY message to its parent window with LPARAM pointing to HEXMENUINFO with its hdr.code member set to HEXCTRL_MSG_MENUCLICK, and wMenuID field containing ID of the menu clicked.

    GetOffset

    [[nodiscard]] auto GetOffset(ULONGLONG ullOffset, bool fGetVirt)const->ULONGLONG;

    Converts offset from virtual to flat, and vice versa.

    GetPagesCount

    [[nodiscard]] auto GetPagesCount()const->ULONGLONG;

    Returns current count of pages set by the SetPageSize method.

    GetPagePos

    [[nodiscard]] auto GetPagePos()const->ULONGLONG;

    Returns a page number that the cursor stays at.

    GetPageSize

    [[nodiscard]] auto GetPageSize()const->DWORD;

    Returns current page size set by the SetPageSize method.

    GetScrollRatio

    [[nodiscard]] auto GetScrollRatio()const->std::tuple<float, bool>;

    Returns tuple of the current scroll ratio and fLines flag set by the SetScrollRatio method.

    GetSelection

    [[nodiscard]] auto GetSelection()const->std::vector<HEXSPAN>;

    Returns std::vector with the offsets and sizes of the current selection.

    GetTemplates

    [[nodiscard]] auto GetTemplates()->IHexTemplates*;

    Returns pointer to the internal IHexTemplates interface that is responsible for templates machinery.

    GetUnprintableChar

    [[nodiscard]] auto GetUnprintableChar()const->wchar_t;

    Returns replacement char for unprintable characters.

    GetWndHandle

    [[nodiscard]] auto GetWndHandle(EHexWnd eWnd, bool fCreate = true)const->HWND;

    Returns HWND for HexCtrl‘s main window or one of its internal dialogs. If fCreate flag is true, the dialog window will be created first before returning, if it was not already.

    GoToOffset

    void GoToOffset(ULONGLONG ullOffset, int iPosAt = 0);

    Go to the given offset. The second argument iPosAt can take three values:

    • -1 – offset will appear at the top line
    •   0 – offset will appear in the center
    •   1 – offset will appear at the bottom line

    HasInfoBar

    [[nodiscard]] bool HasInfoBar()const;

    Shows whether bottom info bar currently visible or not.

    HasSelection

    [[nodiscard]] bool HasSelection()const;

    Returns true if HexCtrl has any area selected.

    HitTest

    [[nodiscard]] auto HitTest(POINT pt, bool fScreen = true)const->std::optional<HEXHITTEST>;

    Hit testing of given point in a screen fScreen = true, or client fScreen = false coordinates. In case of success returns HEXHITTEST structure.

    IsCmdAvail

    [[nodiscard]] bool IsCmdAvail(EHexCmd eCmd)const;

    Returns true if the given command can be executed at the moment, false otherwise.

    IsCreated

    [[nodiscard]] bool IsCreated()const;

    Shows whether HexCtrl is created or not.

    IsDataSet

    [[nodiscard]] bool IsDataSet()const;

    Shows whether a data was set to HexCtrl or not

    IsHexCharsUpper

    [[nodiscard]] bool IsHexCharsUpper()const;

    Shows if hex chars printed in UPPER or lower case.

    IsMutable

    [[nodiscard]] bool IsMutable()const;

    Shows whether HexCtrl is currently in edit mode or not.

    IsOffsetAsHex

    [[nodiscard]] bool IsOffsetAsHex()const;

    Is “Offset” currently represented (shown) as Hex or as Decimal. It can be changed by double clicking at offset area.

    IsOffsetVisible

    [[nodiscard]] auto IsOffsetVisible(ULONGLONG ullOffset)const->HEXVISION;

    Checks for offset visibility and returns HEXVISION as a result.

    IsVirtual

    [[nodiscard]] bool IsVirtual()const;

    Returns true if HexCtrl currently works in Virtual Data Mode.

    ModifyData

    void ModifyData(const HEXMODIFY& hms);

    Modify data currently set in HexCtrl, see the HEXMODIFY struct for details.

    PreTranslateMsg

    [[nodiscard]] bool PreTranslateMsg(MSG* pMsg);

    The HexCtrl has many internal dialog windows. In order for dialog keyboard navigation to work correctly, this method must be hooked into your app’s main message loop before TranslateMessage and DispatchMessage, or into MFC’s PreTranslateMessage virtual function.

    while (GetMessageW(&msg, nullptr, 0, 0)) {
        if (!TranslateAcceleratorW(msg.hwnd, hAccelTable, &msg)) {
            if (!m_pHexCtrl->PreTranslateMsg(&msg)) { //Process further only if it returns false.
                TranslateMessage(&msg);
                DispatchMessageW(&msg);
            }
        }
    }

    If this method returns true it means that no further message processing should be made, HexCtrl has done all processing by itself.

    Redraw

    void Redraw();

    Redraws main window.

    SetCapacity

    void SetCapacity(DWORD dwCapacity);

    Sets HexCtrl‘s current capacity.

    SetCaretPos

    void SetCaretPos(ULONGLONG ullOffset, bool fHighLow = true, bool fRedraw = true);

    Sets the caret to the given offset. The fHighLow flag shows which part of the hex chunk, low or high, a caret must be set to.

    SetCharsExtraSpace

    void SetCharsExtraSpace(DWORD dwSpace);

    Sets extra space to add between chars, in pixels.

    SetCodepage

    void SetCodepage(int iCodePage);

    Sets the code page for the HexCtrl‘s text area. Takes code page identifier as an argument, or -1 for default ASCII-only characters.

    Note

    Code page identifier must represent Single-byte Character Set. Multi-byte character sets are not currently supported.

    SetColors

    void SetColors(const HEXCOLORS& clr);

    Sets all the colors for the control. Takes HEXCOLORS as the argument.

    SetConfig

    bool SetConfig(std::wstring_view wsvPath);

    Sets the path to a JSON config file with keybindings to use in HexCtrl, or empty path (L"") for default. This file is using EHexCmd enum values as keys and strings array as values:

    {
        "CMD_DLG_SEARCH": [ "ctrl+f", "ctrl+h" ],
        "CMD_SEARCH_NEXT": [ "f3" ],
        "CMD_SEARCH_PREV": [ "shift+f3" ]
    }

    For default values see the IDR_HEXCTRL_JSON_KEYBIND.json file from the project sources.

    SetData

    void SetData(const HEXDATA& hds, bool fAdjust = false)

    Main method to set data for HexCtrl. It takes HEXDATA struct as an argument.
    The fAdjust flag when set to true allows adjusting already set data. For example to switch between virtual and normal data modes.

    SetDateInfo

    void SetDateInfo(DWORD dwFormat, wchar_t wchSepar);

    Sets date format-ordering specifier, along with date separator.

    SetDlgProperties

    void SetDlgProperties(EHexWnd eWnd, std::uint64_t u64Flags);

    Sets various properties to the HexCtrl‘s internal dialogs, in form of flags. Flags can be combined together with the OR (|) operation.
    Available flags:

    HEXCTRL_FLAG_DLG_NOESC //Prevent dialog from closing on Esc key.

    SetFont

    void SetFont(const LOGFONTW& lf, bool fMain);

    Sets new main font for the HexCtrl if fMain is true, or infobar font when fMain is false. This font has to be monospaced.

    SetGroupSize

    void SetGroupSize(DWORD dwSize);

    Sets current data grouping size in bytes.

    SetHexCharsCase

    void SetHexCharsCase(bool fUpper);

    Sets printed hex chars to an UPPER or lower case.

    SetMutable

    void SetMutable(bool fMutable);

    Enables or disables mutable mode. In the mutable mode all the data can be modified.

    SetOffsetMode

    void SetOffsetMode(bool fHex);

    Sets offset area being shown as Hex (fHex=true) or as Decimal (fHex=false).

    SetPageSize

    void SetPageSize(DWORD dwSize, std::wstring_view wsvName = L"Page");

    Sets the size of the page to draw the divider line between. This size should be multiple to the current capacity size to take effect. The second argument sets the name to be displayed in the bottom info area of the HexCtrl (“Page”, “Sector”, etc…).
    To remove the divider just set dwSize to 0.

    SetRedraw

    void SetRedraw(bool fRedraw);

    Should the main HexCtrl window be redrawn or not. E.g. should the WM_PAINT message be handled or not.

    SetScrollRatio

    void SetScrollRatio(float flRatio, bool fLines);

    Sets the scroll amount for one scroll-page. Page is the one mouse-wheel tick or page-down key. When fLines is true the flRatio is the amount of text lines to scroll. When it’s false flRatio is a ratio of visible screen height to scroll.

    SetSelection

    void SetSelection(const std::vector<HEXSPAN>& vecSel, bool fRedraw = true, bool fHighlight = false);

    Sets current selection or highlight in the selection, if fHighlight is true.

    SetUnprintableChar

    void SetUnprintableChar(wchar_t wch);

    Sets replacement char for unprintable characters.

    SetVirtualBkm

    void SetVirtualBkm(IHexBookmarks* pVirtBkm);

    Sets a pointer for the Virtual Bookmarks mode, or disables this mode if nullptr is set.

    SetWindowPos

    void SetWindowPos(HWND hWndAfter, int iX, int iY, int iWidth, int iHeight, UINT uFlags);

    Sets HexCtrl window position. This method replicates behavior of the SetWindowPos Windows function.

    ShowInfoBar

    void ShowInfoBar(bool fShow);

    Show/hide bottom Info bar.

    Structures

    Below are listed all HexCtrl‘s structures.

    HEXBKM

    Main bookmarks structure, used with the IHexBookmarks interface.

    struct HEXBKM {
        VecSpan      vecSpan;     //Vector of offsets and sizes.
        std::wstring wstrDesc;    //Bookmark description.
        ULONGLONG    ullID { };   //Bookmark ID, assigned internally by framework.
        ULONGLONG    ullData { }; //User defined custom data.
        HEXCOLOR     stClr;       //Bookmark bk/text color.
    };
    using PHEXBKM = HEXBKM*;

    The member vecSpan is of a std::vector<HEXSPAN> type because a bookmark may have few non adjacent areas. For instance, when selection is made as a block, with Alt pressed.

    HEXBKMINFO

    Bookmark information struct.

    struct HEXBKMINFO {
        NMHDR   hdr { };  //Standard Windows header.
        PHEXBKM pBkm { }; //Bookmark pointer.
    };
    using PHEXBKMINFO = HEXBKMINFO*;

    HEXCOLOR

    Background and Text color struct.

    struct HEXCOLOR {
        COLORREF clrBk { };   //Bk color.
        COLORREF clrText { }; //Text color.
        auto operator<=>(const HEXCOLOR&)const = default;
    };
    using PHEXCOLOR = HEXCOLOR*;

    HEXCOLORINFO

    Struct for hex chunks’ color information.

    struct HEXCOLORINFO {
        NMHDR     hdr { };       //Standard Windows header.
        ULONGLONG ullOffset { }; //Offset for the color.
        HEXCOLOR  stClr;         //Colors of the given offset.
    };

    HEXCOLORS

    This structure contains all colors for fonts, background, and all other visual stuff. All these colors have their default values, so you don’t have to set them all during HexCtrl creation, if you don’t want to.

    struct HEXCOLORS {
        COLORREF clrFontHex { ::GetSysColor(COLOR_WINDOWTEXT) };       //Hex-chunks font color.
        COLORREF clrFontText { ::GetSysColor(COLOR_WINDOWTEXT) };      //Text font color.
        COLORREF clrFontSel { ::GetSysColor(COLOR_HIGHLIGHTTEXT) };    //Selected hex/text font color.
        COLORREF clrFontBkm { ::GetSysColor(COLOR_WINDOWTEXT) };       //Bookmarks font color.
        COLORREF clrFontDataInterp { ::GetSysColor(COLOR_HIGHLIGHTTEXT) }; //Data Interpreter text/hex font color.
        COLORREF clrFontCaption { RGB(0, 0, 180) };                    //Caption font color
        COLORREF clrFontInfoParam { ::GetSysColor(COLOR_WINDOWTEXT) }; //Font color of the Info bar parameters.
        COLORREF clrFontInfoData { RGB(0, 0, 180) };                   //Font color of the Info bar data.
        COLORREF clrFontCaret { ::GetSysColor(COLOR_HIGHLIGHTTEXT) };  //Caret font color.
        COLORREF clrBk { ::GetSysColor(COLOR_WINDOW) };                //Background color.
        COLORREF clrBkSel { ::GetSysColor(COLOR_HIGHLIGHT) };          //Background color of the selected Hex/Text.
        COLORREF clrBkBkm { RGB(240, 240, 0) };                        //Bookmarks background color.
        COLORREF clrBkDataInterp { RGB(147, 58, 22) };                 //Data Interpreter Bk color.
        COLORREF clrBkInfoBar { ::GetSysColor(COLOR_3DFACE) };         //Background color of the bottom Info bar.
        COLORREF clrBkCaret { RGB(0, 0, 255) };                        //Caret background color.
        COLORREF clrBkCaretSel { RGB(0, 0, 200) };                     //Caret background color in selection.
        COLORREF clrLinesMain { ::GetSysColor(COLOR_SCROLLBAR) };      //Main window and pages lines color.
        COLORREF clrLinesTempl { ::GetSysColor(COLOR_WINDOWTEXT) };    //Templates data confining lines color.
        COLORREF clrScrollBar { ::GetSysColor(COLOR_3DFACE) };         //Scrollbar color.
        COLORREF clrScrollThumb { ::GetSysColor(COLOR_SCROLLBAR) };    //Scrollbar thumb color.
        COLORREF clrScrollArrow { ::GetSysColor(COLOR_GRAYTEXT) };     //Scrollbar arrow color.
    };
    using PCHEXCOLORS = const HEXCOLORS*;

    HEXCREATE

    The main initialization struct used for the HexCtrl creation.

    struct HEXCREATE {
        HINSTANCE       hInstRes { };           //Hinstance of the HexCtrl resources, nullptr for current module.
        HWND            hWndParent { };         //Parent window handle.
        PCHEXCOLORS     pColors { };            //HexCtrl colors, nullptr for default.
        const LOGFONTW* pLogFont { };           //Monospaced font for HexCtrl, nullptr for default.
        RECT            rect { };               //Initial window rect.
        UINT            uID { };                //Control ID if it's a child window.
        DWORD           dwStyle { };            //Window styles.
        DWORD           dwExStyle { };          //Extended window styles.
        DWORD           dwCapacity { 16UL };    //Initial capacity size.
        DWORD           dwGroupSize { 1UL };    //Initial data grouping size.
        float           flScrollRatio { 1.0F }; //Either a screen-ratio or lines amount to scroll with Page-scroll (mouse-wheel).
        bool            fScrollLines { false }; //Treat flScrollRatio as screen-ratio (false) or as amount of lines (true).
        bool            fInfoBar { true };      //Show bottom Info bar or not.
        bool            fOffsetHex { true };    //Show offset digits as Hex or Decimal.
        bool            fCustom { false };      //If it's a custom control in a dialog.
    };

    Members:

    HINSTANCE hInstRes

    The hInstRes member allows you to provide an alternative HINSTANCE of a module where all HexCtrl resources (dialogs, menu, etc…) reside. By default HexCtrl uses its current module, whether it’s a .exe or .dll.

    DWORD dwStyle

    Standard window style for the main HexCtrl window.

    DWORD dwExStyle

    Standard extended window style for the main HexCtrl window.

    HEXDATA

    The main struct to set a data to display in the HexCtrl.

    struct HEXDATA {
        SpanByte        spnData;                    //Data span to display.
        IHexVirtData*   pHexVirtData { };           //Pointer for VirtualData mode.
        IHexVirtColors* pHexVirtColors { };         //Pointer for Custom Colors class.
        ULONGLONG       ullMaxVirtOffset { };       //Maximum virtual offset.
        DWORD           dwCacheSize { 0x800000UL }; //Data cache size for VirtualData mode.
        bool            fMutable { false };         //Is data mutable or read-only.
        bool            fHighLatency { false };     //Do not redraw until scroll thumb is released.
    };

    Members:

    ULONGLONG ullMaxVirtOffset

    Used to set maximum virtual data offset in virtual data mode. This is needed for the offset digits amount calculation.

    HEXDATAINFO

    Struct for a data information used in IHexVirtData.

    struct HEXDATAINFO {
        NMHDR    hdr { };   //Standard Windows header.
        HEXSPAN  stHexSpan; //Offset and size of the data.
        SpanByte spnData;   //Data span.
    };

    HEXHITTEST

    Structure is used in HitTest method.

    struct HEXHITTEST {
        ULONGLONG ullOffset { };     //Offset.
        bool      fIsText { false }; //Is cursor at Text or Hex area.
        bool      fIsHigh { false }; //Is it High or Low part of the byte.
    };

    HEXMODIFY

    This struct is used to represent data modification parameters.
    When eModifyMode is set to MODIFY_ONCE, bytes from pData just replace corresponding data bytes as is.
    If eModifyMode is equal to MODIFY_REPEAT then block by block replacement takes place few times.
    For example, if:

    • SUM(vecSpan.ullSize) == 9
    • spnData.size() == 3
    • eModifyMode is set to MODIFY_REPEAT
    • bytes in memory at vecSpan.ullOffset are 010203040506070809
    • bytes pointed to by spnData.data() are 030405

    then, after modification, bytes at vecSpan.ullOffset will become 030405030405030405.

    If eModifyMode is equal to the MODIFY_OPERATION then the eOperMode shows what kind of operation must be performed on the data.

    struct HEXMODIFY {
        EHexModifyMode eModifyMode { };      //Modify mode.
        EHexOperMode   eOperMode { };        //Operation mode, used if eModifyMode == MODIFY_OPERATION.
        EHexDataType   eDataType { };        //Data type of the underlying data, used if eModifyMode == MODIFY_OPERATION.
        SpanCByte      spnData;              //Span of the data to modify with.
        VecSpan        vecSpan;              //Vector of data offsets and sizes to modify.
        bool           fBigEndian { false }; //Treat data as the big endian, used if eModifyMode == MODIFY_OPERATION.
    };

    HEXMENUINFO

    Menu information struct.

    struct HEXMENUINFO {
        NMHDR hdr { };        //Standard Windows header.
        POINT pt { };         //Mouse position when clicked.
        WORD  wMenuID { };    //Menu identifier.
        bool  fShow { true }; //Whether to show menu or not, in case of HEXCTRL_MSG_CONTEXTMENU.
    };
    using PHEXMENUINFO = HEXMENUINFO*;

    HEXSPAN

    This struct is used mostly in selection and bookmarking routines. It holds offset and size of the data region.

    struct HEXSPAN {
        ULONGLONG ullOffset { };
        ULONGLONG ullSize { };
    };
    using VecSpan = std::vector<HEXSPAN>;

    HEXVISION

    This struct is returned from IsOffsetVisible method. Two members i8Vert and i8Horz represent vertical and horizontal visibility respectively. These members can be in three different states:

    • -1 — offset is higher, or at the left, of the visible area.
    •   1 — offset is lower, or at the right.
    •   0 — offset is visible.
    struct HEXVISION {
        std::int8_t i8Vert { }; //Vertical offset.
        std::int8_t i8Horz { }; //Horizontal offset.
        operator bool()const { return i8Vert == 0 && i8Horz == 0; }; //For test simplicity: if(IsOffsetVisible()).
    };

    Interfaces

    IHexBookmarks

    The IHexBookmarks interface responds for the HexCtrl‘s bookmarks machinery. To obtain pointer to this interface use the GetBookmarks method.

    class IHexBookmarks {
    public:
        virtual auto AddBkm(const HEXBKM& hbs, bool fRedraw = true) -> ULONGLONG = 0; //Add new bookmark, returns the new bookmark's ID.
        [[nodiscard]] virtual auto GetByID(ULONGLONG ullID) -> PHEXBKM = 0;           //Get bookmark by ID.
        [[nodiscard]] virtual auto GetByIndex(ULONGLONG ullIndex) -> PHEXBKM = 0;     //Get bookmark by index.
        [[nodiscard]] virtual auto GetCount() -> ULONGLONG = 0;                       //Get bookmarks count.
        [[nodiscard]] virtual auto HitTest(ULONGLONG ullOffset) -> PHEXBKM = 0;       //HitTest for given offset.
        virtual void RemoveAll() = 0;                                                 //Remove all bookmarks.
        virtual void RemoveByID(ULONGLONG ullID) = 0;                                 //Remove by a given ID.
    };

    IHexBookmarks::AddBkm

    ULONGLONG AddBkm(const HEXBKM& hbs, bool fRedraw = false)

    Adds new bookmark to the control, returns created bookmark’s ID.

    Example:

    HEXBKM hbs;
    hbs.vecSpan.emplace_back(0x1, 10);
    hbs.clrBk = RGB(0, 255, 0);
    hbs.clrText = RGB(255, 255, 255);
    hbs.wstrDesc = L"My bookmark, with green bk and white text.";
    myHex->GetBookmarks()->Add(hbs);

    IHexBookmarks::GetByID

    GetByID(ULONGLONG ullID)->HEXBKM*;

    Get bookmark by ID.

    IHexBookmarks::GetByIndex

    auto GetByIndex(ULONGLONG ullIndex)->HEXBKM*;

    Get bookmark by index.

    IHexBookmarks::GetCount

    ULONGLONG GetCount();

    Get bookmarks’ count.

    IHexBookmarks::HitTest

    auto HitTest(ULONGLONG ullOffset)->HEXBKM*;

    Test given offset and retrieves a pointer to HEXBKM if offset contains a bookmark.

    IHexBookmarks::RemoveAll

    void RemoveAll();

    Removes all bookmarks.

    IHexBookmarks::RemoveByID

    void RemoveByID(ULONGLONG ullID);

    Removes bookmark with the given ID.

    IHexTemplates

    class IHexTemplates {
    public:
        virtual auto AddTemplate(const HEXTEMPLATE& hts) -> int = 0; //Adds existing template.
        virtual auto ApplyTemplate(ULONGLONG ullOffset, int iTemplateID) -> int = 0; //Applies template to offset, returns AppliedID.
        virtual void DisapplyAll() = 0;
        virtual void DisapplyByID(int iAppliedID) = 0;
        virtual void DisapplyByOffset(ULONGLONG ullOffset) = 0;
        virtual auto LoadTemplate(const wchar_t* pFilePath) -> int = 0; //Returns TemplateID on success, null otherwise.
        virtual void ShowTooltips(bool fShow) = 0;
        virtual void UnloadAll() = 0;                     //Unload all templates.
        virtual void UnloadTemplate(int iTemplateID) = 0; //Unload/remove loaded template from memory.
        [[nodiscard]] static HEXCTRLAPI auto __cdecl LoadFromFile(const wchar_t* pFilePath)->std::unique_ptr<HEXTEMPLATE>;
    };

    LoadFromFile

    [[nodiscard]] static auto LoadFromFile(const wchar_t* pFilePath)->std::unique_ptr<HEXTEMPLATE>;

    This static method can be used to upfront load a template from a file. The loaded template can then be added to multiple HexCtrl instances, through the IHexTemplates::AddTemplate method. This approach allows to avoid loading the same template from the disk multiple times if multiple HexCtrls would load it through the IHexTemplates::LoadTemplate, each individually.

    IHexVirtColors

    class IHexVirtColors {
    public:
        virtual bool OnHexGetColor(HEXCOLORINFO&) = 0; //Should return true if colors are set.
    };

    IHexVirtData

    class IHexVirtData {
    public:
        virtual void OnHexGetData(HEXDATAINFO&) = 0; //Data to get.
        virtual void OnHexGetOffset(HEXDATAINFO& hdi, bool fGetVirt) = 0; //Offset<->VirtOffset conversion.
        virtual void OnHexSetData(const HEXDATAINFO&) = 0; //Data to set, if mutable.
    };

    OnHexGetOffset

    Internally HexCtrl operates with flat data offsets. If you set data of 1MB size, HexCtrl will have working offsets in the [0-1'048'575] range. However, from the user perspective the real data offsets may differ. For instance, in processes memory model very high virtual memory addresses can be used (e.g. 0x7FF96BA622C0). The process data can be mapped by operating system to literally any virtual address. The OnHexGetOffset method serves exactly for the Flat<->Virtual offset converting purpose.

    Enums

    EHexCmd

    Enum of commands that can be executed within HexCtrl.

    enum class EHexCmd : std::uint8_t {
        CMD_SEARCH_DLG = 0x01, CMD_SEARCH_NEXT, CMD_SEARCH_PREV,
        CMD_NAV_GOTO_DLG, CMD_NAV_REPFWD, CMD_NAV_REPBKW, CMD_NAV_DATABEG, CMD_NAV_DATAEND,
        CMD_NAV_PAGEBEG, CMD_NAV_PAGEEND, CMD_NAV_LINEBEG, CMD_NAV_LINEEND, CMD_GROUPDATA_BYTE,
        CMD_GROUPDATA_WORD, CMD_GROUPDATA_DWORD, CMD_GROUPDATA_QWORD, CMD_GROUPDATA_INC, CMD_GROUPDATA_DEC,
        CMD_BKM_ADD, CMD_BKM_REMOVE, CMD_BKM_NEXT, CMD_BKM_PREV, CMD_BKM_REMOVEALL, CMD_BKM_DLG_MGR,
        CMD_CLPBRD_COPY_HEX, CMD_CLPBRD_COPY_HEXLE, CMD_CLPBRD_COPY_HEXFMT, CMD_CLPBRD_COPY_TEXTCP,
        CMD_CLPBRD_COPY_BASE64, CMD_CLPBRD_COPY_CARR, CMD_CLPBRD_COPY_GREPHEX, CMD_CLPBRD_COPY_PRNTSCRN,
        CMD_CLPBRD_COPY_OFFSET, CMD_CLPBRD_PASTE_HEX, CMD_CLPBRD_PASTE_TEXTUTF16, CMD_CLPBRD_PASTE_TEXTCP,
        CMD_MODIFY_OPERS_DLG, CMD_MODIFY_FILLZEROS, CMD_MODIFY_FILLDATA_DLG, CMD_MODIFY_UNDO, CMD_MODIFY_REDO,
        CMD_SEL_MARKSTARTEND, CMD_SEL_ALL, CMD_SEL_ADDLEFT, CMD_SEL_ADDRIGHT, CMD_SEL_ADDUP,
        CMD_SEL_ADDDOWN, CMD_DATAINTERP_DLG, CMD_CODEPAGE_DLG, CMD_APPEAR_FONT_DLG, CMD_APPEAR_FONTINC,
        CMD_APPEAR_FONTDEC, CMD_APPEAR_CAPACINC, CMD_APPEAR_CAPACDEC, CMD_PRINT_DLG, CMD_ABOUT_DLG,
        CMD_CARET_LEFT, CMD_CARET_RIGHT, CMD_CARET_UP, CMD_CARET_DOWN,
        CMD_SCROLL_PAGEUP, CMD_SCROLL_PAGEDOWN,
        CMD_TEMPL_APPLYCURR, CMD_TEMPL_DISAPPLY, CMD_TEMPL_DISAPPALL, CMD_TEMPL_DLG_MGR
    };

    EHexDataType

    Enum of the data type used in the HEXMODIFY struct with the EHexModifyMode::MODIFY_OPERATION mode.

    enum class EHexDataType : std::uint8_t {
        DATA_INT8, DATA_UINT8, DATA_INT16, DATA_UINT16, DATA_INT32,
        DATA_UINT32, DATA_INT64, DATA_UINT64, DATA_FLOAT, DATA_DOUBLE
    };

    EHexModifyMode

    Enum of the data modification modes, used in HEXMODIFY.

    enum class EHexModifyMode : std::uint8_t {
        MODIFY_ONCE, MODIFY_REPEAT, MODIFY_OPERATION, MODIFY_RAND_MT19937, MODIFY_RAND_FAST
    };

    EHexOperMode

    Enum of the data operation modes, used in HEXMODIFY when HEXMODIFY::enModifyMode is set to MODIFY_OPERATION.

    enum class EHexOperMode : std::uint8_t {
        OPER_ASSIGN, OPER_ADD, OPER_SUB, OPER_MUL, OPER_DIV, OPER_CEIL, OPER_FLOOR, OPER_OR,
        OPER_XOR, OPER_AND, OPER_NOT, OPER_SHL, OPER_SHR, OPER_ROTL, OPER_ROTR, OPER_SWAP,
        OPER_BITREV
    };

    EHexWnd

    Enum of all HexCtrl‘s internal windows, used in the GetWndHandle method.

    enum class EHexWnd : std::uint8_t {
        WND_MAIN, DLG_BKMMGR, DLG_DATAINTERP, DLG_MODIFY,
        DLG_SEARCH, DLG_ENCODING, DLG_GOTO, DLG_TEMPLMGR
    };

    Notification Messages

    During its work the HexCtrl sends notification messages to its parent window through WM_NOTIFY mechanism.
    The LPARAM of the WM_NOTIFY message contains a pointer to the NMHDR standard Windows struct. Depending on the notification message LPARAM can then be casted to a pointer to another struct, see the messages description for details.

    HEXCTRL_MSG_BKMCLICK

    Sent if a bookmark is clicked, LPARAM contains a pointer to the HEXBKMINFO struct.

    HEXCTRL_MSG_CONTEXTMENU

    Sent when a context menu is about to be displayed, LPARAM contains a pointer to the HEXMENUINFO struct. You can disable menu showing-up by setting the PHEXMENUINFO->fShow flag to false in response to this message.

    HEXCTRL_MSG_DESTROY

    Sent to indicate that the HexCtrl‘s window is about to be destroyed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_DLGBKMMGR

    Sent to indicate that the Bookmark Manager dialog is about to be displayed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_DLGCODEPAGE

    Sent to indicate that the Codepage dialog is about to be displayed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_DLGDATAINTERP

    Sent to indicate that the Data interpreter dialog is about to be displayed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_DLGGOTO

    Sent to indicate that the Go to dialog is about to be displayed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_DLGMODIFY

    Sent to indicate that the Modify Data dialog is about to be displayed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_DLGSEARCH

    Sent to indicate that the Search dialog is about to be displayed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_DLGTEMPLMGR

    Sent to indicate that the Template Manager dialog is about to be displayed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_MENUCLICK

    Sent when a user-defined custom menu has been clicked, LPARAM contains a pointer to the HEXMENUINFO struct.

    HEXCTRL_MSG_SETCAPACITY

    Sent when the capacity has changed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_SETCARET

    Sent when the caret position has changed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_SETCODEPAGE

    Sent when the codepage of the text area has changed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_SETDATA

    Sent to indicate that the data has changed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_SETFONT

    Sent when font has changed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_SETGROUPSIZE

    Sent when the data grouping size has changed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_SETSELECTION

    Sent when a selection has been made, LPARAM contains a pointer to the NMHDR struct.

    Licensing

    This software is available under “The HexCtrl License”, it is free for any NON-COMMERCIAL use.
    See the LICENSE file.

    Visit original content creator repository https://github.com/jovibor/HexCtrl
  • HexCtrl

    Hex Control

    Table of Contents

    Introduction

    HexCtrl is the fully-featured Hex Control written in pure Win32 API.

    The main features of the HexCtrl:

    • View and edit data up to 16EB (exabyte)
    • Two working modes: Memory and Virtual Data Mode
    • Fully-featured Bookmarks Manager
    • Fully-featured Search and Replace
    • Fully-featured Data Interpreter
    • Grouping data with arbitrary group size
    • Changeable codepage for the text area
    • Many options to Copy/Paste to/from clipboard
    • Modify data with Filling and many predefined Operations options
    • Undo/Redo
    • Ability to visually divide data into pages
    • Print whole document/pages range/selection
    • Customizable colors for data with Custom Colors
    • Powerful system of Templates
    • Assignable keyboard shortcuts via external config file
    • Customizable look and appearance, font, colors
    • High-DPI compliant
    • Utilizes AVX/AVX2 instruction set for best performance
    • Supports compiling for the ARM64 architecture
    • Written with the /std:c++20 standard conformance

    How To Build

    git clone https://github.com/jovibor/HexCtrl.git

    Integrate Sources

    To build HexCtrl from the sources:

    1. Add all files from the HexCtrl folder into your project
    2. Make sure to disable Precompiled Header usage for all *.ixx files in the project
    3. Add #include "HexCtrl.h"
    4. Declare HexCtrl object: auto myHex { HEXCTRL::CreateHexCtrl() };
    5. Create control instance

    Note

    You can skip adding rapidjson-amalgam.h into your project, to avoid polluting project’s global namespace.

    Dynamic Link Library

    To build and use HexCtrl as a DLL:

    1. Build HexCtrl{x86/x64/ARM64}.dll and HexCtrl{x86/x64/ARM64}.lib with the HexCtrl DLL.vcxproj project
    2. Include HexCtrl.h into your project
    3. Add /DHEXCTRL_DYNAMIC_LIB compiler option, or alternatively #define it before including HexCtrl.h:
      #define HEXCTRL_DYNAMIC_LIB
      #include "HexCtrl.h"
    4. Declare IHexCtrlPtr object: auto myHex { HEXCTRL::CreateHexCtrl() };
    5. Create control instance

    Creating

    Classic Approach

    First you need to create HexCtrl object:

    auto myHex { HEXCTRL::CreateHexCtrl() };

    Then call the Create method, which takes the HEXCREATE struct with the all necessary information for the HexCtrl creation. The HEXCREATE::dwStyle and dwExStyle are window and extended window styles respectively, set these styles according to your needs. For all available options see the HEXCREATE struct description.

    In Dialog

    To use HexCtrl in a Dialog you can create it with the Classic Approach: call Create method and provide all the necessary information.
    But there is another option:

    1. Put the Custom Control from the Toolbox in Visual Studio dialog designer onto your dialog template.
    2. In the Properties of this control in the Class field within the Misc section write: HexCtrl_MainWnd.
    3. Declare IHexCtrlPtr member variable within your dialog class:
      HEXCTRL::IHexCtrlPtr m_myHex { CreateHexCtrl() };
    4. Call the CreateDialogCtrl method from dialog’s OnInitDialog method.
      BOOL CMyDialog::OnInitDialog() {
          CDialogEx::OnInitDialog();
          m_myHex->CreateDialogCtrl(IDC_MY_HEX, m_hWnd);
      }

    CreateHexCtrl

    [[nodiscard]] IHexCtrlPtr CreateHexCtrl();

    This is the main factory function for creating HexCtrl object. The IHexCtrlPtr class is a IHexCtrl interface pointer wrapped into a standard std::unique_ptr with custom deleter, so you don’t need to worry about its destruction.

    Setting Data

    To set a data for the HexCtrl the SetData method is used. The code below shows how to construct HexCtrl object and display first 0x1FF bytes of the current app’s memory:

    IHexCtrlPtr myHex { CreateHexCtrl() };
    
    HEXCREATE hcs;
    hcs.hWndParent = m_hWnd;
    hcs.rect = {0, 0, 600, 400}; //Window rect.
    myHex->Create(hcs);
    
    HEXDATA hds;
    hds.spnData = { reinterpret_cast<std::byte*>(GetModuleHandle(nullptr)), 0x1FF };
    myHex->SetData(hds);

    The next example shows how to display std::string‘s text as hex data:

    std::string str = "My string";
    HEXDATA hds;
    hds.spnData = { reinterpret_cast<std::byte*>(str.data()), str.size() };
    myHex->SetData(hds);

    Virtual Data Mode

    Besides the standard mode, when the HexCtrl just holds a pointer to a data in a memory, it can also work in the Virtual mode. This mode can be useful in cases where you need to display a very large amount of a data that can’t fit in the memory all at once.

    If HEXDATA::pHexVirtData pointer is set, then the whole data routine will be done through it. This pointer is of IHexVirtData class type, which is a pure abstract base class. You have to derive your own class from it and implement all its public methods. Then provide a pointer to the created object of this derived class through the HEXDATA::pHexVirtData member, prior to call the SetData method.

    Virtual Bookmarks

    HexCtrl has innate functional to work with any amount of bookmarked regions. These regions can be assigned with individual background and text colors and description.

    But if you have big and complicated data logic and want to handle all these bookmarks yourself, you can do it with the help of the Virtual Bookmarks mode. In this mode all bookmark’s burden is handled by yourself, by implementing the IHexBookmarks interface and providing pointer to this implementation to the HexCtrl by calling the SetVirtualBkm method.

    Custom Colors

    If you’d like to colorize data regions with your own custom colors, use the IHexVirtColors interface.

    To use it set the HEXDATA::pHexVirtColors member to a valid instance of your own class that implements this interface, prior to calling the SetData method.

    The OnHexGetColor method of this interface takes HEXCOLORINFO struct as an argument. The HEXCOLORINFO::ullOffset member indicates the offset for which the color is requested. This method should return true if it sets custom colors for the given offset or false for default colors.

    Templates


    HexCtrl‘s templates is a powerful system of a data structures’ description with a simple .json file. These files can be loaded through the HexControl‘s internal template manager, or through the API.

    {
        "$schema": "https://raw.githubusercontent.com/jovibor/HexCtrl/master/docs/HexCtrl.Templates.Schema.json",
        "TemplateName": "SampleTemplate",
        "Data": {
            "endianness": "little",
            "clrBk": "#999999",
            "clrText": "#FFFFFF",
            "Fields": [
                {
                    "name": "MyCustomDataSingle",
                    "type": "MyCustomType"
                },
                {
                    "name": "CustomComplexData",
                    "type": "MyCustomComplexType"
                },
                {
                    "name": "ArrayOfDWORDs",
                    "type": "DWORD",
                    "array": 10
                },
                {
                    "name": "MyCustomDataArray",
                    "type": "MyCustomType",
                    "array": 4
                }
            ]
        },
        "CustomTypes": [
            {
                "TypeName": "MyCustomType",
                "Fields": [
                    {
                        "name": "myCustomTypeField1",
                        "type": "DWORD"
                    },
                    {
                        "name": "myCustomTypeField2",
                        "type": "DWORD"
                    }
                ]
            },
            {
                "TypeName": "MyCustomComplexType",
                "Fields": [
                    {
                        "name": "MyCustomTypeData1",
                        "type": "MyCustomType"
                    },
                    {
                        "name": "MyCustomTypeData2",
                        "type": "MyCustomType"
                    }
                ]
            }
        ]
    }

    Every such file contains the following properties:

    • TemplateName [mandatory, string] – the name of the template
    • Data [mandatory, object] – main object that contains all template field’s information
    • CustomTypes [optional, array] – array of a user defined types, that can be then referenced in the type property of the Fields

    CustomTypes objects are the same as Fields objects, the only difference is the TypeName property which Fields objects don’t have.

    Every Data or CustomType object contains Fields property with actual struct members.

    Fields [array] – is an array of objects where every object represents a struct data member. Any such object can have its own Fields sub-objects, which will represent nested structs.
    The Fields‘s properties include:

    • name – [mandatory, string] – name of the field
    • description – [optional, string] – field description
    • type – [optional, string] – field type, such as:
      bool, char, unsigned char, byte, short, unsigned short, WORD, long, unsigned long, int, unsigned int, DWORD, long long, unsigned long long, QWORD, float, double, time32_t, time64_t, FILETIME, SYSTEMTIME, GUID, or any custom type defined in the CustomTypes section
    • size – [optional, int] – size of the field in bytes, if the type field is not provided
    • array – [optional, int] – size of the array, if the given field is an array of fields
    • endianness – [optional, string] – field endianness, “little” or “big”. By default all fields are little-endian.
    • clrBk – [optional, string] – field background color
    • clrText – [optional, string] – field text color

    The endianness, clrBk and clrText properties that locate at the same level as the Fields property, would mean the default properties for all the Fields objects of that level and below the line, unless they explicitly redefined in the field itself.

    For the available templates check the Templates directory.

    Methods

    The HexCtrl has plenty of methods that you can use to manage its behavior.

    ClearData

    void ClearData();

    Clears data from the HexCtrl view, not touching data itself.

    Create

    bool Create(const HEXCREATE& hcs);

    Main initialization method. Takes the HEXCREATE struct as argument. Returns true if created successfully, false otherwise.

    CreateDialogCtrl

    bool CreateDialogCtrl(UINT uCtrlID, HWND hwndDlg);

    Creates HexCtrl from a Custom Control dialog’s template. Takes control id, and dialog’s window handle as arguments. See Creating section for more info.

    Delete

    void Delete();

    Deletes the HexCtrl object. You only use this method if you want, for some reason, to manually delete the HexCtrl object, otherwise IHexCtrlPtr will invoke this method automatically.

    Important

    You usually don’t need to call this method unless you use the HexCtrl through a raw pointer. If you use HexCtrl in the standard way, through the IHexCtrlPtr pointer obtained by the CreateHexCtrl function, this method will be called automatically.

    DestroyWindow

    void DestroyWindow();

    Destroys the HexCtrl main window.

    ExecuteCmd

    void ExecuteCmd(EHexCmd eCmd)const;

    Executes one of the predefined commands of the EHexCmd enum. All these commands are basically replicating HexCtrl‘s inner menu.

    GetActualWidth

    [[nodiscard]] auto GetActualWidth()const->int;

    Returns the width of the HexCtrl bounding rectangle, i.e. the width of the drawn working area.

    GetBookmarks

    [[nodiscard]] auto GetBookmarks()->IHexBookmarks*;

    Returns pointer to the IHexBookmarks interface, which responds for the bookmarks machinery.

    GetCacheSize

    [[nodiscard]] auto GetCacheSize()const->DWORD;

    Returns current cache size set in HEXDATA.

    GetCapacity

    [[nodiscard]] auto GetCapacity()const->DWORD;

    Returns current capacity.

    GetCaretPos

    [[nodiscard]] auto GetCaretPos()const->ULONGLNG;

    Retrieves current caret position offset.

    GetCharsExtraSpace

    [[nodiscard]] auto GetCharsExtraSpace()const->DWORD;

    Get extra space between chars, in pixels. This extra space can be set with the SetCharsExtraSpace method.

    GetColors

    [[nodiscard]] auto GetColors()const->const HEXCOLORS&;

    Returns reference to the current HEXCOLORS struct.

    GetData

    [[nodiscard]] auto GetData(HEXSPAN hss)const->std::byte*;

    Returns a pointer to the data offset no matter what mode the control works in.

    Note

    In the Virtual mode returned data size can not exceed current cache size, and therefore may be less than the size acquired. In the default mode returned pointer is just an offset from the data pointer set in the SetData method.

    GetDataSize

    [[nodiscard]] auto GetDataSize()const->ULONGLONG;

    Returns currently set data size.

    GetDateInfo

    [[nodiscard]] auto GetDateInfo()const->std::tuple<DWORD, wchar_t>;

    Returns tuple of the current date format-ordering specifier, and date separator.

    GetDlgItemHandle

    [[nodiscard]] auto GetDlgItemHandle(EHexDlgItem eItem)const->HWND;

    Returns HWND of a dialog’s internal child control.

    GetCodepage

    [[nodiscard]] auto GetCodepage()const->int;

    Returns code page that is currently in use.

    GetFont

    [[nodiscard]] auto GetFont(bool fMain)const->LOGFONTW;

    Returns current main font if fMain is true, and infobar font if fMain is false.

    GetGroupSize

    [[nodiscard]] auto GetGroupSize()const->DWORD;

    Returns current data grouping size.

    GetMenuHandle

    [[nodiscard]] auto GetMenuHandle()const->HMENU;

    Returns the HMENU handle of the HexCtrl context menu. You can use this handle to customize menu for your needs.
    HexCtrl‘s internal menu uses IDs starting from 0x8001. So if you wish to add your own new menu, assign menu ID starting from 0x9000 to not interfere.
    When a user clicks custom menu, control sends WM_NOTIFY message to its parent window with LPARAM pointing to HEXMENUINFO with its hdr.code member set to HEXCTRL_MSG_MENUCLICK, and wMenuID field containing ID of the menu clicked.

    GetOffset

    [[nodiscard]] auto GetOffset(ULONGLONG ullOffset, bool fGetVirt)const->ULONGLONG;

    Converts offset from virtual to flat, and vice versa.

    GetPagesCount

    [[nodiscard]] auto GetPagesCount()const->ULONGLONG;

    Returns current count of pages set by the SetPageSize method.

    GetPagePos

    [[nodiscard]] auto GetPagePos()const->ULONGLONG;

    Returns a page number that the cursor stays at.

    GetPageSize

    [[nodiscard]] auto GetPageSize()const->DWORD;

    Returns current page size set by the SetPageSize method.

    GetScrollRatio

    [[nodiscard]] auto GetScrollRatio()const->std::tuple<float, bool>;

    Returns tuple of the current scroll ratio and fLines flag set by the SetScrollRatio method.

    GetSelection

    [[nodiscard]] auto GetSelection()const->std::vector<HEXSPAN>;

    Returns std::vector with the offsets and sizes of the current selection.

    GetTemplates

    [[nodiscard]] auto GetTemplates()->IHexTemplates*;

    Returns pointer to the internal IHexTemplates interface that is responsible for templates machinery.

    GetUnprintableChar

    [[nodiscard]] auto GetUnprintableChar()const->wchar_t;

    Returns replacement char for unprintable characters.

    GetWndHandle

    [[nodiscard]] auto GetWndHandle(EHexWnd eWnd, bool fCreate = true)const->HWND;

    Returns HWND for HexCtrl‘s main window or one of its internal dialogs. If fCreate flag is true, the dialog window will be created first before returning, if it was not already.

    GoToOffset

    void GoToOffset(ULONGLONG ullOffset, int iPosAt = 0);

    Go to the given offset. The second argument iPosAt can take three values:

    • -1 – offset will appear at the top line
    •   0 – offset will appear in the center
    •   1 – offset will appear at the bottom line

    HasInfoBar

    [[nodiscard]] bool HasInfoBar()const;

    Shows whether bottom info bar currently visible or not.

    HasSelection

    [[nodiscard]] bool HasSelection()const;

    Returns true if HexCtrl has any area selected.

    HitTest

    [[nodiscard]] auto HitTest(POINT pt, bool fScreen = true)const->std::optional<HEXHITTEST>;

    Hit testing of given point in a screen fScreen = true, or client fScreen = false coordinates. In case of success returns HEXHITTEST structure.

    IsCmdAvail

    [[nodiscard]] bool IsCmdAvail(EHexCmd eCmd)const;

    Returns true if the given command can be executed at the moment, false otherwise.

    IsCreated

    [[nodiscard]] bool IsCreated()const;

    Shows whether HexCtrl is created or not.

    IsDataSet

    [[nodiscard]] bool IsDataSet()const;

    Shows whether a data was set to HexCtrl or not

    IsHexCharsUpper

    [[nodiscard]] bool IsHexCharsUpper()const;

    Shows if hex chars printed in UPPER or lower case.

    IsMutable

    [[nodiscard]] bool IsMutable()const;

    Shows whether HexCtrl is currently in edit mode or not.

    IsOffsetAsHex

    [[nodiscard]] bool IsOffsetAsHex()const;

    Is “Offset” currently represented (shown) as Hex or as Decimal. It can be changed by double clicking at offset area.

    IsOffsetVisible

    [[nodiscard]] auto IsOffsetVisible(ULONGLONG ullOffset)const->HEXVISION;

    Checks for offset visibility and returns HEXVISION as a result.

    IsVirtual

    [[nodiscard]] bool IsVirtual()const;

    Returns true if HexCtrl currently works in Virtual Data Mode.

    ModifyData

    void ModifyData(const HEXMODIFY& hms);

    Modify data currently set in HexCtrl, see the HEXMODIFY struct for details.

    PreTranslateMsg

    [[nodiscard]] bool PreTranslateMsg(MSG* pMsg);

    The HexCtrl has many internal dialog windows. In order for dialog keyboard navigation to work correctly, this method must be hooked into your app’s main message loop before TranslateMessage and DispatchMessage, or into MFC’s PreTranslateMessage virtual function.

    while (GetMessageW(&msg, nullptr, 0, 0)) {
        if (!TranslateAcceleratorW(msg.hwnd, hAccelTable, &msg)) {
            if (!m_pHexCtrl->PreTranslateMsg(&msg)) { //Process further only if it returns false.
                TranslateMessage(&msg);
                DispatchMessageW(&msg);
            }
        }
    }

    If this method returns true it means that no further message processing should be made, HexCtrl has done all processing by itself.

    Redraw

    void Redraw();

    Redraws main window.

    SetCapacity

    void SetCapacity(DWORD dwCapacity);

    Sets HexCtrl‘s current capacity.

    SetCaretPos

    void SetCaretPos(ULONGLONG ullOffset, bool fHighLow = true, bool fRedraw = true);

    Sets the caret to the given offset. The fHighLow flag shows which part of the hex chunk, low or high, a caret must be set to.

    SetCharsExtraSpace

    void SetCharsExtraSpace(DWORD dwSpace);

    Sets extra space to add between chars, in pixels.

    SetCodepage

    void SetCodepage(int iCodePage);

    Sets the code page for the HexCtrl‘s text area. Takes code page identifier as an argument, or -1 for default ASCII-only characters.

    Note

    Code page identifier must represent Single-byte Character Set. Multi-byte character sets are not currently supported.

    SetColors

    void SetColors(const HEXCOLORS& clr);

    Sets all the colors for the control. Takes HEXCOLORS as the argument.

    SetConfig

    bool SetConfig(std::wstring_view wsvPath);

    Sets the path to a JSON config file with keybindings to use in HexCtrl, or empty path (L"") for default. This file is using EHexCmd enum values as keys and strings array as values:

    {
        "CMD_DLG_SEARCH": [ "ctrl+f", "ctrl+h" ],
        "CMD_SEARCH_NEXT": [ "f3" ],
        "CMD_SEARCH_PREV": [ "shift+f3" ]
    }

    For default values see the IDR_HEXCTRL_JSON_KEYBIND.json file from the project sources.

    SetData

    void SetData(const HEXDATA& hds, bool fAdjust = false)

    Main method to set data for HexCtrl. It takes HEXDATA struct as an argument.
    The fAdjust flag when set to true allows adjusting already set data. For example to switch between virtual and normal data modes.

    SetDateInfo

    void SetDateInfo(DWORD dwFormat, wchar_t wchSepar);

    Sets date format-ordering specifier, along with date separator.

    SetDlgProperties

    void SetDlgProperties(EHexWnd eWnd, std::uint64_t u64Flags);

    Sets various properties to the HexCtrl‘s internal dialogs, in form of flags. Flags can be combined together with the OR (|) operation.
    Available flags:

    HEXCTRL_FLAG_DLG_NOESC //Prevent dialog from closing on Esc key.

    SetFont

    void SetFont(const LOGFONTW& lf, bool fMain);

    Sets new main font for the HexCtrl if fMain is true, or infobar font when fMain is false. This font has to be monospaced.

    SetGroupSize

    void SetGroupSize(DWORD dwSize);

    Sets current data grouping size in bytes.

    SetHexCharsCase

    void SetHexCharsCase(bool fUpper);

    Sets printed hex chars to an UPPER or lower case.

    SetMutable

    void SetMutable(bool fMutable);

    Enables or disables mutable mode. In the mutable mode all the data can be modified.

    SetOffsetMode

    void SetOffsetMode(bool fHex);

    Sets offset area being shown as Hex (fHex=true) or as Decimal (fHex=false).

    SetPageSize

    void SetPageSize(DWORD dwSize, std::wstring_view wsvName = L"Page");

    Sets the size of the page to draw the divider line between. This size should be multiple to the current capacity size to take effect. The second argument sets the name to be displayed in the bottom info area of the HexCtrl (“Page”, “Sector”, etc…).
    To remove the divider just set dwSize to 0.

    SetRedraw

    void SetRedraw(bool fRedraw);

    Should the main HexCtrl window be redrawn or not. E.g. should the WM_PAINT message be handled or not.

    SetScrollRatio

    void SetScrollRatio(float flRatio, bool fLines);

    Sets the scroll amount for one scroll-page. Page is the one mouse-wheel tick or page-down key. When fLines is true the flRatio is the amount of text lines to scroll. When it’s false flRatio is a ratio of visible screen height to scroll.

    SetSelection

    void SetSelection(const std::vector<HEXSPAN>& vecSel, bool fRedraw = true, bool fHighlight = false);

    Sets current selection or highlight in the selection, if fHighlight is true.

    SetUnprintableChar

    void SetUnprintableChar(wchar_t wch);

    Sets replacement char for unprintable characters.

    SetVirtualBkm

    void SetVirtualBkm(IHexBookmarks* pVirtBkm);

    Sets a pointer for the Virtual Bookmarks mode, or disables this mode if nullptr is set.

    SetWindowPos

    void SetWindowPos(HWND hWndAfter, int iX, int iY, int iWidth, int iHeight, UINT uFlags);

    Sets HexCtrl window position. This method replicates behavior of the SetWindowPos Windows function.

    ShowInfoBar

    void ShowInfoBar(bool fShow);

    Show/hide bottom Info bar.

    Structures

    Below are listed all HexCtrl‘s structures.

    HEXBKM

    Main bookmarks structure, used with the IHexBookmarks interface.

    struct HEXBKM {
        VecSpan      vecSpan;     //Vector of offsets and sizes.
        std::wstring wstrDesc;    //Bookmark description.
        ULONGLONG    ullID { };   //Bookmark ID, assigned internally by framework.
        ULONGLONG    ullData { }; //User defined custom data.
        HEXCOLOR     stClr;       //Bookmark bk/text color.
    };
    using PHEXBKM = HEXBKM*;

    The member vecSpan is of a std::vector<HEXSPAN> type because a bookmark may have few non adjacent areas. For instance, when selection is made as a block, with Alt pressed.

    HEXBKMINFO

    Bookmark information struct.

    struct HEXBKMINFO {
        NMHDR   hdr { };  //Standard Windows header.
        PHEXBKM pBkm { }; //Bookmark pointer.
    };
    using PHEXBKMINFO = HEXBKMINFO*;

    HEXCOLOR

    Background and Text color struct.

    struct HEXCOLOR {
        COLORREF clrBk { };   //Bk color.
        COLORREF clrText { }; //Text color.
        auto operator<=>(const HEXCOLOR&)const = default;
    };
    using PHEXCOLOR = HEXCOLOR*;

    HEXCOLORINFO

    Struct for hex chunks’ color information.

    struct HEXCOLORINFO {
        NMHDR     hdr { };       //Standard Windows header.
        ULONGLONG ullOffset { }; //Offset for the color.
        HEXCOLOR  stClr;         //Colors of the given offset.
    };

    HEXCOLORS

    This structure contains all colors for fonts, background, and all other visual stuff. All these colors have their default values, so you don’t have to set them all during HexCtrl creation, if you don’t want to.

    struct HEXCOLORS {
        COLORREF clrFontHex { ::GetSysColor(COLOR_WINDOWTEXT) };       //Hex-chunks font color.
        COLORREF clrFontText { ::GetSysColor(COLOR_WINDOWTEXT) };      //Text font color.
        COLORREF clrFontSel { ::GetSysColor(COLOR_HIGHLIGHTTEXT) };    //Selected hex/text font color.
        COLORREF clrFontBkm { ::GetSysColor(COLOR_WINDOWTEXT) };       //Bookmarks font color.
        COLORREF clrFontDataInterp { ::GetSysColor(COLOR_HIGHLIGHTTEXT) }; //Data Interpreter text/hex font color.
        COLORREF clrFontCaption { RGB(0, 0, 180) };                    //Caption font color
        COLORREF clrFontInfoParam { ::GetSysColor(COLOR_WINDOWTEXT) }; //Font color of the Info bar parameters.
        COLORREF clrFontInfoData { RGB(0, 0, 180) };                   //Font color of the Info bar data.
        COLORREF clrFontCaret { ::GetSysColor(COLOR_HIGHLIGHTTEXT) };  //Caret font color.
        COLORREF clrBk { ::GetSysColor(COLOR_WINDOW) };                //Background color.
        COLORREF clrBkSel { ::GetSysColor(COLOR_HIGHLIGHT) };          //Background color of the selected Hex/Text.
        COLORREF clrBkBkm { RGB(240, 240, 0) };                        //Bookmarks background color.
        COLORREF clrBkDataInterp { RGB(147, 58, 22) };                 //Data Interpreter Bk color.
        COLORREF clrBkInfoBar { ::GetSysColor(COLOR_3DFACE) };         //Background color of the bottom Info bar.
        COLORREF clrBkCaret { RGB(0, 0, 255) };                        //Caret background color.
        COLORREF clrBkCaretSel { RGB(0, 0, 200) };                     //Caret background color in selection.
        COLORREF clrLinesMain { ::GetSysColor(COLOR_SCROLLBAR) };      //Main window and pages lines color.
        COLORREF clrLinesTempl { ::GetSysColor(COLOR_WINDOWTEXT) };    //Templates data confining lines color.
        COLORREF clrScrollBar { ::GetSysColor(COLOR_3DFACE) };         //Scrollbar color.
        COLORREF clrScrollThumb { ::GetSysColor(COLOR_SCROLLBAR) };    //Scrollbar thumb color.
        COLORREF clrScrollArrow { ::GetSysColor(COLOR_GRAYTEXT) };     //Scrollbar arrow color.
    };
    using PCHEXCOLORS = const HEXCOLORS*;

    HEXCREATE

    The main initialization struct used for the HexCtrl creation.

    struct HEXCREATE {
        HINSTANCE       hInstRes { };           //Hinstance of the HexCtrl resources, nullptr for current module.
        HWND            hWndParent { };         //Parent window handle.
        PCHEXCOLORS     pColors { };            //HexCtrl colors, nullptr for default.
        const LOGFONTW* pLogFont { };           //Monospaced font for HexCtrl, nullptr for default.
        RECT            rect { };               //Initial window rect.
        UINT            uID { };                //Control ID if it's a child window.
        DWORD           dwStyle { };            //Window styles.
        DWORD           dwExStyle { };          //Extended window styles.
        DWORD           dwCapacity { 16UL };    //Initial capacity size.
        DWORD           dwGroupSize { 1UL };    //Initial data grouping size.
        float           flScrollRatio { 1.0F }; //Either a screen-ratio or lines amount to scroll with Page-scroll (mouse-wheel).
        bool            fScrollLines { false }; //Treat flScrollRatio as screen-ratio (false) or as amount of lines (true).
        bool            fInfoBar { true };      //Show bottom Info bar or not.
        bool            fOffsetHex { true };    //Show offset digits as Hex or Decimal.
        bool            fCustom { false };      //If it's a custom control in a dialog.
    };

    Members:

    HINSTANCE hInstRes

    The hInstRes member allows you to provide an alternative HINSTANCE of a module where all HexCtrl resources (dialogs, menu, etc…) reside. By default HexCtrl uses its current module, whether it’s a .exe or .dll.

    DWORD dwStyle

    Standard window style for the main HexCtrl window.

    DWORD dwExStyle

    Standard extended window style for the main HexCtrl window.

    HEXDATA

    The main struct to set a data to display in the HexCtrl.

    struct HEXDATA {
        SpanByte        spnData;                    //Data span to display.
        IHexVirtData*   pHexVirtData { };           //Pointer for VirtualData mode.
        IHexVirtColors* pHexVirtColors { };         //Pointer for Custom Colors class.
        ULONGLONG       ullMaxVirtOffset { };       //Maximum virtual offset.
        DWORD           dwCacheSize { 0x800000UL }; //Data cache size for VirtualData mode.
        bool            fMutable { false };         //Is data mutable or read-only.
        bool            fHighLatency { false };     //Do not redraw until scroll thumb is released.
    };

    Members:

    ULONGLONG ullMaxVirtOffset

    Used to set maximum virtual data offset in virtual data mode. This is needed for the offset digits amount calculation.

    HEXDATAINFO

    Struct for a data information used in IHexVirtData.

    struct HEXDATAINFO {
        NMHDR    hdr { };   //Standard Windows header.
        HEXSPAN  stHexSpan; //Offset and size of the data.
        SpanByte spnData;   //Data span.
    };

    HEXHITTEST

    Structure is used in HitTest method.

    struct HEXHITTEST {
        ULONGLONG ullOffset { };     //Offset.
        bool      fIsText { false }; //Is cursor at Text or Hex area.
        bool      fIsHigh { false }; //Is it High or Low part of the byte.
    };

    HEXMODIFY

    This struct is used to represent data modification parameters.
    When eModifyMode is set to MODIFY_ONCE, bytes from pData just replace corresponding data bytes as is.
    If eModifyMode is equal to MODIFY_REPEAT then block by block replacement takes place few times.
    For example, if:

    • SUM(vecSpan.ullSize) == 9
    • spnData.size() == 3
    • eModifyMode is set to MODIFY_REPEAT
    • bytes in memory at vecSpan.ullOffset are 010203040506070809
    • bytes pointed to by spnData.data() are 030405

    then, after modification, bytes at vecSpan.ullOffset will become 030405030405030405.

    If eModifyMode is equal to the MODIFY_OPERATION then the eOperMode shows what kind of operation must be performed on the data.

    struct HEXMODIFY {
        EHexModifyMode eModifyMode { };      //Modify mode.
        EHexOperMode   eOperMode { };        //Operation mode, used if eModifyMode == MODIFY_OPERATION.
        EHexDataType   eDataType { };        //Data type of the underlying data, used if eModifyMode == MODIFY_OPERATION.
        SpanCByte      spnData;              //Span of the data to modify with.
        VecSpan        vecSpan;              //Vector of data offsets and sizes to modify.
        bool           fBigEndian { false }; //Treat data as the big endian, used if eModifyMode == MODIFY_OPERATION.
    };

    HEXMENUINFO

    Menu information struct.

    struct HEXMENUINFO {
        NMHDR hdr { };        //Standard Windows header.
        POINT pt { };         //Mouse position when clicked.
        WORD  wMenuID { };    //Menu identifier.
        bool  fShow { true }; //Whether to show menu or not, in case of HEXCTRL_MSG_CONTEXTMENU.
    };
    using PHEXMENUINFO = HEXMENUINFO*;

    HEXSPAN

    This struct is used mostly in selection and bookmarking routines. It holds offset and size of the data region.

    struct HEXSPAN {
        ULONGLONG ullOffset { };
        ULONGLONG ullSize { };
    };
    using VecSpan = std::vector<HEXSPAN>;

    HEXVISION

    This struct is returned from IsOffsetVisible method. Two members i8Vert and i8Horz represent vertical and horizontal visibility respectively. These members can be in three different states:

    • -1 — offset is higher, or at the left, of the visible area.
    •   1 — offset is lower, or at the right.
    •   0 — offset is visible.
    struct HEXVISION {
        std::int8_t i8Vert { }; //Vertical offset.
        std::int8_t i8Horz { }; //Horizontal offset.
        operator bool()const { return i8Vert == 0 && i8Horz == 0; }; //For test simplicity: if(IsOffsetVisible()).
    };

    Interfaces

    IHexBookmarks

    The IHexBookmarks interface responds for the HexCtrl‘s bookmarks machinery. To obtain pointer to this interface use the GetBookmarks method.

    class IHexBookmarks {
    public:
        virtual auto AddBkm(const HEXBKM& hbs, bool fRedraw = true) -> ULONGLONG = 0; //Add new bookmark, returns the new bookmark's ID.
        [[nodiscard]] virtual auto GetByID(ULONGLONG ullID) -> PHEXBKM = 0;           //Get bookmark by ID.
        [[nodiscard]] virtual auto GetByIndex(ULONGLONG ullIndex) -> PHEXBKM = 0;     //Get bookmark by index.
        [[nodiscard]] virtual auto GetCount() -> ULONGLONG = 0;                       //Get bookmarks count.
        [[nodiscard]] virtual auto HitTest(ULONGLONG ullOffset) -> PHEXBKM = 0;       //HitTest for given offset.
        virtual void RemoveAll() = 0;                                                 //Remove all bookmarks.
        virtual void RemoveByID(ULONGLONG ullID) = 0;                                 //Remove by a given ID.
    };

    IHexBookmarks::AddBkm

    ULONGLONG AddBkm(const HEXBKM& hbs, bool fRedraw = false)

    Adds new bookmark to the control, returns created bookmark’s ID.

    Example:

    HEXBKM hbs;
    hbs.vecSpan.emplace_back(0x1, 10);
    hbs.clrBk = RGB(0, 255, 0);
    hbs.clrText = RGB(255, 255, 255);
    hbs.wstrDesc = L"My bookmark, with green bk and white text.";
    myHex->GetBookmarks()->Add(hbs);

    IHexBookmarks::GetByID

    GetByID(ULONGLONG ullID)->HEXBKM*;

    Get bookmark by ID.

    IHexBookmarks::GetByIndex

    auto GetByIndex(ULONGLONG ullIndex)->HEXBKM*;

    Get bookmark by index.

    IHexBookmarks::GetCount

    ULONGLONG GetCount();

    Get bookmarks’ count.

    IHexBookmarks::HitTest

    auto HitTest(ULONGLONG ullOffset)->HEXBKM*;

    Test given offset and retrieves a pointer to HEXBKM if offset contains a bookmark.

    IHexBookmarks::RemoveAll

    void RemoveAll();

    Removes all bookmarks.

    IHexBookmarks::RemoveByID

    void RemoveByID(ULONGLONG ullID);

    Removes bookmark with the given ID.

    IHexTemplates

    class IHexTemplates {
    public:
        virtual auto AddTemplate(const HEXTEMPLATE& hts) -> int = 0; //Adds existing template.
        virtual auto ApplyTemplate(ULONGLONG ullOffset, int iTemplateID) -> int = 0; //Applies template to offset, returns AppliedID.
        virtual void DisapplyAll() = 0;
        virtual void DisapplyByID(int iAppliedID) = 0;
        virtual void DisapplyByOffset(ULONGLONG ullOffset) = 0;
        virtual auto LoadTemplate(const wchar_t* pFilePath) -> int = 0; //Returns TemplateID on success, null otherwise.
        virtual void ShowTooltips(bool fShow) = 0;
        virtual void UnloadAll() = 0;                     //Unload all templates.
        virtual void UnloadTemplate(int iTemplateID) = 0; //Unload/remove loaded template from memory.
        [[nodiscard]] static HEXCTRLAPI auto __cdecl LoadFromFile(const wchar_t* pFilePath)->std::unique_ptr<HEXTEMPLATE>;
    };

    LoadFromFile

    [[nodiscard]] static auto LoadFromFile(const wchar_t* pFilePath)->std::unique_ptr<HEXTEMPLATE>;

    This static method can be used to upfront load a template from a file. The loaded template can then be added to multiple HexCtrl instances, through the IHexTemplates::AddTemplate method. This approach allows to avoid loading the same template from the disk multiple times if multiple HexCtrls would load it through the IHexTemplates::LoadTemplate, each individually.

    IHexVirtColors

    class IHexVirtColors {
    public:
        virtual bool OnHexGetColor(HEXCOLORINFO&) = 0; //Should return true if colors are set.
    };

    IHexVirtData

    class IHexVirtData {
    public:
        virtual void OnHexGetData(HEXDATAINFO&) = 0; //Data to get.
        virtual void OnHexGetOffset(HEXDATAINFO& hdi, bool fGetVirt) = 0; //Offset<->VirtOffset conversion.
        virtual void OnHexSetData(const HEXDATAINFO&) = 0; //Data to set, if mutable.
    };

    OnHexGetOffset

    Internally HexCtrl operates with flat data offsets. If you set data of 1MB size, HexCtrl will have working offsets in the [0-1'048'575] range. However, from the user perspective the real data offsets may differ. For instance, in processes memory model very high virtual memory addresses can be used (e.g. 0x7FF96BA622C0). The process data can be mapped by operating system to literally any virtual address. The OnHexGetOffset method serves exactly for the Flat<->Virtual offset converting purpose.

    Enums

    EHexCmd

    Enum of commands that can be executed within HexCtrl.

    enum class EHexCmd : std::uint8_t {
        CMD_SEARCH_DLG = 0x01, CMD_SEARCH_NEXT, CMD_SEARCH_PREV,
        CMD_NAV_GOTO_DLG, CMD_NAV_REPFWD, CMD_NAV_REPBKW, CMD_NAV_DATABEG, CMD_NAV_DATAEND,
        CMD_NAV_PAGEBEG, CMD_NAV_PAGEEND, CMD_NAV_LINEBEG, CMD_NAV_LINEEND, CMD_GROUPDATA_BYTE,
        CMD_GROUPDATA_WORD, CMD_GROUPDATA_DWORD, CMD_GROUPDATA_QWORD, CMD_GROUPDATA_INC, CMD_GROUPDATA_DEC,
        CMD_BKM_ADD, CMD_BKM_REMOVE, CMD_BKM_NEXT, CMD_BKM_PREV, CMD_BKM_REMOVEALL, CMD_BKM_DLG_MGR,
        CMD_CLPBRD_COPY_HEX, CMD_CLPBRD_COPY_HEXLE, CMD_CLPBRD_COPY_HEXFMT, CMD_CLPBRD_COPY_TEXTCP,
        CMD_CLPBRD_COPY_BASE64, CMD_CLPBRD_COPY_CARR, CMD_CLPBRD_COPY_GREPHEX, CMD_CLPBRD_COPY_PRNTSCRN,
        CMD_CLPBRD_COPY_OFFSET, CMD_CLPBRD_PASTE_HEX, CMD_CLPBRD_PASTE_TEXTUTF16, CMD_CLPBRD_PASTE_TEXTCP,
        CMD_MODIFY_OPERS_DLG, CMD_MODIFY_FILLZEROS, CMD_MODIFY_FILLDATA_DLG, CMD_MODIFY_UNDO, CMD_MODIFY_REDO,
        CMD_SEL_MARKSTARTEND, CMD_SEL_ALL, CMD_SEL_ADDLEFT, CMD_SEL_ADDRIGHT, CMD_SEL_ADDUP,
        CMD_SEL_ADDDOWN, CMD_DATAINTERP_DLG, CMD_CODEPAGE_DLG, CMD_APPEAR_FONT_DLG, CMD_APPEAR_FONTINC,
        CMD_APPEAR_FONTDEC, CMD_APPEAR_CAPACINC, CMD_APPEAR_CAPACDEC, CMD_PRINT_DLG, CMD_ABOUT_DLG,
        CMD_CARET_LEFT, CMD_CARET_RIGHT, CMD_CARET_UP, CMD_CARET_DOWN,
        CMD_SCROLL_PAGEUP, CMD_SCROLL_PAGEDOWN,
        CMD_TEMPL_APPLYCURR, CMD_TEMPL_DISAPPLY, CMD_TEMPL_DISAPPALL, CMD_TEMPL_DLG_MGR
    };

    EHexDataType

    Enum of the data type used in the HEXMODIFY struct with the EHexModifyMode::MODIFY_OPERATION mode.

    enum class EHexDataType : std::uint8_t {
        DATA_INT8, DATA_UINT8, DATA_INT16, DATA_UINT16, DATA_INT32,
        DATA_UINT32, DATA_INT64, DATA_UINT64, DATA_FLOAT, DATA_DOUBLE
    };

    EHexModifyMode

    Enum of the data modification modes, used in HEXMODIFY.

    enum class EHexModifyMode : std::uint8_t {
        MODIFY_ONCE, MODIFY_REPEAT, MODIFY_OPERATION, MODIFY_RAND_MT19937, MODIFY_RAND_FAST
    };

    EHexOperMode

    Enum of the data operation modes, used in HEXMODIFY when HEXMODIFY::enModifyMode is set to MODIFY_OPERATION.

    enum class EHexOperMode : std::uint8_t {
        OPER_ASSIGN, OPER_ADD, OPER_SUB, OPER_MUL, OPER_DIV, OPER_CEIL, OPER_FLOOR, OPER_OR,
        OPER_XOR, OPER_AND, OPER_NOT, OPER_SHL, OPER_SHR, OPER_ROTL, OPER_ROTR, OPER_SWAP,
        OPER_BITREV
    };

    EHexWnd

    Enum of all HexCtrl‘s internal windows, used in the GetWndHandle method.

    enum class EHexWnd : std::uint8_t {
        WND_MAIN, DLG_BKMMGR, DLG_DATAINTERP, DLG_MODIFY,
        DLG_SEARCH, DLG_ENCODING, DLG_GOTO, DLG_TEMPLMGR
    };

    Notification Messages

    During its work the HexCtrl sends notification messages to its parent window through WM_NOTIFY mechanism.
    The LPARAM of the WM_NOTIFY message contains a pointer to the NMHDR standard Windows struct. Depending on the notification message LPARAM can then be casted to a pointer to another struct, see the messages description for details.

    HEXCTRL_MSG_BKMCLICK

    Sent if a bookmark is clicked, LPARAM contains a pointer to the HEXBKMINFO struct.

    HEXCTRL_MSG_CONTEXTMENU

    Sent when a context menu is about to be displayed, LPARAM contains a pointer to the HEXMENUINFO struct. You can disable menu showing-up by setting the PHEXMENUINFO->fShow flag to false in response to this message.

    HEXCTRL_MSG_DESTROY

    Sent to indicate that the HexCtrl‘s window is about to be destroyed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_DLGBKMMGR

    Sent to indicate that the Bookmark Manager dialog is about to be displayed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_DLGCODEPAGE

    Sent to indicate that the Codepage dialog is about to be displayed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_DLGDATAINTERP

    Sent to indicate that the Data interpreter dialog is about to be displayed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_DLGGOTO

    Sent to indicate that the Go to dialog is about to be displayed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_DLGMODIFY

    Sent to indicate that the Modify Data dialog is about to be displayed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_DLGSEARCH

    Sent to indicate that the Search dialog is about to be displayed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_DLGTEMPLMGR

    Sent to indicate that the Template Manager dialog is about to be displayed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_MENUCLICK

    Sent when a user-defined custom menu has been clicked, LPARAM contains a pointer to the HEXMENUINFO struct.

    HEXCTRL_MSG_SETCAPACITY

    Sent when the capacity has changed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_SETCARET

    Sent when the caret position has changed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_SETCODEPAGE

    Sent when the codepage of the text area has changed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_SETDATA

    Sent to indicate that the data has changed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_SETFONT

    Sent when font has changed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_SETGROUPSIZE

    Sent when the data grouping size has changed, LPARAM contains a pointer to the NMHDR struct.

    HEXCTRL_MSG_SETSELECTION

    Sent when a selection has been made, LPARAM contains a pointer to the NMHDR struct.

    Licensing

    This software is available under “The HexCtrl License”, it is free for any NON-COMMERCIAL use.
    See the LICENSE file.

    Visit original content creator repository https://github.com/jovibor/HexCtrl
  • disnake-ext-paginator

    disnake-ext-paginator

    disnake-ext-paginator is a Python library to easily create embed paginators.


    Supported Versions

    Required dependencies requirements.txt

    python >=3.8, <= 3.10
    disnake >= 2.4.0    #(it's really recommended to use 2.6.0)

    To install the required dependencies you can run:

    • with bash
    pip install -r requirements.txt
    
    • with poetry
    poetry install
    

    Installation

    • Using git
    git clone https://github.com/Snipy7374/disnake-ext-paginator
    

    Usage

    Quickstart

    from disnake_ext_paginator import Paginator
    import disnake
    from disnake.ext import commands
    
    bot = commands.Bot(
        command_prefix=commands.when_mentioned,
        intents=disnake.Intents.default()
    )
    
    @bot.slash_command()
    async def test_command(inter: disnake.ApplicationCommandInteraction) -> None:
    
        # Create a list of embeds to paginate.
        embeds = [
            disnake.Embed(
                title="First embed"
            ),
            disnake.Embe(
                title="Second embed"
            ),
            disnake.Embed(
                title="Third embed"
            ),
        ]
        await Paginator().start(inter, pages=embeds)
    
    bot.run('TOKEN')

    Advanced

    To use custom buttons, pass in the corresponding argument when you initiate the paginator.

    from disnake_ext_paginator import Paginator
    import disnake
    from disnake.ext import commands
    
    bot = commands.Bot(
        command_prefix=commands.when_mentioned,
        intents=disnake.Intents.default()
    )
    
    @bot.slash_command()
    async def test_command(inter: disnake.ApplicationCommandInteraction) -> None:
    
        # Create a list of embeds to paginate.
        embeds = [
            disnake.Embed(
                title="First embed"
            ),
            disnake.Embe(
                title="Second embed"
            ),
            disnake.Embed(
                title="Third embed"
            ),
        ]
        paginator = Paginator(
            timeout=400,
            previous_button=disnake.ui.Button(...),
            next_button=disnake.ui.Button(...),
            trash_button=disnake.ui.Button(...),
            page_counter_separator="-",
            page_counter_style=disnake.ButtonStyle.danger,
            initial_page=1,
            on_timeout_message="Paginator expired",
            interaction_check=False # this will allow all users to interact with the paginator
        )
        await paginator.start(inter, pages=embeds)
    
    bot.run('TOKEN')

    Documentation


    class disnake_ext_paginator.Paginator(...)

    class disnake_ext_paginator.Paginator(
        timeout: Union[int, float, None] = 60,
        previous_button: Optional[disnake.ui.Button] = None,
        next_button: Optional[disnake.ui.Button] = None,
        trash_button: Optional[disnake.ui.Button] = None,
        page_counter_separator: str = "https://github.com/",
        page_counter_style: disnake.ButtonStyle = disnake.ButtonStyle.grey,
        initial_page: int = 0,
        on_timeout_message: Optional[str] = None,
        interaction_check: bool = True,
        interaction_check_message = Union[disnake.Embed, str] = disnake.Embed(...),
        ephemeral: bool = False,
        persistent: bool = False
    )

    timeout: int

    • How long the Paginator should timeout in, after the last interaction. (In seconds) (Overrides default of 60)

    Note

    If you’re using a persistent paginator then this must be setted to None.

    previous_button: disnake.ui.Button

    • Overrides default previous button. If not provided or None a default button will be used.

    next_button: disnake.ui.Button

    • Overrides default next button. If not provided or None a default button will be used.

    trash_button: disnake.ui.Button

    • Overrides default trash Button. If not provided or None a default button will be used.

    page_counter_separator: str

    • The separator between page numbers.

    page_counter_style: disnake.ButtonStyle

    • Overrides default page counter style.

    initial_page: int

    • Page to start the pagination on.

    on_timeout_message: Optional[str]

    • Overrides default on_timeout str set as embed footer.
      If None no message will appear on_timeout.

    interaction_check: bool

    • Check whether the users interacting with the paginator are the onwer
      of the command or not. Default set to True.

    interaction_check_message: Union[disnake.Embed, str]

    • The message to send when an interaction_check fails e.g a user
      who is not the command owner attempeted to interact with the paginator.
      This feature can be disabled setting interaction_check to False.

    ephemeral: bool

    • Whether the paginator should only be visible to the command invokator or
      to anyone else.

    persistent: bool

    • Makes the Paginator pesistent.

    Warning

    The use of persistent paginators is not recommended as the paginator needs to be cahed in memory. (Soon there’ll be an update to use low_level_components to save memory)

    Warning

    You must pay attention while using persistent paginators, if used in a normal with several command invokations the memory could be filled completely causing the Bot to crash. This should be used only for single paginators instances e.g. persistent panels that can’t be generated by users with a command invokation.


    def disnake_ext_paginator.Paginator.start(...)

    def disnake_ext_paginator.Paginator.start(
        interaction: disnake.ApplicationCommandInteraction,
        pages: list[disnake.Embed]
    )

    interaction: disnake.ApplicationCommandInteraction

    • The slash command interaction.

    pages: list[disnake.Embed]

    • A list of disnake.Embed objects.

    raises RuntimeError:

    • If the user is attempting to starts two paginators in the same command function body or if the user is attempting to use the same Paginator object to start a paginator twice.

    Contributing

    Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.


    Contacts & Support

    Discord – Snipy#7374


    Licenses

    MIT – (Snipy7374/disnake-ext-paginator)

    MIT – (soosBot-com/Pagination)

    Visit original content creator repository
    https://github.com/Snipy7374/disnake-ext-paginator

  • aws-cognito

    Laravel AWS Cognito Package for Web and API authentication with MFA Feature

    Laravel AWS Cognito Package for Web and API authentication with MFA Feature

    AWS Cognito package using the AWS SDK for PHP

    Release Version  Release Date  Total Downloads 

    Github Stars  Github Forks  GitHub Contributors  APM

    Quality Gate Status Security Rating Maintainability Rating

    This package provides a simple way to use AWS Cognito authentication in Laravel for Web and API Auth Drivers. The idea of this package, and some of the code, is based on the package from Pod-Point which you can find here: Pod-Point/laravel-cognito-auth, black-bits/laravel-cognito-auth and tymondesigns/jwt-auth.

    DEMO Application. You can try and register and login. For the first time, it will force the user to change password. The source code of the demo application is also available of the GitHub.

    We decided to use it and contribute it to the community as a package, that encourages standarised use and a RAD tool for authentication using AWS Cognito.

    Features

    Compatability

    PHP Version Support
    7.4 Yes ✔️
    8.0 Yes ✔️
    8.1 Yes ✔️
    8.24 Yes ✔️
    Laravel Version Support
    7.x Yes ✔️
    8.x Yes ✔️
    9.x Yes ✔️
    10.x Not tested

    Installation

    You can install the package via composer.

    composer require ellaisys/aws-cognito

    Laravel 5.4 and before

    Using a version prior to Laravel 5.5 you need to manually register the service provider.

        // config/app.php
        'providers' => [
            ...
            Ellaisys\Cognito\Providers\AwsCognitoServiceProvider::class,
            
        ];

    Configuration File: Next you can publish the config.

        php artisan vendor:publish --provider="Ellaisys\Cognito\Providers\AwsCognitoServiceProvider"

    Last but not least you want to change the auth driver. To do so got to your config\auth.php file and change it to look the following:

        'guards' => [
            'web' => [
                'driver' => 'cognito-session', // This line is important for using AWS Cognito as Web Driver
                'provider' => 'users',
            ],
            'api' => [
                'driver' => 'cognito-token', // This line is important for using AWS Cognito as API Driver
                'provider' => 'users',
            ],
        ],

    Important

    This is a new feature that is released in V1.2.0 and shall work with Laravel 8.37 (with anonymous migration support). For verions below Laravel 8.37, this feature is disabled. You will need to update the users table migration and add the sub column (type:string, nullable:yes, index:yes).

    Database Migrations

    The AWS Cognito service provider registers its own database migration directory, so remember to migrate your database after installing the package. The AWS Cognito migrations will add a few columns to your users table:

        php artisan migrate

    If you need to overwrite the migrations that ship with AWS Cognito, you can publish them using the vendor:publish Artisan command:

        php artisan vendor:publish --tag="cognito-migrations"

    If you would like to prevent AWS Cognito’s migrations from running entirely, you may use the ignoreMigrations method provided by AWS Cognito. Typically, this method should be called in the register method of your AppServiceProvider:

        use Ellaisys\Cognito\AwsCognito;
        
        /**
         * Register any application services.
         */
        public function register(): void
        {
            AwsCognito::ignoreMigrations();
        }

    Cognito User Pool

    In order to use AWS Cognito as authentication provider, you require a Cognito User Pool.

    If you haven’t created one already, go to your Amazon management console and create a new user pool.

    Next, generate an App Client. This will give you the App client id and the App client secret you need for your .env file.

    IMPORTANT: Don’t forget to activate the checkbox to Enable sign-in API for server-based Authentication. The Auth Flow is called: ADMIN_USER_PASSWORD_AUTH (formerly ADMIN_NO_SRP_AUTH)

    AWS IAM configuration

    You also need a new IAM Role with the following Access Rights:

    • AmazonCognitoDeveloperAuthenticatedIdentities
    • AmazonCognitoPowerUser
    • AmazonESCognitoAccess

    From this IAM User you must use the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY in the laravel environment file.

    Cognito configuration

    Add the following fields to your .env file and set the values according to your AWS settings:

        # AWS configurations for cloud storage
        AWS_ACCESS_KEY_ID="Axxxxxxxxxxxxxxxxxxxxxxxx6"
        AWS_SECRET_ACCESS_KEY="mxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx+"
    
        # AWS Cognito configurations
        AWS_COGNITO_CLIENT_ID="6xxxxxxxxxxxxxxxxxxxxxxxxr"
        AWS_COGNITO_CLIENT_SECRET="1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1"
        AWS_COGNITO_USER_POOL_ID="xxxxxxxxxxxxxxxxx"
        AWS_COGNITO_REGION="xxxxxxxxxxx" //optional - default value is 'us-east-1'
        AWS_COGNITO_VERSION="latest" //optional - default value is 'latest'

    Important

    To sync the web session timeout with the cognito access token ttl value, set the SESSION_LIFETIME parameter in the .env file. This value is in minutes with the default value being 120 mins i.e. 2 hours. This will ensure that the laravel session times out at the same time as the access token.

    For more details on how to find AWS_COGNITO_CLIENT_ID, AWS_COGNITO_CLIENT_SECRET and AWS_COGNITO_USER_POOL_ID for your application, please refer COGNITOCONFIG File

    Importing existing users into the Cognito Pool

    If you are already working on an existing project and want to integrate Cognito you have to import a user csv file to your Cognito Pool.

    Usage

    Our package is providing you 6 traits you can just add to your Auth Controllers to get our package running.

    • Ellaisys\Cognito\Auth\AuthenticatesUsers
    • Ellaisys\Cognito\Auth\RegistersUsers
    • Ellaisys\Cognito\Auth\ResetsPasswords
    • Ellaisys\Cognito\Auth\RespondsMFAChallenge
    • Ellaisys\Cognito\Auth\SendsPasswordResetEmails
    • Ellaisys\Cognito\Auth\VerifiesEmails

    In the simplest way you just go through your Auth Controllers and change namespaces from the traits which are currently implemented from Laravel.

    You can change structure to suit your needs. Please be aware of the @extend statement in the blade file to fit into your project structure. At the current state you need to have those 4 form fields defined in here. Those are token, email, password, password_confirmation.

    Single Sign-On

    With our package and AWS Cognito we provide you a simple way to use Single Sign-Ons. For configuration options take a look at the config cognito.php.

    When you want SSO enabled and a user tries to login into your application, the package checks if the user exists in your AWS Cognito pool. If the user exists, he will be created automatically in your database provided the add_missing_local_user is to true, and is logged in simultaneously.

    That’s what we use the fields sso_user_model and cognito_user_fields for. In sso_user_model you define the class of your user model. In most cases this will simply be App\Models\User.

    With cognito_user_fields you can define the fields which should be stored in Cognito. Put attention here. If you define a field which you do not send with the Register Request this will throw you an InvalidUserFieldException and you won’t be able to register.

    Now that you have registered your users with their attributes in the AWS Cognito pool and your database and you want to attach a second app which should use the same pool. Well, that’s actually pretty easy. You can use the API provisions that allows multiple projects to consume the same AWS Cognito pool.

    *IMPORTANT: if your users table has a password field you are not going to need this anymore. What you want to do is set this field to be nullable, so that users can be created without passwords. From now on, Passwords are stored in Cognito.

    Any additional registration data you have, for example firstname, lastname needs to be added in cognito.php cognito_user_fields config to be pushed to Cognito. Otherwise they are only stored locally and are not available if you want to use Single Sign On’s.*

    Forgot password with resend option

    In case the user has not activated the account, AWS Cognito as a default feature does not allow user of use the forgot password feature. We have introduced the AWS documented feature that allows the password to be resent.

    We have made this configurable for the developers so that they can use it as per the business requirement. The configuration takes a boolean value. Default is true (allows resend of forgot password)

        AWS_COGNITO_ALLOW_FORGOT_PASSWORD_RESEND=true

    Middleware configuration for API Routes

    In case you are using this library as API driver, you can register the middleware into the kernal.php in the $routeMiddleware

        protected $routeMiddleware = [
            ...
            'aws-cognito' => \Ellaisys\Cognito\Http\Middleware\AwsCognitoAuthenticate::class
        ]

    To use the middleware into the Web routes, you can use the std auth middleware as shown below

        Route::middleware('auth')->get('user', 'NameOfTheController@functionName');

    To use the middleware into the API routes, as shown below

        Route::middleware('aws-cognito')->get('user', 'NameOfTheController@functionName');

    Registering Users

    As a default, if you are registering a new user with Cognito, Cognito will send you an email during signUp that includes the username and temporary password for the users to verify themselves.

    Using this library in conjunction with AWS Lambda, once can look to customize the email template and content. The email template can be text or html based. The Lambda code for not included in this code repository. You can create your own. Any object (array) that you pass to the registration method is transferred as is to the lambda function, we are not prescriptive about the attribute names.

    We have made is very easy for anyone to use the default behaviour.

    1. You don’t need to create an extra field to store the verification token.
    2. You don’t have to bother about the Sessions or API tokens, they are managed for you. The session or token is managed via the standard mechanism of Laravel. You have the liberty to keep it where ever you want, no security loop holes.
    3. If you use the trait provided by us ‘Ellaisys\Cognito\Auth\RegistersUsers’, the code will be limited to just a few lines
    4. if you are using the Laravel scafolding, then make the password nullable in DB or drop it from schema. Passwords will be only managed by AWS Cognito.
        use Ellaisys\Cognito\Auth\RegistersUsers;
    
        class UserController extends BaseController
        {
            use RegistersUsers;
    
            public function register(Request $request)
            {
                $validator = $request->validate([
                    'name' => 'required|max:255',
                    'email' => 'required|email|max:64|unique:users',
                    'password' => 'sometimes|confirmed|min:6|max:64',
                ]);
    
                //Create credentials object
                $collection = collect($request->all());
                $data = $collection->only('name', 'email', 'password'); //passing 'password' is optional.
    
                //Register User in cognito
                if ($cognitoRegistered=$this->createCognitoUser($data)) {
    
                    //If successful, create the user in local db
                    User::create($collection->only('name', 'email'));
                } //End if
    
                //Redirect to view
                return view('login');
            }
        }
    1. You don’t need to turn off Cognito to send you emails. We rather propose the use of AWS Cognito or AWS SMS mailers, such that user credentials are always secure.

    2. In case you want to suppress the mails to be sent to the new users, you can configure the parameter given below to skip welcome mails to new user registration. Default configuration shall send the welcome email.

        AWS_COGNITO_NEW_USER_MESSAGE_ACTION="SUPPRESS"
    1. The configuration given below allows the new user’s email address to be auto marked as verified.
        AWS_COGNITO_FORCE_NEW_USER_EMAIL_VERIFIED=true //optional - default value is false.
    1. To assign a default group to a new user when registering set a name of the user group as per the configuration done via AWS Cognito Management Console. The default value is set to null.
        AWS_COGNITO_DEFAULT_USER_GROUP="Customers"
    1. To enable custom password or user defined password, the below configuration if set to true will force the user to set the password during registration, else cognito will generate a random password and send over email and/or SMS based on the configurations.
        AWS_COGNITO_FORCE_NEW_USER_PASSWORD=true //optional - default value is false.  

    User Authentication

    We have provided you with a useful trait that make the authentication very simple (with Web or API routes). You don’t have to worry about any additional code to manage sessions and token (for API).

    Note

    The Access Token is now validated with the AWS Cognito certificate. If the certificate is incorrect or expired, it will throw am exception.

    The trait takes in some additional parameters, refer below the function signature of the trait. Note that the function takes the object of Illuminate\Support\Collection instead of Illuminate\Http\Request. This will allow you to use this function in any tier of the code.

    Also, the ‘guard’ name reference is passed, so that you can reuse the function for multiple guard drivers in your project. The function has the capability to handle the Session and Token Guards with multiple drivers and providers as defined in /config/auth.php

        namespace Ellaisys\Cognito\Auth;
    
        protected function attemptLogin (
            Collection $request, string $guard='web', 
            string $paramUsername='email', string $paramPassword='password', 
            bool $isJsonResponse=false
        ) {
            ...
            ...
    
    
            ...
        }

    In case you want to use this trait for Web login, you can write the code as shown below in the AuthController.php

        namespace App\Http\Controllers;
    
        ...
    
        use Ellaisys\Cognito\AwsCognitoClaim;
        use Ellaisys\Cognito\Auth\AuthenticatesUsers as CognitoAuthenticatesUsers;
    
        class AuthController extends Controller
        {
            use CognitoAuthenticatesUsers;
    
            /**
             * Authenticate User
             * 
             * @throws \HttpException
             * 
             * @return mixed
             */
            public function login(\Illuminate\Http\Request $request)
            {
                ...
    
                //Convert request to collection
                $collection = collect($request->all());
    
                //Authenticate with Cognito Package Trait (with 'web' as the auth guard)
                if ($response = $this->attemptLogin($collection, 'web')) {
                    if ($response===true) {
                        return redirect(route('home'))->with('success', true);
                    } else if ($response===false) {
                        // If the login attempt was unsuccessful you may increment the number of attempts
                        // to login and redirect the user back to the login form. Of course, when this
                        // user surpasses their maximum number of attempts they will get locked out.
                        //
                        //$this->incrementLoginAttempts($request);
                        //
                        //$this->sendFailedLoginResponse($collection, null);
                    } else {
                        return $response;
                    } //End if
                } //End if
    
            } //Function ends
    
            ...
        } //Class ends

    In case you want to use this trait for API based login, you can write the code as shown below in the AuthApiController.php

        namespace App\Api\Controller;
    
        ...
    
        use Ellaisys\Cognito\AwsCognitoClaim;
        use Ellaisys\Cognito\Auth\AuthenticatesUsers as CognitoAuthenticatesUsers;
    
        class AuthApiController extends Controller
        {
            use CognitoAuthenticatesUsers;
    
            /**
             * Authenticate User
             * 
             * @throws \HttpException
             * 
             * @return mixed
             */
            public function login(\Illuminate\Http\Request $request)
            {
                ...
    
                //Convert request to collection
                $collection = collect($request->all());
    
                //Authenticate with Cognito Package Trait (with 'api' as the auth guard)
                if ($claim = $this->attemptLogin($collection, 'api', 'username', 'password', true)) {
                    if ($claim instanceof AwsCognitoClaim) {
                        return $claim->getData();
                    } else {
                        return response()->json(['status' => 'error', 'message' => $claim], 400);
                    } //End if
                } //End if
    
            } //Function ends
    
    
            ...
        } //Class ends

    Signout (Remove Access Token)

    The logout methods are now part of the guard implementations, the logout method removes the access-tokens from AWS and also removes from Application Storage managed by this library. Just calling the auth guard logout method will be sufficient. You can implement it into the routes or controller based on your development preference.

    The logout method now takes an optional boolean parameter (true) to revoke RefreshToken. The default value is (false) and that will persist the Refresh Token with AWS Cognito.

       ...
    
       Auth::guard('api')->logout();
    
    
       ...
    
       Auth::guard('api')->logout(true); //Revoke the Refresh Token.

    Refresh Token

    You can use this trait for API to generate new token

        namespace App\Api\Controller;
    
        ...
    
        use Ellaisys\Cognito\AwsCognitoClaim;
        use Ellaisys\Cognito\Auth\RefreshToken;
    
        class AuthApiController extends Controller
        {
            use RefreshToken;
    
            /**
             * Generate a new token using refresh token.
             * 
             * @throws \HttpException
             * 
             * @return mixed
             */
            public function refreshToken(\Illuminate\Http\Request $request)
            {
                ...
    
                $validator = $request->validate([
                    'email' => 'required|email',
                    'refresh_token' => 'required'
                ]);
                
                try {
                    return $this->refresh($request, 'email', 'refresh_token');
                } catch (Exception $e) {
                    return $e;
                }
    
            } //Function ends
    
    
            ...
        } //Class ends

    Delete User

    If you want to give your users the ability to delete themselves from your app you can use our deleteUser function from the CognitoClient.

    To delete the user you should call deleteUser and pass the email of the user as a parameter to it. After the user has been deleted in your cognito pool, delete your user from your database too.

            $cognitoClient->deleteUser($user->email);
            $user->delete();

    We have implemented a new config option delete_user, which you can access through AWS_COGNITO_DELETE_USER env var. If you set this config to true, the user is deleted in the Cognito pool. If it is set to false, it will stay registered. Per default this option is set to false. If you want this behaviour you should set USE_SSO to true to let the user restore themselves after a successful login.

    To access our CognitoClient you can simply pass it as a parameter to your Controller Action where you want to perform the deletion.

        public function deleteUser(Request $request, AwsCognitoClient $client)

    Laravel will take care of the dependency injection by itself.

        IMPORTANT: You want to secure this action by maybe security questions, a second delete password or by confirming 
        the email address.
    

    Storing Web Sessions or API Tokens in DynamoDB (Useful for multiserver/container implementation)

    If you have a deployment architecture, that involves multiple servers and you want to maintain the web sessions or API tokens across the servers, you can use the AWS DynamoDB. The library is capable of handling the DynamoDB with ease. All that you need to do is create the table in AWS DynamoDB and change a few configurations.

    Creating a new table in AWS DynamoDB

    1. Go to the AWS Console and create a new table.
    2. Enter the unique table name as per your preferences.
    3. The primary key (or partition key) should be key of type string
    4. Use default settings and click the Create button

    Update the .env file for Dynamo DB configurations

    Add/Edit the following fields to your .env file and set the values according to your AWS settings:

        # Cache Configuration
        CACHE_DRIVER="dynamodb"
        DYNAMODB_CACHE_TABLE="table-name-of-your-choice" //This should match the table name provided above
    
        # Session Configuration
        SESSION_DRIVER="dynamodb"
        SESSION_LIFETIME=120
        SESSION_DOMAIN="set-your-domain-name" //The domain name can be as per your preference
        SESSION_SECURE_COOKIE=true
    
        # DynamoDB Configuration
        DYNAMODB_ENDPOINT="https://dynamodb.us-west-2.amazonaws.com" // You can change the endpoint based of different regions

    Refer the AWS DynamoDB Documentation and refer the endpoints provided in Service endpoints section.

    Update the DynamoDB table for the TTL columns as expires_at

    Automatic User Password update for API usage (for New Cognito Users)

    In case of the new cognito users, the AWS SDK will send a session key and the user is expected to change the password, in a forced mode. Make sure you force the users to change the password for the first login by new cognito user.

    However, if you have an API based implementation, and want to automatically authenticate the user without forcing the password change, you may do that with below setting fields to your .env file

        AWS_COGNITO_FORCE_PASSWORD_CHANGE_API=false     //Make true for forcing password change
        AWS_COGNITO_FORCE_PASSWORD_AUTO_UPDATE_API=true //Make false for stopping auto password change

    Support for App Client without Secret enabled

    The library now supports where the AWS configuration of App Client with the Client Secret set to disabled. Use the below configuration into the environment file to enable/disable this. The default is marked as enable (i.e. we expect the App Client Secret to be enabled in AWS Cognito configuration)

       AWS_COGNITO_CLIENT_SECRET_ALLOW=false

    Password Validation based of Cognito Configuration

    This library fetches the password policy from the cognito pool configurations. The laravel request validations are done based on the regular expression that is created based on this policy. This validations are performed during the Sign Up (Registation), Sign In (Login), Reset and Change password based flows. The validation messages for the password are also dynamic in nature and change based on the configurations.

    Important

    In case of special characters, we are supporting all except the pipe character | for now.

    Mapping Cognito User using Subject UUID

    The library maps the Cognito user subject UUID with the local repository. Everytime a new user is created in cognito, the sub UUID is mapped with the local user table with an user specified column name.

    The column in the local BD is identified with the config parameter user_subject_uuid with the default value set to sub.

    However, to customize the column name in the local DB user table, you may do that with below setting fields to your .env file

        AWS_COGNITO_USER_SUBJECT_UUID="sub"
        

    We are working on making sure that pipe character is handled soon.

    Changelog

    Please see CHANGELOG for more information on what has changed recently.

    Security

    If you discover any security related issues, please email support@ellaisys.com and also add it to the issue tracker.

    Roadmap

    https://github.com/ellaisys/aws-cognito/wiki/RoadMap

    How to contribute

    • Star this project on GitHub.
    • Report bugs or suggest features by creating new issues or adding comments to issues
    • Submit pull requests
    • Spread the word by blogging about SimplCommerce or sharing it on social networks
    • Donate to us

    Credits & Contributors

    This project exists thanks to all the people who contribute.

    Click on these badges to see how you might be able to help:

    GitHub repo Issues  GitHub repo Good Issues for newbies  GitHub Help Wanted issues
    GitHub repo PRs  GitHub repo Merged PRs  GitHub Help Wanted PRs

    Support us

    EllaiSys was a web and consulting agency specialized in Cloud Computing (AWS and Azure), DevOps, and Product Engneering. We closed our professional services offerings from Oct 2021, however the team continues to support the open source projects as our commitment towards the community. Anyone interested to support the development is welcome.

    License

    The MIT License (MIT). Please see License File for more information.

    Disclaimer

    This package is currently in production ready mode with already a few implementations done. We would be happy to hear from you, about the defects or new feature enhancements. However, this being a free support, we would not be able to commit to support SLAs or timelines.

    Visit original content creator repository https://github.com/ellaisys/aws-cognito
  • sociahigh

    Sociahigh

    Sociahigh is a complete application developed using the concept of containerized microservices. This application includes a node with fastify and typescript backend, a react, tailwind and typescript frontend, nginx as http server and a custom npm package for use in the backend environment. Every microservice and the http server is containerized with docker. The purpose of the application is the management of small events, providing the management of guests, the items they are taking to the event and updating everyone about changes.


    🟢 Status: Concluded


    ⏮️ How to run the backend

    The first step after downloading the project is to create a docker network

    docker network create \
      --driver=bridge \
      --subnet=171.1.0.0/16 \
      sociahigh_network
    

    Build all the Docker images in the root of the main projects

    docker build -t sociahigh_user_microservice ./sociahigh_user_microservice
    
    docker build -t sociahigh_event_microservice ./sociahigh_event_microservice
    
    docker build -t sociahigh_nginx ./ sociahigh_nginx
    

    Run the containers

    docker run -d \
      --name sociahigh_user_microservice \
      --restart always \
      -p 8800:8800 \
      --ip 171.1.0.88 \
      --network sociahigh_network \
      sociahigh_user_microservice
    
    docker run -d \
      --name sociahigh_event_microservice \
      --restart always \
      -p 8900:8900 \
      --ip 171.1.0.89 \
      --network sociahigh_network \
      sociahigh_event_microservice
    
    docker run -d \
      --name sociahigh_nginx \
      --restart always \
      -p 80:80 \
      --ip 171.1.0.80 \
      --network sociahigh_network \
      sociahigh_nginx
    

    The server will go up at port 80 and you can call every microservice using it routes through nginx. You can run a portainer server using the command below:

    docker volume create portainer_data

    docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest

    ⏭️ How to run the frontend

    Go to the `sociahigh_frontend_web` folder and run the script:

    npm run dev
    

    The server will go up at port 5173


    🧠 Understanding

    A POSTMAN COLLECTION IS INCLUDED IN THE PROJECT. So, you can import this collection and have fun.


    📸 System prints

    See some system screens below

    Home
    Manage
    Element

    🏛 ERD

    The complete database structure:

    ERD


    🎨 Contributor(s)

    Profile
    Ítalo Sérvio
    Visit original content creator repository https://github.com/italoservio/sociahigh
  • PI2_101_Microsoft_DicMath

    PI2_101_Microsoft_DicMath : DicMath – Dictée vocale d’équations Mathématiques

    If you need additional information, do not hesitate to contact me by email annbl.mrcn@gmail.com (Annabel)!

    _________ English version bellow _________

    Note : to create a new python environment allowing the execution of the code, execute the following command in the command prompt : “conda create -n <Dicmath_Microsoft> –file environment.txt”. The environment.txt file is given in the github repository.

    Watch the video

    Résumé Français

    Description du projet

    Notre projet vise à développer un logiciel alimenté par l’IA pour aider les lycéens malvoyants à résoudre des équations mathématiques en utilisant leur voix. L’objectif est de permettre aux étudiants de dicter des équations, de recevoir un retour vocal de l’équation comprise par le logiciel et de naviguer pour les modifier. Les principaux utilisateurs seront des étudiants aveugles jusqu’au niveau bac et mais le logiciel permet également de fournir que des opérateurs mathématiques avancés (intégrales, etc.).

    Pour atteindre cet objectif, nous avons utilisé plusieurs technologies et méthodes de travail. Tout d’abord, nous avons utilisé Whisper, un outil récent de Speech-To-Text de OpenAI pour transcrire la voix de l’utilisateur en équations mathématiques texte. Nous avons ensuite développé une fonction de traduction texte-Latex, qui est le format le plus adapté pour gérer des équations mathématiques. Enfin, nous avons utilisé des services cognitifs Microsoft Azure pour implémenter un bot Text-To-Speech pour relire les équations à l’utilisateur.

    En ce qui concerne l’interface utilisateur, nous avons développé une interface graphique, basée sur Python, qui permet à l’utilisateur de dicter une équation mathématique via le microphone et affiche l’équation transcrite, en utilisant des technologies HTML, CSS et JS. L’interface est travaillée pour être simple et accessible : l’élève peut interagir avec l’interface avec la voix, grâce à des commandes vocales, ou grâce au clavier, l’utilisation de la souris étant impossible pour eux.

    Pour assurer la qualité du logiciel, nous avons mis en place une méthode de travail en équipe, où chaque membre a été assigné à des tâches spécifiques. Certains membres ont travaillé sur l’interface graphique et d’autres encore sur l’intégration des services d’IA. Nous avons également effectué des tests utilisateur réguliers pour vérifier la facilité d’utilisation et la pertinence des fonctionnalités. Enfin, une fois que tous les modules ont été développés, nous les avons fusionnés en un seul projet pour créer une expérience utilisateur fluide. En plus d’être un défi technique car aucune technologie actuelle permet de faire ce que nous avons réalisé, cette expérience nous a permis d’aborder la notion d’accessibilité. Nous sommes extrêmement reconnaissants envers Microsoft de nous avoir offert cette opportunité.

    Pistes d’améliorations et travail qu’il reste à faire

    Tout le module d’IA, de reconnaissance et retour vocal, sont 100% opérationnels. Cependant, il reste du travail, notamment sur l’interface et tout le module de navigation. Voici les pistes de travail que nous proposons :

    L’interface

    • améliorer l’interface : la rendre plus accessible pour les malvoyants (couleurs, emplacement des boutons…)
    • continuer le travail sur les commandes clavier pour pouvoir actionner TOUS les boutons de l’interface
    • ajouter des commandes vocale pour activer les boutons de l’interface par la voix
    • travailler l’affichage des équations (pour le moment, on affiche des images dont les dimentions sont fixes, il faudrait que la taille de l’image soit modulée par la longueur de l’équation pour ne pas la couper)

    Les paramètres

    • permettre le changement de langue
    • permettre le choix de la voix (sexe, rapidité de lecture…). Ces paramètres sont possibles avec le module Microsoft Azure que nous avons utilisé, il s’agit juste de relier les paramètres de l’interface et les variables dans la fonction Microsoft Azure.

    La navigation et les modifications

    • permettre de modifier une équation ou un élément de l’équation (qui est dans l’historique ou dans l’équation en court) Nous avons commencé un travail sur la navigation en fonctionnant sur des blocs séparés par les opérateurs +,-,*,/,(,), mais notre travail n’a pas été intégré à l’interface, n’hésitez pas à nous contacter pour plus de détail.

    Test et tuto

    • développer un tuto d’utilisation (accessible aux malvoyanrs), détaillant les commandes et fonctionnalités de l’interface.
    • aller voir des élèves lycées de l’INJA (Institut National des Jeunes Aveugles à Paris) et tester le logiciel
    • tester également le logiciel sur des malvoyants (personnes dont la vision est réduite)

    English Abstract

    Project description

    Our project aims to develop AI-powered software to help visually impaired high school students solve math equations using their voice. The goal is to allow students to dictate equations, receive voice feedback of the equation understood by the software, and navigate to edit them. The main users will be blind students up to baccalaureate level, but the software also makes it possible to provide only advanced mathematical operators (integrals, etc.).

    To achieve this goal, we used several technologies and working methods. First, we used Whisper, a recent Speech-To-Text tool from OpenAI to transcribe the user’s voice into text math equations. We then developed a text-Latex translation function, which is the most suitable format for managing mathematical equations. Finally, we used Microsoft Azure Cognitive Services to implement a Text-To-Speech bot to read the equations back to the user.

    Regarding the user interface, we have developed a graphical interface, based on Python, which allows the user to dictate a mathematical equation via the microphone and displays the transcribed equation, using HTML, CSS and JS technologies. . The interface is worked to be simple and accessible: the student can interact with the interface with the voice, thanks to voice commands, or thanks to the keyboard, the use of the mouse being impossible for them.

    To ensure the quality of the software, we have implemented a teamwork method, where each member has been assigned to specific tasks. Some members worked on the GUI and still others on the integration of AI services. We also performed regular user testing to check the usability and relevance of features. Finally, once all the modules were developed, we merged them into a single project to create a smooth user experience. In addition to being a technical challenge because no current technology allows us to do what we have achieved, this experience allowed us to approach the notion of accessibility. We are extremely grateful to Microsoft for giving us this opportunity.

    Areas for improvement and work that remains to be done

    All the AI module, recognition and voice feedback, are 100% operational. However, there is still work to be done, especially on the interface and the entire navigation module. Here are the lines of work we offer:

    Interface

    • improve the interface: make it more accessible for the visually impaired (colors, location of buttons, etc.)
    • continue working on the keyboard commands to be able to operate ALL the buttons of the interface
    • add voice commands to activate interface buttons by voice
    • work on the display of equations (for the moment, we display images whose dimensions are fixed, the size of the image should be modulated by the length of the equation so as not to cut it)

    The settings

    • allow language change
    • allow the choice of the voice (sex, speed of reading…). These parameters are possible with the Microsoft Azure module that we used, it is just a matter of linking the interface parameters and the variables in the Microsoft Azure function.

    Navigation and modifications

    • allow to modify an equation or an element of the equation (which is in the history or in the current equation) We have started a work on the navigation by working on blocks separated by the operators +,-,*,/,(,), but our work has not been integrated into the interface, do not hesitate to contact us for more detail.

    Test

    • develop a user tutorial (accessible to the visually impaired), detailing the commands and features of the interface.
    • go see high school students from INJA (National Institute for Young Blind People in Paris) and test the software
    • also test the software on visually impaired people (people with reduced vision)
    Visit original content creator repository https://github.com/Annabel64/PI2_101_Microsoft_DicMath
  • middletools

    Middletools

    Coverage Status Supported python version PyPI package version Downloads

    This is a python library that allows you to integrate middlewares-based system to your project. It contains base tools for creating and running middlewares with async-await style

    import asyncio
    
    import middletools
    
    
    async def middleware1(request, call_next):
        print(f"Run middleware1 (request: {request})")
        response = await call_next()
        print(f"End middleware1 (response: {response})")
        return response
    
    
    async def middleware2(request, call_next):
        print(f"Run middleware2 (request: {request})")
        response = await call_next()
        print(f"End middleware2 (response: {response})")
        return response
    
    
    async def main():
        read_afterwords = await middletools.read_forewords(
            middleware1, middleware2,
            inbox_value=123  # Pass `request` value
        )
        print("Some other code...")
        await read_afterwords(456)  # Pass `response` value
    
    
    asyncio.run(main())

    Output is

    Run middleware1 (request: 123)
    Run middleware2 (request: 123)
    Some other code...
    End middleware2 (response: 456)
    End middleware1 (response: 456)
    

    Installation

    PyPI

    python -m pip install middletools

    GitHub

    python -m pip install https://github.com/deknowny/middlewares/archive/main.zip

    Usage

    The main idea is give an ability just passing the middlewares and inbox/outbox payload values in a few methods instead of running and saving middlewares state by hand

    Standard case: a function runs RESTful API routers and requires a middleware that checks a header in client’s request


    There are 2 endpoints for an abstract GET and POST methods

    # Some abstract router
    @router.get("https://github.com/")
    async def route_get(request):
        return 200, {"response": "some content"}
    
    
    @router.post("https://github.com/")
    async def route_post(request):
        return 201, {"response": "ok"}

    In the core of web framework you used a function like this that just call all routers

    class Router:
        ...
        ...
        
        async def call_routers(self, request):
            for router in self.routers:
                ... # Pass request to routers and check it matched

    middlewares library allows you easy integrate middleware system to your call_routers


    Create middleware function

    import middletools
    
    ...
    ...
    
    # Adding a middleware handler to an abstract 
    @router.add_middleware
    async def my_middleware(
        request: SomeRequest, call_next: middletools.types.CallNext
    ) -> SomeResponse:
        # Just check if header exists, id not set the default value
        if "X-Required-Header" not in request.headers:
            request.header["X-Required-Header"] = "default"
        response = await call_next()
        return response

    Here we add a header to client request if clint didn’t do it. Then await call_next() give control to other middlewares or to our call_routers handler and response from this is the value call_next() returns


    call_routers should looks like this

    import typing
    
    import middletools
    
    
    class Router:
        # You can use generics to describe middleware hand;er
        middlewares: typing.List[
            middletools.types.MiddlewareHandler[
                SomeRequest, SomeResponse
            ]
        ]
        ...
        ...
    
        async def call_routers(self, request):
            read_afterwords = await middletools.read_forewords(
                *self.middlewares, inbox_value=request
            )
            for router in self.routers:
                ... # Pass request to routers and check it matched
                response = ...
                await read_afterwords(response)
                break
            

    middlewares.read_forewords run middlewares until every one of them give control with await call_next(). When we do all our stuff and get the router response we can call await read_afterwords(response) and run all middlewares completely.

    Notes

    If a middleware doesn’t call call_next() it raises middlewares.CallNextNotUsedError. It means that the middleware forcibly decline middlewares handlers and response should be sent immediately without routers running. call_routers should looks like this:

    import middletools
    
    
    async def call_routers(self, request):
        try:
            read_afterwords = await middletools.read_forewords(
                *self.middlewares, inbox_value=request
            )
            for router in self.routers:
                ... # Pass request to routers and check it matched
                response = ...
                await read_afterwords(response)
                return response
        except middletools.CallNextNotUsedError:
            return SomeBadResponseBecauseNotRouted(400, "Require a header!")
        

    If a middleware doesn’t return anything, middlewares dispatching declined forcibly too but after routers handled. (Return nothing means there isn’t any return or return None used). It raises middlewares.NothingReturnedError

    import middletools
    
    
    async def call_routers(self, request):
        try:
            read_afterwords = await middletools.read_forewords(
                *self.middlewares, inbox_value=request
            )
            for router in self.routers:
                ... # Pass request to routers and check it matched
                response = ...
                await read_afterwords(response)
                return response
        except middletools.CallNextNotUsedError:
            return SomeBadResponseBecauseNotRouted(400, "Require a header!")
        except middletools.NothingReturnedError:
            return SomeBadResponseBecauseMiddlewareDntReturnResponse(
                500, "Oops, internal server error"
            )
    Visit original content creator repository https://github.com/deknowny/middletools
  • Remove-MessageClassItems

    Remove-MessageClassItems

    Getting Started

    This script will remove items of a certain class from a mailbox, traversing through mail
    item folders (IPF.Note). You can also specify how the items should be deleted. Example usages
    are cleaning up mailboxes of stubs, by removing the shortcut messages left behind by archiving
    products such as Enterprise Vault.

    Requirements

    • PowerShell 3.0 or later
    • EWS Managed API 1.2 or later

    Usage

    Syntax:

    Remove-MessageClassItems.ps1 [-Identity] <String> [-MessageClass] <String> [-Server <String>] [-Impersonation] [-Credentials <PSCredential>] [-DeleteMode <String>] [-ScanAllFolders] [-Before <DateTime>] [-MailboxOnly] [-ArchiveOnly] [-IncludeFolders <String[]>] [-ExcludeFolders <String[]>] [-NoProgressBar] [-Report] [-WhatIf] [-Confirm] [<CommonParameters>]
    

    Examples:

    .\Remove-MessageClassItems.ps1 -Identity user1 -Impersonation -Verbose -DeleteMode MoveToDeletedItems -MessageClass IPM.Note.EnterpriseVault.Shortcut
    

    Process mailbox of user1, moving “IPM.Note.EnterpriseVault.Shortcut” message class items to the
    DeletedItems folder, using impersonation and verbose output.

    .\Remove-MessageClassItems.ps1 -Identity user1 -Impersonation -Verbose -DeleteMode SoftDelete -MessageClass EnterpriseVault -PartialMatching -ScanAllFolders -Before ((Get-Date).AddDays(-90))
    

    Process mailbox of user1, scanning all folders and soft-deleting items that contain the string ‘EnterpriseVault’ in their
    message class items and are older than 90 days.

    $Credentials= Get-Credential
    .\Remove-MessageClassItems.ps1 -Identity olrik@office365tenant.com -Credentials $Credentials -MessageClass IPM.Note.EnterpriseVault.Shortcut -MailboxOnly
    

    Get credentials and process only the mailbox of olrik@office365tenant.com, removing “IPM.Note.EnterpriseVault.Shortcut” message class items.

    $Credentials= Get-Credential
    .\Remove-MessageClassItems.ps1 -Identity michel@contoso.com -MessageClass IPM* -Credentials $Credentials -WhatIf:$true -Verbose -IncludeFolders Archive\* -ExcludeFolders ArchiveX
    

    Scan mailbox of michel@contoso looking for items of classes starting with IPM using provided credentials, limited to folders named Archive and their subfolders, but
    excluding folders named ArchiveX, showing what it would do (WhatIf) in verbose mode.

    Import-CSV users.csv1 | .\Remove-MessageClassItems.ps1 -Impersonation -DeleteMode HardDelete -MessageClass IPM.ixos-archive
    

    Uses a CSV file to fix specified mailboxes (containing Identity column), removing “IPM.ixos-archive” items permanently, using impersonation.

    About

    For more information on this script, as well as usage and examples, see
    the related blog article, Removing Message Class Items from a Mailbox.

    License

    This project is licensed under the MIT License – see the LICENSE.md for details.

    Visit original content creator repository
    https://github.com/michelderooij/Remove-MessageClassItems

  • evolving-agents

    Evolving Agents Toolkit (EAT)

    License GitHub Stars GitHub Forks

    🚨 PROJECT SUNSET NOTICE – JULY 2025 🚨

    This project has been officially discontinued. While EAT demonstrated powerful concepts in multi-agent orchestration, we recognized that the complex Python architecture was over-engineered for achieving adaptive agent behavior.

    🔄 Evolution to LLMunix

    The core concepts from EAT have been dramatically simplified and reimplemented in our new flagship project:

    👉 LLMunix – Pure Markdown Operating System

    Key improvements:

    • EAT: Complex Python + MongoDB architecture
    • LLMunix: Pure markdown interpreted by LLM runtime engines
    • Result: Same adaptive capabilities, 10x simpler implementation

    🌟 For continued development of adaptive agent concepts, please visit:


    📚 Original EAT Documentation (Archived)

    Build complex, adaptive AI agent systems designed for AI-First strategies. Define high-level goals, and let the toolkit orchestrate the discovery, creation, execution, and evolution of the agents and tools needed to achieve outcomes similar to sophisticated human workflows.

    EAT is a Python toolkit for constructing advanced, multi-agent applications where autonomy, adaptability, and robust orchestration are crucial. It enables the implementation of AI-First strategies, where agent-driven workflows are designed to handle tasks that complex human workflows are currently capable of doing. Move beyond simple agent chains to create ecosystems that can dynamically respond to requirements, learn from interactions, and improve over time—all within defined governance boundaries and now powered by a unified MongoDB backend.


    🎉 MongoDB Migration Update! 🎉

    The Evolving Agents Toolkit has successfully completed its initial migration to MongoDB as its unified backend! This replaces previous file-based storage and ChromaDB, bringing enhanced scalability and robustness.

    • The core framework (SmartLibrary, SmartAgentBus, LLMCache, IntentPlan persistence) now fully utilizes MongoDB.
    • All examples in the examples/ directory, including the comprehensive demo examples/invoice_processing/architect_zero_comprehensive_demo.py, have been updated and are working with the new MongoDB backend.

    The migration of all examples to MongoDB is now complete. We are now focusing on updating the test suite.


    graph TD
        User["User / External System"] -- High-Level Goal --> SA[("SystemAgent\n(Central Orchestrator)")];;;agent
    
        subgraph "Core Infrastructure & Services (MongoDB Backend)"
            direction LR
            SL["Smart Library\n(Component Storage, Search, Versioning)"];;;service
            SB["Smart Agent Bus\n(Discovery, Routing, Communication - System/Data Bus)"];;;service
            LLMS["LLM Service\n(Reasoning, Embeddings, Generation)"];;;service
            FW["Firmware\n(Governance Rules)"];;;service
            Providers["Providers\n(Agent/Tool Factories - BeeAI, OpenAI, etc)"];;;infra
            MongoDB[("MongoDB Atlas / Server\n(Primary Data Store, Vector Search)")]:::infra
            SCtx[("SmartContext\n(Task-Specific Context)")]:::service
        end
    
        subgraph "Key Agents & Factories"
            direction LR
             AgentF["Agent Factory"];;;infra
             ToolF["Tool Factory"];;;infra
             ArchZ["ArchitectZero\n(Optional: Solution Design)"];;;agent
        end
    
        %% Main Control Flow & Dependencies
        SA -- Uses --> Tools["SystemAgent Tools\n(Search, Create, Evolve, Request, Workflow, IntentReview...)"];;;tool
        SA -- Uses --> LLMS
        SA -- Utilizes --> SCtx
        SA -- Relies on --> AgentF
        SA -- Relies on --> ToolF
    
        %% Tool Interactions with Services
        Tools -- Manages Components --> SL
        Tools -- Interacts via --> SB
        Tools -- Uses for Creation --> AgentF
        Tools -- Uses for Creation --> ToolF
        Tools -- Influenced By --> FW
    
        %% Factory Dependencies
        AgentF -- Uses --> Providers
        AgentF -- Uses --> SL
        ToolF -- Uses --> SL
        ToolF -- Uses --> LLMS
    
        %% Internal Service Dependencies
        SL -- Uses --> MongoDB
        SB -- Uses --> MongoDB
        LLMS -- Uses Cache In --> MongoDB
        SL -- Uses --> LLMS
        SB -- Uses --> LLMS
        SCtx -- Relies on --> SL
        SCtx -- Relies on --> LLMS
    
        %% Bus Interaction with Ecosystem
        SB -- Routes Request (Data Bus) --> Ecosystem["Managed Agents / Tools\n(Ecosystem Components)"]
        SB -- Manages Registration/Discovery (System Bus) --> Ecosystem
    
        %% Agent/Tool Creation/Management
        AgentF -- Creates/Manages --> Ecosystem
        ToolF -- Creates/Manages --> Ecosystem
    
        %% Optional Design Interaction (Often Internal to SystemAgent)
        SA -.->|Optional: Requests Design via Bus| ArchZ
    
        %% Final Result Flow
        SA -- Final Result --> User
    
        %% Define styles for clarity
        classDef agent fill:#9cf,stroke:#333,stroke-width:2px;
        classDef service fill:#f9f,stroke:#333,stroke-width:2px;
        classDef tool fill:#ccf,stroke:#333,stroke-width:2px;
        classDef infra fill:#eee,stroke:#666,stroke-width:1px,color:#333;
    
        %% Highlight SystemAgent
        style SA fill:#69c,stroke:#000,stroke-width:3px,color:#fff;
    
    Loading

    Diagram Key: agent = Core EAT Agent, service = Core EAT Service, tool = SystemAgent’s Internal Tools, infra = Supporting Infrastructure. (Note: VDB (ChromaDB) has been replaced with MongoDB Atlas / Server)


    Why Evolving Agents Toolkit for AI-First?

    Building true AI-First systems—where agent workflows are capable of handling tasks currently performed in complex human processes—requires more than just individual agents. EAT focuses on orchestrating the entire agent ecosystem:

    • 🎯 Goal-Oriented Orchestration: Interact via high-level goals given to a central SystemAgent. The SystemAgent handles the complex “how,” mimicking a project manager. It plans, finds or creates components, executes tasks, and manages internal workflows.
    • 🧠 Intelligent Component Management & Discovery: A SmartLibrary (now backed by MongoDB) acts as a central repository for reusable agents and tools, enabling semantic search (using MongoDB Atlas Vector Search or equivalent) and versioning. It supports task-aware retrieval using a dual embedding strategy.
    • 🚌 Dynamic Communication & Service Bus: The SmartAgentBus (registry and logs now in MongoDB) allows agents to discover and request capabilities dynamically, decoupling components.
    • 🌱 Adaptive Evolution: Components aren’t static. EAT provides mechanisms (EvolveComponentTool) for the SystemAgent to adapt agents and tools.
    • 🛡️ Governed Execution & Human-in-the-Loop: Implement optional, multi-level review checkpoints using the IntentReviewAgent. IntentPlans are now persisted in MongoDB.
    • 🧩 Modular & Interoperable: Seamlessly integrate agents and tools built with different frameworks (e.g., BeeAI, OpenAI Assistants SDK).
    • 💡 Task-Specific Context & Unified Backend: The architecture incorporates SmartContext and a Dual Embedding Strategy within the SmartLibrary. All core data persistence, including component metadata, embeddings, agent registry, logs, and LLM cache, is now unified in MongoDB, simplifying the stack and enhancing scalability.
    • 🤖 Self-Management & Improvement: System agents like SystemAgent and ArchitectZero can collaboratively design, implement, manage, and improve the ecosystem.

    In short: EAT provides the essential structure and tools to build AI-First systems that coordinate diverse capabilities, adapt to new challenges, provide relevant context, manage complexity autonomously, and operate under governance—all on a robust and scalable MongoDB backend.

    Key Features

    • SystemAgent Orchestrator: Central ReAct agent managing component lifecycles and task execution.
    • SmartLibrary with Dual Embedding (MongoDB Backend): Persistent storage for components in MongoDB. Features advanced semantic search using MongoDB Atlas Vector Search (or equivalent) for its Dual Embedding Strategy:
      • Content Embedding (content_embedding): Represents T_orig (component code/content).
      • Applicability Embedding (applicability_embedding): Represents T_raz (LLM-generated applicability description).
      • Task-Aware Search: Finds components based on what they are and what they are relevant for.
    • SmartAgentBus (Dual Bus, MongoDB Backend): Manages agent registration, discovery, and communication. Registry and execution logs are stored in MongoDB.
    • SmartContext: Facilitates passing task-relevant data.
    • Internal Workflow Engine: SystemAgent internally uses GenerateWorkflowTool and ProcessWorkflowTool for complex tasks.
    • Intent Review System (MongoDB Backend): Optional human-in-the-loop review. IntentPlan objects are generated by ProcessWorkflowTool and persisted in MongoDB for review via ApprovePlanTool.
    • LLMCache (MongoDB Backend): LLM completions and embeddings are cached in MongoDB with TTL for efficiency.
    • Unified Data Persistence: All primary data stores (SmartLibrary, AgentBus registry/logs, LLMCache, IntentPlans) now reside in MongoDB, eliminating JSON file stores and ChromaDB.
    • … (Component Evolution, Multi-Framework Support, Governance & Safety, ArchitectZero features remain conceptually similar but now operate on MongoDB data)

    Installation

    # Recommended: Create a virtual environment
    python -m venv venv
    source venv/bin/activate # On Windows use `venv\Scripts\activate`
    
    # Clone the repository
    git clone https://github.com/matiasmolinas/evolving-agents.git
    cd evolving-agents
    
    # Install dependencies (includes pymongo, beeai-framework, etc. ChromaDB is removed)
    pip install -r requirements.txt
    
    # Install the package in editable mode
    pip install -e .

    MongoDB Setup

    EAT now uses MongoDB as its unified backend. Using MongoDB Atlas with Vector Search is highly recommended.

    1. Set up MongoDB:
      • Follow the detailed instructions in docs/MONGO-SETUP.md to set up MongoDB Atlas (recommended) or a self-hosted instance.
      • This includes creating a database, user, and configuring network access.
    2. Configure Vector Search Indexes (CRITICAL for SmartLibrary & SmartAgentBus):
      • As described in docs/MONGO-SETUP.md, you must create Vector Search Indexes in MongoDB Atlas for:
        • eat_components collection: Two indexes, one on content_embedding and one on applicability_embedding. (Names in Atlas: idx_components_content_embedding and applicability_embedding respectively, or as defined in SmartLibrary.py).
        • eat_agent_registry collection: One index on description_embedding. (Name in Atlas: vector_index_agent_description, or as defined in SmartAgentBus.py).
      • Ensure the numDimensions in your index definitions match your embedding model’s output (e.g., 1536 for text-embedding-3-small).
    3. Environment Variables:
      • Copy .env.example to .env.
      • Edit .env and add your MONGODB_URI and MONGODB_DATABASE_NAME.
        MONGODB_URI="your_mongodb_srv_connection_string"
        MONGODB_DATABASE_NAME="evolving_agents_db"

    Quick Start

    1. Setup Environment (after MongoDB setup):

    # Ensure .env is configured with your OpenAI API Key and MongoDB URI
    # nano .env OR use your preferred editor
    
    # Optionally enable Intent Review:
    # INTENT_REVIEW_ENABLED=true
    # INTENT_REVIEW_LEVELS=design,components,intents

    Configure other settings like LLM_MODEL, LLM_EMBEDDING_MODEL if needed.

    2. Run the Comprehensive Demo:

    The architect_zero_comprehensive_demo.py script showcases the SystemAgent orchestrating a complex task (invoice processing) using the MongoDB backend. It demonstrates component discovery, potential creation/evolution, and execution. If INTENT_REVIEW_ENABLED=true and the intents level is active, it will pause for human review with intent plans stored in MongoDB.

    python examples/invoice_processing/architect_zero_comprehensive_demo.py

    3. Explore Output:

    After the demo runs:

    • final_processing_output.json: Contains the final structured JSON result from the SystemAgent. (This remains file-based as it’s a direct output of the demo).
    • MongoDB Collections:
      • eat_components: Stores SmartLibrary records (agents, tools, firmware) including their embeddings.
      • eat_agent_registry: Stores SmartAgentBus agent registrations.
      • eat_agent_bus_logs: Stores logs of agent interactions via the bus.
      • eat_llm_cache: Stores cached LLM responses and embeddings (if cache enabled).
      • eat_intent_plans (if review enabled for ‘intents’ level): Stores IntentPlan objects.
      • You can inspect these collections using MongoDB Compass, mongosh, or your MongoDB Atlas Data Explorer.
    • intent_plan_demo.json (If review enabled for ‘intents’ level and output_path in ApprovePlanTool is set): An optional file copy of the generated intent plan that was reviewed.

    (Note: All examples in the examples/ directory have been updated to use the MongoDB backend. The test suite is currently being updated.)

    Dive Deeper

    • Architecture Overview: Understand the core components and their interactions in docs/ARCHITECTURE.md (updated for MongoDB).
    • MongoDB Setup: Detailed guide for setting up MongoDB and Atlas Vector Search: docs/MONGO-SETUP.md.
    • Key Concepts: Learn about the SystemAgent, SmartLibrary (MongoDB), SmartAgentBus (MongoDB), SmartContext, Evolution, Workflows, and Intent Review / Human-in-the-Loop (IntentPlans in MongoDB).
    • Examples: Explore the examples/ directory. All examples have been updated to reflect MongoDB integration.
    • Contributing: We welcome contributions!

    Roadmap / Future Work

    • Test Suite Migration: Update all tests in tests/ to work with MongoDB, potentially using mongomock for unit tests.
    • Circuit Breaker to MongoDB: Migrate SmartAgentBus circuit breaker state from JSON file to MongoDB for unified persistence.
    • Enhanced Vector Search Strategies: Explore more advanced MongoDB $vectorSearch options, such as hybrid search (combining vector and keyword search) within SmartLibrary.
    • Enhanced SmartContext: Further develop SmartContext for more sophisticated contextual data passing and retrieval.
    • UI Integration: Develop a basic UI for interacting with the SystemAgent and visualizing the ecosystem.

    License

    This project is licensed under the Apache License Version 2.0. See the LICENSE file for details.


    🚀 Project Status & Smart Memory Integration Update! 🧠

    We are excited to announce that the core Smart Memory architecture, a key feature for enhancing autonomous learning and contextual understanding in EAT, has been integrated into the main branch!

    • Core Smart Memory Components Integrated:

      • The MemoryManagerAgent is now part of the toolkit, responsible for orchestrating memory operations.
      • Internal tools for MemoryManagerAgent (MongoExperienceStoreTool, SemanticExperienceSearchTool, MessageSummarizationTool) are implemented and use the MongoDB backend.
      • SystemAgent is now equipped with ContextBuilderTool and ExperienceRecorderTool to interact with the Smart Memory system via the SmartAgentBus.
      • The MongoDB schema for eat_agent_experiences is defined (eat_agent_experiences_schema.md) and the necessary Vector Search Index (vector_index_experiences_default) should be created as per docs/MONGO-SETUP.md.
    • Current Example Status:

      • ✅ The comprehensive demo examples/invoice_processing/architect_zero_comprehensive_demo.py has been updated and successfully demonstrates the initialization of Smart Memory components and the SystemAgent‘s new memory-related tools. While this demo doesn’t yet deeply exercise the full feedback loop of Smart Memory influencing SystemAgent‘s choices in complex ways, it verifies the integration.
      • Other Examples & Deeper Integration:
        • The remaining examples in the examples/ directory are pending updates to fully leverage and showcase the Smart Memory capabilities.
        • The scripts/test_smart_memory.py script is specifically designed for focused testing of the Smart Memory system and should be working with the MongoDB backend.
        • We are actively working on updating all examples and creating new ones that clearly demonstrate how Smart Memory:
          • Enhances SystemAgent‘s problem-solving by providing rich historical context.
          • Informs and improves the component evolution process.
    • ⚠️ Important Note for Users & Testers:

      • While the core Smart Memory infrastructure is in place and integrated with MongoDB, the full potential of this feature will be best realized as more examples are updated and as the SystemAgent‘s ReAct logic becomes more sophisticated in its use of the memory tools.
      • For now, when running examples other than architect_zero_comprehensive_demo.py or scripts/test_smart_memory.py, Smart Memory features might not be actively utilized or demonstrated.
    • Coming Soon:

      • Updates to all example scripts to showcase various aspects of Smart Memory interaction.
      • More detailed demonstrations of how SystemAgent uses ContextBuilderTool for informed planning and ExperienceRecorderTool for learning.
      • Examples of how EvolutionStrategistAgent might leverage Smart Memory for more targeted evolution suggestions.

    We appreciate your patience as we roll out these powerful enhancements across the entire toolkit. The move to MongoDB and the integration of Smart Memory are significant steps towards achieving truly autonomous and self-improving AI agent systems with EAT. Please refer to docs/ARCHITECTURE.md for the updated system design including Smart Memory.


    Acknowledgements

    • Leverages concepts and the core ReAct agent from the BeeAI Framework.
    • Integrates with the OpenAI Agents SDK via providers and adapters.
    • Now uses MongoDB and MongoDB Atlas Vector Search as the primary data store and for semantic search.
    • Uses LiteLLM (via BeeAI) for broader LLM compatibility.
    • Original Concept Contributors: Matias Molinas and Ismael Faro.
    Visit original content creator repository https://github.com/matiasmolinas/evolving-agents
  • e107-importer

    === e107 Importer ===
    Contributors: Coolkevman
    Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=XEXREDEHXSQUJ
    Tags: importer, e107, cms, migration, bbPress
    Requires at least: 3.1
    Tested up to: 3.2
    Stable tag: 1.4
    License: GPLv2
    
    e107 import plugin for WordPress.
    
    == Description ==
    
    This plugin allows you to extract the most important content and data from an e107 CMS instance and import them into your WordPress blog.
    
    **Features**:
    
    * Import news (both body and extended parts).
    * Import news categories.
    * Import custom pages (and take care of their private / public visibility).
    * Import comments (both from news and custom pages).
    * Import forums and threads to bbPress.
    * Import images embedded in HTML as attachments.
    * Let you choose which kind of images you want to upload to WordPress (external or not).
    * Import preferences (site name, description, ...).
    * Import new users and their profile (or update existing users).
    * Send new credentials to users by mail.
    * Try to map users to an appropriate role.
    * Convert embedded BBCode to plain HTML.
    * Clean-up HTML to align it with what WordPress produce by default.
    * Redirect old e107 news, pages, users, forums, threads and feeds URLs to new WordPress content via an integrated plugin (for SEO).
    * Replace old e107 URLs in content by new WordPress permalinks.
    
    This tool was tested with:
    
    * [e107 0.7.25](http://e107.org/news.php?item.880),
    * [WordPress 3.2-RC3](http://wordpress.org/news/2011/06/wordpress-3-1-4/) and
    * [bbPress 2.0-beta-3b](http://bbpress.org/blog/2011/06/bbpress-2-0-beta-3/)
    
    If you have any older versions, please upgrade first.
    
    == Installation ==
    
    1. Upload the `e107-importer` folder to the `/wp-content/plugins/` directory
    1. Activate the plugin through the 'Plugins' menu in WordPress
    1. Go to the Tools -> Import screen, Click on e107
    
    == Frequently Asked Questions ==
    
    = What is the status of this plugin ? =
    
    This plugin is **not in activate development**.
    
    As I succeeded in moving to WordPress all my old e107 sites, I have no longer interest of maintaining this plugin. But I'll still integrate code other developers are willing to contribute.
    
    = How can I know the import process finished well ? =
    
    The only way you can tell is by having the "Finished !"https://github.com/"Have fun !" message at the end of the import report. If not, it means the import process didn't had enough time to finish or encountered an error.
    
    = Why the import process failed, or did not end well ? =
    
    While importing content from e107, you may encounter one of the following error:
    
    * *Internal Server Error*
    * *MySQL has gone away*
    * *PHP Fatal error: Maximum execution time exceeded*
    * or not at all ([like the issue described here](http://github.com/kdeldycke/e107-importer/issues/5))
    
    These means that the script has failed one way or another.
    
    Generally, this is due to constraints set by your hosting provider, limiting the execution time of PHP scripts. This issue affect all scripts consuming lots of CPU and memory resources, like all import scripts. The timeout can come from MySQL, Apache or PHP.
    
    The issue and [solutions are detailed in WordPress FAQ](http://codex.wordpress.org/FAQ_Working_with_WordPress#How_do_I_Import_a_WordPress_WXR_file_when_it_says_it_is_too_large_to_import.3F), please read this article before complaining to me.
    
    = How long this plugin takes to import content ? =
    
    Importing big forums takes a lot of time. For example, on my 4-cores 1.5GHz laptop, it takes more than an hour to import a forum with 18000+ replies. That's expected as I didn't designed this plugin for performances: it doesn't make sense to spend time working on performance for a plugin you'll only use once in the life of your WordPress site.
    
    = Can I import content step by step ? =
    
    Yes, you can. I designed this plugin to let you have the opportunity to import one kind of content at a time. So you should be able to import news first, then re-run the importer process to only import pages, then do it again for forums and so on...
    
    = Why accents in my imported content are replaced by strange characters ? =
    
    Looks like you have some kind of Unicode transcoding errors. Before running e107 Importer, your e107 site must be fully encoded in UTF-8. If it's not the case, please have a look at the [*Upgrading database content to UTF-8*](http://wiki.e107.org/?title=Upgrading_database_content_to_UTF8) article on e107 wiki.
    
    = Can you add import of e107 forums to BuddyPress and bbPress 1.x ? =
    
    This plugin currently import forums to bbPress. But [the brand new 2.x plugin version](http://wordpress.org/extend/plugins/bbpress/), not the legacy standalone 1.x version. As for [BuddyPress](http://buddypress.org/) forums, they are [planed to be replaced](http://bbpress.org/blog/2011/05/bbpress-2-0-beta-1/) by a future version of the new 2.x bbPress.
    
    So as you can see, there is no need to add specific support of the these forums. You just have to be patient.
    
    = Why profanities show up in imported content ? =
    
    This plugin ignore the configuration of the profanity filter from e107. If you want to hide words, it should be done by a dedicated WordPress plug-in. As [suggested by Jon Freger](http://kevin.deldycke.com/2006/11/wordpress-to-e107-v06-better-content-rendering-and-extended-news-support/#comment-2937), you can use the [WebPurify plugin](http://wordpress.org/extend/plugins/webpurifytextreplace).
    
    = Why links generated by e107's Linkwords plugin are not preserved ? =
    
    This plugin disable all extra HTML rendering hooks added by e107 plugins. Which means Linkwords plugin will be ignored while rendering imported content. So as for profanities (see above), you have to use a third-party WordPress plugin to apply Linkwords-like transformations to your imported content.
    
    = Can I give you money to fix my problem ? =
    
    That's nice from you to propose a donation but quite frankly, money is not the kind of incentives that will push the development of my plugins. But code, bug reports and testing is the kind of contributions I'm looking for. In fact getting rid of my old e107 instances is the best motivator I have. But by popular demand, here is my [donation link](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=XEXREDEHXSQUJ) anyway...
    
    = Where can I report bugs ? =
    
    Bug reports and feature requests must be done via [GitHub's ticket system](http://github.com/kdeldycke/e107-importer/issues).
    
    = Can I update the plugin ? =
    
    That's nice from you to propose to update it. All contributions are welcome ! I'll be happy to apply all your patches in the original code to let anyone benefits your work. Even after I will declare this plugin dead.
    
    = How can I contribute code ? =
    
    Feel free to send me patches and code by mail. Or better yet, use GitHub fork/merge features.
    
    = Where can I find the source code ? =
    
    Development of this plugin happen in a [dedicated GitHub repository](http://github.com/kdeldycke/e107-importer). The latter is the official repository of this plugin. All developments are done there. This repository is the reference repository.
    
    FYI, this plugin is [also hosted on WordPress plugins' Subversion](http://plugins.svn.wordpress.org/e107-importer), but this repository is just a copy of GitHub's. **No original development should be performed in the Subversion repository**: changes made there will be ignored and deleted if not mirrored in the GitHub repository.
    
    == Screenshots ==
    
    1. e107 Importer options. (e107-importer 1.3)
    
    == Tested with... ==
    
    Here is a list of e107 and WordPress versions I tested my plugin with:
    
    * e107-importer 1.5.dev : Not tested yet.
    * e107-importer 1.4 : e107 0.7.25 / WordPress 3.2-RC3 / bbPress 2.0-beta-3b
    * e107-importer 1.3 : e107 0.7.25 / WordPress 3.1.2 / bbPress plugin SVN r3113
    * e107-importer 1.2 : e107 0.7.25-rc1 / WordPress 3.1 / bbPress plugin SVN r2992
    * e107-importer 1.1 : e107 0.7.24 / WordPress 3.1 / bbPress plugin SVN r2942
    * e107-importer 1.0 : e107 0.7.24 / WordPress 3.1-RC3
    * e107-importer 0.9 : e107 0.7.11 / WordPress 2.3.2
    * e107-importer 0.8 : e107 0.7.8  / WordPress 2.1.3
    * e107-importer 0.7 : e107 0.7.8  / WordPress 2.1.2
    * e107-importer 0.6 : e107 0.7.6  / WordPress 2.0.5
    * e107-importer 0.5 : e107 0.7.5  / WordPress 2.0.5
    * e107-importer 0.4 : e107 0.7.5  / WordPress 2.0.4
    * e107-importer 0.3 : e107 0.7.5  / WordPress 2.0.4
    
    == Copyright notice ==
    
    This plugin contain original code from the e107 project, licensed under the GPL.
    
    == Changelog ==
    
    = 1.5.dev =
    * Check that the site URL we get from e107 preferences is set properly.
    
    = 1.4 =
    * Declare this plugin as unmaintained.
    * Based on the official bbPress 2.0-beta-3b release.
    * Reuse already imported content.
    * Fix BBCode's quote tag transformation by enhanced parser.
    
    = 1.3 =
    * Upgrade embedded e107 code with latest 0.7.25.
    * Redirect imported images to attachments.
    * Purge invalid mapping entries on import.
    * Replace old e107 URLs in content by new WordPress permalinks.
    * Allow both imported and already-existing content to by updated with new permalinks.
    * Let user specify the list of e107 forums to import.
    * Phased imports should work without major problems.
    
    = 1.2 =
    * Upgrade e107 code to match latest 0.7.25-rc1.
    * Fix variable bleeding when importing items in batches.
    * Add a new way of handling e107 extended news using WordPress' excerpts.
    * Parse BBCode and replace e107 constants in news excerpt.
    * Use internal WordPress library (kses) to parse HTML in the image upload step.
    * Do not upload the same images more than once.
    * Add a new enhanced BBCode parser on top of the one from e107. Make it the default parser.
    * Each time we alter the original imported content, we create a post revision.
    
    = 1.1 =
    * Add import of forums and threads to bbPress WordPress plugin.
    * Parse BBCode and e107 constants in forums and thread.
    * Add forums and threads redirections.
    * Make e107 user import optional. This needs you to set a pre-existing WordPress user that will take ownership of all imported content.
    * Parse BBCode in titles too.
    * Import images embedded in comments and forum threads.
    * Description update of existing users is no longer destructive.
    * Add an entry in the FAQ regarding script ending prematurely.
    * Disable all extra HTML rendering hooks like the one coming from e107 linkwords plugin.
    * Allow news and pages import to be skipped.
    * Add missing news category redirects.
    * Minimal requirement set to WordPress 3.1.
    * Some pages are not tied to a user. In this case, default to the current user.
    
    = 1.0 =
    * Upgrade e107 code from e107 v0.7.24.
    * Minimal requirement set to WordPress 3.0.0.
    * Use new WordPress importer framework.
    * Add an e107 to WordPress 301 redirector plugin (support news, pages, users and feeds).
    * Disable the URL rewriting feature introduced in v0.9.
    * Make image import optional.
    * Add an option to upload images from allowed domains only.
    * Align naming conventions with other WordPress importer.
    * Add a complete WordPress plugin hosting compatible readme file with full metadatas.
    * Add screenshots.
    * List all versions of e107 and WordPress I tested this plugin with.
    * Add a PayPal donation link.
    * Add a minimal FAQ.
    * Add an overview of features in description.
    * Update source code repository location.
    * Remove patching of Kubrick theme to support comments on static pages.
    
    = 0.9 =
    * "One-click migration" instead of multiple step process (more user-friendly).
    * Better error management (a must-have for precise bug reports).
    * Replace all links to old content with permalinks (increased SEO).
    * Better database management.
    * Code cleaned up.
    
    = 0.8 =
    * Import images embedded in e107 news and custom pages.
    * Import e107 site preferences.
    * Better import of user profile data.
    * An existing user on the blog can be detected and updated automatically.
    * Fix the profanity filter bug.
    
    = 0.7 =
    * Import e107 news categories.
    * Mails can be sent to each user to warn them about their new password.
    * Static pages can be set as private.
    * Simplify the import process.
    * Some little UI improvements.
    
    = 0.6 =
    * Render content according user's preferences.
    * Take care of extended news.
    
    = 0.5 =
    * Add import of static pages.
    
    = 0.4 =
    * Fix lots of bugs, especially due to non-escaped SQL queries.
    * Import news comments and link them to users.
    
    = 0.3 =
    * Import all users and associate them with their posts.
    
    = 0.2 =
    * Add BBCode support to news content.
    
    = 0.1 =
    * First draft of e107 to WordPress importer.
    
    == Upgrade Notice ==
    = 1.4 =
    Based on official bbPress 2.0-beta-1 release.
    
    = 1.3 =
    Upgraded against e107 0.7.25. Replace old e107 URLs by permalinks in content. Allow phased import.
    
    = 1.2 =
    Upgraded against e107 0.7.25-rc1. Add new enhanced BBCode parser.
    
    = 1.1 =
    Add import of forums and threads. User, news and pages import now optional.
    
    = 1.0 =
    First release compatible with the WordPress 3.x series.
    

    Visit original content creator repository
    https://github.com/kdeldycke/e107-importer