fscalc/index.html
2025-09-27 23:32:40 +02:00

1755 lines
77 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dateisystem-Offset-Rechner</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Consolas', 'Courier New', monospace;
background-color: #1a1a1a;
color: #e0e0e0;
line-height: 1.6;
min-height: 100vh;
display: flex;
flex-direction: column;
}
/* Header */
.header {
background-color: #2a2a2a;
border-bottom: 2px solid #3a3a3a;
padding: 15px 0;
}
.header-content {
max-width: 1400px;
margin: 0 auto;
padding: 0 20px;
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
}
.logo {
font-size: 1.5em;
font-weight: bold;
color: #ffffff;
}
.nav {
display: flex;
gap: 20px;
}
.nav a {
color: #cccccc;
text-decoration: none;
transition: color 0.2s;
}
.nav a:hover {
color: #ffffff;
}
/* Main Content */
.main-content {
flex: 1;
padding: 20px;
}
.container {
max-width: 1400px;
margin: 0 auto;
}
h1 {
text-align: center;
margin-bottom: 30px;
color: #ffffff;
font-size: 2.2em;
font-weight: normal;
}
/* Tabs */
.tabs {
display: flex;
background-color: #2a2a2a;
border-radius: 6px 6px 0 0;
border: 1px solid #3a3a3a;
border-bottom: none;
overflow-x: auto;
}
.tab {
padding: 15px 25px;
cursor: pointer;
background-color: #2a2a2a;
border-right: 1px solid #3a3a3a;
color: #cccccc;
transition: all 0.2s;
white-space: nowrap;
min-width: 120px;
text-align: center;
}
.tab:last-child {
border-right: none;
}
.tab:hover {
background-color: #353535;
}
.tab.active {
background-color: #3a3a3a;
color: #ffffff;
border-bottom: 2px solid #666666;
}
.tab-content {
display: none;
background-color: #2a2a2a;
border: 1px solid #3a3a3a;
border-radius: 0 0 6px 6px;
padding: 20px;
}
.tab-content.active {
display: block;
}
/* Constants and Calculator Layout */
.constants-calculator-container {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin-bottom: 20px;
}
@media (max-width: 1024px) {
.constants-calculator-container {
grid-template-columns: 1fr;
gap: 15px;
}
}
/* Calculator Styles */
.hex-calculator {
background-color: #1a1a1a;
min-height: fit-content;
}
.calculator-container {
display: flex;
flex-direction: column;
gap: 15px;
}
.calc-display {
background-color: #111111;
border: 1px solid #404040;
border-radius: 6px;
padding: 15px;
}
.calc-input input {
width: 100%;
background-color: #2a2a2a;
border: 1px solid #555555;
border-radius: 4px;
color: #ffffff;
font-family: 'Consolas', monospace;
font-size: 18px;
font-weight: bold;
padding: 12px;
text-align: right;
margin-bottom: 12px;
}
.calc-conversions {
display: flex;
flex-direction: column;
gap: 8px;
}
.conversion-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 6px 0;
border-bottom: 1px solid #333333;
}
.conversion-row:last-child {
border-bottom: none;
}
.conv-label {
color: #888888;
font-weight: bold;
font-size: 0.9em;
min-width: 40px;
}
.conv-value {
color: #cccccc;
font-family: 'Consolas', monospace;
font-size: 0.9em;
word-break: break-all;
text-align: right;
flex: 1;
margin-left: 10px;
}
.calc-buttons {
display: flex;
flex-direction: column;
gap: 8px;
}
.calc-row {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 6px;
}
.calc-btn {
background-color: #2a2a2a;
border: 1px solid #4a4a4a;
border-radius: 4px;
color: #ffffff;
cursor: pointer;
font-family: 'Consolas', monospace;
font-size: 0.85em;
font-weight: bold;
min-height: 40px;
padding: 8px;
text-align: center;
transition: all 0.2s;
user-select: none;
}
.calc-btn:hover {
background-color: #3a3a3a;
border-color: #666666;
}
.calc-btn:active {
background-color: #444444;
transform: translateY(1px);
}
.calc-btn.number {
background-color: #333333;
}
.calc-btn.number:hover {
background-color: #444444;
}
.calc-btn.operation {
background-color: #2a4a2a;
color: #88cc88;
}
.calc-btn.operation:hover {
background-color: #3a5a3a;
}
.calc-btn.memory {
background-color: #4a2a2a;
color: #cc8888;
font-size: 0.75em;
}
.calc-btn.memory:hover {
background-color: #5a3a3a;
}
.calc-btn.clear {
background-color: #4a2a4a;
color: #cc88cc;
}
.calc-btn.clear:hover {
background-color: #5a3a5a;
}
.calc-btn.equals {
background-color: #2a2a4a;
color: #8888cc;
}
.calc-btn.equals:hover {
background-color: #3a3a5a;
}
.calc-btn.backspace {
background-color: #4a4a2a;
color: #cccc88;
}
.calc-btn.backspace:hover {
background-color: #5a5a3a;
}
.calc-btn.wide {
grid-column: span 2;
}
@media (max-width: 768px) {
.calc-btn {
min-height: 35px;
font-size: 0.8em;
padding: 6px;
}
.calc-input input {
font-size: 16px;
padding: 10px;
}
}
/* Sections */
.section {
background-color: #252525;
border-radius: 6px;
padding: 20px;
margin-bottom: 20px;
border: 1px solid #3a3a3a;
}
.section h2 {
color: #cccccc;
margin-bottom: 15px;
border-bottom: 1px solid #3a3a3a;
padding-bottom: 8px;
font-weight: normal;
font-size: 1.3em;
}
.constants {
background-color: #202020;
}
.results {
background-color: #202020;
}
.formulas {
background-color: #1a1a1a;
}
.formula-box {
background-color: #151515;
border: 1px solid #404040;
border-radius: 4px;
padding: 15px;
margin: 10px 0;
font-family: 'Consolas', monospace;
font-size: 0.9em;
}
.formula {
margin: 8px 0;
color: #d0d0d0;
word-wrap: break-word;
}
.calculated {
color: #ffffff;
font-weight: bold;
}
.input-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 15px;
margin: 20px 0;
}
@media (max-width: 768px) {
.input-grid {
grid-template-columns: 1fr;
gap: 12px;
}
}
.input-group {
display: flex;
flex-direction: column;
}
.input-group label {
margin-bottom: 6px;
color: #cccccc;
font-weight: normal;
font-size: 0.95em;
}
.unit-indicator {
color: #88cc88;
font-weight: bold;
font-size: 0.85em;
}
.input-group input {
padding: 12px;
background-color: #333333;
border: 1px solid #4a4a4a;
border-radius: 4px;
color: #ffffff;
font-family: 'Consolas', monospace;
font-size: 14px;
transition: border-color 0.2s;
}
.input-group input:focus {
outline: none;
border-color: #666666;
background-color: #383838;
}
.result-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 0;
border-bottom: 1px solid #3a3a3a;
position: relative;
}
.result-item:last-child {
border-bottom: none;
}
.result-label {
color: #cccccc;
font-weight: normal;
flex: 1;
cursor: help;
}
.result-value-container {
display: flex;
align-items: center;
gap: 8px;
}
.result-value {
color: #ffffff;
font-family: 'Consolas', monospace;
text-align: right;
font-weight: bold;
min-width: 120px;
cursor: help;
}
.copy-btn {
background: none;
border: none;
color: #888888;
cursor: pointer;
padding: 4px;
border-radius: 3px;
transition: all 0.2s;
font-size: 14px;
}
.copy-btn:hover {
color: #ffffff;
background-color: #404040;
}
.copy-btn:active {
color: #88cc88;
}
/* Tooltip */
.tooltip {
position: absolute;
background-color: #1a1a1a;
color: #ffffff;
padding: 8px 12px;
border-radius: 4px;
font-size: 0.85em;
border: 1px solid #555555;
z-index: 1000;
max-width: 400px;
word-wrap: break-word;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
font-family: 'Consolas', monospace;
line-height: 1.4;
}
@media (max-width: 600px) {
.result-item {
flex-direction: column;
align-items: flex-start;
gap: 5px;
}
.result-value {
text-align: left;
min-width: auto;
}
}
@media (max-width: 600px) {
.header-content {
flex-direction: column;
gap: 10px;
}
.nav {
justify-content: center;
}
}
.error {
color: #ff8888;
font-style: italic;
}
/* Footer */
.footer {
background-color: #2a2a2a;
border-top: 1px solid #3a3a3a;
padding: 20px 0;
margin-top: 40px;
}
.footer-content {
max-width: 1400px;
margin: 0 auto;
padding: 0 20px;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 30px;
}
.footer-section h3 {
color: #ffffff;
margin-bottom: 10px;
font-size: 1.1em;
}
.footer-section p,
.footer-section a {
color: #cccccc;
font-size: 0.9em;
text-decoration: none;
margin-bottom: 5px;
display: block;
}
.footer-section a:hover {
color: #ffffff;
}
.footer-bottom {
text-align: center;
padding-top: 20px;
margin-top: 20px;
border-top: 1px solid #3a3a3a;
color: #888888;
font-size: 0.85em;
}
@media (max-width: 768px) {
.main-content {
padding: 15px;
}
h1 {
font-size: 1.8em;
margin-bottom: 20px;
}
.section {
padding: 15px;
}
.formula-box {
padding: 12px;
font-size: 0.85em;
}
.tab {
padding: 12px 15px;
min-width: 100px;
}
}
@media (min-width: 1200px) {
.input-grid {
grid-template-columns: repeat(3, 1fr);
}
}
</style>
</head>
<body>
<header class="header">
<div class="header-content">
<div class="logo">Dateisystem-Offset-Rechner</div>
<nav class="nav">
<a href="#home">Home</a>
<a href="mailto:mstoeck3@hs-mittweida.de">Contact</a>
</nav>
</div>
</header>
<main class="main-content">
<div class="container">
<h1>Dateisystem-Offset-Rechner</h1>
<div class="tabs">
<div class="tab active" onclick="switchTab('fat1216')">FAT12/16</div>
<div class="tab" onclick="switchTab('fat32')">FAT32</div>
</div>
<!-- FAT12/16 Tab -->
<div class="tab-content active" id="fat1216">
<div class="constants-calculator-container">
<div class="section constants">
<h2>Konstanten</h2>
<div class="input-grid">
<div class="input-group">
<label for="baseOffset1216">Base Offset <span
class="unit-indicator">(Bytes)</span>:</label>
<input type="text" id="baseOffset1216" value="0x0" placeholder="0x0">
</div>
<div class="input-group">
<label for="sectorSize1216">Größe eines Sektors <span
class="unit-indicator">(Bytes)</span>:</label>
<input type="text" id="sectorSize1216" value="0x200" placeholder="0x200">
</div>
</div>
</div>
<div class="section hex-calculator">
<h2>Hex Calculator</h2>
<div class="calculator-container">
<div class="calc-display">
<div class="calc-input">
<input type="text" id="calcInput" placeholder="0x0" readonly>
</div>
<div class="calc-conversions">
<div class="conversion-row">
<span class="conv-label">HEX:</span>
<span class="conv-value" id="hexValue">0x0</span>
</div>
<div class="conversion-row">
<span class="conv-label">DEC:</span>
<span class="conv-value" id="decValue">0</span>
</div>
<div class="conversion-row">
<span class="conv-label">BIN:</span>
<span class="conv-value" id="binValue">0b0</span>
</div>
</div>
</div>
<div class="calc-buttons">
<div class="calc-row">
<button class="calc-btn memory" onclick="calcMemory('MC')">MC</button>
<button class="calc-btn memory" onclick="calcMemory('MR')">MR</button>
<button class="calc-btn memory" onclick="calcMemory('M+')">M+</button>
<button class="calc-btn memory" onclick="calcMemory('M-')">M-</button>
<button class="calc-btn clear" onclick="calcClear()">C</button>
</div>
<div class="calc-row">
<button class="calc-btn number" onclick="calcInput('A')">A</button>
<button class="calc-btn number" onclick="calcInput('B')">B</button>
<button class="calc-btn number" onclick="calcInput('C')">C</button>
<button class="calc-btn number" onclick="calcInput('D')">D</button>
<button class="calc-btn operation" onclick="calcOperation('<<')">&lt;&lt;</button>
</div>
<div class="calc-row">
<button class="calc-btn number" onclick="calcInput('E')">E</button>
<button class="calc-btn number" onclick="calcInput('F')">F</button>
<button class="calc-btn number" onclick="calcInput('7')">7</button>
<button class="calc-btn number" onclick="calcInput('8')">8</button>
<button class="calc-btn operation" onclick="calcOperation('>>')">&gt;&gt;</button>
</div>
<div class="calc-row">
<button class="calc-btn operation" onclick="calcOperation('AND')">AND</button>
<button class="calc-btn operation" onclick="calcOperation('OR')">OR</button>
<button class="calc-btn number" onclick="calcInput('9')">9</button>
<button class="calc-btn operation" onclick="calcOperation('/')">/</button>
<button class="calc-btn operation" onclick="calcOperation('MOD')">MOD</button>
</div>
<div class="calc-row">
<button class="calc-btn operation" onclick="calcOperation('XOR')">XOR</button>
<button class="calc-btn operation" onclick="calcOperation('NOT')">NOT</button>
<button class="calc-btn number" onclick="calcInput('4')">4</button>
<button class="calc-btn number" onclick="calcInput('5')">5</button>
<button class="calc-btn number" onclick="calcInput('6')">6</button>
</div>
<div class="calc-row">
<button class="calc-btn operation" onclick="calcOperation('*')">*</button>
<button class="calc-btn number" onclick="calcInput('1')">1</button>
<button class="calc-btn number" onclick="calcInput('2')">2</button>
<button class="calc-btn number" onclick="calcInput('3')">3</button>
<button class="calc-btn operation" onclick="calcOperation('-')">-</button>
</div>
<div class="calc-row">
<button class="calc-btn operation" onclick="calcOperation('+')">+</button>
<button class="calc-btn number wide" onclick="calcInput('0')">0</button>
<button class="calc-btn backspace" onclick="calcBackspace()"></button>
<button class="calc-btn equals" onclick="calcEquals()">=</button>
</div>
</div>
</div>
</div>
</div>
<div class="section">
<h2>Eingabeparameter</h2>
<div class="input-grid">
<div class="input-group">
<label for="reservedSectors1216">Anzahl reservierter Sektoren <span
class="unit-indicator">(Sektoren)</span>:</label>
<input type="text" id="reservedSectors1216" placeholder="0x1">
</div>
<div class="input-group">
<label for="numFATs1216">Anzahl FATs <span class="unit-indicator">(Anzahl)</span>:</label>
<input type="text" id="numFATs1216" placeholder="0x2">
</div>
<div class="input-group">
<label for="fatSizeBytes1216">Größe einer FAT <span
class="unit-indicator">(Bytes)</span>:</label>
<input type="text" id="fatSizeBytes1216" placeholder="0x1000">
</div>
<div class="input-group">
<label for="maxRootEntries1216">Max. Wurzelverzeichnis-Einträge <span
class="unit-indicator">(Anzahl)</span>:</label>
<input type="text" id="maxRootEntries1216" placeholder="0x200">
</div>
<div class="input-group">
<label for="partitionSizeInSectors1216">Größe Partition <span
class="unit-indicator">(Sektoren)</span>:</label>
<input type="text" id="partitionSizeInSectors1216" placeholder="0x4015">
</div>
<div class="input-group">
<label for="clusterSizeSectors1216">Größe eines Clusters <span
class="unit-indicator">(Sektoren)</span>:</label>
<input type="text" id="clusterSizeSectors1216" placeholder="0x1">
</div>
<div class="input-group">
<label for="clusterNumber1216">Cluster Nummer für Position <span
class="unit-indicator">(Nummer)</span>:</label>
<input type="text" id="clusterNumber1216" placeholder="0x2">
</div>
</div>
</div>
<div class="section results">
<h2>Berechnete Werte</h2>
<div id="results1216">
<div class="result-item">
<span class="result-label" data-formula="reservedSectors × sectorSize + baseOffset">Beginn
FAT-Bereich:</span>
<div class="result-value-container">
<span class="result-value" id="fatStart1216" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('fatStart1216')"
title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="numFATs × fatSizeBytes">Größe FAT-Bereich:</span>
<div class="result-value-container">
<span class="result-value" id="fatSize1216" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('fatSize1216')"
title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="fatStart + fatSize">Ende FAT-Bereich:</span>
<div class="result-value-container">
<span class="result-value" id="fatEnd1216" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('fatEnd1216')"
title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="fatEnd">Beginn Wurzelverzeichnis:</span>
<div class="result-value-container">
<span class="result-value" id="rootDirStart1216" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('rootDirStart1216')"
title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="maxRootEntries × 0x20">Größe
Wurzelverzeichnis:</span>
<div class="result-value-container">
<span class="result-value" id="rootDirSize1216" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('rootDirSize1216')"
title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="fatEnd + rootDirSize">Beginn Daten-Bereich:</span>
<div class="result-value-container">
<span class="result-value" id="dataStart1216" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('dataStart1216')"
title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label"
data-formula="(partitionSizeInSectors × sectorSize) - (dataStart - baseOffset)">Größe
Daten-Bereich:</span>
<div class="result-value-container">
<span class="result-value" id="dataSize1216" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('dataSize1216')"
title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="sectorSize × clusterSizeSectors">Größe eines
Clusters:</span>
<div class="result-value-container">
<span class="result-value" id="clusterSize1216" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('clusterSize1216')"
title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="dataSize ÷ clusterSize">Anzahl Cluster:</span>
<div class="result-value-container">
<span class="result-value" id="numClusters1216" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('numClusters1216')"
title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label"
data-formula="dataStart + (clusterNumber - 0x2) × clusterSize">Beginn Cluster:</span>
<div class="result-value-container">
<span class="result-value" id="clusterStart1216" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('clusterStart1216')"
title="Copy to clipboard">📋</button>
</div>
</div>
</div>
</div>
<div class="section formulas">
<h2>Berechnungsformeln FAT12/16</h2>
<div class="formula-box">
<div class="formula"><span class="calculated">Beginn FAT-Bereich</span> = Anzahl reservierter
Sektoren × Größe eines Sektors + Base Offset</div>
<div class="formula"><span class="calculated">Größe FAT-Bereich</span> = Anzahl FATs × Größe
einer FAT</div>
<div class="formula"><span class="calculated">Ende FAT-Bereich</span> = Beginn FAT-Bereich +
Größe FAT-Bereich</div>
<div class="formula"><span class="calculated">Größe Wurzelverzeichnis</span> = Anzahl max.
Wurzelverzeichnis-Einträge × 0x20</div>
<div class="formula"><span class="calculated">Beginn Daten-Bereich</span> = Ende FAT-Bereich +
Größe Wurzelverzeichnis</div>
<div class="formula"><span class="calculated">Größe Daten-Bereich</span> = (Größe Partition in
Sektoren × Größe eines Sektors) - (Beginn Daten-Bereich - Base Offset)</div>
<div class="formula"><span class="calculated">Größe eines Clusters</span> = Größe eines Sektors
× Größe eines Clusters in Sektoren</div>
<div class="formula"><span class="calculated">Anzahl Cluster</span> = Größe Daten-Bereich ÷
Größe eines Clusters</div>
<div class="formula"><span class="calculated">Beginn Cluster</span> = Beginn Daten-Bereich +
(Cluster - 0x2) × Größe eines Clusters</div>
</div>
</div>
</div>
<!-- FAT32 Tab -->
<div class="tab-content" id="fat32">
<div class="constants-calculator-container">
<div class="section constants">
<h2>Konstanten</h2>
<div class="input-grid">
<div class="input-group">
<label for="baseOffset32">Base Offset <span
class="unit-indicator">(Bytes)</span>:</label>
<input type="text" id="baseOffset32" value="0x0" placeholder="0x0">
</div>
<div class="input-group">
<label for="sectorSize32">Größe eines Sektors <span
class="unit-indicator">(Bytes)</span>:</label>
<input type="text" id="sectorSize32" value="0x200" placeholder="0x200">
</div>
</div>
</div>
<div class="section hex-calculator">
<h2>Hex Calculator</h2>
<div class="calculator-container">
<div class="calc-display">
<div class="calc-input">
<input type="text" id="calcInput32" placeholder="0x0" readonly>
</div>
<div class="calc-conversions">
<div class="conversion-row">
<span class="conv-label">HEX:</span>
<span class="conv-value" id="hexValue32">0x0</span>
</div>
<div class="conversion-row">
<span class="conv-label">DEC:</span>
<span class="conv-value" id="decValue32">0</span>
</div>
<div class="conversion-row">
<span class="conv-label">BIN:</span>
<span class="conv-value" id="binValue32">0b0</span>
</div>
</div>
</div>
<div class="calc-buttons">
<div class="calc-row">
<button class="calc-btn memory" onclick="calcMemory('MC', 'fat32')">MC</button>
<button class="calc-btn memory" onclick="calcMemory('MR', 'fat32')">MR</button>
<button class="calc-btn memory" onclick="calcMemory('M+', 'fat32')">M+</button>
<button class="calc-btn memory" onclick="calcMemory('M-', 'fat32')">M-</button>
<button class="calc-btn clear" onclick="calcClear('fat32')">C</button>
</div>
<div class="calc-row">
<button class="calc-btn number" onclick="calcInput('A', 'fat32')">A</button>
<button class="calc-btn number" onclick="calcInput('B', 'fat32')">B</button>
<button class="calc-btn number" onclick="calcInput('C', 'fat32')">C</button>
<button class="calc-btn number" onclick="calcInput('D', 'fat32')">D</button>
<button class="calc-btn operation"
onclick="calcOperation('<<', 'fat32')">&lt;&lt;</button>
</div>
<div class="calc-row">
<button class="calc-btn number" onclick="calcInput('E', 'fat32')">E</button>
<button class="calc-btn number" onclick="calcInput('F', 'fat32')">F</button>
<button class="calc-btn number" onclick="calcInput('7', 'fat32')">7</button>
<button class="calc-btn number" onclick="calcInput('8', 'fat32')">8</button>
<button class="calc-btn operation"
onclick="calcOperation('>>', 'fat32')">&gt;&gt;</button>
</div>
<div class="calc-row">
<button class="calc-btn operation"
onclick="calcOperation('AND', 'fat32')">AND</button>
<button class="calc-btn operation"
onclick="calcOperation('OR', 'fat32')">OR</button>
<button class="calc-btn number" onclick="calcInput('9', 'fat32')">9</button>
<button class="calc-btn operation" onclick="calcOperation('/', 'fat32')">/</button>
<button class="calc-btn operation"
onclick="calcOperation('MOD', 'fat32')">MOD</button>
</div>
<div class="calc-row">
<button class="calc-btn operation"
onclick="calcOperation('XOR', 'fat32')">XOR</button>
<button class="calc-btn operation"
onclick="calcOperation('NOT', 'fat32')">NOT</button>
<button class="calc-btn number" onclick="calcInput('4', 'fat32')">4</button>
<button class="calc-btn number" onclick="calcInput('5', 'fat32')">5</button>
<button class="calc-btn number" onclick="calcInput('6', 'fat32')">6</button>
</div>
<div class="calc-row">
<button class="calc-btn operation" onclick="calcOperation('*', 'fat32')">*</button>
<button class="calc-btn number" onclick="calcInput('1', 'fat32')">1</button>
<button class="calc-btn number" onclick="calcInput('2', 'fat32')">2</button>
<button class="calc-btn number" onclick="calcInput('3', 'fat32')">3</button>
<button class="calc-btn operation" onclick="calcOperation('-', 'fat32')">-</button>
</div>
<div class="calc-row">
<button class="calc-btn operation" onclick="calcOperation('+', 'fat32')">+</button>
<button class="calc-btn number wide" onclick="calcInput('0', 'fat32')">0</button>
<button class="calc-btn backspace" onclick="calcBackspace('fat32')"></button>
<button class="calc-btn equals" onclick="calcEquals('fat32')">=</button>
</div>
</div>
</div>
</div>
</div>
<div class="section">
<h2>Eingabeparameter</h2>
<div class="input-grid">
<div class="input-group">
<label for="reservedSectors32">Anzahl reservierter Sektoren <span
class="unit-indicator">(Sektoren)</span>:</label>
<input type="text" id="reservedSectors32" placeholder="0x20">
</div>
<div class="input-group">
<label for="numFATs32">Anzahl FATs <span class="unit-indicator">(Anzahl)</span>:</label>
<input type="text" id="numFATs32" placeholder="0x2">
</div>
<div class="input-group">
<label for="fatSizeBytes32">Größe einer FAT <span
class="unit-indicator">(Bytes)</span>:</label>
<input type="text" id="fatSizeBytes32" placeholder="0x10000">
</div>
<div class="input-group">
<label for="rootDirCluster32">Root Directory Cluster <span
class="unit-indicator">(Nummer)</span>:</label>
<input type="text" id="rootDirCluster32" placeholder="0x2">
</div>
<div class="input-group">
<label for="partitionSizeInSectors32">Größe Partition <span
class="unit-indicator">(Sektoren)</span>:</label>
<input type="text" id="partitionSizeInSectors32" placeholder="0x20000">
</div>
<div class="input-group">
<label for="clusterSizeSectors32">Größe eines Clusters <span
class="unit-indicator">(Sektoren)</span>:</label>
<input type="text" id="clusterSizeSectors32" placeholder="0x8">
</div>
<div class="input-group">
<label for="clusterNumber32">Cluster Nummer für Position <span
class="unit-indicator">(Nummer)</span>:</label>
<input type="text" id="clusterNumber32" placeholder="0x2">
</div>
</div>
</div>
<div class="section results">
<h2>Berechnete Werte</h2>
<div id="results32">
<div class="result-item">
<span class="result-label" data-formula="reservedSectors × sectorSize + baseOffset">Beginn
FAT-Bereich:</span>
<div class="result-value-container">
<span class="result-value" id="fatStart32" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('fatStart32')"
title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="numFATs × fatSizeBytes">Größe FAT-Bereich:</span>
<div class="result-value-container">
<span class="result-value" id="fatSize32" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('fatSize32')"
title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="fatStart + fatSize">Ende FAT-Bereich:</span>
<div class="result-value-container">
<span class="result-value" id="fatEnd32" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('fatEnd32')"
title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="fatEnd">Beginn Daten-Bereich:</span>
<div class="result-value-container">
<span class="result-value" id="dataStart32" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('dataStart32')"
title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label"
data-formula="(partitionSizeInSectors × sectorSize) - (dataStart - baseOffset)">Größe
Daten-Bereich:</span>
<div class="result-value-container">
<span class="result-value" id="dataSize32" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('dataSize32')"
title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="sectorSize × clusterSizeSectors">Größe eines
Clusters:</span>
<div class="result-value-container">
<span class="result-value" id="clusterSize32" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('clusterSize32')"
title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="dataSize ÷ clusterSize">Anzahl Cluster:</span>
<div class="result-value-container">
<span class="result-value" id="numClusters32" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('numClusters32')"
title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label"
data-formula="dataStart + (clusterNumber - 0x2) × clusterSize">Beginn Cluster:</span>
<div class="result-value-container">
<span class="result-value" id="clusterStart32" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('clusterStart32')"
title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label"
data-formula="dataStart + (rootDirCluster - 0x2) × clusterSize">Root Directory
Position:</span>
<div class="result-value-container">
<span class="result-value" id="rootDirPos32" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('rootDirPos32')"
title="Copy to clipboard">📋</button>
</div>
</div>
</div>
</div>
<div class="section formulas">
<h2>Berechnungsformeln FAT32</h2>
<div class="formula-box">
<div class="formula"><span class="calculated">Beginn FAT-Bereich</span> = Anzahl reservierter
Sektoren × Größe eines Sektors + Base Offset</div>
<div class="formula"><span class="calculated">Größe FAT-Bereich</span> = Anzahl FATs × Größe
einer FAT</div>
<div class="formula"><span class="calculated">Ende FAT-Bereich</span> = Beginn FAT-Bereich +
Größe FAT-Bereich</div>
<div class="formula"><span class="calculated">Beginn Daten-Bereich</span> = Ende FAT-Bereich
(kein festes Root Directory)</div>
<div class="formula"><span class="calculated">Größe Daten-Bereich</span> = (Größe Partition in
Sektoren × Größe eines Sektors) - (Beginn Daten-Bereich - Base Offset)</div>
<div class="formula"><span class="calculated">Größe eines Clusters</span> = Größe eines Sektors
× Größe eines Clusters in Sektoren</div>
<div class="formula"><span class="calculated">Anzahl Cluster</span> = Größe Daten-Bereich ÷
Größe eines Clusters</div>
<div class="formula"><span class="calculated">Beginn Cluster</span> = Beginn Daten-Bereich +
(Cluster - 0x2) × Größe eines Clusters</div>
<div class="formula"><span class="calculated">Root Directory Position</span> = Beginn
Daten-Bereich + (Root Directory Cluster - 0x2) × Größe eines Clusters</div>
</div>
</div>
</div>
</div>
</main>
<footer class="footer">
<div class="footer-content">
<div class="footer-section">
<h3>About</h3>
<p>Offset calculator for educational and forensic purposes.</p>
<p>Version 0.2.0</p>
</div>
<div class="footer-section">
<h3>Support</h3>
<a href="mailto:mstoeck3@hs-mittweida.de">Contact Support</a>
<a href="https://git.cc24.dev/mstoeck3/fscalc/issues/new">Report Bug</a>
</div>
<div class="footer-section">
<h3>Legal</h3>
<a href="https://git.cc24.dev/mstoeck3/fscalc/src/branch/main/LICENSE">License</a>
</div>
<div class="footer-section">
<h3>Connect</h3>
<a href="https://git.cc24.dev/mstoeck3/fscalc">Gitea Repository</a>
</div>
</div>
<div class="footer-bottom">
<p>&copy; 2025 Offset Calculator. All rights reserved. | Built with ❤️ for computer science education.</p>
</div>
</footer>
<script>
// Global tooltip element
let tooltip = null;
// Calculator state
const calculatorState = {
fat1216: {
currentValue: 0,
previousValue: 0,
operation: null,
waitingForOperand: false,
memory: 0
},
fat32: {
currentValue: 0,
previousValue: 0,
operation: null,
waitingForOperand: false,
memory: 0
}
};
function getCurrentTab() {
const activeTab = document.querySelector('.tab-content.active');
return activeTab.id === 'fat32' ? 'fat32' : 'fat1216';
}
function getCalculatorState(tab = null) {
const currentTab = tab || getCurrentTab();
return currentTab === 'fat32' ? calculatorState.fat32 : calculatorState.fat1216;
}
function updateCalculatorDisplay(tab = null) {
const currentTab = tab || getCurrentTab();
const state = getCalculatorState(currentTab);
const suffix = currentTab === 'fat32' ? '32' : '';
const inputElement = document.getElementById(`calcInput${suffix}`);
const hexElement = document.getElementById(`hexValue${suffix}`);
const decElement = document.getElementById(`decValue${suffix}`);
const binElement = document.getElementById(`binValue${suffix}`);
// Ensure value is within JavaScript's safe integer range
const value = Math.max(0, Math.min(state.currentValue, Number.MAX_SAFE_INTEGER));
const hexStr = '0x' + value.toString(16).toUpperCase();
const decStr = value.toString(10);
const binStr = '0b' + value.toString(2);
inputElement.value = hexStr;
hexElement.textContent = hexStr;
decElement.textContent = decStr;
binElement.textContent = binStr;
}
function calcInput(digit, tab = null) {
const currentTab = tab || getCurrentTab();
const state = getCalculatorState(currentTab);
if (state.waitingForOperand) {
state.currentValue = 0;
state.waitingForOperand = false;
}
// Convert hex digit to number
const digitValue = parseInt(digit, 16);
if (isNaN(digitValue)) return;
// Prevent overflow by limiting to a reasonable hex value
const newValue = state.currentValue * 16 + digitValue;
if (newValue <= 0xFFFFFFFFFFFFFF) { // Limit to 56 bits for safety
state.currentValue = newValue;
}
updateCalculatorDisplay(currentTab);
}
function calcOperation(operation, tab = null) {
const currentTab = tab || getCurrentTab();
const state = getCalculatorState(currentTab);
if (operation === 'NOT') {
// Unary operation - apply immediately
state.currentValue = (~state.currentValue) >>> 0; // Use unsigned 32-bit
updateCalculatorDisplay(currentTab);
return;
}
if (state.previousValue !== 0 && !state.waitingForOperand) {
calcEquals(currentTab, false);
}
state.previousValue = state.currentValue;
state.operation = operation;
state.waitingForOperand = true;
}
function calcEquals(tab = null, updateDisplay = true) {
const currentTab = tab || getCurrentTab();
const state = getCalculatorState(currentTab);
if (state.operation && state.previousValue !== null) {
const prev = state.previousValue;
const curr = state.currentValue;
try {
switch (state.operation) {
case '+':
state.currentValue = prev + curr;
break;
case '-':
state.currentValue = prev - curr;
break;
case '*':
state.currentValue = prev * curr;
break;
case '/':
if (curr === 0) {
alert('Division by zero!');
return;
}
state.currentValue = Math.floor(prev / curr);
break;
case 'MOD':
if (curr === 0) {
alert('Modulo by zero!');
return;
}
state.currentValue = prev % curr;
break;
case 'AND':
state.currentValue = (prev & curr) >>> 0;
break;
case 'OR':
state.currentValue = (prev | curr) >>> 0;
break;
case 'XOR':
state.currentValue = (prev ^ curr) >>> 0;
break;
case '<<':
state.currentValue = (prev << curr) >>> 0;
break;
case '>>':
state.currentValue = (prev >> curr) >>> 0;
break;
}
// Ensure positive value
if (state.currentValue < 0) {
state.currentValue = 0;
}
} catch (error) {
alert('Calculation error: ' + error.message);
state.currentValue = 0;
}
state.operation = null;
state.previousValue = 0;
state.waitingForOperand = true;
}
if (updateDisplay) {
updateCalculatorDisplay(currentTab);
}
}
function calcClear(tab = null) {
const currentTab = tab || getCurrentTab();
const state = getCalculatorState(currentTab);
state.currentValue = 0;
state.previousValue = 0;
state.operation = null;
state.waitingForOperand = false;
updateCalculatorDisplay(currentTab);
}
function calcBackspace(tab = null) {
const currentTab = tab || getCurrentTab();
const state = getCalculatorState(currentTab);
if (!state.waitingForOperand) {
state.currentValue = Math.floor(state.currentValue / 16);
updateCalculatorDisplay(currentTab);
}
}
function calcMemory(operation, tab = null) {
const currentTab = tab || getCurrentTab();
const state = getCalculatorState(currentTab);
switch (operation) {
case 'MC':
state.memory = 0;
break;
case 'MR':
state.currentValue = state.memory;
state.waitingForOperand = false;
updateCalculatorDisplay(currentTab);
break;
case 'M+':
state.memory += state.currentValue;
break;
case 'M-':
state.memory -= state.currentValue;
break;
}
}
// Create tooltip element
function createTooltip() {
if (!tooltip) {
tooltip = document.createElement('div');
tooltip.className = 'tooltip';
tooltip.style.display = 'none';
document.body.appendChild(tooltip);
}
}
// Show tooltip
function showTooltip(element, text) {
createTooltip();
tooltip.innerHTML = text;
tooltip.style.display = 'block';
const rect = element.getBoundingClientRect();
const tooltipRect = tooltip.getBoundingClientRect();
let left = rect.left + (rect.width / 2) - (tooltipRect.width / 2);
let top = rect.top - tooltipRect.height - 8;
// Keep tooltip within viewport
if (left < 10) left = 10;
if (left + tooltipRect.width > window.innerWidth - 10) {
left = window.innerWidth - tooltipRect.width - 10;
}
if (top < 10) {
top = rect.bottom + 8;
}
tooltip.style.left = left + 'px';
tooltip.style.top = top + 'px';
}
// Hide tooltip
function hideTooltip() {
if (tooltip) {
tooltip.style.display = 'none';
}
}
// Filesystem calculation implementations
const filesystems = {
fat1216: {
requiredFields: ['reservedSectors1216', 'numFATs1216', 'fatSizeBytes1216', 'maxRootEntries1216', 'partitionSizeInSectors1216', 'clusterSizeSectors1216'],
calculate: function () {
const baseOffset = parseHex(document.getElementById('baseOffset1216').value);
const sectorSize = parseHex(document.getElementById('sectorSize1216').value);
const reservedSectors = parseHex(document.getElementById('reservedSectors1216').value);
const numFATs = parseHex(document.getElementById('numFATs1216').value);
const fatSizeBytes = parseHex(document.getElementById('fatSizeBytes1216').value);
const maxRootEntries = parseHex(document.getElementById('maxRootEntries1216').value);
const partitionSizeInSectors = parseHex(document.getElementById('partitionSizeInSectors1216').value);
const clusterSizeSectors = parseHex(document.getElementById('clusterSizeSectors1216').value);
const clusterNumber = parseHex(document.getElementById('clusterNumber1216').value);
const fatStart = reservedSectors * sectorSize + baseOffset;
const fatSize = numFATs * fatSizeBytes;
const fatEnd = fatStart + fatSize;
const rootDirStart = fatEnd;
const rootDirSize = maxRootEntries * 0x20;
const dataStart = fatEnd + rootDirSize;
const dataSize = partitionSizeInSectors * sectorSize - (dataStart - baseOffset);
const clusterSize = sectorSize * clusterSizeSectors;
const numClusters = clusterSize > 0 ? Math.floor(dataSize / clusterSize) : 0;
const clusterStart = dataStart + (clusterNumber - 0x2) * clusterSize;
const calculations = {
fatStart: `${reservedSectors.toString(16)} × ${sectorSize.toString(16)} + ${baseOffset.toString(16)} = ${fatStart.toString(16)}`,
fatSize: `${numFATs.toString(16)} × ${fatSizeBytes.toString(16)} = ${fatSize.toString(16)}`,
fatEnd: `${fatStart.toString(16)} + ${fatSize.toString(16)} = ${fatEnd.toString(16)}`,
rootDirStart: `${fatEnd.toString(16)}`,
rootDirSize: `${maxRootEntries.toString(16)} × 0x20 = ${rootDirSize.toString(16)}`,
dataStart: `${fatEnd.toString(16)} + ${rootDirSize.toString(16)} = ${dataStart.toString(16)}`,
dataSize: `(${partitionSizeInSectors.toString(16)} × ${sectorSize.toString(16)}) - (${dataStart.toString(16)} - ${baseOffset.toString(16)}) = ${dataSize.toString(16)}`,
clusterSize: `${sectorSize.toString(16)} × ${clusterSizeSectors.toString(16)} = ${clusterSize.toString(16)}`,
numClusters: `${dataSize.toString(16)} ÷ ${clusterSize.toString(16)} = ${numClusters.toString(16)}`,
clusterStart: `${dataStart.toString(16)} + (${clusterNumber.toString(16)} - 0x2) × ${clusterSize.toString(16)} = ${clusterStart.toString(16)}`
};
return {
fatStart, fatSize, fatEnd, rootDirStart, rootDirSize, dataStart, dataSize,
clusterSize, numClusters, clusterStart, calculations
};
}
},
fat32: {
requiredFields: ['reservedSectors32', 'numFATs32', 'fatSizeBytes32', 'rootDirCluster32', 'partitionSizeInSectors32', 'clusterSizeSectors32'],
calculate: function () {
const baseOffset = parseHex(document.getElementById('baseOffset32').value);
const sectorSize = parseHex(document.getElementById('sectorSize32').value);
const reservedSectors = parseHex(document.getElementById('reservedSectors32').value);
const numFATs = parseHex(document.getElementById('numFATs32').value);
const fatSizeBytes = parseHex(document.getElementById('fatSizeBytes32').value);
const rootDirCluster = parseHex(document.getElementById('rootDirCluster32').value);
const partitionSizeInSectors = parseHex(document.getElementById('partitionSizeInSectors32').value);
const clusterSizeSectors = parseHex(document.getElementById('clusterSizeSectors32').value);
const clusterNumber = parseHex(document.getElementById('clusterNumber32').value);
const fatStart = reservedSectors * sectorSize + baseOffset;
const fatSize = numFATs * fatSizeBytes;
const fatEnd = fatStart + fatSize;
const dataStart = fatEnd;
const dataSize = partitionSizeInSectors * sectorSize - (dataStart - baseOffset);
const clusterSize = sectorSize * clusterSizeSectors;
const numClusters = clusterSize > 0 ? Math.floor(dataSize / clusterSize) : 0;
const clusterStart = dataStart + (clusterNumber - 0x2) * clusterSize;
const rootDirPos = dataStart + (rootDirCluster - 0x2) * clusterSize;
const calculations = {
fatStart: `${reservedSectors.toString(16)} × ${sectorSize.toString(16)} + ${baseOffset.toString(16)} = ${fatStart.toString(16)}`,
fatSize: `${numFATs.toString(16)} × ${fatSizeBytes.toString(16)} = ${fatSize.toString(16)}`,
fatEnd: `${fatStart.toString(16)} + ${fatSize.toString(16)} = ${fatEnd.toString(16)}`,
dataStart: `${fatEnd.toString(16)}`,
dataSize: `(${partitionSizeInSectors.toString(16)} × ${sectorSize.toString(16)}) - (${dataStart.toString(16)} - ${baseOffset.toString(16)}) = ${dataSize.toString(16)}`,
clusterSize: `${sectorSize.toString(16)} × ${clusterSizeSectors.toString(16)} = ${clusterSize.toString(16)}`,
numClusters: `${dataSize.toString(16)} ÷ ${clusterSize.toString(16)} = ${numClusters.toString(16)}`,
clusterStart: `${dataStart.toString(16)} + (${clusterNumber.toString(16)} - 0x2) × ${clusterSize.toString(16)} = ${clusterStart.toString(16)}`,
rootDirPos: `${dataStart.toString(16)} + (${rootDirCluster.toString(16)} - 0x2) × ${clusterSize.toString(16)} = ${rootDirPos.toString(16)}`
};
return {
fatStart, fatSize, fatEnd, dataStart, dataSize,
clusterSize, numClusters, clusterStart, rootDirPos, calculations
};
}
}
};
function parseHex(value) {
if (!value) return 0;
let cleanValue = value.toString().trim();
if (cleanValue.startsWith('0x') || cleanValue.startsWith('0X')) {
cleanValue = cleanValue.substring(2);
}
const parsed = parseInt(cleanValue, 16);
return isNaN(parsed) ? 0 : parsed;
}
function formatHex(value) {
if (isNaN(value) || value < 0) {
return '<span class="error">Fehler</span>';
}
return '0x' + value.toString(16).toUpperCase();
}
function copyToClipboard(elementId) {
const element = document.getElementById(elementId);
const text = element.textContent.trim();
if (text === '-' || text.includes('Fehler')) {
return;
}
navigator.clipboard.writeText(text).then(() => {
const btn = element.parentElement.querySelector('.copy-btn');
const originalText = btn.textContent;
btn.textContent = '✓';
btn.style.color = '#88cc88';
setTimeout(() => {
btn.textContent = originalText;
btn.style.color = '';
}, 1000);
}).catch(err => {
console.error('Failed to copy to clipboard:', err);
});
}
function switchTab(tabId) {
document.querySelectorAll('.tab-content').forEach(content => {
content.classList.remove('active');
});
document.querySelectorAll('.tab').forEach(tab => {
tab.classList.remove('active');
});
document.getElementById(tabId).classList.add('active');
event.target.classList.add('active');
// Update calculator display when switching tabs
updateCalculatorDisplay(tabId);
}
function calculate(fsType) {
try {
const fs = filesystems[fsType];
if (!fs) {
alert('Unknown filesystem type: ' + fsType);
return;
}
const results = fs.calculate();
if (fsType === 'fat1216') {
const mapping = {
'fatStart1216': ['fatStart', 'fatStart'],
'fatSize1216': ['fatSize', 'fatSize'],
'fatEnd1216': ['fatEnd', 'fatEnd'],
'rootDirStart1216': ['rootDirStart', 'rootDirStart'],
'rootDirSize1216': ['rootDirSize', 'rootDirSize'],
'dataStart1216': ['dataStart', 'dataStart'],
'dataSize1216': ['dataSize', 'dataSize'],
'clusterSize1216': ['clusterSize', 'clusterSize'],
'numClusters1216': ['numClusters', 'numClusters'],
'clusterStart1216': ['clusterStart', 'clusterStart']
};
Object.entries(mapping).forEach(([elementId, [resultKey, calcKey]]) => {
const element = document.getElementById(elementId);
element.innerHTML = formatHex(results[resultKey]);
element.setAttribute('data-result-formula', results.calculations[calcKey]);
});
} else if (fsType === 'fat32') {
const mapping = {
'fatStart32': ['fatStart', 'fatStart'],
'fatSize32': ['fatSize', 'fatSize'],
'fatEnd32': ['fatEnd', 'fatEnd'],
'dataStart32': ['dataStart', 'dataStart'],
'dataSize32': ['dataSize', 'dataSize'],
'clusterSize32': ['clusterSize', 'clusterSize'],
'numClusters32': ['numClusters', 'numClusters'],
'clusterStart32': ['clusterStart', 'clusterStart'],
'rootDirPos32': ['rootDirPos', 'rootDirPos']
};
Object.entries(mapping).forEach(([elementId, [resultKey, calcKey]]) => {
const element = document.getElementById(elementId);
element.innerHTML = formatHex(results[resultKey]);
element.setAttribute('data-result-formula', results.calculations[calcKey]);
});
}
} catch (error) {
alert('Fehler bei der Berechnung: ' + error.message);
console.error('Calculation error:', error);
}
}
// Add event listeners
document.addEventListener('DOMContentLoaded', function () {
// Initialize calculator displays
updateCalculatorDisplay('fat1216');
updateCalculatorDisplay('fat32');
// Real-time calculation for required fields
Object.keys(filesystems).forEach(fsType => {
const fs = filesystems[fsType];
fs.requiredFields.forEach(fieldId => {
const input = document.getElementById(fieldId);
if (input) {
input.addEventListener('input', function () {
const allFilled = fs.requiredFields.every(id =>
document.getElementById(id).value.trim() !== ''
);
if (allFilled) {
calculate(fsType);
}
});
}
});
});
// Real-time calculation for constants fields
['baseOffset1216', 'sectorSize1216'].forEach(fieldId => {
const input = document.getElementById(fieldId);
if (input) {
input.addEventListener('input', function () {
const fs = filesystems.fat1216;
const allFilled = fs.requiredFields.every(id =>
document.getElementById(id).value.trim() !== ''
);
if (allFilled) {
calculate('fat1216');
}
});
}
});
['baseOffset32', 'sectorSize32'].forEach(fieldId => {
const input = document.getElementById(fieldId);
if (input) {
input.addEventListener('input', function () {
const fs = filesystems.fat32;
const allFilled = fs.requiredFields.every(id =>
document.getElementById(id).value.trim() !== ''
);
if (allFilled) {
calculate('fat32');
}
});
}
});
// Add separate listeners for cluster number fields
['clusterNumber1216', 'clusterNumber32'].forEach(fieldId => {
const input = document.getElementById(fieldId);
if (input) {
input.addEventListener('input', function () {
const fsType = fieldId.includes('32') ? 'fat32' : 'fat1216';
const fs = filesystems[fsType];
const allFilled = fs.requiredFields.every(id =>
document.getElementById(id).value.trim() !== ''
);
if (allFilled) {
calculate(fsType);
}
});
}
});
// Keyboard input support for calculator
document.addEventListener('keydown', function (e) {
// Only handle keyboard input when not in an input field
if (e.target.tagName === 'INPUT') return;
const currentTab = getCurrentTab();
const key = e.key.toUpperCase();
// Handle hex digits
if (/^[0-9A-F]$/.test(key)) {
e.preventDefault();
calcInput(key, currentTab);
}
// Handle operations
else if (key === '+') {
e.preventDefault();
calcOperation('+', currentTab);
}
else if (key === '-') {
e.preventDefault();
calcOperation('-', currentTab);
}
else if (key === '*') {
e.preventDefault();
calcOperation('*', currentTab);
}
else if (key === '/') {
e.preventDefault();
calcOperation('/', currentTab);
}
else if (key === 'ENTER' || key === '=') {
e.preventDefault();
calcEquals(currentTab);
}
else if (key === 'ESCAPE' || key === 'C') {
e.preventDefault();
calcClear(currentTab);
}
else if (key === 'BACKSPACE') {
e.preventDefault();
calcBackspace(currentTab);
}
// Handle shift operations
else if (e.shiftKey && key === ',') { // < key
e.preventDefault();
calcOperation('<<', currentTab);
}
else if (e.shiftKey && key === '.') { // > key
e.preventDefault();
calcOperation('>>', currentTab);
}
});
// Tooltip event listeners
document.addEventListener('mouseover', function (e) {
if (e.target.classList.contains('result-label')) {
const formula = e.target.getAttribute('data-formula');
if (formula) {
showTooltip(e.target, `Formula: ${formula}`);
}
} else if (e.target.classList.contains('result-value')) {
const formula = e.target.getAttribute('data-result-formula');
if (formula && formula !== '') {
showTooltip(e.target, `Calculation: ${formula}`);
}
}
});
document.addEventListener('mouseout', function (e) {
if (e.target.classList.contains('result-label') || e.target.classList.contains('result-value')) {
hideTooltip();
}
});
// Hide tooltip when scrolling
document.addEventListener('scroll', hideTooltip);
});
</script>
</body>
</html>