393 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			393 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
// FAT filesystem implementation (FAT12/16 and FAT32)
 | 
						||
 | 
						||
// FAT filesystem implementation (FAT12/16 and FAT32 split)
 | 
						||
 | 
						||
import { BaseFilesystem } from './base.js';
 | 
						||
import { checkDependencies, updateResultItem } from '../utils.js';
 | 
						||
 | 
						||
export class FAT12_16Filesystem extends BaseFilesystem {
 | 
						||
    calculate(variantId) {
 | 
						||
        if (variantId !== 'fat1216') return;
 | 
						||
        const values = {};
 | 
						||
        const results = {};
 | 
						||
        // Gather all input values for this variant
 | 
						||
        const variant = this.variants.find(v => v.id === variantId);
 | 
						||
        if (!variant) return;
 | 
						||
        [...variant.constants, ...variant.inputs].forEach(field => {
 | 
						||
            const el = document.getElementById(field.id);
 | 
						||
            if (el) {
 | 
						||
                let val = el.value;
 | 
						||
                if (val && val.startsWith('0x')) {
 | 
						||
                    values[field.id] = parseInt(val, 16);
 | 
						||
                } else {
 | 
						||
                    values[field.id] = Number(val) || 0;
 | 
						||
                }
 | 
						||
            }
 | 
						||
        });
 | 
						||
        this.calculateFAT1216(values, results);
 | 
						||
    }
 | 
						||
    constructor() {
 | 
						||
        super('FAT12/16', [
 | 
						||
            {
 | 
						||
                id: 'fat1216',
 | 
						||
                name: 'FAT12/16',
 | 
						||
                constants: [
 | 
						||
                    { id: 'baseOffset1216', label: 'Basis-Offset', unit: 'Bytes', default: '0x0' },
 | 
						||
                    { id: 'sectorSize1216', label: 'Sektor-Größe (Boot-Offset 0x0B)', unit: 'Bytes', default: '0x200' }
 | 
						||
                ],
 | 
						||
                inputs: [
 | 
						||
                    { id: 'reservedSektoren1216', label: 'Reservierte Sektoren (Boot-Offset 0x0E)', unit: 'Anzahl', placeholder: '0x1' },
 | 
						||
                    { id: 'numFATs1216', label: 'Anzahl FATs (Boot-Offset 0x10)', unit: 'Anzahl', placeholder: '0x2' },
 | 
						||
                    { id: 'fatSizeSectors1216', label: 'FAT-Größe (Boot-Offset 0x16)', unit: 'Sektoren', placeholder: '0x4000' },
 | 
						||
                    { id: 'maxRootEntries1216', label: 'Max. Root-Einträge (Boot-Offset 0x11)', unit: 'Anzahl', placeholder: '0x200' },
 | 
						||
                    { id: 'partitionSizeInSectors1216', label: 'Partitionsgröße (Boot-Offset 0x13 oder 0x20)', unit: 'Sektoren', placeholder: '0x4015' },
 | 
						||
                    { id: 'clusterSizeSectors1216', label: 'Clustergröße (Boot-Offset 0x0D)', unit: 'Sektoren', placeholder: '0x2' },
 | 
						||
                    { id: 'clusterNumber1216', label: 'Cluster-Nummer', unit: 'Nummer', placeholder: '0x2' }
 | 
						||
                ],
 | 
						||
                resultGroups: [
 | 
						||
                    {
 | 
						||
                        name: 'FAT-Struktur',
 | 
						||
                        results: [
 | 
						||
                            { id: 'fatStart1216', label: 'FAT-Bereich Anfang', dependencies: ['reservedSektoren1216', 'sectorSize1216', 'baseOffset1216'], formula: 'reservedSektoren × sectorSize + baseOffset' },
 | 
						||
                            { id: 'fatSize1216', label: 'FAT-Bereich Größe', dependencies: ['numFATs1216', 'fatSizeSectors1216', 'sectorSize1216'], formula: 'numFATs × fatSizeSectors × sectorSize' },
 | 
						||
                            { id: 'fat2Start1216', label: 'FAT2 Anfang', dependencies: ['reservedSektoren1216', 'sectorSize1216', 'baseOffset1216', 'fatSizeSectors1216'], formula: 'fatStart + (fatSizeSectors × sectorSize)' },
 | 
						||
                            { id: 'fatEnd1216', label: 'FAT-Bereich Ende', dependencies: ['reservedSektoren1216', 'sectorSize1216', 'baseOffset1216', 'numFATs1216', 'fatSizeSectors1216'], formula: 'fatStart + fatSize' }
 | 
						||
                        ]
 | 
						||
                    },
 | 
						||
                    {
 | 
						||
                        name: 'Root-Directory',
 | 
						||
                        results: [
 | 
						||
                            { id: 'rootDirStart1216', label: 'Root-Directory Anfang', dependencies: ['reservedSektoren1216', 'sectorSize1216', 'baseOffset1216', 'numFATs1216', 'fatSizeSectors1216'], formula: 'fatEnd' },
 | 
						||
                            { id: 'rootDirSize1216', label: 'Root-Directory Größe', dependencies: ['maxRootEntries1216'], formula: 'maxRootEntries × 0x20' }
 | 
						||
                        ]
 | 
						||
                    },
 | 
						||
                    {
 | 
						||
                        name: 'Daten-Bereich',
 | 
						||
                        results: [
 | 
						||
                            { id: 'dataStart1216', label: 'Daten-Bereich Anfang', dependencies: ['reservedSektoren1216', 'sectorSize1216', 'baseOffset1216', 'numFATs1216', 'fatSizeSectors1216', 'maxRootEntries1216'], formula: 'fatEnd + rootDirSize' },
 | 
						||
                            { id: 'dataSize1216', label: 'Daten-Bereich Größe', dependencies: ['partitionSizeInSectors1216', 'sectorSize1216', 'reservedSektoren1216', 'baseOffset1216', 'numFATs1216', 'fatSizeSectors1216', 'maxRootEntries1216'], formula: '(partitionSizeInSectors × sectorSize) - (dataStart - baseOffset)' },
 | 
						||
                            { id: 'clusterSize1216', label: 'Cluster-Größe', dependencies: ['sectorSize1216', 'clusterSizeSectors1216'], formula: 'sectorSize × clusterSizeSectors' },
 | 
						||
                            { id: 'numClusters1216', label: 'Anzahl Cluster', dependencies: ['partitionSizeInSectors1216', 'sectorSize1216', 'reservedSektoren1216', 'baseOffset1216', 'numFATs1216', 'fatSizeSectors1216', 'maxRootEntries1216', 'clusterSizeSectors1216'], formula: 'dataSize ÷ clusterSize' }
 | 
						||
                        ]
 | 
						||
                    },
 | 
						||
                    {
 | 
						||
                        name: 'Spezifischer Cluster',
 | 
						||
                        results: [
 | 
						||
                            { id: 'clusterStart1216', label: 'Cluster Anfang', dependencies: ['reservedSektoren1216', 'sectorSize1216', 'baseOffset1216', 'numFATs1216', 'fatSizeSectors1216', 'maxRootEntries1216', 'clusterSizeSectors1216', 'clusterNumber1216'], formula: 'dataStart + (clusterNumber - 0x2) × clusterSize' },
 | 
						||
                            { id: 'fatEntryPos1216', label: 'FAT-Eintrag Position (nur FAT16)', dependencies: ['reservedSektoren1216', 'sectorSize1216', 'baseOffset1216', 'clusterNumber1216'], formula: 'fatStart + (clusterNumber × 2) für FAT16' }
 | 
						||
                        ]
 | 
						||
                    }
 | 
						||
                ],
 | 
						||
                formulas: [
 | 
						||
                    { name: 'FAT-Bereich Anfang', expression: 'Reservierte Sektoren × Sektorgröße + Basis-Offset' },
 | 
						||
                    { name: 'FAT-Bereich Größe', expression: 'Anzahl FATs × FAT-Größe in Sektoren × Sektorgröße' },
 | 
						||
                    { name: 'FAT2 Anfang', expression: 'FAT-Bereich Anfang + FAT-Größe in Bytes' },
 | 
						||
                    { name: 'FAT-Bereich Ende', expression: 'FAT-Bereich Anfang + FAT-Bereich Größe' },
 | 
						||
                    { name: 'Root-Directory Größe', expression: 'Max. Root-Einträge × 0x20' },
 | 
						||
                    { name: 'Daten-Bereich Anfang', expression: 'FAT-Bereich Ende + Root-Directory Größe' },
 | 
						||
                    { name: 'Daten-Bereich Größe', expression: '(Partitionsgröße × Sektorgröße) - (Daten-Bereich Anfang - Basis-Offset)' },
 | 
						||
                    { name: 'Cluster-Größe', expression: 'Sektorgröße × Cluster-Größe in Sektoren' },
 | 
						||
                    { name: 'Anzahl Cluster', expression: 'Daten-Bereich Größe ÷ Cluster-Größe' },
 | 
						||
                    { name: 'Cluster Anfang', expression: 'Daten-Bereich Anfang + (Cluster-Nummer - 0x2) × Cluster-Größe' },
 | 
						||
                    { name: 'FAT-Eintrag Position', expression: 'FAT-Bereich Anfang + (Cluster-Nummer × Eintraggröße)' }
 | 
						||
                ]
 | 
						||
            }
 | 
						||
        ]);
 | 
						||
    }
 | 
						||
 | 
						||
    calculateFAT1216(values, results) {
 | 
						||
        const suffix = '1216';
 | 
						||
        // FAT Start (show both bytes and sector in one row)
 | 
						||
        if (checkDependencies([`reservedSektoren${suffix}`, `sectorSize${suffix}`, `baseOffset${suffix}`])) {
 | 
						||
            results.fatStart = values.reservedSektoren1216 * values.sectorSize1216 + values.baseOffset1216;
 | 
						||
            results.fatStartSector = Math.floor(results.fatStart / values.sectorSize1216);
 | 
						||
            updateResultItem(`fatStart${suffix}`, { bytes: results.fatStart, sectors: results.fatStartSector }, true,
 | 
						||
                `0x${values.reservedSektoren1216.toString(16)} × 0x${values.sectorSize1216.toString(16)} + 0x${values.baseOffset1216.toString(16)} = 0x${results.fatStart.toString(16)}`);
 | 
						||
        } else {
 | 
						||
            updateResultItem(`fatStart${suffix}`, 0, false);
 | 
						||
        }
 | 
						||
        // FAT Size (bytes and sectors)
 | 
						||
        if (checkDependencies([`numFATs${suffix}`, `fatSizeSectors${suffix}`, `sectorSize${suffix}`])) {
 | 
						||
            results.fatSize = values.numFATs1216 * values.fatSizeSectors1216 * values.sectorSize1216;
 | 
						||
            results.fatSizeSectors = values.numFATs1216 * values.fatSizeSectors1216;
 | 
						||
            updateResultItem(`fatSize${suffix}`, { bytes: results.fatSize, sectors: results.fatSizeSectors }, true,
 | 
						||
                `0x${values.numFATs1216.toString(16)} × 0x${values.fatSizeSectors1216.toString(16)} × 0x${values.sectorSize1216.toString(16)} = 0x${results.fatSize.toString(16)}`);
 | 
						||
        } else {
 | 
						||
            updateResultItem(`fatSize${suffix}`, 0, false);
 | 
						||
        }
 | 
						||
        // FAT2 Start (bytes and sector)
 | 
						||
        if (checkDependencies([`reservedSektoren${suffix}`, `sectorSize${suffix}`, `baseOffset${suffix}`, `fatSizeSectors${suffix}`]) && results.fatStart !== undefined) {
 | 
						||
            results.fat2Start = results.fatStart + (values.fatSizeSectors1216 * values.sectorSize1216);
 | 
						||
            results.fat2StartSector = Math.floor(results.fat2Start / values.sectorSize1216);
 | 
						||
            updateResultItem(`fat2Start${suffix}`, { bytes: results.fat2Start, sectors: results.fat2StartSector }, true,
 | 
						||
                `0x${results.fatStart.toString(16)} + 0x${(values.fatSizeSectors1216 * values.sectorSize1216).toString(16)} = 0x${results.fat2Start.toString(16)}`);
 | 
						||
        } else {
 | 
						||
            updateResultItem(`fat2Start${suffix}`, 0, false);
 | 
						||
        }
 | 
						||
        // FAT End (bytes and sector)
 | 
						||
        if (results.fatStart !== undefined && results.fatSize !== undefined) {
 | 
						||
            results.fatEnd = results.fatStart + results.fatSize;
 | 
						||
            results.fatEndSector = Math.floor(results.fatEnd / values.sectorSize1216);
 | 
						||
            updateResultItem(`fatEnd${suffix}`, { bytes: results.fatEnd, sectors: results.fatEndSector }, true,
 | 
						||
                `0x${results.fatStart.toString(16)} + 0x${results.fatSize.toString(16)} = 0x${results.fatEnd.toString(16)}`);
 | 
						||
        } else {
 | 
						||
            updateResultItem(`fatEnd${suffix}`, 0, false);
 | 
						||
        }
 | 
						||
        // Root Directory Size
 | 
						||
        if (checkDependencies(['maxRootEntries1216'])) {
 | 
						||
            results.rootDirSize = values.maxRootEntries1216 * 0x20;
 | 
						||
            updateResultItem('rootDirSize1216', results.rootDirSize, true,
 | 
						||
                `0x${values.maxRootEntries1216.toString(16)} × 0x20 = 0x${results.rootDirSize.toString(16)}`);
 | 
						||
        } else {
 | 
						||
            updateResultItem('rootDirSize1216', 0, false);
 | 
						||
        }
 | 
						||
        // Root Directory Start (bytes and sector)
 | 
						||
        if (results.fatEnd !== undefined) {
 | 
						||
            results.rootDirStart = results.fatEnd;
 | 
						||
            results.rootDirStartSector = Math.floor(results.rootDirStart / values.sectorSize1216);
 | 
						||
            updateResultItem('rootDirStart1216', { bytes: results.rootDirStart, sectors: results.rootDirStartSector }, true,
 | 
						||
                `0x${results.fatEnd.toString(16)}`);
 | 
						||
        } else {
 | 
						||
            updateResultItem('rootDirStart1216', 0, false);
 | 
						||
        }
 | 
						||
        // Data Start (bytes and sector)
 | 
						||
        if (results.fatEnd !== undefined && results.rootDirSize !== undefined) {
 | 
						||
            results.dataStart = results.fatEnd + results.rootDirSize;
 | 
						||
            results.dataStartSector = Math.floor(results.dataStart / values.sectorSize1216);
 | 
						||
            updateResultItem('dataStart1216', { bytes: results.dataStart, sectors: results.dataStartSector }, true,
 | 
						||
                `0x${results.fatEnd.toString(16)} + 0x${results.rootDirSize.toString(16)} = 0x${results.dataStart.toString(16)}`);
 | 
						||
        } else {
 | 
						||
            updateResultItem('dataStart1216', 0, false);
 | 
						||
        }
 | 
						||
        // Data Size (Daten-Bereich Größe)
 | 
						||
        if (checkDependencies(['partitionSizeInSectors1216', 'sectorSize1216', 'reservedSektoren1216', 'numFATs1216', 'fatSizeSectors1216', 'maxRootEntries1216'])) {
 | 
						||
            // RootDirGröße in Sektoren = Math.ceil(maxRootEntries × 32 / sectorSize)
 | 
						||
            const rootDirSectors = Math.ceil((values.maxRootEntries1216 * 32) / values.sectorSize1216);
 | 
						||
            const dataAreaSectors = values.partitionSizeInSectors1216 - (values.reservedSektoren1216 + (values.numFATs1216 * values.fatSizeSectors1216) + rootDirSectors);
 | 
						||
            results.dataSize = dataAreaSectors * values.sectorSize1216;
 | 
						||
            results.dataAreaSectors = dataAreaSectors;
 | 
						||
            updateResultItem('dataSize1216', results.dataSize, true,
 | 
						||
                `(${values.partitionSizeInSectors1216} - (${values.reservedSektoren1216} + (${values.numFATs1216} × ${values.fatSizeSectors1216}) + ${rootDirSectors})) × ${values.sectorSize1216} = ${results.dataSize}`);
 | 
						||
        } else {
 | 
						||
            updateResultItem('dataSize1216', 0, false);
 | 
						||
        }
 | 
						||
        // Cluster Size
 | 
						||
        if (checkDependencies(['sectorSize1216', 'clusterSizeSectors1216'])) {
 | 
						||
            results.clusterSize = values.sectorSize1216 * values.clusterSizeSectors1216;
 | 
						||
            updateResultItem('clusterSize1216', results.clusterSize, true,
 | 
						||
                `0x${values.sectorSize1216.toString(16)} × 0x${values.clusterSizeSectors1216.toString(16)} = 0x${results.clusterSize.toString(16)}`);
 | 
						||
        } else {
 | 
						||
            updateResultItem('clusterSize1216', 0, false);
 | 
						||
        }
 | 
						||
        // Number of Clusters (Anzahl Cluster)
 | 
						||
        if (checkDependencies(['partitionSizeInSectors1216', 'sectorSize1216', 'reservedSektoren1216', 'numFATs1216', 'fatSizeSectors1216', 'maxRootEntries1216', 'clusterSizeSectors1216']) && results.dataAreaSectors !== undefined && values.clusterSizeSectors1216 > 0) {
 | 
						||
            results.numClusters = Math.floor(results.dataAreaSectors / values.clusterSizeSectors1216);
 | 
						||
            updateResultItem('numClusters1216', results.numClusters, true,
 | 
						||
                `${results.dataAreaSectors} ÷ ${values.clusterSizeSectors1216} = ${results.numClusters}`);
 | 
						||
        } else {
 | 
						||
            updateResultItem('numClusters1216', 0, false);
 | 
						||
        }
 | 
						||
        // Specific Cluster Start (bytes and sector)
 | 
						||
        if (checkDependencies(['reservedSektoren1216', 'sectorSize1216', 'baseOffset1216', 'numFATs1216', 'fatSizeSectors1216', 'maxRootEntries1216', 'clusterSizeSectors1216', 'clusterNumber1216']) && results.dataStart !== undefined && results.clusterSize !== undefined) {
 | 
						||
            results.clusterStart = results.dataStart + (values.clusterNumber1216 - 0x2) * results.clusterSize;
 | 
						||
            results.clusterStartSector = Math.floor(results.clusterStart / values.sectorSize1216);
 | 
						||
            updateResultItem('clusterStart1216', { bytes: results.clusterStart, sectors: results.clusterStartSector }, true,
 | 
						||
                `0x${results.dataStart.toString(16)} + (0x${values.clusterNumber1216.toString(16)} - 0x2) × 0x${results.clusterSize.toString(16)} = 0x${results.clusterStart.toString(16)}`);
 | 
						||
        } else {
 | 
						||
            updateResultItem('clusterStart1216', 0, false);
 | 
						||
        }
 | 
						||
        // FAT Entry Position (FAT16 only)
 | 
						||
        if (checkDependencies(['reservedSektoren1216', 'sectorSize1216', 'baseOffset1216', 'clusterNumber1216']) && results.fatStart !== undefined) {
 | 
						||
            const entrySize = 2; // FAT16 uses 2 bytes per entry
 | 
						||
            results.fatEntryPos = results.fatStart + (values.clusterNumber1216 * entrySize);
 | 
						||
            updateResultItem('fatEntryPos1216', results.fatEntryPos, true,
 | 
						||
                `0x${results.fatStart.toString(16)} + (0x${values.clusterNumber1216.toString(16)} × ${entrySize}) = 0x${results.fatEntryPos.toString(16)}`);
 | 
						||
        } else {
 | 
						||
            updateResultItem('fatEntryPos1216', 0, false);
 | 
						||
        }
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
export class FAT32Filesystem extends BaseFilesystem {
 | 
						||
    calculate(variantId) {
 | 
						||
        if (variantId !== 'fat32') return;
 | 
						||
        const values = {};
 | 
						||
        const results = {};
 | 
						||
        // Gather all input values for this variant
 | 
						||
        const variant = this.variants.find(v => v.id === variantId);
 | 
						||
        if (!variant) return;
 | 
						||
        [...variant.constants, ...variant.inputs].forEach(field => {
 | 
						||
            const el = document.getElementById(field.id);
 | 
						||
            if (el) {
 | 
						||
                let val = el.value;
 | 
						||
                if (val && val.startsWith('0x')) {
 | 
						||
                    values[field.id] = parseInt(val, 16);
 | 
						||
                } else {
 | 
						||
                    values[field.id] = Number(val) || 0;
 | 
						||
                }
 | 
						||
            }
 | 
						||
        });
 | 
						||
        this.calculateFAT32(values, results);
 | 
						||
    }
 | 
						||
    constructor() {
 | 
						||
        super('FAT32', [
 | 
						||
            {
 | 
						||
                id: 'fat32',
 | 
						||
                name: 'FAT32',
 | 
						||
                constants: [
 | 
						||
                    { id: 'baseOffset32', label: 'Basis-Offset', unit: 'Bytes', default: '0x0' },
 | 
						||
                    { id: 'sectorSize32', label: 'Sektor-Größe (Boot-Offset 0x0B)', unit: 'Bytes', default: '0x200' }
 | 
						||
                ],
 | 
						||
                inputs: [
 | 
						||
                    { id: 'reservedSectors32', label: 'Reservierte Sektoren (Boot-Offset 0x0E)', unit: 'Anzahl', placeholder: '0x20' },
 | 
						||
                    { id: 'numFATs32', label: 'Anzahl FATs (Boot-Offset 0x10)', unit: 'Anzahl', placeholder: '0x2' },
 | 
						||
                    { id: 'fatSizeSectors32', label: 'FAT-Größe (Boot-Offset 0x24)', unit: 'Sektoren', placeholder: '0x20000' },
 | 
						||
                    { id: 'rootDirCluster32', label: 'Root-Directory Cluster (Boot-Offset 0x2C)', unit: 'Nummer', placeholder: '0x2' },
 | 
						||
                    { id: 'partitionSizeInSectors32', label: 'Partitionsgröße (Boot-Offset 0x20)', unit: 'Sektoren', placeholder: '0x100000' },
 | 
						||
                    { id: 'clusterSizeSectors32', label: 'Clustergröße (Boot-Offset 0x0D)', unit: 'Sektoren', placeholder: '0x8' },
 | 
						||
                    { id: 'clusterNumber32', label: 'Cluster-Nummer', unit: 'Nummer', placeholder: '0x2' }
 | 
						||
                ],
 | 
						||
                resultGroups: [
 | 
						||
                    {
 | 
						||
                        name: 'FAT-Struktur',
 | 
						||
                        results: [
 | 
						||
                            { id: 'fatStart32', label: 'FAT-Bereich Anfang', dependencies: ['reservedSectors32', 'sectorSize32', 'baseOffset32'], formula: 'reservedSectors × sectorSize + baseOffset' },
 | 
						||
                            { id: 'fatSize32', label: 'FAT-Bereich Größe', dependencies: ['numFATs32', 'fatSizeSectors32', 'sectorSize32'], formula: 'numFATs × fatSizeSectors × sectorSize' },
 | 
						||
                            { id: 'fat2Start32', label: 'FAT2 Anfang', dependencies: ['reservedSectors32', 'sectorSize32', 'baseOffset32', 'fatSizeSectors32'], formula: 'fatStart + (fatSizeSectors × sectorSize)' },
 | 
						||
                            { id: 'fatEnd32', label: 'FAT-Bereich Ende', dependencies: ['reservedSectors32', 'sectorSize32', 'baseOffset32', 'numFATs32', 'fatSizeSectors32'], formula: 'fatStart + fatSize' }
 | 
						||
                        ]
 | 
						||
                    },
 | 
						||
                    {
 | 
						||
                        name: 'Daten-Bereich',
 | 
						||
                        results: [
 | 
						||
                            { id: 'dataStart32', label: 'Daten-Bereich Anfang', dependencies: ['reservedSectors32', 'sectorSize32', 'baseOffset32', 'numFATs32', 'fatSizeSectors32'], formula: 'fatEnd' },
 | 
						||
                            { id: 'dataSize32', label: 'Daten-Bereich Größe', dependencies: ['partitionSizeInSectors32', 'sectorSize32', 'reservedSectors32', 'baseOffset32', 'numFATs32', 'fatSizeSectors32'], formula: '(partitionSizeInSectors × sectorSize) - (dataStart - baseOffset)' },
 | 
						||
                            { id: 'clusterSize32', label: 'Cluster-Größe', dependencies: ['sectorSize32', 'clusterSizeSectors32'], formula: 'sectorSize × clusterSizeSectors' },
 | 
						||
                            { id: 'numClusters32', label: 'Anzahl Cluster', dependencies: ['partitionSizeInSectors32', 'sectorSize32', 'reservedSectors32', 'baseOffset32', 'numFATs32', 'fatSizeSectors32', 'clusterSizeSectors32'], formula: 'dataSize ÷ clusterSize' }
 | 
						||
                        ]
 | 
						||
                    },
 | 
						||
                    {
 | 
						||
                        name: 'Spezifischer Cluster',
 | 
						||
                        results: [
 | 
						||
                            { id: 'clusterStart32', label: 'Cluster Anfang', dependencies: ['reservedSectors32', 'sectorSize32', 'baseOffset32', 'numFATs32', 'fatSizeSectors32', 'clusterSizeSectors32', 'clusterNumber32'], formula: 'dataStart + (clusterNumber - 0x2) × clusterSize' },
 | 
						||
                            { id: 'fatEntryPos32', label: 'FAT-Eintrag Position', dependencies: ['reservedSectors32', 'sectorSize32', 'baseOffset32', 'clusterNumber32'], formula: 'fatStart + (clusterNumber × 4)' },
 | 
						||
                            { id: 'rootDirPos32', label: 'Root-Directory Position', dependencies: ['reservedSectors32', 'sectorSize32', 'baseOffset32', 'numFATs32', 'fatSizeSectors32', 'clusterSizeSectors32', 'rootDirCluster32'], formula: 'dataStart + (rootDirCluster - 0x2) × clusterSize' }
 | 
						||
                        ]
 | 
						||
                    }
 | 
						||
                ],
 | 
						||
                formulas: [
 | 
						||
                    { name: 'FAT-Bereich Anfang', expression: 'Reservierte Sektoren × Sektorgröße + Basis-Offset' },
 | 
						||
                    { name: 'FAT-Bereich Größe', expression: 'Anzahl FATs × FAT-Größe in Sektoren × Sektorgröße' },
 | 
						||
                    { name: 'FAT2 Anfang', expression: 'FAT-Bereich Anfang + FAT-Größe in Bytes' },
 | 
						||
                    { name: 'FAT-Bereich Ende', expression: 'FAT-Bereich Anfang + FAT-Bereich Größe' },
 | 
						||
                    { name: 'Daten-Bereich Anfang', expression: 'FAT-Bereich Ende (kein festes Root Directory)' },
 | 
						||
                    { name: 'Daten-Bereich Größe', expression: '(Partitionsgröße × Sektorgröße) - (Daten-Bereich Anfang - Basis-Offset)' },
 | 
						||
                    { name: 'Cluster-Größe', expression: 'Sektorgröße × Cluster-Größe in Sektoren' },
 | 
						||
                    { name: 'Anzahl Cluster', expression: 'Daten-Bereich Größe ÷ Cluster-Größe' },
 | 
						||
                    { name: 'Cluster Anfang', expression: 'Daten-Bereich Anfang + (Cluster-Nummer - 0x2) × Cluster-Größe' },
 | 
						||
                    { name: 'FAT-Eintrag Position', expression: 'FAT-Bereich Anfang + (Cluster-Nummer × 4)' },
 | 
						||
                    { name: 'Root-Directory Position', expression: 'Daten-Bereich Anfang + (Root-Directory Cluster - 0x2) × Cluster-Größe' }
 | 
						||
                ]
 | 
						||
            }
 | 
						||
        ]);
 | 
						||
    }
 | 
						||
 | 
						||
    calculateFAT32(values, results) {
 | 
						||
        const suffix = '32';
 | 
						||
        // FAT Start (show both bytes and sector in one row)
 | 
						||
        if (checkDependencies([`reservedSectors${suffix}`, `sectorSize${suffix}`, `baseOffset${suffix}`])) {
 | 
						||
            results.fatStart = values[`reservedSectors${suffix}`] * values[`sectorSize${suffix}`] + values[`baseOffset${suffix}`];
 | 
						||
            results.fatStartSector = Math.floor(results.fatStart / values[`sectorSize${suffix}`]);
 | 
						||
            updateResultItem(`fatStart${suffix}`, { bytes: results.fatStart, sectors: results.fatStartSector }, true,
 | 
						||
                `0x${values[`reservedSectors${suffix}`].toString(16)} × 0x${values[`sectorSize${suffix}`].toString(16)} + 0x${values[`baseOffset${suffix}`].toString(16)} = 0x${results.fatStart.toString(16)}`);
 | 
						||
        } else {
 | 
						||
            updateResultItem(`fatStart${suffix}`, 0, false);
 | 
						||
        }
 | 
						||
        // FAT Size (bytes and sectors)
 | 
						||
        if (checkDependencies([`numFATs${suffix}`, `fatSizeSectors${suffix}`, `sectorSize${suffix}`])) {
 | 
						||
            results.fatSize = values[`numFATs${suffix}`] * values[`fatSizeSectors${suffix}`] * values[`sectorSize${suffix}`];
 | 
						||
            results.fatSizeSectors = values[`numFATs${suffix}`] * values[`fatSizeSectors${suffix}`];
 | 
						||
            updateResultItem(`fatSize${suffix}`, { bytes: results.fatSize, sectors: results.fatSizeSectors }, true,
 | 
						||
                `0x${values[`numFATs${suffix}`].toString(16)} × 0x${values[`fatSizeSectors${suffix}`].toString(16)} × 0x${values[`sectorSize${suffix}`].toString(16)} = 0x${results.fatSize.toString(16)}`);
 | 
						||
        } else {
 | 
						||
            updateResultItem(`fatSize${suffix}`, 0, false);
 | 
						||
        }
 | 
						||
        // FAT2 Start (bytes and sector)
 | 
						||
        if (checkDependencies([`reservedSectors${suffix}`, `sectorSize${suffix}`, `baseOffset${suffix}`, `fatSizeSectors${suffix}`]) && results.fatStart !== undefined) {
 | 
						||
            results.fat2Start = results.fatStart + (values[`fatSizeSectors${suffix}`] * values[`sectorSize${suffix}`]);
 | 
						||
            results.fat2StartSector = Math.floor(results.fat2Start / values[`sectorSize${suffix}`]);
 | 
						||
            updateResultItem(`fat2Start${suffix}`, { bytes: results.fat2Start, sectors: results.fat2StartSector }, true,
 | 
						||
                `0x${results.fatStart.toString(16)} + 0x${(values[`fatSizeSectors${suffix}`] * values[`sectorSize${suffix}`]).toString(16)} = 0x${results.fat2Start.toString(16)}`);
 | 
						||
        } else {
 | 
						||
            updateResultItem(`fat2Start${suffix}`, 0, false);
 | 
						||
        }
 | 
						||
        // FAT End (bytes and sector)
 | 
						||
        if (results.fatStart !== undefined && results.fatSize !== undefined) {
 | 
						||
            results.fatEnd = results.fatStart + results.fatSize;
 | 
						||
            results.fatEndSector = Math.floor(results.fatEnd / values[`sectorSize${suffix}`]);
 | 
						||
            updateResultItem(`fatEnd${suffix}`, { bytes: results.fatEnd, sectors: results.fatEndSector }, true,
 | 
						||
                `0x${results.fatStart.toString(16)} + 0x${results.fatSize.toString(16)} = 0x${results.fatEnd.toString(16)}`);
 | 
						||
        } else {
 | 
						||
            updateResultItem(`fatEnd${suffix}`, 0, false);
 | 
						||
        }
 | 
						||
        // Data Start (bytes and sector)
 | 
						||
        if (results.fatEnd !== undefined) {
 | 
						||
            results.dataStart = results.fatEnd;
 | 
						||
            results.dataStartSector = Math.floor(results.dataStart / values[`sectorSize${suffix}`]);
 | 
						||
            updateResultItem(`dataStart${suffix}`, { bytes: results.dataStart, sectors: results.dataStartSector }, true,
 | 
						||
                `0x${results.fatEnd.toString(16)}`);
 | 
						||
        } else {
 | 
						||
            updateResultItem(`dataStart${suffix}`, 0, false);
 | 
						||
        }
 | 
						||
        // Data Size
 | 
						||
        if (checkDependencies([`partitionSizeInSectors${suffix}`, `sectorSize${suffix}`, `reservedSectors${suffix}`, `baseOffset${suffix}`, `numFATs${suffix}`, `fatSizeSectors${suffix}`]) && results.dataStart !== undefined) {
 | 
						||
            results.dataSize = (values[`partitionSizeInSectors${suffix}`] * values[`sectorSize${suffix}`]) - (results.dataStart - values[`baseOffset${suffix}`]);
 | 
						||
            updateResultItem(`dataSize${suffix}`, results.dataSize, true,
 | 
						||
                `(0x${values[`partitionSizeInSectors${suffix}`].toString(16)} × 0x${values[`sectorSize${suffix}`].toString(16)}) - (0x${results.dataStart.toString(16)} - 0x${values[`baseOffset${suffix}`].toString(16)}) = 0x${results.dataSize.toString(16)}`);
 | 
						||
        } else {
 | 
						||
            updateResultItem(`dataSize${suffix}`, 0, false);
 | 
						||
        }
 | 
						||
        // Cluster Size
 | 
						||
        if (checkDependencies([`sectorSize${suffix}`, `clusterSizeSectors${suffix}`])) {
 | 
						||
            results.clusterSize = values[`sectorSize${suffix}`] * values[`clusterSizeSectors${suffix}`];
 | 
						||
            updateResultItem(`clusterSize${suffix}`, results.clusterSize, true,
 | 
						||
                `0x${values[`sectorSize${suffix}`].toString(16)} × 0x${values[`clusterSizeSectors${suffix}`].toString(16)} = 0x${results.clusterSize.toString(16)}`);
 | 
						||
        } else {
 | 
						||
            updateResultItem(`clusterSize${suffix}`, 0, false);
 | 
						||
        }
 | 
						||
        // Number of Clusters
 | 
						||
        if (checkDependencies([`partitionSizeInSectors${suffix}`, `sectorSize${suffix}`, `reservedSectors${suffix}`, `baseOffset${suffix}`, `numFATs${suffix}`, `fatSizeSectors${suffix}`, `clusterSizeSectors${suffix}`]) && results.dataSize !== undefined && results.clusterSize !== undefined) {
 | 
						||
            results.numClusters = Math.floor(results.dataSize / results.clusterSize);
 | 
						||
            updateResultItem(`numClusters${suffix}`, results.numClusters, true,
 | 
						||
                `0x${results.dataSize.toString(16)} ÷ 0x${results.clusterSize.toString(16)} = 0x${results.numClusters.toString(16)}`);
 | 
						||
        } else {
 | 
						||
            updateResultItem(`numClusters${suffix}`, 0, false);
 | 
						||
        }
 | 
						||
        // Specific Cluster Start (bytes and sector)
 | 
						||
        if (checkDependencies([`reservedSectors${suffix}`, `sectorSize${suffix}`, `baseOffset${suffix}`, `numFATs${suffix}`, `fatSizeSectors${suffix}`, `clusterSizeSectors${suffix}`, `clusterNumber${suffix}`]) && results.dataStart !== undefined && results.clusterSize !== undefined) {
 | 
						||
            results.clusterStart = results.dataStart + (values[`clusterNumber${suffix}`] - 0x2) * results.clusterSize;
 | 
						||
            results.clusterStartSector = Math.floor(results.clusterStart / values[`sectorSize${suffix}`]);
 | 
						||
            updateResultItem(`clusterStart${suffix}`, { bytes: results.clusterStart, sectors: results.clusterStartSector }, true,
 | 
						||
                `0x${results.dataStart.toString(16)} + (0x${values[`clusterNumber${suffix}`].toString(16)} - 0x2) × 0x${results.clusterSize.toString(16)} = 0x${results.clusterStart.toString(16)}`);
 | 
						||
        } else {
 | 
						||
            updateResultItem(`clusterStart${suffix}`, 0, false);
 | 
						||
        }
 | 
						||
        // FAT Entry Position
 | 
						||
        if (checkDependencies([`reservedSectors${suffix}`, `sectorSize${suffix}`, `baseOffset${suffix}`, `clusterNumber${suffix}`]) && results.fatStart !== undefined) {
 | 
						||
            const entrySize = 4; // FAT32 uses 4 bytes per entry
 | 
						||
            results.fatEntryPos = results.fatStart + (values[`clusterNumber${suffix}`] * entrySize);
 | 
						||
            updateResultItem(`fatEntryPos${suffix}`, results.fatEntryPos, true,
 | 
						||
                `0x${results.fatStart.toString(16)} + (0x${values[`clusterNumber${suffix}`].toString(16)} × ${entrySize}) = 0x${results.fatEntryPos.toString(16)}`);
 | 
						||
        } else {
 | 
						||
            updateResultItem(`fatEntryPos${suffix}`, 0, false);
 | 
						||
        }
 | 
						||
        // Root Directory Position (FAT32 specific)
 | 
						||
        if (checkDependencies([`reservedSectors${suffix}`, `sectorSize${suffix}`, `baseOffset${suffix}`, `numFATs${suffix}`, `fatSizeSectors${suffix}`, `clusterSizeSectors${suffix}`, `rootDirCluster${suffix}`]) && results.dataStart !== undefined && results.clusterSize !== undefined) {
 | 
						||
            results.rootDirPos = results.dataStart + (values[`rootDirCluster${suffix}`] - 0x2) * results.clusterSize;
 | 
						||
            updateResultItem(`rootDirPos${suffix}`, results.rootDirPos, true,
 | 
						||
                `0x${results.dataStart.toString(16)} + (0x${values[`rootDirCluster${suffix}`].toString(16)} - 0x2) × 0x${results.clusterSize.toString(16)} = 0x${results.rootDirPos.toString(16)}`);
 | 
						||
        } else {
 | 
						||
            updateResultItem(`rootDirPos${suffix}`, 0, false);
 | 
						||
        }
 | 
						||
    }
 | 
						||
} |