Skip to content

Instantly share code, notes, and snippets.

@Kreijstal
Last active May 23, 2025 15:21
Show Gist options
  • Save Kreijstal/e34e6109c900149e1982bfb5e0017d46 to your computer and use it in GitHub Desktop.
Save Kreijstal/e34e6109c900149e1982bfb5e0017d46 to your computer and use it in GitHub Desktop.
seclab
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Real-time Format Converter</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: #f5f5f5;
}
h1 {
color: #333;
text-align: center;
}
.converter, .struct-viewer {
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
margin-bottom: 20px;
}
.input-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
color: #555;
}
textarea {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
resize: vertical;
min-height: 40px;
font-family: monospace;
}
textarea.error {
border-color: #ff6b6b;
background-color: #fff0f0;
}
.error-message {
color: #ff6b6b;
font-size: 14px;
margin-top: 5px;
min-height: 20px;
}
.byte-count {
margin-top: 5px;
font-size: 14px;
color: #666;
}
.description {
margin-bottom: 10px;
color: #666;
font-size: 14px;
}
.struct-field {
display: flex;
margin-bottom: 8px;
font-family: monospace;
}
.struct-field-name {
width: 150px;
font-weight: bold;
}
.struct-field-value {
flex-grow: 1;
}
.struct-field-type {
width: 80px;
color: #666;
text-align: right;
}
.section-toggle {
display: block;
width: 100%;
padding: 10px;
background-color: #f0f0f0;
border: none;
border-radius: 4px;
text-align: left;
font-weight: bold;
cursor: pointer;
margin-bottom: 15px;
}
.section-toggle:hover {
background-color: #e0e0e0;
}
.section-content {
display: none;
}
.section-content.active {
display: block;
}
</style>
</head>
<body>
<h1>Real-time Format Converter</h1>
<button class="section-toggle" id="converter-toggle">Data Format Converter</button>
<div class="section-content active" id="converter-section">
<div class="converter">
<div class="input-group">
<label for="ascii">ASCII Text</label>
<div class="description">Plain text input (e.g., "Hello")</div>
<textarea id="ascii" placeholder="Enter ASCII text"></textarea>
<div id="ascii-error" class="error-message"></div>
<div id="ascii-byte-count" class="byte-count"></div>
</div>
<div class="input-group">
<label for="c-escaped">C Escaped String</label>
<div class="description">C-style escaped string (e.g., "Hello\n\x01\e\033\0")</div>
<textarea id="c-escaped" placeholder="Enter C escaped string"></textarea>
<div id="c-escaped-error" class="error-message"></div>
<div id="c-escaped-byte-count" class="byte-count"></div>
</div>
<div class="input-group">
<label for="hex">Hex (no prefix)</label>
<div class="description">Hexadecimal without prefix (e.g., "48656C6C6F")</div>
<textarea id="hex" placeholder="Enter hex"></textarea>
<div id="hex-error" class="error-message"></div>
<div id="hex-byte-count" class="byte-count"></div>
</div>
<div class="input-group">
<label for="hex-0x">Hex (0x prefix)</label>
<div class="description">Hexadecimal with 0x prefix for each byte (e.g., "0x48,0x65,0x6C,0x6C,0x6F")</div>
<textarea id="hex-0x" placeholder="Enter hex with 0x prefix"></textarea>
<div id="hex-0x-error" class="error-message"></div>
<div id="hex-0x-byte-count" class="byte-count"></div>
</div>
<div class="input-group">
<label for="hex-0x-long">Hex (0x long format)</label>
<div class="description">Hexadecimal in 32-bit format (e.g., "0x48656C6C6F")</div>
<textarea id="hex-0x-long" placeholder="Enter hex in 0x long format"></textarea>
<div id="hex-0x-long-error" class="error-message"></div>
<div id="hex-0x-long-byte-count" class="byte-count"></div>
</div>
<div class="input-group">
<label for="hex-spaces">Hex (space separated)</label>
<div class="description">Hexadecimal with spaces between bytes (e.g., "48 65 6C 6C 6F")</div>
<textarea id="hex-spaces" placeholder="Enter space-separated hex"></textarea>
<div id="hex-spaces-error" class="error-message"></div>
<div id="hex-spaces-byte-count" class="byte-count"></div>
</div>
<div class="input-group">
<label for="hex-four-byte">Hex (4-byte separated, little-endian)</label>
<div class="description">Hexadecimal with spaces between 4 bytes, little-endian (e.g., "6C6C6548 6F")</div>
<textarea id="hex-four-byte" placeholder="Enter 4-byte separated hex"></textarea>
<div id="hex-four-byte-error" class="error-message"></div>
<div id="hex-four-byte-byte-count" class="byte-count"></div>
</div>
</div>
</div>
<button class="section-toggle" id="struct-toggle">Struct Viewer</button>
<div class="section-content" id="struct-section">
<div class="struct-viewer">
<div class="input-group">
<label for="struct-config">Struct Configuration (JSON)</label>
<div class="description">Define the structure format as JSON: [{"name":"field1", "type":"uint8", "length":1}, ...]</div>
<textarea id="struct-config" placeholder='Enter struct config as JSON: [{"name":"magic", "type":"uint32", "length":1}, {"name":"command", "type":"uint8", "length":1}]'></textarea>
<div id="struct-config-error" class="error-message"></div>
</div>
<div id="struct-view">
<div class="description">The parsed struct will appear here once you configure it and enter data</div>
</div>
</div>
</div>
<script>
// DOM elements
const asciiInput = document.getElementById('ascii');
const cEscapedInput = document.getElementById('c-escaped');
const hexInput = document.getElementById('hex');
const hex0xInput = document.getElementById('hex-0x');
const hex0xLongInput = document.getElementById('hex-0x-long');
const hexSpacesInput = document.getElementById('hex-spaces');
const hexFourByteInput = document.getElementById('hex-four-byte');
const structConfigInput = document.getElementById('struct-config');
const structView = document.getElementById('struct-view');
const asciiError = document.getElementById('ascii-error');
const cEscapedError = document.getElementById('c-escaped-error');
const hexError = document.getElementById('hex-error');
const hex0xError = document.getElementById('hex-0x-error');
const hex0xLongError = document.getElementById('hex-0x-long-error');
const hexSpacesError = document.getElementById('hex-spaces-error');
const hexFourByteError = document.getElementById('hex-four-byte-error');
const structConfigError = document.getElementById('struct-config-error');
const asciiByteCount = document.getElementById('ascii-byte-count');
const cEscapedByteCount = document.getElementById('c-escaped-byte-count');
const hexByteCount = document.getElementById('hex-byte-count');
const hex0xByteCount = document.getElementById('hex-0x-byte-count');
const hex0xLongByteCount = document.getElementById('hex-0x-long-byte-count');
const hexSpacesByteCount = document.getElementById('hex-spaces-byte-count');
const hexFourByteByteCount = document.getElementById('hex-four-byte-byte-count');
// Section toggles
const converterToggle = document.getElementById('converter-toggle');
const structToggle = document.getElementById('struct-toggle');
const converterSection = document.getElementById('converter-section');
const structSection = document.getElementById('struct-section');
converterToggle.addEventListener('click', function() {
converterSection.classList.toggle('active');
});
structToggle.addEventListener('click', function() {
structSection.classList.toggle('active');
});
// Track the last updated input to prevent circular updates
let activeInput = null;
// Current data state
let currentHexValue = "";
let structConfig = [];
// Conversion functions
function stringToHex(str) {
return Array.from(str)
.map(char => char.charCodeAt(0).toString(16).padStart(2, '0'))
.join('');
}
function hexToString(hex) {
if (hex.length % 2 !== 0) return null;
const bytes = [];
for (let i = 0; i < hex.length; i += 2) {
const byte = parseInt(hex.substr(i, 2), 16);
if (isNaN(byte)) return null;
bytes.push(byte);
}
return String.fromCharCode(...bytes);
}
function stringToCEscaped(str) {
return Array.from(str).map(char => {
const code = char.charCodeAt(0);
if (char === '\\') return '\\\\';
if (code >= 32 && code <= 126) {
// Printable ASCII characters (32–126) are kept as-is
return char;
}
// Common control characters
switch (code) {
case 0: return '\\0';
case 7: return '\\a';
case 8: return '\\b';
case 9: return '\\t';
case 10: return '\\n';
case 11: return '\\v';
case 12: return '\\f';
case 13: return '\\r';
case 27: return '\\e';
default:
// Other non-printable characters as \xHH
return `\\x${code.toString(16).padStart(2, '0')}`;
}
}).join('');
}
function cEscapedToString(cEscaped) {
let result = '';
let i = 0;
while (i < cEscaped.length) {
if (cEscaped[i] === '\\' && i + 1 < cEscaped.length) {
i++;
if (cEscaped[i] === '\\') {
result += '\\';
i++;
continue;
}
switch (cEscaped[i]) {
case '0':
// Handle octal escapes (\0 to \377)
if (i + 1 < cEscaped.length && /[0-3]/.test(cEscaped[i + 1])) {
let octal = cEscaped.substr(i, 3);
if (/^[0-3][0-7][0-7]$/.test(octal)) {
result += String.fromCharCode(parseInt(octal, 8));
i += 3;
break;
}
}
// Single \0 for null
result += String.fromCharCode(0);
i++;
break;
case 'a': result += String.fromCharCode(7); i++; break;
case 'b': result += String.fromCharCode(8); i++; break;
case 't': result += String.fromCharCode(9); i++; break;
case 'n': result += String.fromCharCode(10); i++; break;
case 'v': result += String.fromCharCode(11); i++; break;
case 'f': result += String.fromCharCode(12); i++; break;
case 'r': result += String.fromCharCode(13); i++; break;
case 'e': result += String.fromCharCode(27); i++; break;
case 'x':
if (i + 2 < cEscaped.length) {
const hex = cEscaped.substr(i + 1, 2);
const byte = parseInt(hex, 16);
if (!isNaN(byte)) {
result += String.fromCharCode(byte);
i += 3;
} else {
return null; // Invalid hex
}
} else {
return null; // Incomplete \xHH
}
break;
default:
// Handle octal escapes (\1 to \377)
let octal = cEscaped.substr(i, 3);
if (/^[0-3][0-7][0-7]$/.test(octal)) {
result += String.fromCharCode(parseInt(octal, 8));
i += 3;
} else {
octal = cEscaped.substr(i, 2);
if (/^[0-7][0-7]$/.test(octal)) {
result += String.fromCharCode(parseInt(octal, 8));
i += 2;
} else if (/^[0-7]$/.test(cEscaped[i])) {
result += String.fromCharCode(parseInt(cEscaped[i], 8));
i++;
} else {
result += cEscaped[i];
i++;
}
}
}
} else {
result += cEscaped[i];
i++;
}
}
return result;
}
function isValidHex(hex) {
return /^[0-9A-Fa-f]*$/.test(hex) && hex.length % 2 === 0;
}
function isValidHex0x(hex) {
if (!hex) return true;
return /^(0x[0-9A-Fa-f]{2},)*0x[0-9A-Fa-f]{2}$/.test(hex);
}
function isValidHex0xLong(hex) {
if (!hex) return true;
return /^0x[0-9A-Fa-f]*$/.test(hex) && hex.length % 2 === 0;
}
function isValidHexSpaces(hex) {
if (!hex) return true;
return /^([0-9A-Fa-f]{2}\s)*[0-9A-Fa-f]{2}$/.test(hex);
}
function isValidHexFourByte(hex) {
if (!hex) return true;
return /^([0-9A-Fa-f]{1,8}\s)*[0-9A-Fa-f]{1,8}$/.test(hex);
}
function isValidCEscaped(str) {
if (!str) return true;
let i = 0;
while (i < str.length) {
if (str[i] === '\\' && i + 1 < str.length) {
i++;
switch (str[i]) {
case '0':
// Handle octal escapes (\0 to \377)
if (i + 1 < str.length && /[0-3]/.test(str[i + 1])) {
if (/^[0-3][0-7][0-7]$/.test(str.substr(i, 3))) {
i += 3;
break;
}
}
i++; // Single \0
break;
case 'a':
case 'b':
case 't':
case 'n':
case 'v':
case 'f':
case 'r':
case 'e':
i++;
break;
case 'x':
if (i + 2 < str.length && /^[0-9A-Fa-f]{2}$/.test(str.substr(i + 1, 2))) {
i += 3;
} else {
return false;
}
break;
default:
// Handle octal escapes (\1 to \377)
if (/^[0-3][0-7][0-7]$/.test(str.substr(i, 3))) {
i += 3;
} else if (/^[0-7][0-7]$/.test(str.substr(i, 2))) {
i += 2;
} else if (/^[0-7]$/.test(str[i])) {
i++;
} else {
i++;
}
}
} else {
const code = str.charCodeAt(i);
if (code < 32 || code > 126) return false; // Only printable ASCII allowed unescaped
i++;
}
}
return true;
}
function hex0xToHex(hex0x) {
if (!hex0x) return '';
return hex0x.split(',')
.map(byte => byte.replace('0x', ''))
.join('');
}
function hex0xLongToHex(hex0xLong) {
if (!hex0xLong) return '';
return hex0xLong.replace('0x', '');
}
function hexSpacesToHex(hexSpaces) {
if (!hexSpaces) return '';
return hexSpaces.replace(/\s+/g, '');
}
function hexFourByteToHex(hexFourByte) {
if (!hexFourByte) return '';
return hexFourByte.split(/\s+/).map(group => {
group = group.padStart(Math.ceil(group.length / 2) * 2, '0');
const bytes = group.match(/.{1,2}/g) || [];
return bytes.reverse().join('');
}).join('');
}
function hexToHex0x(hex) {
if (!hex) return '';
const result = [];
for (let i = 0; i < hex.length; i += 2) {
result.push('0x' + hex.substr(i, 2));
}
return result.join(',');
}
function hexToHex0xLong(hex) {
if (!hex) return '';
return '0x' + hex;
}
function hexToHexSpaces(hex) {
if (!hex) return '';
const result = [];
for (let i = 0; i < hex.length; i += 2) {
result.push(hex.substr(i, 2));
}
return result.join(' ');
}
function hexToHexFourByte(hex) {
if (!hex) return '';
const result = [];
for (let i = 0; i < hex.length; i += 8) {
const chunk = hex.substr(i, 8).padStart(8, '0');
const bytes = chunk.match(/.{1,2}/g) || [];
result.push(bytes.reverse().join(''));
}
return result.join(' ');
}
function hexToCEscaped(hex) {
const str = hexToString(hex);
return str ? stringToCEscaped(str) : '';
}
function updateByteCount(hex, asciiLength) {
const byteCount = hex ? hex.length / 2 : 0;
const byteText = byteCount === 1 ? 'byte' : 'bytes';
const hexCount = byteCount.toString(16).toUpperCase();
const countText = `Length: ${byteCount} ${byteText} (0x${hexCount})`;
asciiByteCount.textContent = countText;
cEscapedByteCount.textContent = countText;
hexByteCount.textContent = countText;
hex0xByteCount.textContent = countText;
hex0xLongByteCount.textContent = countText;
hexSpacesByteCount.textContent = countText;
hexFourByteByteCount.textContent = countText;
currentHexValue = hex;
updateStructView();
}
// Struct parsing functions
function parseStructConfig() {
try {
if (!structConfigInput.value.trim()) {
structView.innerHTML = '<div class="description">The parsed struct will appear here once you configure it and enter data</div>';
structConfig = [];
return;
}
structConfig = JSON.parse(structConfigInput.value);
if (!Array.isArray(structConfig)) {
throw new Error("Struct config must be an array");
}
for (const field of structConfig) {
if (!field.name || !field.type || !field.length) {
throw new Error("Each field must have name, type, and length properties");
}
}
structConfigError.textContent = '';
structConfigInput.classList.remove('error');
updateStructView();
} catch (e) {
structConfigError.textContent = 'Invalid JSON structure: ' + e.message;
structConfigInput.classList.add('error');
}
}
function updateStructView() {
if (!currentHexValue || structConfig.length === 0) {
return;
}
let html = '';
let byteOffset = 0;
for (const field of structConfig) {
try {
const { name, type, length } = field;
let value, typeName, byteLength;
switch (type.toLowerCase()) {
case 'uint8':
byteLength = 1 * length;
if (byteOffset + byteLength > currentHexValue.length / 2) {
throw new Error(`Not enough data for ${name}`);
}
if (length === 1) {
value = parseInt(currentHexValue.substr(byteOffset * 2, 2), 16);
typeName = 'uint8';
} else {
value = Array(length).fill().map((_, i) =>
parseInt(currentHexValue.substr((byteOffset + i) * 2, 2), 16)
);
typeName = `uint8[${length}]`;
}
break;
case 'uint16':
byteLength = 2 * length;
if (byteOffset + byteLength > currentHexValue.length / 2) {
throw new Error(`Not enough data for ${name}`);
}
if (length === 1) {
value = parseInt(currentHexValue.substr(byteOffset * 2, 4), 16);
typeName = 'uint16';
} else {
value = Array(length).fill().map((_, i) =>
parseInt(currentHexValue.substr((byteOffset + i * 2) * 2, 4), 16)
);
typeName = `uint16[${length}]`;
}
break;
case 'uint32':
byteLength = 4 * length;
if (byteOffset + byteLength > currentHexValue.length / 2) {
throw new Error(`Not enough data for ${name}`);
}
if (length === 1) {
value = parseInt(currentHexValue.substr(byteOffset * 2, 8), 16);
typeName = 'uint32';
} else {
value = Array(length).fill().map((_, i) =>
parseInt(currentHexValue.substr((byteOffset + i * 4) * 2, 8), 16)
);
typeName = `uint32[${length}]`;
}
break;
case 'string':
byteLength = length;
if (byteOffset + byteLength > currentHexValue.length / 2) {
throw new Error(`Not enough data for ${name}`);
}
value = hexToString(currentHexValue.substr(byteOffset * 2, byteLength * 2));
typeName = `char[${length}]`;
break;
default:
throw new Error(`Unknown type: ${type}`);
}
html += `
<div class="struct-field">
<div class="struct-field-name">${name}</div>
<div class="struct-field-value">${Array.isArray(value) ? JSON.stringify(value) : value}</div>
<div class="struct-field-type">${typeName}</div>
</div>`;
byteOffset += byteLength;
} catch (e) {
html += `
<div class="struct-field">
<div class="struct-field-name">${field.name}</div>
<div class="struct-field-value" style="color: #ff6b6b;">Error: ${e.message}</div>
<div class="struct-field-type">${field.type}</div>
</div>`;
break;
}
}
structView.innerHTML = html;
}
// Event handlers
asciiInput.addEventListener('input', function() {
if (activeInput === 'ascii') return;
activeInput = 'ascii';
try {
const ascii = this.value;
const hex = stringToHex(ascii);
cEscapedInput.value = stringToCEscaped(ascii);
hexInput.value = hex;
hex0xInput.value = hexToHex0x(hex);
hex0xLongInput.value = hexToHex0xLong(hex);
hexSpacesInput.value = hexToHexSpaces(hex);
hexFourByteInput.value = hexToHexFourByte(hex);
updateByteCount(hex, ascii.length);
asciiError.textContent = '';
cEscapedError.textContent = '';
hexError.textContent = '';
hex0xError.textContent = '';
hex0xLongError.textContent = '';
hexSpacesError.textContent = '';
hexFourByteError.textContent = '';
asciiInput.classList.remove('error');
cEscapedInput.classList.remove('error');
hexInput.classList.remove('error');
hex0xInput.classList.remove('error');
hex0xLongInput.classList.remove('error');
hexSpacesInput.classList.remove('error');
hexFourByteInput.classList.remove('error');
} catch (e) {
asciiError.textContent = 'Invalid input';
asciiInput.classList.add('error');
} finally {
activeInput = null;
}
});
cEscapedInput.addEventListener('input', function() {
if (activeInput === 'cEscaped') return;
activeInput = 'cEscaped';
try {
const cEscaped = this.value;
if (cEscaped && !isValidCEscaped(cEscaped)) {
cEscapedError.textContent = 'Invalid C escaped string (e.g., use \\n, \\xHH, \\e, \\0, \\033)';
cEscapedInput.classList.add('error');
activeInput = null;
return;
}
const ascii = cEscapedToString(cEscaped);
if (ascii === null && cEscaped) {
cEscapedError.textContent = 'Invalid escape sequence';
cEscapedInput.classList.add('error');
activeInput = null;
return;
}
const hex = stringToHex(ascii);
asciiInput.value = ascii || '';
hexInput.value = hex;
hex0xInput.value = hexToHex0x(hex);
hex0xLongInput.value = hexToHex0xLong(hex);
hexSpacesInput.value = hexToHexSpaces(hex);
hexFourByteInput.value = hexToHexFourByte(hex);
updateByteCount(hex, ascii ? ascii.length : 0);
asciiError.textContent = '';
cEscapedError.textContent = '';
hexError.textContent = '';
hex0xError.textContent = '';
hex0xLongError.textContent = '';
hexSpacesError.textContent = '';
hexFourByteError.textContent = '';
asciiInput.classList.remove('error');
cEscapedInput.classList.remove('error');
hexInput.classList.remove('error');
hex0xInput.classList.remove('error');
hex0xLongInput.classList.remove('error');
hexSpacesInput.classList.remove('error');
hexFourByteInput.classList.remove('error');
} catch (e) {
cEscapedError.textContent = 'Invalid input';
cEscapedInput.classList.add('error');
} finally {
activeInput = null;
}
});
hexInput.addEventListener('input', function() {
if (activeInput === 'hex') return;
activeInput = 'hex';
try {
const hex = this.value.replace(/\s+/g, '');
if (hex && !isValidHex(hex)) {
hexError.textContent = 'Invalid hex format (must be even number of hex digits)';
hexInput.classList.add('error');
activeInput = null;
return;
}
const ascii = hexToString(hex);
if (ascii === null && hex) {
hexError.textContent = 'Invalid hex characters';
hexInput.classList.add('error');
activeInput = null;
return;
}
asciiInput.value = ascii || '';
cEscapedInput.value = hexToCEscaped(hex);
hex0xInput.value = hexToHex0x(hex);
hex0xLongInput.value = hexToHex0xLong(hex);
hexSpacesInput.value = hexToHexSpaces(hex);
hexFourByteInput.value = hexToHexFourByte(hex);
updateByteCount(hex, ascii ? ascii.length : 0);
asciiError.textContent = '';
cEscapedError.textContent = '';
hexError.textContent = '';
hex0xError.textContent = '';
hex0xLongError.textContent = '';
hexSpacesError.textContent = '';
hexFourByteError.textContent = '';
asciiInput.classList.remove('error');
cEscapedInput.classList.remove('error');
hexInput.classList.remove('error');
hex0xInput.classList.remove('error');
hex0xLongInput.classList.remove('error');
hexSpacesInput.classList.remove('error');
hexFourByteInput.classList.remove('error');
} catch (e) {
hexError.textContent = 'Invalid input';
hexInput.classList.add('error');
} finally {
activeInput = null;
}
});
hex0xInput.addEventListener('input', function() {
if (activeInput === 'hex0x') return;
activeInput = 'hex0x';
try {
const hex0x = this.value;
if (hex0x && !isValidHex0x(hex0x)) {
hex0xError.textContent = 'Invalid 0x format (must be 0xXX,0xXX...)';
hex0xInput.classList.add('error');
activeInput = null;
return;
}
const hex = hex0xToHex(hex0x);
const ascii = hexToString(hex);
asciiInput.value = ascii || '';
cEscapedInput.value = hexToCEscaped(hex);
hexInput.value = hex;
hex0xLongInput.value = hexToHex0xLong(hex);
hexSpacesInput.value = hexToHexSpaces(hex);
hexFourByteInput.value = hexToHexFourByte(hex);
updateByteCount(hex, ascii ? ascii.length : 0);
asciiError.textContent = '';
cEscapedError.textContent = '';
hexError.textContent = '';
hex0xError.textContent = '';
hex0xLongError.textContent = '';
hexSpacesError.textContent = '';
hexFourByteError.textContent = '';
asciiInput.classList.remove('error');
cEscapedInput.classList.remove('error');
hexInput.classList.remove('error');
hex0xInput.classList.remove('error');
hex0xLongInput.classList.remove('error');
hexSpacesInput.classList.remove('error');
hexFourByteInput.classList.remove('error');
} catch (e) {
hex0xError.textContent = 'Invalid input';
hex0xInput.classList.add('error');
} finally {
activeInput = null;
}
});
hex0xLongInput.addEventListener('input', function() {
if (activeInput === 'hex0xLong') return;
activeInput = 'hex0xLong';
try {
const hex0xLong = this.value;
if (hex0xLong && !isValidHex0xLong(hex0xLong)) {
hex0xLongError.textContent = 'Invalid 0x long format (must be 0xXXXX...)';
hex0xLongInput.classList.add('error');
activeInput = null;
return;
}
const hex = hex0xLongToHex(hex0xLong);
if (hex && !isValidHex(hex)) {
hex0xLongError.textContent = 'Invalid hex format (must be even number of hex digits)';
hex0xLongInput.classList.add('error');
activeInput = null;
return;
}
const ascii = hexToString(hex);
asciiInput.value = ascii || '';
cEscapedInput.value = hexToCEscaped(hex);
hexInput.value = hex;
hex0xInput.value = hexToHex0x(hex);
hexSpacesInput.value = hexToHexSpaces(hex);
hexFourByteInput.value = hexToHexFourByte(hex);
updateByteCount(hex, ascii ? ascii.length : 0);
asciiError.textContent = '';
cEscapedError.textContent = '';
hexError.textContent = '';
hex0xError.textContent = '';
hex0xLongError.textContent = '';
hexSpacesError.textContent = '';
hexFourByteError.textContent = '';
asciiInput.classList.remove('error');
cEscapedInput.classList.remove('error');
hexInput.classList.remove('error');
hex0xInput.classList.remove('error');
hex0xLongInput.classList.remove('error');
hexSpacesInput.classList.remove('error');
hexFourByteInput.classList.remove('error');
} catch (e) {
hex0xLongError.textContent = 'Invalid input';
hex0xLongInput.classList.add('error');
} finally {
activeInput = null;
}
});
hexSpacesInput.addEventListener('input', function() {
if (activeInput === 'hexSpaces') return;
activeInput = 'hexSpaces';
try {
const hexSpaces = this.value;
if (hexSpaces && !isValidHexSpaces(hexSpaces)) {
hexSpacesError.textContent = 'Invalid space-separated hex format (must be XX XX XX...)';
hexSpacesInput.classList.add('error');
activeInput = null;
return;
}
const hex = hexSpacesToHex(hexSpaces);
const ascii = hexToString(hex);
asciiInput.value = ascii || '';
cEscapedInput.value = hexToCEscaped(hex);
hexInput.value = hex;
hex0xInput.value = hexToHex0x(hex);
hex0xLongInput.value = hexToHex0xLong(hex);
hexFourByteInput.value = hexToHexFourByte(hex);
updateByteCount(hex, ascii ? ascii.length : 0);
asciiError.textContent = '';
cEscapedError.textContent = '';
hexError.textContent = '';
hex0xError.textContent = '';
hex0xLongError.textContent = '';
hexSpacesError.textContent = '';
hexFourByteError.textContent = '';
asciiInput.classList.remove('error');
cEscapedInput.classList.remove('error');
hexInput.classList.remove('error');
hex0xInput.classList.remove('error');
hex0xLongInput.classList.remove('error');
hexSpacesInput.classList.remove('error');
hexFourByteInput.classList.remove('error');
} catch (e) {
hexSpacesError.textContent = 'Invalid input';
hexSpacesInput.classList.add('error');
} finally {
activeInput = null;
}
});
hexFourByteInput.addEventListener('input', function() {
if (activeInput === 'hexFourByte') return;
activeInput = 'hexFourByte';
try {
const hexFourByte = this.value;
if (hexFourByte && !isValidHexFourByte(hexFourByte)) {
hexFourByteError.textContent = 'Invalid 4-byte hex format (must be XXXXXXXX XXXXXXXX...)';
hexFourByteInput.classList.add('error');
activeInput = null;
return;
}
const hex = hexFourByteToHex(hexFourByte);
const ascii = hexToString(hex);
asciiInput.value = ascii || '';
cEscapedInput.value = hexToCEscaped(hex);
hexInput.value = hex;
hex0xInput.value = hexToHex0x(hex);
hex0xLongInput.value = hexToHex0xLong(hex);
hexSpacesInput.value = hexToHexSpaces(hex);
updateByteCount(hex, ascii ? ascii.length : 0);
asciiError.textContent = '';
cEscapedError.textContent = '';
hexError.textContent = '';
hex0xError.textContent = '';
hex0xLongError.textContent = '';
hexSpacesError.textContent = '';
hexFourByteError.textContent = '';
asciiInput.classList.remove('error');
cEscapedInput.classList.remove('error');
hexInput.classList.remove('error');
hex0xInput.classList.remove('error');
hex0xLongInput.classList.remove('error');
hexSpacesInput.classList.remove('error');
hexFourByteInput.classList.remove('error');
} catch (e) {
hexFourByteError.textContent = 'Invalid input';
hexFourByteInput.classList.add('error');
} finally {
activeInput = null;
}
});
structConfigInput.addEventListener('input', function() {
parseStructConfig();
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment