FedericoBoccaccioPersonale/Programmi-HexEditorView
GitHub: FedericoBoccaccioPersonale/Programmi-HexEditorView
Stars: 0 | Forks: 0
# Speciali\Hex Editor View (UserControl VB.NET 8) ✨👨💻 🇮🇹
https://federicoboccaccio.wordpress.com/hex-editor-view-vb-net-8/
# Download
[Ultima versione](https://github.com/FedericoBoccaccioPersonale/Programmi-HexEditorView/releases/latest)
# Attenzione
Puoi scaricare l' eseguibile per vedere come funzionerà ma questo è un esempio per lo user control.\
È un progetto per altri sviluppatori, non un programma usabile.
# Informazioni
Su GitHub c' è il repository principale, su GitLab è presente il suo clone per backup.
# 📚 Documentazione: HexEditorView - Visualizzatore esadecimale WinForms
## 1. Scopo e funzionalità attuali
Il componente `HexEditorView` è un controllo utente (UserControl) personalizzato per .NET Windows Forms. Il suo scopo è fornire una visualizzazione esadecimale e ASCII ad alte prestazioni per file di dati grezzi, destinato a integrarsi come modulo in un editor WinForms più ampio.\
Lo scopo ultimo sarà supplire alle limitazioni di ImHex (che non permette di fare quel che promette), ma in sostanza permette di analizzare e studiare file binari di formato sconosciuto, identificando i marcatori, quindi impostando cosa visualizzare, personalizzando questo programma base o integrandolo in uno più ampio.
**Funzionalità principali implementate:**
* **Visualizzazione a tre colonne logiche:** Offset formattato (es. `0000 00A4`), 16 colonne di byte esadecimali, e una colonna ASCII.
* **Motore Regex:** Evidenziazione automatica (colori di testo e sfondo personalizzabili) di specifiche sequenze di byte analizzate come testo ASCII, permettendo di individuare visivamente pattern o firme (es. "PMOC").
* **Selezione col mouse:** Selezione fluida tramite trascinamento (Drag) funzionante *esclusivamente* sulle celle dei dati esadecimali.
* **Modificare la selezione (Shift+Click):** Modifica intelligente di una selezione esistente avvicinando l' estremo logico più vicino al punto cliccato, mantenendo ancorato l' estremo opposto.
* **Controlli di selezione integrati:** Il controllo possiede ora un pannello inferiore autonomo con due `NumericUpDown` per impostare manualmente i byte di inizio e fine in esadecimale, senza dipendere da controlli esterni.
* **Barra di Stato (con decodifica):** Label informativa integrata che mostra in tempo reale la dimensione della selezione in decimale e in hex, gli offset di inizio e fine, e **decodifica automaticamente il valore intero senza segno (Little Endian)** se la selezione è compresa tra 1 e 8 byte. Questa funzione sarebbe da espandere, ma per ilmio scopo attuale è sufficiente.
* **Ricerca sequenze (`TrovaSequenza`):** Funzione integrata per cercare un array di byte partendo dall' attuale selezione e scorrendo automaticamente la visualizzazione fino al risultato.
* **Esportazione Zero-Allocation:** Evento pubblico `SelezioneModificata` che espone i dati selezionati tramite `ArraySegment(Of Byte)`, azzerando i costi di memoria per la copia degli array.
### Funzioni extra
## 2. Architettura e implementazione
Il controllo è basato su un controllo `DataGridView` nativo, pesantemente modificato e "blindato" per ottenere comportamenti da editor di basso livello:
* **Modalità Virtuale (Virtual Mode):** I dati non vengono caricati nelle celle fisiche. L' evento `CellValueNeeded` attinge direttamente all' array di byte caricato in memoria, permettendo al controllo di gestire array enormi senza latenza.
* **Pre-elaborazione Regex su Dizionario Sparso:** La ricerca delle espressioni regolari non avviene a runtime durante il ridisegno. Durante il caricamento, viene generato un `Dictionary(Of Integer, ByteFormatting)` chiamato `_colorMap`. Rispetto a un array parallelo, il dizionario alloca memoria solo per i byte che corrispondono effettivamente a un pattern, azzerando il consumo di RAM inutile. La scansione testuale è inoltra limitata a chunk di sicurezza (primi 10 MB) per prevenire saturazioni. Questo permette la ricerca anche se la stringa da cercare è su più righe.
* **Assegnazione atomica (Zero-Loop):** Modificare l' inizio e la fine della selezione avviene tramite un metodo unico `SetSelection(inizio, fine)`. Le vecchie property in scrittura sono state rimosse perché generavano trigger doppi e stati di memoria semanticamente errati.
* **Intercettazione del rendering (Custom Painting):** L'evento `CellPainting` scavalca il disegno standard. Disegna manualmente lo sfondo delle selezioni, i colori delle Regex e, soprattutto, renderizza i caratteri ASCII uno ad uno per assicurare il perfetto allineamento con il font monospace.
* **Blocco delle Dimensioni (UI Lockdown):** In base alla larghezza calcolata in pixel del font `Consolas` scelto, il codice forza matematicamente la larghezza delle colonne e blocca le proprietà `MinimumSize` e `MaximumSize` del controllo intero, impedendo che l'interfaccia si deformi.
* La proprietà **MappingMode** consente di scegliere come visualizzare i caratteri non ASCII di base (Strict, Extended, o ControlPictures Unicode).
## 3. Storico dei problemi e soluzioni
* **Problema:** *Sfarfallio visivo (Flickering) durante lo scrolling o il trascinamento della selezione.*
* **Soluzione:** Abilitata la proprietà `DoubleBuffered` sul DataGridView tramite *Reflection*, costringendo il controllo a disegnare prima in memoria e poi a schermo. Credo che l' obbligo di usare la Reflection sia un errore progettuale della piattaforma NET.
* **Problema:** *Selezione nativa visibile.* Il DataGridView evidenziava di default le celle cliccate (comprese colonne Offset e ASCII), creando confusione.
* **Soluzione:** Disattivata visivamente impostando `SelectionBackColor = Transparent`. Inoltre, l' evento `SelectionChanged` è stato intercettato per forzare un continuo `ClearSelection()`.
* **Problema:** *Testo sgranato o disallineato nella colonna ASCII.* Il sistema predefinito (`TextRenderer`) sfalsava i caratteri monospazio, e il rendering puro `Graphics.DrawString` funzionava bene su Windows 11 ma causava imprecisioni su Windows 10 🤮.
* **Soluzione:** Oltre a usare una struttura `StringFormat.GenericTypographic` rigorosa, è stata imposta la proprietà `TextRenderingHint.ClearTypeGridFit` sul motore grafico per forzare i pixel ad allinearsi perfettamente alla griglia dello schermo su qualsiasi OS. E comunque funziona male su widnows 10 🤮🤮🤮.
* **Problema:** *Artefatti visivi di testo sovrapposto.* Durante le selezioni rapide con Shift, alcuni byte sembravano in grassetto o sovrapposti.
* **Soluzione:** Inserita la chiamata esplicita `e.PaintBackground` nel custom painting, che forza il sistema a "pulire" la tela della singola cella prima di scriverci sopra il nuovo stato.
* **Problema:** *Contrazione errata della selezione con Shift+Click.* Cliccando all' interno o vicino a una selezione esistente, la logica spostava entrambi gli estremi sul byte cliccato.
* **Soluzione:** Ristrutturata la logica introducendo i concetti di **ancora** e **punto mobile**. Il programma ora calcola la distanza tra il click e i limiti della selezione: fissa come ancora l' estremo più lontano e usa il punto cliccato come nuovo Punto Mobile.
* **Problema:** Il DataGridView nasconde la scrollbar se non è necessaria, e questo lascia un odioso rettangolo vuoto sulla destra.\
Questo è un problema perché non ha alcuna proprietà ScrollBarsAlwaysVisible. Oltre ad altri strumenti di base.\
Dato che mi rifiuto di aggiungere un nuovo componente da sovrapporre a quello vero, dovrà restare così. Oltre al problema che se non ha sopra il mouse viene disegnata sottilissima.
* **Soluzione:** Ridisegnare nell'evento Paint una ScrollBar usando la classe nativa `ScrollBarRenderer`. Questo purtroppo non risolve la visualizzazione "moderna".
* **Problema:** *Loop infinito (StackOverflowException) modificando la selezione da UI esterne o interne.*
* **Soluzione:** L' aggiornamento simultaneo tra interfaccia (NumericUpDown) e backend generava ricorsione infinita. Risolto implementando una flag anti-loop `_isUpdatingUI` che disattiva temporaneamente gli eventi mentre i valori vengono sincronizzati.
* **Problema:** *Crash (Eccezione indice negativo) cancellando totalmente il file.* * **Soluzione:** Sostituendo i dati con una dimensione finale di 0, l' istruzione `Dim newData(-1)` mandava in crash il software. Inserita una guardia che cattura `newTotalLen = 0` e re-inizializza il controllo con un array vuoto (`New Byte() {}`) pulendo i metadati.
* **Problema:** *Esaurimento memoria (OutOfMemoryException) con file di 1GB a causa delle Regex.* Convertire 1GB di binario in una String e creare array paralleli saturava immediatamente la RAM.
* **Soluzione:** (Vedi sezione Architettura). Passaggio a un *Dizionario Sparso* per i colori e introduzione di un limite di sicurezza all' analisi testuale (`Math.Min(10MB)`).
## 4A. Manipolazione dei dati (con copia)
Il controllo `HexEditorView` è stato esteso per supportare non solo la visualizzazione, ma anche la manipolazione diretta della memoria virtuale (array di byte). Sono state introdotte funzioni sicure per estrarre e iniettare dati, gestendo dinamicamente le variazioni di dimensione del buffer principale.
**Metodi Implementati:**
* **`GetSelectedBytes() As Byte()`**
* **Scopo:** Estrae una copia indipendente della porzione di memoria attualmente evidenziata dalla selezione dell' utente.
* **Comportamento:** Utilizza `Array.Copy` per garantire la massima velocità. Non altera l'array originale in memoria. Se non c'è alcuna selezione attiva, restituisce un array vuoto (`Byte() {}`), evitando eccezioni per riferimenti nulli.
* **`ReplaceSelectedBytes(newBytes As Byte())`**
* **Scopo:** Sostituisce i dati evidenziati dalla selezione con un nuovo payload fornito come parametro. Supporta operazioni di overwrite (sovrascrittura), insert (inserimento) e delete (eliminazione/contrazione).
* **Comportamento (scenari gestiti automaticamente):**
* **Stessa lunghezza (overwrite):** Se il payload ha la stessa dimensione della selezione, esegue una copia sul posto `O(N)` senza riallocare l'array base, massimizzando le prestazioni.
* **Lunghezza Diversa (Insert/Shrink):** Se il payload è più grande o più piccolo, il metodo crea un nuovo buffer ricalcolando la dimensione totale (`Dimensione_Originale - Dimensione_Selezionata + Dimensione_Nuovi_Dati`), "incollando" le sezioni non modificate prima e dopo il blocco sostituito.
* Se la dimensione ricalcolata raggiunge `0`, svuota il controllo in sicurezza impedendo eccezioni relative a limiti di array negativi.
* **Gestione dello Stato Interno:** Dopo ogni operazione di rimpiazzo, il controllo aggiorna automaticamente la dimensione visiva del `DataGridView`, i limiti dei NumericUpDown, ricalcola l' intera mappa cromatica delle Regex, e adatta la selezione del mouse per avvolgere perfettamente i nuovi dati appena inseriti.
## 4B. Manipolazione dei dati (senza copia)
Il controllo `HexEditorView` supporta l' estrazione e l' iniezione sicura dei dati, mantenendo un'impronta di memoria ottimizzata e gestendo dinamicamente le variazioni di dimensione del buffer principale.
**Metodi Implementati:**
* **`GetSelectedBytesSenzaRiallocazione() As ArraySegment(Of Byte)`**
* **Scopo:** Fornisce un accesso diretto e in sola lettura alla porzione di memoria attualmente evidenziata.
* **Comportamento (Zero-Allocation):** Invece di creare un nuovo array in memoria e copiarvi i dati, restituisce una struttura `ArraySegment(Of Byte)`. Questo agisce come una "finestra" virtuale sul buffer di origine (`_fileData`), indicando il riferimento all' array base, l' offset di partenza e la lunghezza della selezione. Questo azzera totalmente i costi di memoria e i tempi di CPU durante l' estrazione dei dati. Se nessuna selezione è attiva, restituisce un segmento vuoto controllabile tramite la proprietà `.Count = 0`.
## 5. Ricerca Binaria (Trova)
Il controllo include un motore base di ricerca lineare per pattern binari.
* **`TrovaSequenza(pattern As Byte())`**
* **Scopo:** Localizza una sequenza specifica di byte partendo dalla fine della selezione attuale (o dall' inizio del file se nessuna selezione è attiva).
* **Comportamento:** Scorre il buffer confrontando gli elementi. Quando il pattern viene identificato, aggiorna automaticamente `SelStartByte` e `SelEndByte` tramite il metodo atomico `SetSelection` ed esegue l' auto-scroll del `DataGridView` (`FirstDisplayedScrollingRowIndex`) per portare la riga interessata a schermo. Se non trova nulla fino alla fine del file, ricomincia la ricerca dall' indice 0. Altrimenti, mostra una MessageBox informativa.
* Valutare un nuopvo metodo che restituisce la coppia di valori inizio e fine senza aggiornare la selezione. L' atturale metodo userà il nuovo metodo.
## Modifiche dalla versione precedente
* Aggiunto metodo di ricerca
* Migliorata visualizzazione su windows 10
* Integrazione di visualizzatore valore decimale LitteEndian fino a 8 byte
* Integrazione del visualizzatore/modifica di inizio e fine selezione (e rimozione loop infinito)
* supporto (non testato) ai file >1GB