hex_editor

Terminal hex editor & binary analysis toolkit: 20 format parsers, wildcard search, entropy analysis, steganography detection, Base64/URL/Unicode/Hex codecs. Cross-platform (Windows/Linux), dual-target (Native + Wasm-GC).

hex
editor
binary
tui
parser
forensics
entropy
steganography
moon add R00TK17/hex_editor@0.1.2
Download zip
Author
Version
0.1.2
License
Apache-2.0
Last updated
last month
Downloads
28

Dependencies

README

#R00TK17/hex_editor

CI

Terminal hex editor and binary file analysis toolkit written in MoonBit.

#Features

  • Hex Editor TUI — interactive terminal UI with gap-buffer O(1) editing, undo/redo, clipboard
  • 20 Format Parsers — JPEG, PNG, GIF, BMP, WAV, FLAC, MP3, OGG, AVI, MP4, WebM/MKV, ZIP, RAR, TAR, ZLIB, GZip, 7z, BZip2, PE, ELF
  • Wildcard Search — BMH exact, Shift-Or bit-parallel (??), greedy segment (*, *N)
  • Signature Scanner — Aho-Corasick multi-pattern matching with 18 per-format validators
  • Entropy Analysis — Shannon entropy on 256-byte blocks (precomputed lookup table)
  • Codecs — Base64, URL percent-encoding, Unicode escape, Hex encode/decode
  • Strings Extraction — printable ASCII sequences ≥ 4 chars
  • File Browser — UTF-8 path support, multi-file switching, persistent bookmarks
  • Steganography Detection — embedded file extraction, trailing data detection

#Quick Start

# Clone and setup (auto-installs MoonBit, GCC, builds, tests) git clone https://github.com/R00TK17/moonbit-HexEditor.git cd moonbit-HexEditor chmod +x setup.sh && ./setup.sh # Linux # .\setup.ps1 # Windows # CLI usage moon run cmd/main -- struct file.bin moon run cmd/main -- scan file.bin moon run cmd/main -- entropy file.bin # TUI mode moon run cmd/main -- file.bin

#Usage as a Library

// Parse binary file structure

///|
let fields = @R00TK17/hex_editor.parse_structure(bytes)

// Scan for embedded file signatures

///|
let matches = @R00TK17/hex_editor.scan_signatures(bytes)

// Shannon entropy analysis (256-byte blocks)

///|
let blocks = @R00TK17/hex_editor.entropy_scan(bytes)

// Search with wildcards

///|
let result = @R00TK17/hex_editor.find_hex_pattern(bytes, "FF ?? ?? EE")

///|
let result = @R00TK17/hex_editor.find_text_pattern(bytes, "He*ld")

// Codecs

///|
let b64 = @R00TK17/hex_editor.base64_encode(bytes)

///|
let decoded = @R00TK17/hex_editor.base64_decode(b64)

#Platform Support

PlatformNativeWasm-GC
Windows✓ TUI + CLIN/A
Linux✓ TUI + CLIN/A
Browser✓ CLI only

#
EntropyBlock

pub struct EntropyBlock {
start : Int
end : Int
entropy : Double
} derive(
Debug
)

#
HexBuffer

type HexBuffer

A mutable buffer for hex editing with Gap Buffer optimization.

Physical layout: [bytes | gap | bytes]
  • gap_start: first index of the gap
  • gap_end: first index after the gap
  • len: logical byte count (excluding gap)

The gap moves to the edit cursor on insert/delete. Consecutive edits at the same position are O(1).

#
HexBuffer::byte_at

fn HexBuffer::byte_at(self : HexBuffer, idx : Int) -> Byte

Fast byte read for rendering (no bounds check, no Option). Caller must ensure idx < self.len.

#
HexBuffer::data_ref

fn HexBuffer::data_ref(self : HexBuffer) -> FixedArray[Byte]

Returns internal data array (includes gap). Use byte_at() for correct access.

#
HexBuffer::delete_byte

fn HexBuffer::delete_byte(self : HexBuffer, offset : Int) -> Bool

Delete byte at logical offset. O(1) if gap is already at offset.
  1. Move gap to offset
  2. Expand gap_end by 1 (the byte at gap_end is "deleted")

#
HexBuffer::from_bytes

fn HexBuffer::from_bytes(bytes : Bytes) -> HexBuffer

Creates a HexBuffer from bytes. Gap is placed at the end. Layout: [file_bytes | gap]

#
HexBuffer::from_file

fn HexBuffer::from_file(path : String) -> HexBuffer raise

#
HexBuffer::get_byte

fn HexBuffer::get_byte(self : HexBuffer, offset : Int) -> Byte?

Safe byte read with bounds check.

#
HexBuffer::get_file_path

fn HexBuffer::get_file_path(self : HexBuffer) -> String?

#
HexBuffer::insert_byte

fn HexBuffer::insert_byte(self : HexBuffer, offset : Int, value : Byte) -> Bool

Insert a byte at logical offset. O(1) if gap is already at offset.
  1. Grow gap if exhausted
  2. Move gap to offset
  3. Write byte into gap_start, advance gap_start

#
HexBuffer::is_empty

fn HexBuffer::is_empty(self : HexBuffer) -> Bool

#
HexBuffer::is_modified

fn HexBuffer::is_modified(self : HexBuffer) -> Bool

#
HexBuffer::length

fn HexBuffer::length(self : HexBuffer) -> Int

#
HexBuffer::new

fn HexBuffer::new() -> HexBuffer

Creates a new empty HexBuffer with 256-byte initial gap.

#
HexBuffer::save

fn HexBuffer::save(self : HexBuffer, path? : String) -> Unit raise

#
HexBuffer::set_byte

fn HexBuffer::set_byte(self : HexBuffer, offset : Int, value : Byte) -> Bool

Set byte at logical offset. Returns false if out of bounds.

#
HexBuffer::set_file_path

fn HexBuffer::set_file_path(self : HexBuffer, path : String) -> Unit

#
HexBuffer::to_bytes

fn HexBuffer::to_bytes(self : HexBuffer) -> Bytes

Compact copy of logical bytes (no gap).

#
HexBuffer::to_fixedarray

fn HexBuffer::to_fixedarray(self : HexBuffer) -> FixedArray[Byte]

#
HexViewConfig

type HexViewConfig

Configuration for hex dump display formatting.

#
HexViewConfig::default

fn HexViewConfig::default() -> HexViewConfig

Creates a default HexViewConfig.

#
HexViewConfig::with_ascii

fn HexViewConfig::with_ascii(self : HexViewConfig, show : Bool) -> HexViewConfig

Creates a HexViewConfig with custom show_ascii setting.

#
HexViewConfig::with_bytes_per_row

fn HexViewConfig::with_bytes_per_row(self : HexViewConfig, bpr : Int) -> HexViewConfig

Creates a HexViewConfig with custom bytes per row.

#
HexViewConfig::with_uppercase

fn HexViewConfig::with_uppercase(self : HexViewConfig, upper : Bool) -> HexViewConfig

Creates a HexViewConfig with custom uppercase_hex setting.

#
ScanMatch

pub struct ScanMatch {
offset : Int
name : String
size : Int
confidence : Int
} derive(
Debug
)

#
StringMatch

pub struct StringMatch {
offset : Int
text : String
} derive(
Debug
)

#
StructField

type StructField derive(
Debug
)

A parsed field from a file structure.

#
base64_decode

fn base64_decode(text : String) -> Bytes?

Decode Base64 string to bytes.

#
base64_encode

fn base64_encode(data : Bytes) -> String

Encode bytes to Base64 string.

#
entropy_scan

fn entropy_scan(bytes : Bytes) -> Array[EntropyBlock]

Scan bytes in 256-byte blocks, compute Shannon entropy per block. Full blocks use precomputed table (pure lookup, no log2 calls).

#
extract_region

fn extract_region(bytes : Bytes, start : Int, name : String, base_path : String) -> String

#
find_all_bytes

fn find_all_bytes(data : Bytes, pattern : Bytes) -> Array[Int]

Boyer-Moore-Horspool search — all occurrences.

#
find_hex_pattern

fn find_hex_pattern(data : Bytes, pattern : String) -> (Array[Int], Array[Int])?

Search data for a hex pattern with ?? and * wildcards. Returns Some((offsets, match_lengths)) or None if pattern is invalid.

#
find_strings

fn find_strings(bytes : Bytes) -> Array[StringMatch]

Scan bytes for printable ASCII strings of length >= 4.

#
find_text_pattern

fn find_text_pattern(data : Bytes, pattern : String) -> (Array[Int], Array[Int])?

Search data for a text pattern with ?, *, *N wildcards and \ escape. Returns Some((offsets, match_lengths)) or None if pattern is invalid.

#
format_ascii

fn format_ascii(byte : Byte) -> Char

Converts a byte to its ASCII representation for the text column. Printable ASCII characters (0x20-0x7E) are shown as-is. Non-printable bytes are shown as '.'.

#
format_buffer_info

fn format_buffer_info(buffer : HexBuffer) -> String

Returns a brief summary of a HexBuffer.

#
format_byte_hex

fn format_byte_hex(byte : Byte, uppercase? : Bool) -> String

Converts a byte to a 2-character hex string.

#
format_hex_dump

fn format_hex_dump(buffer : HexBuffer, start_offset? : Int, length? : Int, config? : HexViewConfig) -> String

Formats a complete hex dump from a HexBuffer.

#
format_hex_row

fn format_hex_row(data : FixedArray[Byte], start : Int, length : Int, base_offset : Int, config : HexViewConfig) -> String

Formats a single row of a hex dump.

#
format_offset

fn format_offset(offset : Int, width? : Int, uppercase? : Bool) -> String

Formats an integer offset as a hex address string.

#
format_size

fn format_size(len : Int) -> String

Formats a byte count in human-readable form.

#
format_strings_export

fn format_strings_export(matches : Array[StringMatch]) -> String

Format strings matches as plain text for export.

#
format_structure

fn format_structure(fields : Array[StructField]) -> String

Display parsed structure as readable text.

#
format_structure_json

fn format_structure_json(fields : Array[StructField]) -> String

Format StructField array as JSON string.

#
hex_decode

fn hex_decode(text : String) -> Bytes?

Hex decode: space-separated hex values → bytes. Example: "48 65 6C" → b"\x48\x65\x6C"

#
hex_encode

fn hex_encode(data : Bytes) -> String

Hex encode: bytes → space-separated hex values. Example: b"\x48\x65" → "48 65"

#
parse_hex_string

fn parse_hex_string(hex_str : String) -> Bytes?

Parses a hex string like "FF 00 AB" into a Bytes sequence.

#
parse_structure

fn parse_structure(bytes : Bytes) -> Array[StructField]

Parse structure of file bytes. Returns top-level fields or empty array.

#
scan_signatures

fn scan_signatures(bytes : Bytes) -> Array[ScanMatch]

#
to_hex_string

fn to_hex_string(n : Int, width? : Int) -> String

Converts a number to a fixed-width hex string (useful for UI).

#
unicode_decode

fn unicode_decode(text : String) -> Bytes?

Unicode decode: parse \uXXXX sequences to bytes. Plain ASCII characters are kept as-is. Codepoints <= 0x7F → 1 byte, <= 0x7FF → 2 bytes, else → 3 bytes (UTF-8). Returns None on invalid input.

#
unicode_encode

fn unicode_encode(data : Bytes) -> String

Unicode encode: each byte → \u00XX notation.

#
url_decode

fn url_decode(text : String) -> Bytes?

URL percent-decode a string to bytes. %XX is decoded, + is decoded as space. Returns None on invalid input.

#
url_encode

fn url_encode(data : Bytes) -> String

URL percent-encode bytes. Unreserved characters (A-Z, a-z, 0-9, -, _, ., ~) pass through, all others become %XX.