Binary File Hex Dump Viewer & Annotator
Paste raw hex data to visualize the dump and log forensic annotations.
1. Raw Hexadecimal Input
Note: Input must be a continuous hex sequence (0-9, A-F).
2. Add Annotation
Paste raw hex data above to visualize the dump.
'; return; } const bytesPerLine = 16; const totalLength = rawHex.length; // Render Title outputDiv.innerHTML += `Hex Dump Visualization
`;
// Sort annotations by offset
annotations.sort((a, b) => a.offset - b.offset);
let nextAnnotationIndex = 0;
for (let offset = 0; offset < totalLength; offset += bytesPerLine * 2) {
const lineHex = rawHex.substring(offset, offset + bytesPerLine * 2);
if (lineHex.length === 0) break;
const lineAscii = hexToAscii(lineHex);
const address = '0x' + offset.toString(16).padStart(8, '0');
let hexFormatted = '';
for (let i = 0; i < lineHex.length; i += 2) {
hexFormatted += lineHex.substring(i, i + 2) + ' ';
}
const lineDiv = document.createElement('div');
lineDiv.className = 'bhdva-hex-line';
lineDiv.innerHTML = `
${address}
${hexFormatted}
${lineAscii}
`;
outputDiv.appendChild(lineDiv);
// Inject annotations if they fall on this line
while (nextAnnotationIndex < annotations.length) {
const currentAnno = annotations[nextAnnotationIndex];
if (currentAnno.offset >= offset && currentAnno.offset < offset + bytesPerLine * 2) {
// Annotation belongs to this line
const relativeOffset = currentAnno.offset - offset;
const annoDiv = document.createElement('div');
annoDiv.className = 'bhdva-hex-line';
annoDiv.innerHTML = `
â””>
(${currentAnno.offset.toString(16).padStart(4, '0')}) ${escapeHtml(currentAnno.text)}
`;
outputDiv.appendChild(annoDiv);
nextAnnotationIndex++;
} else if (currentAnno.offset >= offset + bytesPerLine * 2) {
// Annotation belongs to a later line
break;
} else {
// Annotation was skipped or is misplaced
nextAnnotationIndex++;
}
}
}
};
// --- Annotation Management ---
window.bhdvaAddAnnotation = function() {
const offsetInput = document.getElementById('bhdva-annotation-offset').value.trim();
const text = document.getElementById('bhdva-annotation-text').value.trim();
if (!offsetInput || !text) {
alert("Please provide both a Hex Offset and Annotation Text.");
return;
}
// Parse hex address to integer offset
const offset = parseInt(offsetInput.toLowerCase().startsWith('0x') ? offsetInput : '0x' + offsetInput, 16);
if (isNaN(offset)) {
alert("Invalid Hex Offset format. Use 0x1A or 1A.");
return;
}
annotations.push({ offset, text });
// Clear input
document.getElementById('bhdva-annotation-offset').value = '0x';
document.getElementById('bhdva-annotation-text').value = '';
bhdvaGenerateDump(); // Regenerate display
bhdvaRenderAnnotationList(); // Update management list
};
window.bhdvaRemoveAnnotation = function(offset) {
annotations = annotations.filter(a => a.offset !== offset);
bhdvaGenerateDump();
bhdvaRenderAnnotationList();
};
function bhdvaRenderAnnotationList() {
const list = document.getElementById('bhdva-annotation-list');
list.innerHTML = '';
if (annotations.length === 0) {
list.innerHTML = 'No annotations logged.
'; return; } // Sort by offset for display annotations.sort((a, b) => a.offset - b.offset); annotations.forEach(a => { const item = document.createElement('div'); item.className = 'flex justify-between items-center bg-gray-50 p-2 rounded'; item.innerHTML = ` 0x${a.offset.toString(16).padStart(4, '0')} ${escapeHtml(a.text)} `; list.appendChild(item); }); } // --- PDF Download --- window.bhdvaDownloadPDF = function() { // Ensure dump is generated before downloading bhdvaGenerateDump(); const element = document.getElementById('bhdva-viewer-output'); document.body.classList.add('bhdva-generating-pdf'); const opt = { margin: [0.5, 0.5], filename: `Binary_Hex_Dump_Annotated.pdf`, image: { type: 'jpeg', quality: 0.98 }, html2canvas: { scale: 2, useCORS: true }, jsPDF: { unit: 'in', format: 'letter', orientation: 'landscape' } }; html2pdf().set(opt).from(element).save().then(() => { document.body.classList.remove('bhdva-generating-pdf'); }); }; // Utility: HTML Escape function escapeHtml(text) { if (!text) return ''; return text.replace(/[&<>"']/g, function(m) { switch (m) { case '&': return '&'; case '<': return '<'; case '>': return '>'; case '"': return '"'; case "'": return '''; default: return m; } }); }