איך פיתחתי עורך בינארי שפועל בדפדפן
מהו עורך בינארי?
עורך בינארי הוא כלי שמאפשר לערוך קובץ ישירות בכתיב הקסדצימלי או ASCII. בעוד שעורך טקסט רגיל עובד על “מחרוזות” כיחידת העריכה, עורך בינארי נותן גישה לרצף הבתים הגולמי שמרכיב את הקובץ, כך שאפשר לשנות כל ביט או בית בכל היסט שרוצים.
עורכים בינאריים חיוניים לניתוח תוכנה, לשחזור נתונים ולחקירת פרוטוקולים.
אפליקציות עם ממשק גרפי כמו HxD
או Binary Ninja
מוכרות היטב.
המטרה שלי הפעם הייתה לבנות עורך בינארי שמורכב מקובץ בודד ופועל כולו בדפדפן.
גישת המימוש
- כולו בצד הלקוח (בלי שליחת נתונים)
- שימוש ב-
FileReader
כדי לטעון קבצים מקומיים - הצגה של הקס משמאל ו-ASCII מימין
- כניסה למצב עריכה בלחיצה וכתיבה מחדש במקום
- סימון אדום של תאים שעברו עריכה
- מעבר בין מצב עריכת הקס למצב עריכת ASCII
- הורדה מחדש של התוצאה כקובץ
המכשולים והפתרונות
1. מסגרת העריכה הייתה מוזחת
בגרסה הראשונה, המסגרת הצהובה שמדגישה את התא הפעיל הייתה טיפה מחוץ למרכז וזה נראה מוזר.
התברר ש-line-height
של CSS והפריסה של flex
הם האשמים: קו הבסיס של הגליף ושל המסגרת לא הסתדרו אחד עם השני.
גם כשמניחים פונט מונוספייס, מנועי העיבוד של הדפדפן יכולים להציב את קו הבסיס אחרת עבור כל פונט, והמסגרת זזה למעלה או למטה.
הפתרון היה להכריח vertical-align: middle
ולהפוך את התא ל-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"
, ובסופו של דבר נכתבו "EE"
.
הפתרון פשוט: ללכוד את Escape
במאזין keydown
, לבטל את העריכה ולמנוע את ברירת המחדל.
document.addEventListener("keydown", e => {
if (e.key === "Escape") {
cancelEdit();
e.preventDefault(); // לא לאפשר למקש להגיע לנתיב הקלט הכללי
}
});
מאז ESC רק מבטל עריכה ולא כותב תווים.
3. האדום נשאר אחרי טעינה מחדש
אחרי שערכתי קובץ אחד, פתיחת קובץ אחר השאירה את הסימון האדום על המסך.
השורש היה שהמערכים והמצבים שעוקבים אחרי תאים ששונו לא אופסו כשהוטען קובץ חדש. ניקוי אזור התצוגה לבד לא הספיק, כי דגל ה"שונה" נשאר וגרם לקובץ החדש להיראות כאילו כבר ערכו אותו.
קריאה ל-clearModifiedState()
מיד אחרי הטעינה מאפסת את הדגלים ומחזירה את העיצוב הנייטרלי.
4. מעבר בין מצבי HEX ו-ASCII
בגרסה הראשונה אפשרתי לערוך בו-זמנית ב-HEX וב-ASCII. זה יצר בלבול לגבי איזה קלט קובע, ועבודה על אותו בית דרך שני נתיבים גרמה להתנגשויות. עדכון ASCII דרס מיד את תצוגת ה-HEX, אבל במהלך ההקלדה הופיעו מצבים זמניים לא עקביים.
כדי למנוע את הבלבול עברתי לבחירה מפורשת של מצב באמצעות תיבת select, וקבעתי שעריכת 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)
אחראית לסימון האדום.
זו פונקציה פשוטה שמוסיפה מחלקת CSS כשהערך שונה מהמקור.
סיכום
העורך הבינארי לדפדפן פועל כעת גם במצב לא מקוון ושומר את כל העיבוד בצד הלקוח, כך שהוא כלי מבוסס-דפדפן בלבד.
- תיקוני בינארי קטנים כשלא רוצים להתקין שום דבר
- חקירה בסביבות נעולות שבהן אי אפשר להוסיף אפליקציות מקוריות
- הוראה ולמידה שמפתחות אינטואיציה לרצפי בתים גולמיים
אלו בדיוק התרחישים שבהם העורך זורח.