fscalc/index.html
overcuriousity 1a6cb18b32 typo
2025-09-27 22:44:16 +02:00

1041 lines
47 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>Filesystem Calculator</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;
}
/* 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">Filesystem Calculator</div>
<nav class="nav">
<a href="#home">Home</a>
<a href="#contact">Contact</a>
</nav>
</div>
</header>
<main class="main-content">
<div class="container">
<h1>Filesystem Structure Calculator</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="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">
<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="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="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">
<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>Filesystem calculator for educational and forensic purposes.</p>
<p>Version 0.2.0</p>
</div>
<div class="footer-section">
<h3>Support</h3>
<a href="#contact">Contact Support</a>
<a href="#bug-report">Report Bug</a>
</div>
<div class="footer-section">
<h3>Legal</h3>
<a href="#privacy">Privacy Policy</a>
<a href="#terms">Terms of Service</a>
<a href="#license">License</a>
</div>
<div class="footer-section">
<h3>Connect</h3>
<a href="#github">Gitea Repository</a>
</div>
</div>
<div class="footer-bottom">
<p>&copy; 2025 Filesystem Calculator. All rights reserved. | Built with ❤️ for computer science education.</p>
</div>
</footer>
<script>
// Global tooltip element
let tooltip = null;
// 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 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;
// Store calculation formulas with actual values
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)}`,
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, 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');
}
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'],
'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);
}
}
function clearAll(fsType) {
const fs = filesystems[fsType];
if (!fs) return;
fs.requiredFields.forEach(fieldId => {
const element = document.getElementById(fieldId);
if (element) element.value = '';
});
const clusterField = document.getElementById(`clusterNumber${fsType === 'fat1216' ? '1216' : '32'}`);
if (clusterField) clusterField.value = '';
if (fsType === 'fat1216') {
const resultElements = ['fatStart1216', 'fatSize1216', 'fatEnd1216', 'rootDirSize1216', 'dataStart1216', 'dataSize1216', 'clusterSize1216', 'numClusters1216', 'clusterStart1216'];
resultElements.forEach(id => {
const element = document.getElementById(id);
element.innerHTML = '-';
element.setAttribute('data-result-formula', '');
});
} else if (fsType === 'fat32') {
const resultElements = ['fatStart32', 'fatSize32', 'fatEnd32', 'dataStart32', 'dataSize32', 'clusterSize32', 'numClusters32', 'clusterStart32', 'rootDirPos32'];
resultElements.forEach(id => {
const element = document.getElementById(id);
element.innerHTML = '-';
element.setAttribute('data-result-formula', '');
});
}
}
// Add event listeners
document.addEventListener('DOMContentLoaded', function() {
// Real-time calculation
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);
}
});
}
});
});
// 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, `Formel: ${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>