// Base filesystem class that defines the common interface for all filesystem implementations. // Now supports multi-value result rows (bytes, sectors, etc.) in a single output line. import { parseHex, validateInput, checkDependencies, updateResultItem } from '../utils.js'; export class BaseFilesystem { constructor(name, variants = []) { this.name = name; this.variants = variants; // Array of variant configurations } // Abstract method to be implemented by subclasses getVariants() { return this.variants; } // Generate HTML for constants section generateConstantsHTML(variantId) { const variant = this.variants.find(v => v.id === variantId); if (!variant) return ''; // Helper function to format labels with offset information const formatLabel = (label) => { // Match patterns like "(Boot-Offset 0x00)", "(MFT-Header-Offset 0x14)", "(Superblock-Offset 0x00)", "(GDT-Offset 0x08)", "(Offset 0x00)" and wrap offset info const offsetPattern = /(\((Boot-Offset|MFT-Header-Offset|Superblock-Offset|GDT-Offset|Offset) [^)]+\))/g; return label.replace(offsetPattern, '$1'); }; return `

Konstanten

${variant.constants.map(constant => `
`).join('')}
`; } // Generate HTML for timestamp converter section (to be overridden by subclasses) generateTimestampConverterHTML(variantId) { // Default implementation returns empty string // Subclasses can override to provide filesystem-specific converters return ''; } // Generate HTML for input parameters section generateInputsHTML(variantId) { const variant = this.variants.find(v => v.id === variantId); if (!variant) return ''; // Helper function to format labels with offset information const formatLabel = (label) => { // Match patterns like "(Boot-Offset 0x00)", "(MFT-Header-Offset 0x14)", "(Superblock-Offset 0x00)", "(GDT-Offset 0x08)", "(Offset 0x00)" and wrap offset info const offsetPattern = /(\((Boot-Offset|MFT-Header-Offset|Superblock-Offset|GDT-Offset|Offset) [^)]+\))/g; return label.replace(offsetPattern, '$1'); }; return `

Eingabeparameter

${variant.inputs.map(input => `
`).join('')}
`; } // Generate HTML for results section generateResultsHTML(variantId) { const variant = this.variants.find(v => v.id === variantId); if (!variant) return ''; // Helper: get display units for a result (bytes, sectors, ...) function getDisplayUnits(result) { // Heuristic: if label contains (Bytes) or (Sektor), show both const label = result.label.toLowerCase(); const units = []; if (label.includes('bytes') || label.includes('byte')) units.push('bytes'); if (label.includes('sektor')) units.push('sectors'); // Add more as needed return units; } return `

Berechnete Werte

${variant.resultGroups.map(group => `

${group.name}

${group.results.map(result => { // For each result, show all representations in one row // The calculation logic must fill in all values in the result-value element, separated by // return `
${result.label}:
-
`; }).join('')}
`).join('')}
`; } // Generate HTML for formulas section generateFormulasHTML(variantId) { const variant = this.variants.find(v => v.id === variantId); if (!variant) return ''; return `

Berechnungsformeln ${this.name}

${variant.formulas.map(formula => `
${formula.name} = ${formula.expression}
`).join('')}
`; } // Generate complete tab content HTML generateTabContentHTML(variantId, calculatorHTML) { const timestampHTML = this.generateTimestampConverterHTML(variantId); return `
${this.generateConstantsHTML(variantId)} ${timestampHTML}

Hex-Rechner

${calculatorHTML}
${this.generateInputsHTML(variantId)} ${this.generateResultsHTML(variantId)} ${this.generateFormulasHTML(variantId)}
`; } // Abstract method for calculations - to be implemented by subclasses calculate(variantId) { throw new Error('calculate method must be implemented by subclass'); } // Validate that input values are within reasonable ranges validateInputRanges(variantId, values) { const variant = this.variants.find(v => v.id === variantId); if (!variant) return { valid: true, errors: [] }; const errors = []; // Basic sanity checks that can be applied to all filesystems // Check for extremely large values that would cause issues const maxSafeValue = Number.MAX_SAFE_INTEGER / 1024; // Allow some headroom Object.entries(values).forEach(([key, value]) => { if (typeof value === 'number' && value > maxSafeValue) { errors.push(`${key}: Wert zu groß (${value})`); } }); return { valid: errors.length === 0, errors: errors }; } // Abstract method for subclasses to override with specific validation validateFilesystemSpecific(variantId, values) { // Subclasses can override this for filesystem-specific validation return { valid: true, errors: [] }; } // Setup input event listeners for this filesystem setupInputListeners(variantId) { const variant = this.variants.find(v => v.id === variantId); if (!variant) return; const allInputIds = [ ...variant.constants.map(c => c.id), ...variant.inputs.map(i => i.id) ]; allInputIds.forEach(inputId => { const input = document.getElementById(inputId); if (input) { input.addEventListener('input', () => { validateInput(inputId, input.value); this.calculate(variantId); }); } }); } // Get all input values for a variant getInputValues(variantId) { const variant = this.variants.find(v => v.id === variantId); if (!variant) return {}; const values = {}; // Get constants variant.constants.forEach(constant => { const element = document.getElementById(constant.id); if (element) { const parsedValue = parseHex(element.value); values[constant.id] = parsedValue !== null ? parsedValue : 0; } }); // Get inputs variant.inputs.forEach(input => { const element = document.getElementById(input.id); if (element) { const parsedValue = parseHex(element.value); values[input.id] = parsedValue !== null ? parsedValue : 0; } }); return values; } }