Trải nghiệm xây dựng trình chỉnh sửa nhị phân chạy trong trình duyệt
Trình chỉnh sửa nhị phân là gì?
Trình chỉnh sửa nhị phân cho phép chỉnh sửa tệp trực tiếp ở dạng thập lục phân hoặc ASCII. Trong khi trình soạn thảo văn bản thông thường coi “chuỗi” là đối tượng chỉnh sửa, trình chỉnh sửa nhị phân truy cập “dãy byte thô” của tệp và có thể thay đổi từng bit hoặc byte tại bất cứ vị trí nào.
Công cụ này không thể thiếu khi phân tích phần mềm, khôi phục dữ liệu hay khảo sát giao thức. Trong thế giới GUI, HxD
và Binary Ninja
khá nổi tiếng. Tuy nhiên, mục tiêu lần này của tôi là tạo ra “trình chỉnh sửa nhị phân dạng tệp đơn chạy hoàn toàn trong trình duyệt”.
Định hướng triển khai
- Hoạt động hoàn toàn phía khách (không truyền dữ liệu ra ngoài)
- Đọc tệp cục bộ bằng API
FileReader
- Bên trái hiển thị Hex, bên phải hiển thị ASCII
- Nhấp chuột để vào chế độ chỉnh sửa và đổi giá trị trực tiếp
- Ô đã chỉnh sửa được tô đỏ nổi bật
- Cho phép chuyển đổi giữa chế độ chỉnh sửa HEX và ASCII
- Kết quả chỉnh sửa có thể xuất lại thành tệp để tải xuống
Vấn đề gặp phải và cách khắc phục
1. Viền chỉnh sửa bị lệch
Ở bản đầu tiên, khi viền vàng xuất hiện quanh ô đang chỉnh sửa, nó hơi lệch khỏi trung tâm nên trông rất khó chịu. Nguyên nhân là các thuộc tính CSS line-height
và bố cục flex
khiến điểm chuẩn giữa ký tự và viền không trùng khớp. Dù đã giả định dùng phông chữ monospace, quá trình kết xuất của trình duyệt có thể đặt đường cơ sở khác nhau, tạo ra độ lệch lên hoặc xuống.
Buộc vertical-align: middle
và đặt phần tử thành display: inline-block
để đồng bộ chiều cao đã giải quyết được vấn đề.
.hex-cell.editing {
outline: 2px solid yellow;
vertical-align: middle;
}
2. Nhấn ESC lại nhập ký tự
Trong bản thử nghiệm đầu, nhấn ESC khi ô đang chỉnh sửa sẽ chèn chuỗi như “EE”.
Nguyên nhân là sự kiện keydown
không được bắt, nên trình duyệt đưa mã phím thẳng vào quy trình nhập của ô. Thông thường chỉ cho phép 0–9 và A–F, nhưng Escape
cũng có mã phím (trước đây là keyCode=27
, còn theo chuẩn hiện tại là key="Escape"
), vì vậy bị hiểu thành "E"
.
Giải pháp rất đơn giản: bắt Escape
trong keydown
và chuyển sang xử lý hủy chỉnh sửa.
document.addEventListener("keydown", e => {
if (e.key === "Escape") {
cancelEdit();
e.preventDefault(); // chặn quy trình nhập mặc định
}
});
Nhờ vậy ESC chỉ còn nhiệm vụ “hủy chỉnh sửa” và không để lại ký tự nào trong ô.
3. Viền đỏ vẫn còn sau khi tải lại
Sau khi chỉnh sửa một tệp rồi tải tệp khác, các ô đỏ của tệp trước vẫn xuất hiện.
Đó là vì mảng hoặc trạng thái theo dõi ô đã sửa không được khởi tạo lại khi đọc tệp mới. Dù vùng hiển thị đã được xóa, “cờ thay đổi” bên trong vẫn giữ nguyên nên tệp mới cũng bị đánh dấu đỏ.
Khắc phục bằng cách gọi clearModifiedState()
ngay sau khi đọc xong tệp để đặt lại toàn bộ cờ.
4. Chuyển đổi giữa chế độ HEX và ASCII
Lúc đầu cho phép chỉnh sửa HEX và ASCII đồng thời, nên khó biết giá trị nào mới là đúng. Khi một byte được xử lý bởi hai biểu mẫu, cùng một ô bị ghi từ hai hướng khác nhau. Nhập ASCII sẽ ghi đè lên hiển thị HEX, khiến trong lúc gõ xuất hiện trạng thái không đồng nhất.
Tôi thêm một menu chọn chế độ và đặt mặc định là chỉnh sửa HEX. Người dùng biết rõ mình đang nhập HEX, còn phần đồng bộ cũng trở nên gọn gàng hơn.
Một phần mã
Phần xử lý chỉnh sửa thực tế như sau.
function applyEdit(offset, newValue) {
if (mode === "hex") {
buffer[offset] = parseInt(newValue, 16);
} else {
buffer[offset] = newValue.charCodeAt(0);
}
markModified(offset);
render();
}
markModified(offset)
dùng cho phần tô đỏ: chỉ cần phát hiện giá trị khác với ban đầu là thêm lớp tương ứng. Cách làm khá đơn giản.
Tổng kết
Trình chỉnh sửa nhị phân chạy trên trình duyệt này có thể hoạt động ngoại tuyến và với tư cách “công cụ hoàn toàn phía khách” cũng đáp ứng yêu cầu bảo mật.
- Khi cần chỉnh nhanh một phần nhỏ dữ liệu nhị phân
- Khi phải điều tra trong môi trường không thể cài ứng dụng chuyên dụng
- Khi dạy học hoặc tự học để trực quan hóa “chuỗi byte”
Trong mọi tình huống đó, công cụ đều tỏ ra hữu ích.