calculator

This commit is contained in:
overcuriousity 2025-09-27 23:08:09 +02:00
parent 737f3b3400
commit d2970d42f4

View File

@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Filesystem Calculator</title>
<title>Dateisystem-Offset-Rechner</title>
<style>
* {
margin: 0;
@ -126,6 +126,198 @@
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;
@ -410,7 +602,7 @@
<div class="logo">Dateisystem-Offset-Rechner</div>
<nav class="nav">
<a href="#home">Home</a>
<a href="mailto:mstoeck3@hs-mittweida.de">Kontakt</a>
<a href="mailto:mstoeck3@hs-mittweida.de">Contact</a>
</nav>
</div>
</header>
@ -426,11 +618,12 @@
<!-- 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">Partitions-Offset <span class="unit-indicator">(Bytes)</span>:</label>
<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">
@ -440,6 +633,82 @@
</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">
@ -561,6 +830,7 @@
<!-- FAT32 Tab -->
<div class="tab-content" id="fat32">
<div class="constants-calculator-container">
<div class="section constants">
<h2>Konstanten</h2>
<div class="input-grid">
@ -575,6 +845,82 @@
</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">
@ -700,7 +1046,7 @@
<div class="footer-content">
<div class="footer-section">
<h3>About</h3>
<p>Filesystem calculator for educational and forensic purposes.</p>
<p>Offset calculator for educational and forensic purposes.</p>
<p>Version 0.2.0</p>
</div>
<div class="footer-section">
@ -718,7 +1064,7 @@
</div>
</div>
<div class="footer-bottom">
<p>&copy; 2025 Filesystem Calculator. All rights reserved. | Built with ❤️ for it-forensics education.</p>
<p>&copy; 2025 Offset Calculator. All rights reserved. | Built with ❤️ for computer science education.</p>
</div>
</footer>
@ -726,6 +1072,213 @@
// 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) {
@ -905,6 +1458,9 @@
document.getElementById(tabId).classList.add('active');
event.target.classList.add('active');
// Update calculator display when switching tabs
updateCalculatorDisplay(tabId);
}
function calculate(fsType) {
@ -961,37 +1517,12 @@
}
}
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() {
// Initialize calculator displays
updateCalculatorDisplay('fat1216');
updateCalculatorDisplay('fat32');
// Real-time calculation
Object.keys(filesystems).forEach(fsType => {
const fs = filesystems[fsType];
@ -1010,12 +1541,29 @@
});
});
// Add separate listeners for cluster number fields (optional but affect results)
['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);
}
});
}
});
// 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}`);
showTooltip(e.target, `Formula: ${formula}`);
}
} else if (e.target.classList.contains('result-value')) {
const formula = e.target.getAttribute('data-result-formula');