"Fossies" - the Fresh Open Source Software Archive

Member "cutter-1.10.3/src/widgets/HexWidget.h" (8 May 2020, 14235 Bytes) of package /linux/privat/cutter-1.10.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "HexWidget.h" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.10.2_vs_1.10.3.

    1 #ifndef HEXWIDGET_H
    2 #define HEXWIDGET_H
    3 
    4 #include "Cutter.h"
    5 #include "dialogs/HexdumpRangeDialog.h"
    6 #include "common/IOModesController.h"
    7 
    8 #include <QScrollArea>
    9 #include <QTimer>
   10 #include <QMenu>
   11 #include <memory>
   12 
   13 struct BasicCursor
   14 {
   15     uint64_t address;
   16     bool pastEnd;
   17     BasicCursor(uint64_t pos) : address(pos), pastEnd(false) {}
   18     BasicCursor() : address(0), pastEnd(false) {}
   19     BasicCursor &operator+=(int64_t offset)
   20     {
   21         if (offset < 0 && uint64_t(-offset) > address) {
   22             address = 0;
   23             pastEnd = false;
   24         } else if (offset > 0 && uint64_t(offset) > (UINT64_MAX - address)) {
   25             address = UINT64_MAX;
   26             pastEnd = true;
   27         } else {
   28             address += uint64_t(offset);
   29             pastEnd = false;
   30         }
   31         return *this;
   32     }
   33     BasicCursor &operator+=(int offset)
   34     {
   35         *this += int64_t(offset);
   36         return *this;
   37     }
   38     BasicCursor &operator+=(uint64_t offset)
   39     {
   40         if (uint64_t(offset) > (UINT64_MAX - address)) {
   41             address = UINT64_MAX;
   42             pastEnd = true;
   43         } else {
   44             address += offset;
   45             pastEnd = false;
   46         }
   47         return *this;
   48     }
   49     bool operator<(const BasicCursor &r)
   50     {
   51         return  address < r.address || (pastEnd < r.pastEnd);
   52     }
   53 };
   54 
   55 struct HexCursor
   56 {
   57     HexCursor() { isVisible = false; onAsciiArea = false; }
   58 
   59     bool isVisible;
   60     bool onAsciiArea;
   61     QTimer blinkTimer;
   62     QRectF screenPos;
   63     uint64_t address;
   64     QString cachedChar;
   65     QColor cachedColor;
   66 
   67     void blink() { isVisible = !isVisible; }
   68     void setBlinkPeriod(int msec) { blinkTimer.setInterval(msec / 2); }
   69     void startBlinking() { blinkTimer.start(); }
   70     void stopBlinking() { blinkTimer.stop(); }
   71 };
   72 
   73 class AbstractData
   74 {
   75 public:
   76     virtual ~AbstractData() {}
   77     virtual void fetch(uint64_t addr, int len) = 0;
   78     virtual bool copy(void *out, uint64_t adr, size_t len) = 0;
   79     virtual uint64_t maxIndex() = 0;
   80     virtual uint64_t minIndex() = 0;
   81 };
   82 
   83 class BufferData : public AbstractData
   84 {
   85 public:
   86     BufferData()
   87     {
   88         m_buffer.fill(0, 1);
   89     }
   90 
   91     BufferData(const QByteArray &buffer)
   92     {
   93         if (buffer.isEmpty()) {
   94             m_buffer.fill(0, 1);
   95         } else {
   96             m_buffer = buffer;
   97         }
   98     }
   99 
  100     ~BufferData() override {}
  101 
  102     void fetch(uint64_t, int) override { }
  103 
  104     bool copy(void *out, uint64_t addr, size_t len) override {
  105         if (addr < static_cast<uint64_t>(m_buffer.size()) && (static_cast<uint64_t>(m_buffer.size()) - addr) < len) {
  106             memcpy(out, m_buffer.constData() + addr, len);
  107             return true;
  108         }
  109         return false;
  110     }
  111 
  112     uint64_t maxIndex() override
  113     {
  114         return m_buffer.size() - 1;
  115     }
  116 
  117 private:
  118     QByteArray m_buffer;
  119 };
  120 
  121 class MemoryData : public AbstractData
  122 {
  123 public:
  124     MemoryData() {}
  125     ~MemoryData() override {}
  126     static constexpr size_t BLOCK_SIZE = 4096;
  127 
  128     void fetch(uint64_t address, int length) override
  129     {
  130         // FIXME: reuse data if possible
  131         const uint64_t blockSize = 0x1000ULL;
  132         uint64_t alignedAddr = address & ~(blockSize - 1);
  133         int offset = address - alignedAddr;
  134         int len = (offset + length + (blockSize - 1)) & ~(blockSize - 1);
  135         m_firstBlockAddr = alignedAddr;
  136         m_lastValidAddr = length ? alignedAddr + len - 1 : 0;
  137         if (m_lastValidAddr < m_firstBlockAddr) {
  138             m_lastValidAddr = -1;
  139             len = m_lastValidAddr - m_firstBlockAddr + 1;
  140         }
  141         m_blocks.clear();
  142         uint64_t addr = alignedAddr;
  143         for (ut64 i = 0; i < len / blockSize; ++i, addr += blockSize) {
  144             m_blocks.append(Core()->ioRead(addr, blockSize));
  145         }
  146     }
  147 
  148     bool copy(void *out, uint64_t addr, size_t len) override {
  149         if (addr < m_firstBlockAddr || addr > m_lastValidAddr ||
  150                 (m_lastValidAddr - addr + 1) < len /* do not merge with last check to handle overflows */) {
  151             return false;
  152         }
  153 
  154         int totalOffset = addr - m_firstBlockAddr;
  155         int blockId = totalOffset / BLOCK_SIZE;
  156         int blockOffset = totalOffset % BLOCK_SIZE;
  157         size_t first_part = BLOCK_SIZE - blockOffset;
  158         if (first_part >= len) {
  159             memcpy(out, m_blocks.at(blockId).constData() + blockOffset, len);
  160         } else {
  161             memcpy(out, m_blocks.at(blockId).constData() + blockOffset, first_part);
  162             memcpy(static_cast<char*>(out) + first_part, m_blocks.at(blockId + 1).constData(), len - first_part);
  163         }
  164         return true;
  165     }
  166 
  167     virtual uint64_t maxIndex() override
  168     {
  169         return m_lastValidAddr;
  170     }
  171 
  172     virtual uint64_t minIndex() override
  173     {
  174         return m_firstBlockAddr;
  175     }
  176 
  177 private:
  178     QVector<QByteArray> m_blocks;
  179     uint64_t m_firstBlockAddr = 0;
  180     uint64_t m_lastValidAddr = 0;
  181 };
  182 
  183 class HexSelection
  184 {
  185 public:
  186     HexSelection() { m_empty = true; }
  187 
  188     inline void init(BasicCursor addr)
  189     {
  190         m_empty = true;
  191         m_init = addr;
  192     }
  193 
  194     void set(uint64_t start, uint64_t end)
  195     {
  196         m_empty = false;
  197         m_init = m_start = start;
  198         m_end = end;
  199     }
  200 
  201     void update(BasicCursor addr)
  202     {
  203         m_empty = false;
  204         if (m_init < addr) {
  205             m_start = m_init.address;
  206             m_end = addr.address;
  207             if (!addr.pastEnd)
  208                 m_end -= 1;
  209         } else if (addr < m_init) {
  210             m_start = addr.address;
  211             m_end = m_init.address;
  212             if (!m_init.pastEnd)
  213                 m_end -= 1;
  214         } else {
  215             m_start = m_end = m_init.address;
  216             m_empty = true;
  217         }
  218     }
  219 
  220     bool intersects(uint64_t start, uint64_t end)
  221     {
  222         return !m_empty && m_end >= start && m_start <= end;
  223     }
  224 
  225     bool contains(uint64_t pos) const
  226     {
  227         return !m_empty && m_start <= pos && pos <= m_end;
  228     }
  229 
  230     uint64_t size()
  231     {
  232         uint64_t size = 0;
  233         if (!isEmpty())
  234             size = m_end - m_start + 1;
  235         return size;
  236     }
  237 
  238     inline bool isEmpty() { return m_empty; }
  239     inline uint64_t start() { return m_start; }
  240     inline uint64_t end() { return m_end; }
  241 
  242 private:
  243     BasicCursor m_init;
  244     uint64_t m_start;
  245     uint64_t m_end;
  246     bool m_empty;
  247 };
  248 
  249 class HexWidget : public QScrollArea
  250 {
  251     Q_OBJECT
  252 
  253 public:
  254     explicit HexWidget(QWidget *parent = nullptr);
  255     ~HexWidget();
  256 
  257     void setMonospaceFont(const QFont &font);
  258 
  259     enum AddrWidth { AddrWidth32 = 8, AddrWidth64 = 16 };
  260     enum ItemSize { ItemSizeByte = 1, ItemSizeWord = 2, ItemSizeDword = 4, ItemSizeQword = 8 };
  261     enum ItemFormat { ItemFormatHex, ItemFormatOct, ItemFormatDec, ItemFormatSignedDec, ItemFormatFloat };
  262     enum class ColumnMode { Fixed, PowerOf2 };
  263 
  264     void setItemSize(int nbytes);
  265     void setItemFormat(ItemFormat format);
  266     void setItemEndianess(bool bigEndian);
  267     void setItemGroupSize(int size);
  268     /**
  269      * @brief Sets line size in bytes.
  270      * Changes column mode to fixed. Command can be rejected if current item format is bigger than requested size.
  271      * @param bytes line size in bytes.
  272      */
  273     void setFixedLineSize(int bytes);
  274     void setColumnMode(ColumnMode mode);
  275 
  276     /**
  277      * @brief Select non empty inclusive range [start; end]
  278      * @param start
  279      * @param end
  280      */
  281     void selectRange(RVA start, RVA end);
  282     void clearSelection();
  283 
  284     struct Selection {
  285         bool empty;
  286         RVA startAddress;
  287         RVA endAddress;
  288     };
  289     Selection getSelection();
  290 public slots:
  291     void seek(uint64_t address);
  292     void refresh();
  293     void updateColors();
  294 signals:
  295     void selectionChanged(Selection selection);
  296     void positionChanged(RVA start);
  297 
  298 protected:
  299     void paintEvent(QPaintEvent *event) override;
  300     void resizeEvent(QResizeEvent *event) override;
  301     void mouseMoveEvent(QMouseEvent *event) override;
  302     void mousePressEvent(QMouseEvent *event) override;
  303     void mouseReleaseEvent(QMouseEvent *event) override;
  304     void wheelEvent(QWheelEvent *event) override;
  305     void keyPressEvent(QKeyEvent *event) override;
  306     void contextMenuEvent(QContextMenuEvent *event) override;
  307 
  308 private slots:
  309     void onCursorBlinked();
  310     void onHexPairsModeEnabled(bool enable);
  311     void copy();
  312     void copyAddress();
  313     void onRangeDialogAccepted();
  314 
  315     // Write command slots
  316     void w_writeString();
  317     void w_increaseDecrease();
  318     void w_writeZeros();
  319     void w_write64();
  320     void w_writeRandom();
  321     void w_duplFromOffset();
  322     void w_writePascalString();
  323     void w_writeWideString();
  324     void w_writeCString();
  325 
  326 private:
  327     void updateItemLength();
  328     void updateCounts();
  329     void drawHeader(QPainter &painter);
  330     void drawCursor(QPainter &painter, bool shadow = false);
  331     void drawAddrArea(QPainter &painter);
  332     void drawItemArea(QPainter &painter);
  333     void drawAsciiArea(QPainter &painter);
  334     void fillSelectionBackground(QPainter &painter, bool ascii = false);
  335     void updateMetrics();
  336     void updateAreasPosition();
  337     void updateAreasHeight();
  338     void moveCursor(int offset, bool select = false);
  339     void setCursorAddr(BasicCursor addr, bool select = false);
  340     void updateCursorMeta();
  341     void setCursorOnAscii(bool ascii);
  342     bool isItemDifferentAt(uint64_t address);
  343     const QColor itemColor(uint8_t byte);
  344     QVariant readItem(int offset, QColor *color = nullptr);
  345     QString renderItem(int offset, QColor *color = nullptr);
  346     QChar renderAscii(int offset, QColor *color = nullptr);
  347     QString getFlagsAndComment(uint64_t address);
  348     /**
  349      * @brief Get the location on which operations such as Writing should apply.
  350      * @return Start of selection if multiple bytes are selected. Otherwise, the curren seek of the widget.
  351      */
  352     RVA getLocationAddress();
  353 
  354     void fetchData();
  355     /**
  356      * @brief Convert mouse position to address.
  357      * @param point mouse position in widget
  358      * @param middle start next position from middle of symbol. Use middle=true for vertical cursror position between symbols,
  359      * middle=false for insert mode cursor and getting symbol under cursor.
  360      * @return
  361      */
  362     BasicCursor screenPosToAddr(const QPoint &point, bool middle = false) const;
  363     BasicCursor asciiPosToAddr(const QPoint &point, bool middle = false) const;
  364     BasicCursor currentAreaPosToAddr(const QPoint &point, bool middle = false) const;
  365     BasicCursor mousePosToAddr(const QPoint &point, bool middle = false) const;
  366     /**
  367      * @brief Rectangle for single item in data area.
  368      * @param offset relative to first byte on screen
  369      * @return
  370      */
  371     QRectF itemRectangle(int offset);
  372     /**
  373      * @brief Rectangle for single item in ascii area.
  374      * @param offset relative to first byte on screen
  375      * @return
  376      */
  377     QRectF asciiRectangle(int offset);
  378     QVector<QPolygonF> rangePolygons(RVA start, RVA last, bool ascii);
  379     void updateWidth();
  380 
  381     inline qreal itemWidth() const
  382     {
  383         return itemCharLen * charWidth;
  384     }
  385 
  386     inline int itemGroupCharLen() const
  387     {
  388         return itemCharLen * itemGroupSize;
  389     }
  390 
  391     inline int columnExCharLen() const
  392     {
  393         return itemGroupCharLen() + columnSpacing;
  394     }
  395 
  396     inline int itemGroupByteLen() const
  397     {
  398         return itemByteLen * itemGroupSize;
  399     }
  400 
  401     inline qreal columnWidth() const
  402     {
  403         return itemGroupCharLen() * charWidth;
  404     }
  405 
  406     inline qreal columnExWidth() const
  407     {
  408         return columnExCharLen() * charWidth;
  409     }
  410 
  411     inline qreal columnSpacingWidth() const
  412     {
  413         return columnSpacing * charWidth;
  414     }
  415 
  416     inline int itemRowCharLen() const
  417     {
  418         return itemColumns * columnExCharLen() - columnSpacing;
  419     }
  420 
  421     inline int itemRowByteLen() const
  422     {
  423         return rowSizeBytes;
  424     }
  425 
  426     inline int bytesPerScreen() const
  427     {
  428         return itemRowByteLen() * visibleLines;
  429     }
  430 
  431     inline qreal itemRowWidth() const
  432     {
  433         return itemRowCharLen() * charWidth;
  434     }
  435 
  436     inline qreal asciiRowWidth() const
  437     {
  438         return itemRowByteLen() * charWidth;
  439     }
  440 
  441     inline qreal areaSpacingWidth() const
  442     {
  443         return areaSpacing * charWidth;
  444     }
  445 
  446     inline uint64_t lastVisibleAddr() const
  447     {
  448         return (startAddress - 1) + bytesPerScreen();
  449     }
  450 
  451     const QRectF &currentArea() const
  452     {
  453         return cursorOnAscii ? asciiArea : itemArea;
  454     }
  455 
  456     bool cursorEnabled;
  457     bool cursorOnAscii;
  458     HexCursor cursor;
  459     HexCursor shadowCursor;
  460 
  461     HexSelection selection;
  462     bool updatingSelection;
  463 
  464     QRectF addrArea;
  465     QRectF itemArea;
  466     QRectF asciiArea;
  467 
  468     int itemByteLen = 1;
  469     int itemGroupSize = 1; ///< Items per group (default: 1), 2 in case of hexpair mode
  470     int rowSizeBytes = 16; ///< Line size in bytes
  471     int itemColumns = 16; ///< Number of columns, single column consists of itemGroupSize items
  472     int itemCharLen = 2;
  473     int itemPrefixLen = 0;
  474     ColumnMode columnMode;
  475 
  476     ItemFormat itemFormat;
  477 
  478     bool itemBigEndian;
  479 
  480     int visibleLines;
  481     uint64_t startAddress;
  482     qreal charWidth;
  483     int byteWidth;
  484     qreal lineHeight;
  485     int addrCharLen;
  486     int addrAreaWidth;
  487     QFont monospaceFont;
  488 
  489     bool showHeader;
  490     bool showAscii;
  491     bool showExHex;
  492     bool showExAddr;
  493 
  494     QColor borderColor;
  495     QColor backgroundColor;
  496     QColor defColor;
  497     QColor addrColor;
  498     QColor diffColor;
  499     QColor b0x00Color;
  500     QColor b0x7fColor;
  501     QColor b0xffColor;
  502     QColor printableColor;
  503 
  504     HexdumpRangeDialog  rangeDialog;
  505 
  506     /* Spacings in characters */
  507     const int columnSpacing = 1;
  508     const int areaSpacing = 2;
  509 
  510     const QString hexPrefix = QStringLiteral("0x");
  511 
  512     QMenu* rowSizeMenu;
  513     QAction* actionRowSizePowerOf2;
  514     QList<QAction *> actionsItemSize;
  515     QList<QAction *> actionsItemFormat;
  516     QAction *actionItemBigEndian;
  517     QAction *actionHexPairs;
  518     QAction *actionCopy;
  519     QAction *actionCopyAddress;
  520     QAction *actionSelectRange;
  521     QList<QAction *> actionsWriteString;
  522     QList<QAction *> actionsWriteOther;
  523 
  524     std::unique_ptr<AbstractData> oldData;
  525     std::unique_ptr<AbstractData> data;
  526     IOModesController ioModesController;
  527 
  528 };
  529 
  530 #endif // HEXWIDGET_H