Как я разработал бинарный редактор прямо в браузере
Что такое бинарный редактор?
Бинарный редактор — это инструмент, который позволяет редактировать файлы непосредственно в шестнадцатеричном или ASCII-представлении. В то время как обычные текстовые редакторы работают со «строками», бинарный редактор получает доступ к «сырым последовательностям байтов» файла и может изменять любой бит или байт напрямую.
В анализе ПО, восстановлении данных и исследовании протоколов без него не обойтись. Среди настольных GUI-приложений популярны HxD
и Binary Ninja
. Но моя цель заключалась в том, чтобы создать «один-единственный файл бинарного редактора, который работает исключительно в браузере».
Подход к реализации
- Полностью на стороне клиента (никаких внешних передач данных)
- Чтение локальных файлов через
FileReader
API - Слева отображается шестнадцатеричное представление (Hex), справа — ASCII
- Клик переводит ячейку в режим редактирования и позволяет менять значение напрямую
- Изменённые ячейки подсвечиваются красным цветом
- Можно переключаться между режимами редактирования HEX и ASCII
- Результат редактирования снова сохраняется в файл для загрузки
Проблемы и их решение
1. Смещённая рамка редактирования
В первой версии, когда вокруг целевой ячейки появлялась жёлтая рамка, она немного смещалась от центра и выглядела странно. Причиной стали эффекты CSS-свойств line-height
и компоновки flex
: базовые точки символа и рамки не совпадали. Хотя я рассчитывал на моноширинный шрифт, браузеры могут по-разному выстраивать базовую линию, и итогом становится визуальный сдвиг вверх или вниз.
Проблема решилась, когда я принудительно задал vertical-align: middle
и сделал элемент display: inline-block
, чтобы выровнять высоту.
.hex-cell.editing {
outline: 2px solid yellow;
vertical-align: middle;
}
2. Нажатие ESC приводило к вводу символов
В ранней реализации, если при активной рамке нажать ESC, в ячейке появлялись строки вроде «EE».
Происходило это потому, что обработчик keydown
не перехватывал событие, и браузер передавал код клавиши прямо в логику ввода ячейки. Обычный ввод рассчитан только на 0–9 и A–F, но у Escape
тоже есть код (раньше keyCode=27
, сейчас стандарт говорит key="Escape"
), поэтому он попадал в обработчик и трактовался как "E"
.
Решение простое: перехватить Escape
в keydown
и заменить ввод на отмену редактирования.
document.addEventListener("keydown", e => {
if (e.key === "Escape") {
cancelEdit();
e.preventDefault(); // блокируем исходный путь ввода
}
});
Теперь ESC служит только для отмены редактирования и не оставляет символов в ячейке.
3. Красная подсветка сохранялась при повторной загрузке
После редактирования файла и загрузки другого красная подсветка предыдущих изменений оставалась.
Причина в том, что массив или состояние, отслеживающее изменённые ячейки, не обнулялось при чтении нового файла. Даже если область вывода очищалась, внутренний «флаг изменений» оставался, и новый файл унаследовал красную подсветку.
Я добавил вызов clearModifiedState()
сразу после чтения файла, чтобы полностью сбрасывать флаги.
4. Переключение между режимами HEX и ASCII
Изначально редактирование HEX и ASCII было доступно одновременно, и понять, какое значение «правильное», было сложно. Один и тот же байт обрабатывался двумя формами ввода, из-за чего возникала конкуренция за запись в ячейку по разным путям. ASCII мгновенно переписывал HEX, но в процессе ввода на экране возникала кратковременная несогласованность.
Я убрал параллельный ввод: добавил выпадающий список для явного выбора режима и по умолчанию оставил HEX. Пользователь теперь точно понимает, что вводит, а логика синхронизации упростилась.
Фрагмент кода
Основная логика редактирования выглядит так.
function applyEdit(offset, newValue) {
if (mode === "hex") {
buffer[offset] = parseInt(newValue, 16);
} else {
buffer[offset] = newValue.charCodeAt(0);
}
markModified(offset);
render();
}
markModified(offset)
отвечает за красную подсветку: если значение отличается от исходного, добавляется соответствующий класс. Реализация предельно простая.
Итоги
Браузерный бинарный редактор работает офлайн и, будучи «полностью клиентским инструментом», удовлетворяет требованиям безопасности.
- Когда нужно быстро поправить небольшие участки бинарных данных
- Для исследований в среде, где нельзя установить специальное приложение
- В учебных целях, чтобы наглядно объяснить «последовательность байтов»
Во всех этих сценариях инструмент оказывается полезен.