This repository contains a hex editor in Haskell with the brick
library as the terminal UI. A hex editor is a computer program that allows for manipulation of the fundamental binary data that constitutes a computer file. We aim to build a hex editor that is easy to use and has a friendly user interface in command line.
Key features of the hex editor include:
- Hexadecimal Display: The application presents the binary content of files in a hexadecimal format, allowing users to visually inspect the data.
- ASCII Representation: Alongside the hexadecimal display, the editor shows the ASCII representation of the data, making it easier for users to interpret text-based information within the binary file.
- Navigation and Editing: Users can navigate through the file, move to specific offsets, or edit the content at the byte level. Considering the special workloads of hex editors, the editor provides functionalities to replace or append bytes.
- Search and Replace: The hex editor provides search and replace functionalities, allowing users to locate specific byte sequences within the file and replace them with desired values.
- Large File Optimization: The editor can handle large files without crashing or slowing down.
- This project is developed with cse130-assignments/cse130-devcontainer on Docker.
- The image
cse130-assignments/cse130-devcontainer
is based on Debian GNU/Linux 11 and GHC 9.2.7 withstack
. - To launch the program, run
stack run
at the root directory.
The code is located in the src
directory, while the tests are located in the test
directory. The codebase is roughly divided into 2 components: the core (Lib.hs
) and the interface (UI.hs
).
The core editor is responsible for operations involving File I/O and editing.
- Binary files are loaded into memory with
System.IO.MMap
in pages, and stored as a file buffer frame inData.Vector
. The buffer frame is also the buffer frame used for displaying and searching. - The core editor responds to the user inputs from the interface, and make modifications accordingly. Since all the modifications in our editor are generated by human, we use the modification buffer (
Data.Map
) to store all the modifications to the file. The modifications within the range of the buffer frame are flushed to the buffer frame. - The core editor provides functionalities to search and replace. It can handle inputs in both hexadecimal and ASCII format. For hexadecimal inputs, we require that the string contains full bytes (half bytes are not accepted).
- The core editor is responsible for saving the file. It flushes the modification buffer to the file with
System.IO
, specificallyhSeek
andhPutChar
. If the user requests a "Save As" operation, the core editor will create a new file and save the content to the new file.
The interface is responsible for displaying the editor buffers and handling user inputs.
- It implements the menu, the status bar, file content in hexadecimal and the corresponding ASCII representation. It's implemented with the
brick
library in the event-driven manner, by providing hooks to functionalities in the core editor. - The menu provides a list of common operations for file I/O (Open, Save, Save As) and editing (Jump, Search, Replace). When some operations require user input, a prompt will be displayed for user inputs.
- The status bar provides information regarding current status of the file, including the offset and file size. It also displays error message in the possible error cases.
- The file content is displayed in hexadecimal format, with the corresponding ASCII representation. The user can nevigate the contents of the file through direction buttons. When the user press a key in the file content display, the replacing instruction will be sent to the core editor. A user can switch between the hexadecimal and ASCII representation by pressing
Tab
. - When the user presses
~
, the editor enters "Append Mode", where all the direction buttons are disabled, and the user can only append bytes to the end of the file. The editor will exit "Append Mode" when the user presses~
again.
- Our implementation features optimizations to various console sizes. The editor automatically adjusts the display to fit the console size. The file buffer frame also adjusts according to the height of the console size to balance the performance and memory usage.
- Our implementation features optimizations to handle large files. We use memory mapping for input, and conventional file interface for output. This approach balances the I/O performance and memory usage based on our specific workloads.
- Junqi Xie
- Chengsong Diao
- Dier Hou
- Kaifeng Jin
- MIT License applies to this project. See
LICENSE
for more information.