English
terminalToolAcre
memory Client-Side DOM Engine shield Zero Data Retention

HTML Entities Encoder & Decoder

Convert special characters, markup tags, and extended Unicode symbols to named, decimal, and hexadecimal HTML entities without accidental DOM execution or XSS exposure.

expand_more
edit_note Input Plain Text or Markup
0 chars | 1 line
Memory Buffer Safe
Auto-transform enabled
terminal Converted Entity Output 0 replaced
0 chars • 0 entities
format_image_left No innerHTML parsing
Syntactic Tags
0
code
Quotes & Apos
0
format_quote
Ampersands
0
alternate_email
Unicode Codepoints
0
translate

Standard HTML5 Entity Cheat Table

Instant reference table for W3C markup delimiters, typography, mathematical sets, and symbols.

filter_alt
Character Named Reference Decimal Code Hex Code W3C Description Quick Insert
& & & & Ampersand delimiter (Critical)
< &lt; &#60; &#x3C; Opening tag delimiter (Critical)
> &gt; &#62; &#x3E; Closing tag delimiter (Critical)
" &quot; &#34; &#x22; Attribute quote enclosure (Critical)
' &apos; &#39; &#x27; Attribute apostrophe delimiter (Critical)
␣ &nbsp; &#160; &#xA0; Non-breaking white space
© &copy; &#169; &#xA9; Copyright symbol
® &reg; &#174; &#xAE; Registered trademark sign
€ &euro; &#8364; &#x20AC; Euro currency symbol
— &mdash; &#8212; &#x2014; Em dash typographic separator
Security Architecture & Specification

Deep-Dive: Escaping Mechanisms in Web Engines

gavel

The Five XML/HTML Critical Characters and XSS Defense

Standard markup lexers treat < and > as syntactic delimiters for DOM element boundaries. When user-supplied text enters an HTML document unescaped, an attacker can break out of string context to execute malicious inline scripts (<script>) or hijack event handlers.

Equally insidious are unescaped quote literals (" and ') inside attribute nodes like value="INPUT", allowing an attacker to inject " onmouseover=".... Escaping the foundational 5 characters neutralizes markup breakout at zero runtime performance penalty.

dialpad

Named vs Numeric Entities: Why Hex Is Universally Portable

While named character references such as &euro; or &trade; are human-legible, XML parsers (including strict SVG and XHTML runtimes) only natively acknowledge five named entities without an explicit DTD schema declaration.

In contrast, numeric entities—both decimal (&#8364;) and hexadecimal (&#x20AC;)—map explicitly to ISO 10646 and Unicode code points. Hexadecimal representation corresponds 1:1 with standard UTF-16 surrogate pairs and UTF-32 hex references, making it the most resilient format across legacy mainframes, XML parsers, and micro-embedded web views.

verified_user

Decoding Entities Without innerHTML To Prevent Client-Side Exploits

A frequent yet disastrous anti-pattern found in developer tools is delegating entity decoding to a phantom browser DOM element via el.innerHTML = input; return el.textContent;. If an unvetted payload includes active elements like <img src=x onerror=alert(1)>, the DOM parser initiates asynchronous execution in memory.

ToolAcre implements an air-gapped synthetic tokenizer. We decode hexadecimal/decimal codepoints via direct native String.fromCodePoint() and resolve named references through a static immutable hash dictionary. The browser DOM tree is never traversed or queried, completely precluding DOM-based execution.

Local Pipeline Architecture

Direct Character-Stream Pipeline

Every string transformation executes synchronously on worker memory. No sockets, no local-storage caching, no analytics probes on payload bodies. Inspect the execution flowchart below to see how raw strings are segmented and resolved.

Raw Stream UTF-8 / Unicode Scope Evaluator Syntax | Diacritics Regex Zero-Backtrack Codepoint Mapper fromCodePoint() Named & Hex Resolvers Sanitized Output Zero Egress
Advertisement
ad_units Developer Cloud Infrastructure • High-Performance Bare Metal Servers
` inside & verify security.\n
', diacritics: 'Café résumé with jalapeño, naïve façade, Noël smörgåsbord, and Crème Brûlée.\nAccented glyphs: à, è, ì, ò, ù, ñ, ç, å, ø, ü, é.', math: 'Financial Summary:\nAccount balance: €4,500.80 & £2,150.00 ≈ ¥350,000.\nFormulas: f(x) ≤ 100 × y ± √2; A ∩ B ≠ ∅; Limit → ∞.', ampersands: 'https://cdn.example.com/api/v2/query?session=89ab2f&locale=en-US&sort=desc&filter=tags\nAT&T, Ben & Jerry\'s, Barnes & Noble & Sons & Co.' }; // Scope match filters const CRITICAL_CHARS = ['&', '<', '>', '"', "'"]; function isCritical(char) { return CRITICAL_CHARS.includes(char); } function isExtended(char) { return char.charCodeAt(0) > 127; } function shouldEncodeChar(char, scope) { if (scope === 'syntax') { return isCritical(char); } else if (scope === 'extended') { return isCritical(char) || isExtended(char); } else { // 'all' return isCritical(char) || isExtended(char) || /[^a-zA-Z0-9\s]/.test(char); } } function encodeCharacter(char, format) { const code = char.codePointAt(0); if (format === 'named' && NAMED_MAP[char]) { return NAMED_MAP[char]; } if (format === 'decimal') { return `&#${code};`; } if (format === 'hex') { return `&#x${code.toString(16).toUpperCase()};`; } // Fallback if named is not mapped return `&#${code};`; } // Safe Decoder Engine (No innerHTML, strictly programmatic codepoints) function decodeEntities(str) { let count = 0; const decoded = str.replace(/&(#x[0-9a-fA-F]+|#[0-9]+|[a-zA-Z]+);/g, (match, body) => { count++; if (body.startsWith('#x') || body.startsWith('#X')) { const hex = body.slice(2); const cp = parseInt(hex, 16); if (!isNaN(cp)) return String.fromCodePoint(cp); } else if (body.startsWith('#')) { const dec = body.slice(1); const cp = parseInt(dec, 10); if (!isNaN(cp)) return String.fromCodePoint(cp); } else { const fullEntity = `&${body};`; if (REVERSE_NAMED[fullEntity]) return REVERSE_NAMED[fullEntity]; } return match; }); return { result: decoded, replacements: count }; } // Safe Encoder Engine function encodeEntities(str, scope, format) { let count = 0; let diffHtml = ''; let result = ''; // Iterate Unicode codepoints correctly for (const char of str) { if (shouldEncodeChar(char, scope)) { const ent = encodeCharacter(char, format); result += ent; count++; // Build visual difference tokens diffHtml += `${escapeForDisplay(ent)}`; } else { result += char; diffHtml += escapeForDisplay(char); } } return { result, replacements: count, diffHtml }; } function escapeForDisplay(text) { return text.replace(/&/g, '&').replace(//g, '>'); } // Core Compute Function function processTransformation() { const input = rawInput.value; // Update stats const chars = input.length; const lines = input ? input.split('\n').length : 1; charCountInput.textContent = `${chars.toLocaleString()} chars`; lineCountInput.textContent = `${lines} ${lines === 1 ? 'line' : 'lines'}`; // Compute metrics const tagsCount = (input.match(/[<>]/g) || []).length; const quoteCount = (input.match(/['"]/g) || []).length; const ampCount = (input.match(/&/g) || []).length; let unicodeCount = 0; for (const c of input) { if (c.charCodeAt(0) > 127) unicodeCount++; } statTags.textContent = tagsCount.toString(); statQuotes.textContent = quoteCount.toString(); statAmps.textContent = ampCount.toString(); statUnicode.textContent = unicodeCount.toString(); if (!input) { rawOutput.value = ''; diffOverlay.innerHTML = ''; diffCounterPill.textContent = '0 replaced'; outputMetaStats.textContent = '0 chars • 0 entities'; return; } if (currentMode === 'encode') { const { result, replacements, diffHtml } = encodeEntities(input, currentScope, currentFormat); rawOutput.value = result; diffOverlay.innerHTML = diffHtml; diffCounterPill.textContent = `${replacements.toLocaleString()} replaced`; outputMetaStats.textContent = `${result.length.toLocaleString()} chars • ${replacements} encoded`; } else { const { result, replacements } = decodeEntities(input); rawOutput.value = result; diffOverlay.innerHTML = escapeForDisplay(result); diffCounterPill.textContent = `${replacements.toLocaleString()} decoded`; outputMetaStats.textContent = `${result.length.toLocaleString()} chars • ${replacements} decoded`; } } // Scope Buttons Handling document.querySelectorAll('.scope-btn').forEach(btn => { btn.addEventListener('click', () => { document.querySelectorAll('.scope-btn').forEach(b => { b.classList.remove('bg-primary', 'text-on-primary', 'shadow-sm'); b.classList.add('bg-surface-container-low', 'text-secondary'); }); btn.classList.add('bg-primary', 'text-on-primary', 'shadow-sm'); btn.classList.remove('bg-surface-container-low', 'text-secondary'); currentScope = btn.dataset.scope; processTransformation(); }); }); // Format Buttons Handling document.querySelectorAll('.format-btn').forEach(btn => { btn.addEventListener('click', () => { document.querySelectorAll('.format-btn').forEach(b => { b.classList.remove('bg-primary', 'text-on-primary', 'shadow-sm'); b.classList.add('bg-surface-container-low', 'text-secondary'); }); btn.classList.add('bg-primary', 'text-on-primary', 'shadow-sm'); btn.classList.remove('bg-surface-container-low', 'text-secondary'); currentFormat = btn.dataset.format; processTransformation(); }); }); // Mode Switch Handling modeEncodeBtn.addEventListener('click', () => { currentMode = 'encode'; modeEncodeBtn.classList.add('bg-surface-container-lowest', 'text-primary', 'shadow-sm'); modeEncodeBtn.classList.remove('text-secondary'); modeDecodeBtn.classList.remove('bg-surface-container-lowest', 'text-primary', 'shadow-sm'); modeDecodeBtn.classList.add('text-secondary'); inputPaneLabel.textContent = 'Input Plain Text or Markup'; outputPaneLabel.textContent = 'Converted Entity Output'; processTransformation(); }); modeDecodeBtn.addEventListener('click', () => { currentMode = 'decode'; modeDecodeBtn.classList.add('bg-surface-container-lowest', 'text-primary', 'shadow-sm'); modeDecodeBtn.classList.remove('text-secondary'); modeEncodeBtn.classList.remove('bg-surface-container-lowest', 'text-primary', 'shadow-sm'); modeEncodeBtn.classList.add('text-secondary'); inputPaneLabel.textContent = 'Input Encoded Entities Markup'; outputPaneLabel.textContent = 'Decoded Plain Text Output'; processTransformation(); }); // Diff Viewer Toggle toggleDiffBtn.addEventListener('click', () => { showDiff = !showDiff; if (showDiff) { rawOutput.classList.add('hidden'); diffOverlay.classList.remove('hidden'); diffToggleText.textContent = 'Show Raw'; toggleDiffBtn.classList.add('bg-primary', 'text-on-primary'); toggleDiffBtn.classList.remove('bg-surface-container', 'text-on-surface'); } else { rawOutput.classList.remove('hidden'); diffOverlay.classList.add('hidden'); diffToggleText.textContent = 'Show Diff'; toggleDiffBtn.classList.remove('bg-primary', 'text-on-primary'); toggleDiffBtn.classList.add('bg-surface-container', 'text-on-surface'); } }); // Clipboard Action copyBtn.addEventListener('click', async () => { if (!rawOutput.value) return; try { await navigator.clipboard.writeText(rawOutput.value); copyBtnText.textContent = 'Copied!'; setTimeout(() => { copyBtnText.textContent = 'Copy'; }, 1800); } catch (e) { rawOutput.select(); document.execCommand('copy'); copyBtnText.textContent = 'Copied!'; setTimeout(() => { copyBtnText.textContent = 'Copy'; }, 1800); } }); // File Snippet Download downloadBtn.addEventListener('click', () => { if (!rawOutput.value) return; const blob = new Blob([rawOutput.value], { type: 'text/html;charset=utf-8' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `entities-${currentMode}-${Date.now()}.html`; a.click(); URL.revokeObjectURL(url); }); // Clear Buffer clearBtn.addEventListener('click', () => { rawInput.value = ''; rawInput.focus(); processTransformation(); }); // Sample Load sampleSelector.addEventListener('change', (e) => { const val = e.target.value; if (SAMPLES[val]) { rawInput.value = SAMPLES[val]; processTransformation(); } }); // Realtime listener rawInput.addEventListener('input', processTransformation); // Searchable Table Filter const tableFilterInput = document.getElementById('entity-table-filter'); const tableRows = document.querySelectorAll('#entity-table-body tr'); tableFilterInput.addEventListener('input', (e) => { const query = e.target.value.toLowerCase().trim(); tableRows.forEach(row => { const text = row.textContent.toLowerCase(); row.style.display = text.includes(query) ? '' : 'none'; }); }); // Global window insert helper window.insertEntityToInput = function(char) { const start = rawInput.selectionStart || 0; const end = rawInput.selectionEnd || 0; const current = rawInput.value; rawInput.value = current.substring(0, start) + char + current.substring(end); rawInput.focus(); rawInput.selectionStart = rawInput.selectionEnd = start + char.length; processTransformation(); }; // Initialize default test sample on first load rawInput.value = SAMPLES.html; processTransformation(); })();