fscalc/index.html
2025-09-27 22:09:31 +02:00

809 lines
33 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;
}
.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;
}
.result-item:last-child {
border-bottom: none;
}
.result-label {
color: #cccccc;
font-weight: normal;
flex: 1;
}
.result-value {
color: #ffffff;
font-family: 'Consolas', monospace;
text-align: right;
font-weight: bold;
min-width: 120px;
}
@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 (Partition Start):</label>
<input type="text" id="baseOffset1216" value="0x0" placeholder="0x0">
</div>
<div class="input-group">
<label for="sectorSize1216">Größe eines Sektors (Bytes):</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:</label>
<input type="text" id="reservedSectors1216" placeholder="0x1">
</div>
<div class="input-group">
<label for="numFATs1216">Anzahl FATs:</label>
<input type="text" id="numFATs1216" placeholder="0x2">
</div>
<div class="input-group">
<label for="fatSizeBytes1216">Größe einer FAT (Bytes):</label>
<input type="text" id="fatSizeBytes1216" placeholder="0x1000">
</div>
<div class="input-group">
<label for="maxRootEntries1216">Anzahl max. Wurzelverzeichnis-Einträge:</label>
<input type="text" id="maxRootEntries1216" placeholder="0x200">
</div>
<div class="input-group">
<label for="partitionSize1216">Größe Partition (Bytes):</label>
<input type="text" id="partitionSize1216" placeholder="0x100000">
</div>
<div class="input-group">
<label for="clusterSizeSectors1216">Größe eines Clusters (Sektoren):</label>
<input type="text" id="clusterSizeSectors1216" placeholder="0x1">
</div>
<div class="input-group">
<label for="clusterNumber1216">Cluster Nummer (für Position):</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">Beginn FAT-Bereich:</span>
<span class="result-value" id="fatStart1216">-</span>
</div>
<div class="result-item">
<span class="result-label">Größe FAT-Bereich:</span>
<span class="result-value" id="fatSize1216">-</span>
</div>
<div class="result-item">
<span class="result-label">Ende FAT-Bereich:</span>
<span class="result-value" id="fatEnd1216">-</span>
</div>
<div class="result-item">
<span class="result-label">Größe Wurzelverzeichnis:</span>
<span class="result-value" id="rootDirSize1216">-</span>
</div>
<div class="result-item">
<span class="result-label">Beginn Daten-Bereich:</span>
<span class="result-value" id="dataStart1216">-</span>
</div>
<div class="result-item">
<span class="result-label">Größe Daten-Bereich:</span>
<span class="result-value" id="dataSize1216">-</span>
</div>
<div class="result-item">
<span class="result-label">Größe eines Clusters:</span>
<span class="result-value" id="clusterSize1216">-</span>
</div>
<div class="result-item">
<span class="result-label">Anzahl Cluster:</span>
<span class="result-value" id="numClusters1216">-</span>
</div>
<div class="result-item">
<span class="result-label">Beginn Cluster:</span>
<span class="result-value" id="clusterStart1216">-</span>
</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 - (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 (Partition Start):</label>
<input type="text" id="baseOffset32" value="0x0" placeholder="0x0">
</div>
<div class="input-group">
<label for="sectorSize32">Größe eines Sektors (Bytes):</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:</label>
<input type="text" id="reservedSectors32" placeholder="0x20">
</div>
<div class="input-group">
<label for="numFATs32">Anzahl FATs:</label>
<input type="text" id="numFATs32" placeholder="0x2">
</div>
<div class="input-group">
<label for="fatSizeBytes32">Größe einer FAT (Bytes):</label>
<input type="text" id="fatSizeBytes32" placeholder="0x10000">
</div>
<div class="input-group">
<label for="rootDirCluster32">Root Directory Cluster:</label>
<input type="text" id="rootDirCluster32" placeholder="0x2">
</div>
<div class="input-group">
<label for="partitionSize32">Größe Partition (Bytes):</label>
<input type="text" id="partitionSize32" placeholder="0x10000000">
</div>
<div class="input-group">
<label for="clusterSizeSectors32">Größe eines Clusters (Sektoren):</label>
<input type="text" id="clusterSizeSectors32" placeholder="0x8">
</div>
<div class="input-group">
<label for="clusterNumber32">Cluster Nummer (für Position):</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">Beginn FAT-Bereich:</span>
<span class="result-value" id="fatStart32">-</span>
</div>
<div class="result-item">
<span class="result-label">Größe FAT-Bereich:</span>
<span class="result-value" id="fatSize32">-</span>
</div>
<div class="result-item">
<span class="result-label">Ende FAT-Bereich:</span>
<span class="result-value" id="fatEnd32">-</span>
</div>
<div class="result-item">
<span class="result-label">Beginn Daten-Bereich:</span>
<span class="result-value" id="dataStart32">-</span>
</div>
<div class="result-item">
<span class="result-label">Größe Daten-Bereich:</span>
<span class="result-value" id="dataSize32">-</span>
</div>
<div class="result-item">
<span class="result-label">Größe eines Clusters:</span>
<span class="result-value" id="clusterSize32">-</span>
</div>
<div class="result-item">
<span class="result-label">Anzahl Cluster:</span>
<span class="result-value" id="numClusters32">-</span>
</div>
<div class="result-item">
<span class="result-label">Beginn Cluster:</span>
<span class="result-value" id="clusterStart32">-</span>
</div>
<div class="result-item">
<span class="result-label">Root Directory Position:</span>
<span class="result-value" id="rootDirPos32">-</span>
</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 - (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.1.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>
// Filesystem calculation implementations
const filesystems = {
fat1216: {
requiredFields: ['reservedSectors1216', 'numFATs1216', 'fatSizeBytes1216', 'maxRootEntries1216', 'partitionSize1216', '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 partitionSize = parseHex(document.getElementById('partitionSize1216').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 = partitionSize - (dataStart - baseOffset);
const clusterSize = sectorSize * clusterSizeSectors;
const numClusters = clusterSize > 0 ? Math.floor(dataSize / clusterSize) : 0;
const clusterStart = dataStart + (clusterNumber - 0x2) * clusterSize;
return {
fatStart, fatSize, fatEnd, rootDirSize, dataStart, dataSize,
clusterSize, numClusters, clusterStart
};
}
},
fat32: {
requiredFields: ['reservedSectors32', 'numFATs32', 'fatSizeBytes32', 'rootDirCluster32', 'partitionSize32', '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 partitionSize = parseHex(document.getElementById('partitionSize32').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; // No fixed root directory in FAT32
const dataSize = partitionSize - (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;
return {
fatStart, fatSize, fatEnd, dataStart, dataSize,
clusterSize, numClusters, clusterStart, rootDirPos
};
}
}
};
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 switchTab(tabId) {
// Hide all tab contents
document.querySelectorAll('.tab-content').forEach(content => {
content.classList.remove('active');
});
// Remove active class from all tabs
document.querySelectorAll('.tab').forEach(tab => {
tab.classList.remove('active');
});
// Show selected tab content
document.getElementById(tabId).classList.add('active');
// Add active class to clicked tab
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();
// Update results based on filesystem type
if (fsType === 'fat1216') {
document.getElementById('fatStart1216').innerHTML = formatHex(results.fatStart);
document.getElementById('fatSize1216').innerHTML = formatHex(results.fatSize);
document.getElementById('fatEnd1216').innerHTML = formatHex(results.fatEnd);
document.getElementById('rootDirSize1216').innerHTML = formatHex(results.rootDirSize);
document.getElementById('dataStart1216').innerHTML = formatHex(results.dataStart);
document.getElementById('dataSize1216').innerHTML = formatHex(results.dataSize);
document.getElementById('clusterSize1216').innerHTML = formatHex(results.clusterSize);
document.getElementById('numClusters1216').innerHTML = formatHex(results.numClusters);
document.getElementById('clusterStart1216').innerHTML = formatHex(results.clusterStart);
} else if (fsType === 'fat32') {
document.getElementById('fatStart32').innerHTML = formatHex(results.fatStart);
document.getElementById('fatSize32').innerHTML = formatHex(results.fatSize);
document.getElementById('fatEnd32').innerHTML = formatHex(results.fatEnd);
document.getElementById('dataStart32').innerHTML = formatHex(results.dataStart);
document.getElementById('dataSize32').innerHTML = formatHex(results.dataSize);
document.getElementById('clusterSize32').innerHTML = formatHex(results.clusterSize);
document.getElementById('numClusters32').innerHTML = formatHex(results.numClusters);
document.getElementById('clusterStart32').innerHTML = formatHex(results.clusterStart);
document.getElementById('rootDirPos32').innerHTML = formatHex(results.rootDirPos);
}
} catch (error) {
alert('Fehler bei der Berechnung: ' + error.message);
console.error('Calculation error:', error);
}
}
function clearAll(fsType) {
const fs = filesystems[fsType];
if (!fs) return;
// Clear input fields
fs.requiredFields.forEach(fieldId => {
const element = document.getElementById(fieldId);
if (element) element.value = '';
});
// Clear cluster number field
const clusterField = document.getElementById(`clusterNumber${fsType === 'fat1216' ? '1216' : '32'}`);
if (clusterField) clusterField.value = '';
// Reset results
if (fsType === 'fat1216') {
const resultElements = ['fatStart1216', 'fatSize1216', 'fatEnd1216', 'rootDirSize1216', 'dataStart1216', 'dataSize1216', 'clusterSize1216', 'numClusters1216', 'clusterStart1216'];
resultElements.forEach(id => {
document.getElementById(id).innerHTML = '-';
});
} else if (fsType === 'fat32') {
const resultElements = ['fatStart32', 'fatSize32', 'fatEnd32', 'dataStart32', 'dataSize32', 'clusterSize32', 'numClusters32', 'clusterStart32', 'rootDirPos32'];
resultElements.forEach(id => {
document.getElementById(id).innerHTML = '-';
});
}
}
// Add event listeners for real-time calculation
document.addEventListener('DOMContentLoaded', function() {
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);
}
});
}
});
});
});
</script>
</body>
</html>
87.123.43.152