Last active
May 23, 2025 15:21
-
-
Save Kreijstal/e34e6109c900149e1982bfb5e0017d46 to your computer and use it in GitHub Desktop.
seclab
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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