diff --git a/Directory.Build.props b/Directory.Build.props
index dd9cd12c..39e9cfec 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -5,6 +5,6 @@
true
- 5.1.4
+ 5.2.0
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 49689917..ad68b280 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -6,13 +6,16 @@
+
+
+
diff --git a/README.md b/README.md
index dbfe401e..afe5b615 100644
--- a/README.md
+++ b/README.md
@@ -42,7 +42,7 @@ EXPECTED_VERSION=X.Y.Z bash tools/ci/verify_nuget_release.sh
- Migration: Verwende ausschließlich `Tomtastisch.FileClassifier` (Details in `docs/guides/004_GUIDE_MIGRATE_LEGACY_NUGET.MD`).
## 5. Compatibility / TFMs
-- Library-Zielplattformen: `net8.0` und `net10.0`
+- Library-Zielplattformen: `netstandard2.0`, `net8.0` und `net10.0`
- Release-Versioning: Git-Tag `vX.Y.Z` (optional `-prerelease`) ist SSOT
## 6. Architekturüberblick
diff --git a/docs/audit/000_INDEX.MD b/docs/audit/000_INDEX.MD
index cbe4309d..30188de3 100644
--- a/docs/audit/000_INDEX.MD
+++ b/docs/audit/000_INDEX.MD
@@ -24,6 +24,9 @@ Zentrale Einstiegsseite fuer Dritte: `SECURITY_ASSURANCE_INDEX.md`.
- `docs/audit/012_WAVE_EXECUTION_DOD.MD`
- `docs/audit/013_SCORECARD_GOVERNANCE_ALERT_MAPPING.MD`
- `docs/audit/014_EVIDENCE_REPORT_ISSUE_67.MD`
+- `docs/audit/compat/001_NETSTANDARD2_POLICY_SNAPSHOT.MD`
+- `docs/audit/compat/002_NETSTANDARD2_INVENTORY.MD`
+- `docs/audit/compat/003_NETSTANDARD2_COMPAT_EVIDENCE.MD`
## Maschinelle Nachweise
- `artifacts/ci/security-claims-evidence/`
diff --git a/docs/audit/100_INDEX.MD b/docs/audit/100_INDEX.MD
index c36d89f4..a6d680c2 100644
--- a/docs/audit/100_INDEX.MD
+++ b/docs/audit/100_INDEX.MD
@@ -24,6 +24,9 @@ Root landing page for third parties: `SECURITY_ASSURANCE_INDEX.md`.
- `docs/audit/112_WAVE_EXECUTION_DOD.MD`
- `docs/audit/113_SCORECARD_GOVERNANCE_ALERT_MAPPING.MD`
- `docs/audit/114_EVIDENCE_REPORT_ISSUE_67.MD`
+- `docs/audit/compat/001_NETSTANDARD2_POLICY_SNAPSHOT.MD`
+- `docs/audit/compat/002_NETSTANDARD2_INVENTORY.MD`
+- `docs/audit/compat/003_NETSTANDARD2_COMPAT_EVIDENCE.MD`
## Machine Evidence
- `artifacts/ci/security-claims-evidence/`
diff --git a/docs/audit/compat/001_NETSTANDARD2_POLICY_SNAPSHOT.MD b/docs/audit/compat/001_NETSTANDARD2_POLICY_SNAPSHOT.MD
new file mode 100644
index 00000000..55ab98b4
--- /dev/null
+++ b/docs/audit/compat/001_NETSTANDARD2_POLICY_SNAPSHOT.MD
@@ -0,0 +1,52 @@
+# Policy Snapshot: netstandard2 Compat Refactor
+
+## 1. Zweck
+Dieses Dokument extrahiert verbindliche Anforderungen fuer den netstandard2.0-Kompatibilitaetsrefactor.
+
+## 2. Geltungsbereich
+- Quelle A: `docs/governance/045_CODE_QUALITY_POLICY_DE.MD`
+- Quelle B: `docs/versioning/001_POLICY_VERSIONING.MD`
+- Quelle C: `docs/governance/004_POLICY_DOCUMENTATION.MD`
+
+## 3. Regeln/Architektur
+### 3.1 Muss (verbindlich)
+- Keine Public-Signaturaenderungen und kein Behavior-Drift in bestehenden Public APIs.
+- Build/Test muessen erfolgreich sein.
+- Fail-closed Verhalten (Fehlerpfade und Logging) darf nicht aufgeweicht werden.
+- Versionierungsentscheidung muss SemVer-konform sein.
+- Dokumentdateien unter `docs/` muessen `UPPER_SNAKE_CASE` mit `.MD` nutzen.
+- Doku-Checks sind verpflichtend:
+ - `python3 tools/check-doc-consistency.py`
+ - `python3 tools/check-docs.py`
+
+### 3.2 Kann (erlaubt unter Bedingungen)
+- Interne Refactorings und Strukturverbesserungen sind erlaubt, wenn Public API und Semantik erhalten bleiben.
+- Interne Abstraktionen fuer TFM-sensitive APIs sind erlaubt.
+
+### 3.3 Nicht erlaubt
+- Runtime-Provider-Switching oder environment-basierte Pfadwahl.
+- Unbelegte Annahmen ohne Evidence.
+- Nicht-policy-konforme Dokumentbenennung.
+
+## 4. Verifikation/Nachweise
+Auszuege der Policyquellen:
+- `docs/governance/045_CODE_QUALITY_POLICY_DE.MD:36-39` (keine Semantikaenderung, keine Signaturaenderung)
+- `docs/governance/045_CODE_QUALITY_POLICY_DE.MD:196-204` (DoD Build/Test, keine Public-Signature-Aenderung)
+- `docs/versioning/001_POLICY_VERSIONING.MD:22-26` (MINOR/PATCH Klassifikation)
+- `docs/governance/004_POLICY_DOCUMENTATION.MD:16-24` (Benennungsregeln)
+- `docs/governance/004_POLICY_DOCUMENTATION.MD:55-59` (Doku-Pflichtchecks)
+
+## 5. Grenzen/Nicht-Ziele
+- Keine Aenderung an `SECURITY.md`.
+- Keine Erweiterung der fachlichen Semantik.
+- Keine Einfuehrung neuer externer Runtime-Abhaengigkeiten ausser zur Kompatibilitaet notwendige Library-Referenzen.
+
+## 6. Verlinkte SSOT-Quellen
+- [Code Quality Policy DE](https://github.com/tomtastisch/FileClassifier/blob/main/docs/governance/045_CODE_QUALITY_POLICY_DE.MD)
+- [Versioning Policy DE](https://github.com/tomtastisch/FileClassifier/blob/main/docs/versioning/001_POLICY_VERSIONING.MD)
+- [Documentation Policy DE](https://github.com/tomtastisch/FileClassifier/blob/main/docs/governance/004_POLICY_DOCUMENTATION.MD)
+
+## RoC-Bezug
+- [Artifact-Contract-Regel](https://github.com/tomtastisch/FileClassifier/blob/main/tools/ci/policies/rules/artifact_contract.yaml)
+- [Docs-Drift-Regel](https://github.com/tomtastisch/FileClassifier/blob/main/tools/ci/policies/rules/docs_drift.yaml)
+- [Shell-Safety-Regeln](https://github.com/tomtastisch/FileClassifier/blob/main/tools/ci/policies/rules/shell_safety.yaml)
diff --git a/docs/audit/compat/002_NETSTANDARD2_INVENTORY.MD b/docs/audit/compat/002_NETSTANDARD2_INVENTORY.MD
new file mode 100644
index 00000000..ef97afa2
--- /dev/null
+++ b/docs/audit/compat/002_NETSTANDARD2_INVENTORY.MD
@@ -0,0 +1,66 @@
+# Inventory: netstandard2 Compat Baseline
+
+## 1. Zweck
+Dieses Dokument protokolliert den Ausgangs-/Zwischenstand der TFM- und API-sensitiven Fundstellen fuer den netstandard2.0-Refactor.
+
+## 2. Geltungsbereich
+- Library-Projekt: `src/FileTypeDetection/FileTypeDetectionLib.vbproj`
+- Produktionscode: `src/FileTypeDetection/**/*.vb`
+- Tests: `tests/FileTypeDetectionLib.Tests/**/*`
+
+## 3. Regeln/Architektur
+Erfasste Suchmuster:
+- `Convert.ToHexString`
+- `SHA256.HashData`
+- `System.IO.Hashing`
+- `XxHash3`
+- `FrameworkReference Microsoft.AspNetCore.App`
+- `TargetFrameworks`
+
+## 4. Verifikation/Nachweise
+### 4.1 Projekt/TFMs
+Befehl:
+```bash
+rg -n "TargetFrameworks|FrameworkReference|PackageReference Include=\"System\.IO\.Hashing\"|PackageReference Include=\"Microsoft\.Extensions\.Logging\.Abstractions\"" src/FileTypeDetection/FileTypeDetectionLib.vbproj
+```
+Ausgabe:
+- `src/FileTypeDetection/FileTypeDetectionLib.vbproj:6` -> `TargetFrameworks netstandard2.0;net8.0;net10.0`
+- `src/FileTypeDetection/FileTypeDetectionLib.vbproj:26` -> `Microsoft.Extensions.Logging.Abstractions`
+- `src/FileTypeDetection/FileTypeDetectionLib.vbproj:29` -> `System.IO.Hashing`
+
+### 4.2 Produktionscode
+Befehl:
+```bash
+rg -n "Convert\.ToHexString|SHA256\.HashData|System\.IO\.Hashing|XxHash3" src/FileTypeDetection --glob '*.vb' --glob '*.vbproj'
+```
+Relevante Treffer:
+- `src/FileTypeDetection/Providers/Net8_0Plus/HashPrimitivesProvider.vb:49` (`Convert.ToHexString`)
+- `src/FileTypeDetection/Providers/Net8_0Plus/HashPrimitivesProvider.vb:64` (`SHA256.HashData`)
+- `src/FileTypeDetection/Providers/Net8_0Plus/HashPrimitivesProvider.vb:77` (`XxHash3`)
+- `src/FileTypeDetection/Providers/NetStandard2_0/HashPrimitivesProvider.vb:91` (`XxHash3`)
+
+### 4.3 AspNetCore FrameworkReference
+Befehl:
+```bash
+rg -n "Microsoft\.AspNetCore\.App|AspNetCore" src/FileTypeDetection --glob '*.vb' --glob '*.vbproj'
+```
+Ausgabe:
+- Keine Treffer (exit code 1) -> FrameworkReference entfernt.
+
+### 4.4 Tests
+Befehl:
+```bash
+rg -n "Convert\.ToHexString|SHA256\.HashData|System\.IO\.Hashing|XxHash3" tests/FileTypeDetectionLib.Tests --glob '*.cs' --glob '*.txt'
+```
+Relevante Treffer (expected in tests):
+- `tests/FileTypeDetectionLib.Tests/Support/FixtureManifestCatalog.cs:133-134`
+- `tests/FileTypeDetectionLib.Tests/Unit/HashingEvidenceTests.cs:2,45,61,349,372-373`
+- `tests/FileTypeDetectionLib.Tests/Contracts/public-api.snapshot.txt:75-76`
+
+## 5. Grenzen/Nicht-Ziele
+- Dieses Inventar ist ein technischer Suchlauf und ersetzt keine Laufzeit- oder CI-Verifikation.
+- Nicht gelistet sind reine Dokumenttexte ausserhalb des Produktions-/Testcodes.
+
+## 6. Verlinkte SSOT-Quellen
+- [Versioning Policy](https://github.com/tomtastisch/FileClassifier/blob/main/docs/versioning/001_POLICY_VERSIONING.MD)
+- [Code Quality Policy](https://github.com/tomtastisch/FileClassifier/blob/main/docs/governance/045_CODE_QUALITY_POLICY_DE.MD)
diff --git a/docs/audit/compat/003_NETSTANDARD2_COMPAT_EVIDENCE.MD b/docs/audit/compat/003_NETSTANDARD2_COMPAT_EVIDENCE.MD
new file mode 100644
index 00000000..5c3bdd5d
--- /dev/null
+++ b/docs/audit/compat/003_NETSTANDARD2_COMPAT_EVIDENCE.MD
@@ -0,0 +1,116 @@
+# Evidence Report: netstandard2 Compat
+
+## 1. Zweck
+Dieser Report dokumentiert die technische Umsetzung und Verifikation fuer die net48-Kompatibilitaet ueber `netstandard2.0`.
+
+## 2. Geltungsbereich
+- Library: `src/FileTypeDetection/FileTypeDetectionLib.vbproj`
+- Hashing-Core-Fassade: `src/FileTypeDetection/EvidenceHashing.vb`
+- Provider-Abstraktionen und TFM-Provider unter `src/FileTypeDetection/Abstractions/Providers`, `src/FileTypeDetection/Composition`, `src/FileTypeDetection/Providers`
+
+## 3. Regeln/Architektur
+### 3.1 Before/After TargetFrameworks
+- Before: `net8.0;net10.0`
+- After: `netstandard2.0;net8.0;net10.0`
+- Nachweisdatei: `src/FileTypeDetection/FileTypeDetectionLib.vbproj`
+
+### 3.2 Interface-Abstraktionen und API-Mapping
+- `IHexCodec`
+ - abstrahiert: Lower-Hex-Encoding (`Convert.ToHexString(...).ToLowerInvariant()` bzw. nibble-map)
+- `ISha256Primitives`
+ - abstrahiert: `SHA256.HashData`/`SHA256.Create().ComputeHash`
+- `IFastHash64`
+ - abstrahiert: `System.IO.Hashing.XxHash3.HashToUInt64`
+- `IHashPrimitives`
+ - Aggregation + `ProviderMarker`
+
+### 3.3 Hashing-Verhalten je TFM
+- `netstandard2.0`:
+ - SHA256: `SHA256.Create()`
+ - Hex: deterministischer lower-hex nibble-codec
+ - FastHash: `XxHash3.HashToUInt64(...).ToString("x16")`
+- `net8.0` und `net10.0`:
+ - SHA256: `SHA256.HashData`
+ - Hex: `Convert.ToHexString(...).ToLowerInvariant()`
+ - FastHash: `XxHash3.HashToUInt64(...).ToString("x16")`
+- FastHash ist auf `netstandard2.0` **nicht** deaktiviert.
+
+### 3.4 Provider-Selektion (compile-time)
+MSBuild-Conditionen in `src/FileTypeDetection/FileTypeDetectionLib.vbproj`:
+- global: ``
+- `netstandard2.0`: ``
+- `net8.0|net10.0`: ``
+
+## 4. Verifikation/Nachweise
+### 4.1 Befehle und Exit-Codes
+1. `dotnet --info` -> `0`
+2. `dotnet restore FileClassifier.sln -v minimal` -> `0`
+3. `dotnet restore --locked-mode FileClassifier.sln -v minimal` -> `0`
+4. `dotnet build FileClassifier.sln -c Release --no-restore -warnaserror -v minimal` -> `0`
+5. `dotnet test tests/FileTypeDetectionLib.Tests/FileTypeDetectionLib.Tests.csproj -c Release --no-build -v minimal` -> `0` (`414` Tests gruen)
+6. `dotnet test tests/FileTypeDetectionLib.Tests/FileTypeDetectionLib.Tests.csproj -c Release --no-build --filter "Category=ApiContract" -v minimal` -> `0` (`3` Tests gruen)
+7. `dotnet pack src/FileTypeDetection/FileTypeDetectionLib.vbproj -c Release --no-build -o artifacts/ci/netstandard2-compat/nuget -v minimal` -> `0`
+8. `dotnet build src/FileTypeDetection/FileTypeDetectionLib.vbproj -c Release -f netstandard2.0 -v diag > artifacts/ci/netstandard2-compat/build-netstandard2.0.log` -> `0`
+9. `dotnet build src/FileTypeDetection/FileTypeDetectionLib.vbproj -c Release -f net8.0 -v diag > artifacts/ci/netstandard2-compat/build-net8.0.log` -> `0`
+10. `dotnet build src/FileTypeDetection/FileTypeDetectionLib.vbproj -c Release -f net10.0 -v diag > artifacts/ci/netstandard2-compat/build-net10.0.log` -> `0`
+11. `python3 tools/check-doc-consistency.py` -> `0`
+12. `python3 tools/check-docs.py` -> `0`
+13. `bash tools/ci/bin/run.sh versioning-svt` -> `0`
+14. `bash tools/ci/bin/run.sh version-convergence` -> `0`
+15. `bash tools/ci/bin/run.sh security-nuget` -> `0`
+
+### 4.2 Build-/Pack-Proof
+- Build-Matrix erfolgreich:
+ - `src/FileTypeDetection/bin/Release/netstandard2.0/Tomtastisch.FileClassifier.dll`
+ - `src/FileTypeDetection/bin/Release/net8.0/Tomtastisch.FileClassifier.dll`
+ - `src/FileTypeDetection/bin/Release/net10.0/Tomtastisch.FileClassifier.dll`
+- NUPKG-Inhalt (`unzip -l ... | rg "lib/"`):
+ - `lib/netstandard2.0/Tomtastisch.FileClassifier.dll`
+ - `lib/net8.0/Tomtastisch.FileClassifier.dll`
+ - `lib/net10.0/Tomtastisch.FileClassifier.dll`
+
+### 4.3 Provider-Compile-Proof
+- `netstandard2.0`:
+ - `artifacts/ci/netstandard2-compat/build-netstandard2.0.log:48497`
+ - Treffer: `Providers/NetStandard2_0/HashPrimitivesProvider.vb (Aufgaben-ID: 7)`
+- `net8.0`:
+ - `artifacts/ci/netstandard2-compat/build-net8.0.log:48421`
+ - Treffer: `Providers/Net8_0Plus/HashPrimitivesProvider.vb (Aufgaben-ID: 12)`
+- `net10.0`:
+ - `artifacts/ci/netstandard2-compat/build-net10.0.log:48416`
+ - Treffer: `Providers/Net8_0Plus/HashPrimitivesProvider.vb (Aufgaben-ID: 12)`
+- Negativ-Proof:
+ - kein Treffer fuer `Providers/Net8_0Plus/HashPrimitivesProvider.vb (Aufgaben-ID: 7)` in `build-netstandard2.0.log`
+ - kein Treffer fuer `Providers/NetStandard2_0/HashPrimitivesProvider.vb (Aufgaben-ID: 12)` in `build-net8.0.log` und `build-net10.0.log`
+
+### 4.4 Forbidden-API Grep-Proof (Core)
+Befehl:
+```bash
+rg -n "Convert\.ToHexString|SHA256\.HashData|System\.IO\.Hashing|Microsoft\.AspNetCore\.App" src/FileTypeDetection/Core
+```
+Ergebnis:
+- keine Treffer, Exit-Code `1` (expected for no-match)
+
+### 4.5 CI-Teilchecks
+- `artifacts/ci/versioning-svt/versioning-svt-summary.json` -> `status: pass`
+- `artifacts/ci/version-convergence/summary.json` -> `status: pass`, `repo_version=5.2.0`, `vbproj_version=5.2.0`, `docs_latest_version=5.2.0`
+- `artifacts/ci/security-nuget/result.json` -> `status: pass`
+
+### 4.6 Policy Ambiguity
+Ambiguitaet zwischen:
+- `docs/versioning/001_POLICY_VERSIONING.MD:43` (in PR/CI keine statischen Versionfelder), und
+- existierendem SVT/Convergence-Setup (`verify-version-convergence.sh`, `check-versioning-svt.sh`), das `RepoVersion` und `Version`/`PackageVersion` in `FileTypeDetectionLib.vbproj` erwartet.
+
+Entscheidung fuer diesen Scope:
+- fail-closed nach bestehendem CI/Repo-Vertrag: Versionen auf `5.2.0` synchron gehalten und durch `versioning-svt` + `version-convergence` verifiziert.
+
+## 5. Grenzen/Nicht-Ziele
+- Keine oeffentliche API-Signatur geaendert.
+- Keine Runtime-Provider-Umschaltung eingefuehrt.
+- Keine Blocker-Datei notwendig (`999_NETSTANDARD2_BLOCKERS.MD` nicht erstellt).
+
+## 6. Verlinkte SSOT-Quellen
+- [Versioning Policy](https://github.com/tomtastisch/FileClassifier/blob/main/docs/versioning/001_POLICY_VERSIONING.MD)
+- [Code Quality Policy](https://github.com/tomtastisch/FileClassifier/blob/main/docs/governance/045_CODE_QUALITY_POLICY_DE.MD)
+- [Documentation Policy](https://github.com/tomtastisch/FileClassifier/blob/main/docs/governance/004_POLICY_DOCUMENTATION.MD)
+- [Audit Index](https://github.com/tomtastisch/FileClassifier/blob/main/docs/audit/000_INDEX.MD)
diff --git a/docs/governance/045_CODE_QUALITY_POLICY_DE.MD b/docs/governance/045_CODE_QUALITY_POLICY_DE.MD
new file mode 100644
index 00000000..2f45a718
--- /dev/null
+++ b/docs/governance/045_CODE_QUALITY_POLICY_DE.MD
@@ -0,0 +1,760 @@
+
+[DE](045_CODE_QUALITY_POLICY_DE.MD) | [EN](145_CODE_QUALITY_POLICY_DE.MD)
+
+
+# Code-Quality- & Dokumentations-Policy (DE)
+Status: verbindlich (Projekt-Policy)
+Geltungsbereich: src/FileTypeDetection/* (VB.NET und C#), Public API + interne Implementierung
+
+## 1. Zweck
+Diese Policy definiert ein einheitliches, auditierbares Schema für:
+- Code-Aufbau (Lesbarkeit, Semantik, Member-Ordnung)
+- Fehlerbehandlung (fail-closed, konsistentes Logging)
+- Dokumentation (deutsch, vollständig, mit echten Umlauten)
+- reproduzierbare Codex-Änderungen ohne Verhaltensdrift
+
+## 2. Normative Orientierung (DIN/ISO/IEC/IEEE)
+Hinweis: Es existiert keine einzelne „DIN für Code-Formatierung“. Wir definieren hier ein internes Regelwerk,
+das sich an etablierten Normen für Informationsqualität und Softwarequalität orientiert:
+
+- ISO/IEC/IEEE 26514:2022-01 — Systems and software engineering: Design and development of information for users
+ Quelle: https://www.dinmedia.de/en/standard/iso-iec-ieee-26514/350342422
+
+- ISO/IEC 25010:2023 — Systems and software engineering: Product quality model (SQuaRE)
+ Quelle: ISO-Katalogeintrag 78176 (über die ISO-Suche abrufbar)
+
+- ISO/IEC/IEEE 15289:2019 — Content of life-cycle information items (documentation)
+ Quelle: ISO-Katalogeintrag 74909 (über die ISO-Suche abrufbar)
+
+Optional (für generische Nutzungsinformationen):
+- DIN EN IEC/IEEE 82079-1:2021-09 — Erstellung von Nutzungsinformationen (Gebrauchsanleitungen) für Produkte
+ Quelle: https://www.dinmedia.de/en/standard/din-en-iec-ieee-82079-1/342226844
+
+## 3. Grundsätze (hart)
+- Keine Umschreibung deutscher Umlaute: ä ö ü Ä Ö Ü ß (keine ae/oe/ue/ss).
+- Dateien bleiben UTF-8; keine Encoding-Konvertierung.
+- Keine Behavior-Änderungen durch Formatierung/Doku:
+ - keine Signaturänderungen
+ - keine Semantikänderungen in Exceptions/Returns/Side effects
+ - keine neuen externen Dependencies
+
+## 4. Shared vs. Instanz (Konstruktionsregel)
+### 4.1 Shared (Utility) ist erlaubt, wenn ALLE Punkte erfüllt sind
+- Typ ist zustandslos (stateless)
+- keine Dependency Injection / keine ersetzbaren Abhängigkeiten notwendig
+- kein Polymorphismus/Test-Doubles über Interfaces erforderlich
+- typisch: NotInheritable + Private Sub New() + ausschließlich Shared Members
+
+### 4.2 Instanz-/Service-Typ ist Pflicht, wenn mindestens ein Punkt zutrifft
+- Abhängigkeiten sollen injizierbar/tauschbar sein (I/O, Logger, Policies, Clock, Provider, etc.)
+- Testbarkeit via DI/Interfaces ist erforderlich
+- Konfiguration/Zustand pro Instanz ist fachlich sinnvoll
+
+Wichtig: Im Rahmen von Codex-Format-/Doku-Überarbeitung werden Typ-Arten NICHT geändert,
+außer der Typ ist bereits eindeutig als Utility/Service etabliert.
+
+## 5. Datei- und Type-Struktur (Pflicht-Reihenfolge)
+### 5.1 Datei-Reihenfolge
+1) Datei-Header-Kommentar (Policy-/Kontextblock, keine XML-Docs)
+2) Option Strict On / Option Explicit On (VB)
+3) Imports
+4) Namespace
+5) Types
+
+### 5.2 Type-Layout (Member-Ordnung)
+1) XML-Doku am Type (summary + remarks)
+2) Konstanten (Const) / Shared ReadOnly
+3) Felder/Properties (nur wenn Typzustand existiert)
+4) Konstruktor(en)
+5) Public API (alle Public Members, geordnet)
+6) Internal/Private Helpers
+7) Nested Types (nur wenn nötig; am Ende)
+
+### 5.3 Semantische Blöcke in Funktionen
+Blöcke werden sichtbar getrennt (Leerzeile + Kommentartrenner):
+- Options/Snapshot
+- Guard-Clauses (fail-closed)
+- Normalisierung/Canonicalization (z.B. Pfad)
+- Branches (z.B. SecureExtract)
+- Fallback
+- I/O Helpers separat
+
+## 6. Variablenregel (Pflicht)
+- Alle lokalen Variablen werden im „Deklarationsblock“ am Anfang der Funktion definiert.
+- Platzierung:
+ - funktionslokal, wenn nur dort benötigt
+ - als Klassenvariable nur, wenn über mehrere Member sinnvoll geteilt wird
+- Alignment: spaltenartig (Tabs/Spaces), so dass Dim / Name / As / Initialwert vertikal ausgerichtet sind.
+- Ausnahme: Using-/For-Header dürfen lokale Variablen enthalten, wenn das idiomatisch ist und Lesbarkeit erhöht;
+ Default bleibt: zentraler Deklarationsblock.
+
+## 6.1 Namenskonventionen (Pflicht, VB.NET + C#)
+
+Ziel:
+- Einheitliche Benennung für Lesbarkeit, Konsistenz und reduzierte IDE-/Analyser-Warnungen.
+- Keine „Mischformen“ (z.B. camelCase in Public API, snake_case bei lokalen Variablen, etc.).
+
+Grundsatz:
+- Public API ist ein Vertrag: Public/Protected müssen strikt konventionskonform sein.
+- Private/Local folgt ebenfalls dem Standard, außer es gibt technische Gründe (z.B. Interop/externes Schema).
+
+### 6.1.1 Allgemeine Regeln (beide Sprachen)
+- Keine deutschen Umlaute in Bezeichnernamen (Identifiers). Umlaute sind nur in Kommentaren/Dokumentation erlaubt.
+- Keine Unterstriche in Public API-Namen (Ausnahme: echte Interop-/Extern-Verträge, die so vorgegeben sind).
+- Keine unklaren Abkürzungen:
+ - Erlaubt: IO, URI, URL, HTTP, JSON, XML, SHA256, HMAC, ZIP, TAR, RFC, GUID, UTF8 (als bekannte Akronyme)
+ - Vermeiden: „mgr“, „proc“, „util“, „tmp“ in Public API
+- Akronyme:
+ - PascalCase bleibt erhalten: „HttpClient“, „ZipArchive“, „UriBuilder“
+ - Keine ALLCAPS innerhalb eines Wortes außer etablierte Typen/Namen erzwingen es.
+
+### 6.1.2 VB.NET Naming (Option Strict/Explicit On)
+VB.NET-Konventionen (Projektstandard):
+- Namespace / Type / Member:
+ - Namespace: PascalCase
+ - Class/Module/Structure/Enum/Interface: PascalCase
+ - Public/Protected Methods/Functions/Properties/Events: PascalCase
+ - Public/Protected Constants: PascalCase
+- Parameter:
+ - camelCase (z.B. destinationPath, overwrite, secureExtract)
+- Lokale Variablen:
+ - camelCase (z.B. destinationFull, descriptor, parent)
+- Private Fields:
+ - camelCase mit Präfix "_" (underscore) ist erlaubt und empfohlen, wenn Felder existieren:
+ - Beispiel: _logger, _options
+ - Falls dein Repo bereits einen anderen Standard nutzt (z.B. "m_" Präfix), dann gilt SSOT = bestehender Repo-Standard.
+- Boolean-Namen:
+ - Keine negativen Namen in Public API („NotX“), bevorzugt positive Bedeutung:
+ - IsEnabled statt NotDisabled
+ - Lokale Booleans beginnen mit is/has/can/should:
+ - isOk, hasValue, canExtract, shouldOverwrite
+- Asynchronität (falls vorhanden):
+ - Async-Suffix nur, wenn es echte Async/Task-Semantik gibt (in VB/C# analog)
+ - Kein Async-Suffix bei synchronen Methoden.
+
+### 6.1.3 C# Naming (falls src/FileTypeDetection auch C# enthält)
+C#-Konventionen (Projektstandard):
+- Namespace / Type / Member:
+ - Namespace: PascalCase
+ - Class/Struct/Record/Enum/Interface: PascalCase (Interfaces mit I-Präfix, z.B. IArchiveExtractor)
+ - Public/Protected Methods/Properties/Events: PascalCase
+ - Private Fields: _camelCase
+ - Const: PascalCase (oder ALL_CAPS nur wenn Repo das bereits so macht; SSOT = bestehender Repo-Standard)
+- Parameter und Locals:
+ - camelCase
+- Boolean-Namen:
+ - is/has/can/should (z.B. isSafe, hasSignature, canExtract)
+
+### 6.1.4 Unterstrich-Regeln (wann "_" erlaubt ist)
+- Public API:
+ - Keine "_" in Method/Property/Type-Namen.
+- Private Fields:
+ - "_" Präfix ist erlaubt/empfohlen (_logger).
+- Lokale Variablen/Parameter:
+ - Kein "_" Präfix, außer zur Konfliktauflösung (z.B. @class in C# statt _class; in VB entsprechend vermeiden).
+- Methoden-Namen:
+ - Kein "_" innerhalb des Namens (z.B. nicht Try_NormalizePath).
+
+### 6.1.5 DoD-Erweiterung (Naming)
+- Keine neuen IDE-Warnungen durch Naming-Drift (insb. Public API).
+- Neue oder angepasste Bezeichner entsprechen dieser Konvention.
+- Falls bestehende Namen abweichen:
+ - In diesem Ticket nur korrigieren, wenn es keine API-/Semantikänderung erzeugt und eindeutig „Style-only“ ist.
+ - Public API-Namen werden NICHT umbenannt, wenn das einen Breaking Change bedeuten würde.
+
+## 7. Exception-Handling & Logging (Fail-Closed)
+- Catch-Filter-Form bevorzugt (VB):
+ Catch ex As Exception When TypeOf ex Is ...
+- Verboten ist der redundante Pseudo-Filter:
+ Catch ex As Exception When TypeOf ex Is Exception
+ Wenn alle Exceptions behandelt werden sollen, ist stattdessen `Catch ex As Exception` zu verwenden.
+- Keine catch-all ohne Filter, außer wenn zwingend notwendig UND dokumentiert.
+- Keine stillen Swallows: bei Fehler -> loggen (Warn/Error) + fail-closed Rückgabe/Exception wie bisher.
+- Log-Text ist konsistent, deutsch, mit Umlauten.
+- Keine Änderung der Exception-Semantik (kein Wrapping, keine neuen Throws).
+
+## 8. Dokumentationsstandard (Public API)
+### 8.1 Sprache/Zeichen
+- Deutsch, echte Umlaute.
+- Keine maschinelle Umschreibung.
+
+### 8.2 Mindestumfang pro Public Type/Member
+- Type:
+ - : 1–3 Sätze Zweck/Scope
+ - : strukturierte Abschnitte:
+ Zweck, Verantwortlichkeiten, Nicht-Ziele, Nebenwirkungen, Fehlerfälle, Security-Hinweise, Threading (falls relevant)
+- Public Functions/Methods:
+ - , (alle), (immer)
+ - nur wenn die API tatsächlich Exceptions nach außen propagiert; sonst über „fail-closed“ in remarks beschreiben.
+ - wenn sinnvoll (kurz, korrekt)
+
+### 8.3 „DIN-/Norm-orientiert“ bedeutet konkret
+- klare Begriffe, keine schwammigen Formulierungen („macht Dinge“)
+- konsistente Terminologie (z.B. „Materialisierung“, „Normalisierung“, „Archivprüfung“)
+- eindeutig dokumentierte Fehlerpfade und Nebenwirkungen
+
+## 9. Definition of Done (DoD)
+- Für jedes File in src/FileTypeDetection/*:
+ - Layout entspricht Abschnitt 5–7
+ - Public API ist nach Abschnitt 8 dokumentiert
+ - Umlaute bleiben korrekt (kein ae/oe/ue)
+ - Build/Test erfolgreich
+ - Keine Public Signatures geändert
+ - Kein Behavior-Drift (keine neuen Dependencies, keine Semantikänderung)
+
+## 10. STYLE REFERENCE (SSOT)
+- Der folgende Codeblock ist die verbindliche Style-/Semantik-Referenz für Aufbau, Umbrüche, Alignment,
+ Signaturformat und Try/Catch-Struktur.
+- Wende dieses Schema auf alle Dateien unter src/FileTypeDetection/* an.
+- Abweichungen nur, wenn technisch zwingend und dann im Diff-Summary begründen.
+
+### REFERENCE CODE (do not change; layout-template only):
+```
+' ============================================================================
+' FILE: ExampleMaterializer.vb
+'
+' INTERNE POLICY (DIN-/Norm-orientiert, als Regelwerk)
+' Normative Orientierung (Informationsstruktur / Qualität):
+' - ISO/IEC/IEEE 26514:2022-01 (User-/API-Informationen)
+' - ISO/IEC 25010 (Qualitätsmodell; hier angewandt auf Maintainability/Usability/Robustness)
+'
+' DATEI-STRUKTUR (Pflicht-Reihenfolge)
+' 1) Option Strict/Explicit
+' 2) Imports
+' 3) Namespace
+' 4) Types in Reihenfolge:
+' 4.1) Type-Header (''' summary + remarks)
+' 4.2) Const / Shared ReadOnly
+' 4.3) Felder/Properties (nur bei Instanztyp)
+' 4.4) Konstruktor(en)
+' 4.5) Public API
+' 4.6) Private Helpers (I/O)
+' 4.7) Guards/Policy
+' 4.8) Nested Types (am Ende, nur falls nötig)
+'
+' SHARED VS. INSTANZ (harte Regel)
+' - Shared NUR bei stateless Utility:
+' - NotInheritable + Private Sub New()
+' - keine Dependency Injection erforderlich
+' - kein Polymorphismus/Test-Doubles via Interfaces
+'
+' - Instanztyp (Service) wenn:
+' - Abhängigkeiten injizierbar sein müssen (Logger, Policy, I/O, Clock, Provider, …)
+' - Testbarkeit via Interfaces notwendig ist
+' - Zustand/Konfiguration pro Instanz sinnvoll ist
+'
+' VARIABLENREGEL (hart)
+' - Alle Dim-Deklarationen im Deklarationsblock am Anfang der Funktion.
+' - Spaltenartig ausgerichtet (Dim / Name / As / Initialwert), mittels Tabs/Spaces.
+' ============================================================================
+
+Option Strict On
+Option Explicit On
+
+Imports System
+Imports System.IO
+
+Namespace Global.Tomtastisch.FileClassifier
+
+ '''
+ ''' Einheitliche, fail-closed Materialisierung von Byte-Daten auf ein Ziel (Datei oder Verzeichnis).
+ '''
+ '''
+ ''' Zweck:
+ ''' - Persistiert Bytes deterministisch als Datei.
+ ''' - Optional: sichere Archiv-Extraktion (wenn Archiv erkannt und als sicher bewertet).
+ '''
+ ''' Verantwortlichkeiten:
+ ''' - Guard-Clauses (Null/Größe/Pfad).
+ ''' - Pfad-Normalisierung (Canonical Path).
+ ''' - Delegation an Rohbytes- oder Archiv-Materialisierung.
+ '''
+ ''' Fehlerverhalten:
+ ''' - Fail-closed: Rückgabe False bei ungültigen Eingaben oder I/O-Fehlern.
+ ''' - Exceptions werden innerhalb der I/O-Helfer behandelt (Logging + False).
+ '''
+ Public NotInheritable Class ExampleMaterializer
+
+ '''
+ ''' Verhindert Instanziierung (Utility-Typ).
+ '''
+ Private Sub New()
+ End Sub
+
+
+ ' =====================================================================
+ ' Public API (Shared; Utility, stateless)
+ ' =====================================================================
+
+ '''
+ ''' Persistiert an ohne Overwrite und ohne Extraktion.
+ '''
+ ''' Die zu persistierenden Bytes (Nothing => False).
+ ''' Zielpfad zur Datei (leer/whitespace => False).
+ ''' True bei erfolgreicher Materialisierung, sonst False (fail-closed).
+ Public Shared Function Persist _
+ (
+ data As Byte(),
+ destinationPath As String
+ ) As Boolean
+
+ ' Deklarationsblock (Pflicht, spaltenartig)
+ Dim overwrite As Boolean = False
+ Dim secureExtract As Boolean = False
+
+ Return Persist(data, destinationPath, overwrite, secureExtract)
+
+ End Function
+
+ '''
+ ''' Persistiert an mit optionalem Overwrite.
+ '''
+ ''' Die zu persistierenden Bytes (Nothing => False).
+ ''' Zielpfad zur Datei (leer/whitespace => False).
+ ''' True erlaubt das Überschreiben/Ersetzen eines bestehenden Ziels.
+ ''' True bei erfolgreicher Materialisierung, sonst False (fail-closed).
+ Public Shared Function Persist _
+ (
+ data As Byte(),
+ destinationPath As String,
+ overwrite As Boolean
+ ) As Boolean
+
+ ' Deklarationsblock (Pflicht, spaltenartig)
+ Dim secureExtract As Boolean = False
+
+ Return Persist(data, destinationPath, overwrite, secureExtract)
+
+ End Function
+
+ '''
+ ''' Persistiert Bytes als Datei oder extrahiert optional ein als sicher bewertetes Archiv.
+ '''
+ '''
+ ''' Ablauf (Schema):
+ ''' 1) Options/Snapshot laden
+ ''' 2) Guard-Clauses (data/size/path)
+ ''' 3) Zielpfad normalisieren (TryNormalizePath)
+ ''' 4) Branch: secureExtract (Describe -> SafetyGate -> Extract)
+ ''' 5) Fallback: Rohbytes schreiben
+ '''
+ ''' Fail-Closed:
+ ''' - Bei ungültiger Eingabe, unsicherem Archiv oder I/O-Fehlern wird False zurückgegeben.
+ '''
+ ''' Die zu verarbeitenden Bytes.
+ ''' Zielpfad (Datei oder Zielordner bei Extraktion).
+ ''' Overwrite-Regel.
+ ''' True aktiviert Archivprüfung und Extraktion (wenn möglich).
+ ''' True bei Erfolg, sonst False (fail-closed).
+ Public Shared Function Persist _
+ (
+ data As Byte(),
+ destinationPath As String,
+ overwrite As Boolean,
+ secureExtract As Boolean
+ ) As Boolean
+
+ ' Deklarationsblock (Pflicht, spaltenartig)
+ Dim opt As MaterializerOptions = GetOptionsSnapshot()
+ Dim destinationFull As String = Nothing
+
+ Dim isOk As Boolean = False
+ Dim canExtract As Boolean = False
+
+
+ ' -----------------------------------------------------------------
+ ' Guard-Clauses (fail-closed)
+ ' -----------------------------------------------------------------
+ If data Is Nothing Then Return False
+
+ If CLng(data.Length) > opt.MaxBytes Then
+ opt.LogWarn($"[Materialize] Daten zu groß ({data.Length} > {opt.MaxBytes}).")
+ Return False
+ End If
+
+ If String.IsNullOrWhiteSpace(destinationPath) Then Return False
+
+
+ ' -----------------------------------------------------------------
+ ' Pfad-Normalisierung / Zielermittlung
+ ' -----------------------------------------------------------------
+ isOk = TryNormalizePath(destinationPath, destinationFull, opt)
+ If Not isOk Then Return False
+
+
+ ' -----------------------------------------------------------------
+ ' Optional: Secure Extract (nur wenn angefordert)
+ ' -----------------------------------------------------------------
+ If secureExtract Then
+
+ Dim descriptor As String = Nothing
+
+ canExtract = TryDescribeArchive(data, descriptor, opt)
+ If canExtract Then
+
+ If Not IsArchiveSafe(data, descriptor, opt) Then
+ opt.LogWarn("[Materialize] Archiv-Validierung fehlgeschlagen.")
+ Return False
+ End If
+
+ Return MaterializeArchiveBytes(data, destinationFull, overwrite, opt, descriptor)
+
+ End If
+
+ End If
+
+
+ ' -----------------------------------------------------------------
+ ' Fallback: Rohbytes (wenn kein Extract möglich/gewünscht)
+ ' -----------------------------------------------------------------
+ Return MaterializeRawBytes(data, destinationFull, overwrite, opt)
+
+ End Function
+
+
+
+ ' =====================================================================
+ ' Private Helpers (I/O + Error-Handling konsistent)
+ ' =====================================================================
+
+ '''
+ ''' Persistiert Bytes als Datei an .
+ '''
+ '''
+ ''' I/O-Helfer:
+ ''' - Behandelt I/O-Exceptions intern (Logging + False).
+ ''' - Propagiert keine Exceptions nach außen (fail-closed).
+ '''
+ ''' Die zu schreibenden Bytes.
+ ''' Normalisierter Zielpfad (muss nicht leer sein).
+ ''' Overwrite-Regel.
+ ''' Options-/Logging-Kontext.
+ ''' True bei Erfolg, sonst False.
+ Private Shared Function MaterializeRawBytes _
+ (
+ data As Byte(),
+ destinationFull As String,
+ overwrite As Boolean,
+ opt As MaterializerOptions
+ ) As Boolean
+
+ ' Deklarationsblock
+ Dim parent As String = Nothing
+
+ Try
+
+ If Not PrepareTarget(destinationFull, overwrite, opt) Then _
+ Return False
+
+ parent = Path.GetDirectoryName(destinationFull)
+ If String.IsNullOrWhiteSpace(parent) Then Return False
+
+ Directory.CreateDirectory(parent)
+
+ Using _
+ fs As _
+ New FileStream(destinationFull,
+ FileMode.CreateNew,
+ FileAccess.Write,
+ FileShare.None,
+ bufferSize:=64 * 1024,
+ options:=FileOptions.SequentialScan)
+
+ fs.Write(data, 0, data.Length)
+
+ End Using
+
+ Return True
+
+ Catch ex As Exception When _
+ TypeOf ex Is UnauthorizedAccessException OrElse _
+ TypeOf ex Is System.Security.SecurityException OrElse _
+ TypeOf ex Is IOException OrElse _
+ TypeOf ex Is NotSupportedException OrElse _
+ TypeOf ex Is ArgumentException
+
+ opt.LogError("[Materialize] Byte-Persistenz fehlgeschlagen.", ex)
+ Return False
+
+ End Try
+
+ End Function
+
+ '''
+ ''' Extrahiert ein Archiv aus nach .
+ '''
+ '''
+ ''' I/O-Helfer:
+ ''' - Erwartet, dass Archivtyp bereits erkannt und als sicher bewertet wurde.
+ ''' - Behandelt I/O-Fehler intern (Logging + False).
+ '''
+ ''' Archivdaten als Bytes.
+ ''' Zielordner (normalisiert).
+ ''' Overwrite-Regel.
+ ''' Options-/Logging-Kontext.
+ ''' Archiv-Descriptor (z.B. Typ/Signatur).
+ ''' True bei erfolgreicher Extraktion, sonst False.
+ Private Shared Function MaterializeArchiveBytes _
+ (
+ data As Byte(),
+ destinationFull As String,
+ overwrite As Boolean,
+ opt As MaterializerOptions,
+ descriptor As String
+ ) As Boolean
+
+ ' Deklarationsblock
+ Dim ms As MemoryStream = Nothing
+
+ Try
+
+ If Not PrepareTarget(destinationFull, overwrite, opt) Then _
+ Return False
+
+ ms = New MemoryStream(data, writable:=False)
+ Using ms
+ Return FakeExtract(ms, destinationFull, descriptor, opt)
+ End Using
+
+ Catch ex As Exception When _
+ TypeOf ex Is UnauthorizedAccessException OrElse _
+ TypeOf ex Is System.Security.SecurityException OrElse _
+ TypeOf ex Is IOException OrElse _
+ TypeOf ex Is NotSupportedException OrElse _
+ TypeOf ex Is ArgumentException
+
+ opt.LogError("[Materialize] Archiv-Extraktion fehlgeschlagen.", ex)
+ Return False
+
+ End Try
+
+ End Function
+
+
+
+ ' =====================================================================
+ ' Local Policy/Guards (keine I/O-Details, nur Regelwerk)
+ ' =====================================================================
+
+ '''
+ ''' Liefert einen konsistenten Options-Snapshot (keine Side-Effects).
+ '''
+ '''
+ ''' Erwartung:
+ ''' - Der Snapshot darf keine I/O- oder Environment-Side-Effects auslösen.
+ ''' - Wird früh in Public API geladen, um Logging/MaxBytes konsistent zu haben.
+ '''
+ ''' Options-Snapshot für diese Operation.
+ Private Shared Function GetOptionsSnapshot() As MaterializerOptions
+
+ ' Deklarationsblock
+ Dim maxBytes As Long = 10_000_000
+
+ Return New MaterializerOptions(maxBytes:=maxBytes)
+
+ End Function
+
+ '''
+ ''' Normalisiert fail-closed zu einem kanonischen Pfad.
+ '''
+ '''
+ ''' Fehlerverhalten:
+ ''' - Gibt False zurück, wenn Pfad nicht normalisierbar ist.
+ ''' - Loggt Warnungen mit Exception-Message.
+ '''
+ ''' Eingabepfad (nicht leer).
+ ''' Ausgabe: normalisierter Vollpfad oder Nothing.
+ ''' Options-/Logging-Kontext.
+ ''' True, wenn Normalisierung erfolgreich war, sonst False.
+ Private Shared Function TryNormalizePath _
+ (
+ destinationPath As String,
+ ByRef destinationFull As String,
+ opt As MaterializerOptions
+ ) As Boolean
+
+ ' Deklarationsblock
+ Dim normalized As String = Nothing
+
+ Try
+
+ normalized = Path.GetFullPath(destinationPath)
+ destinationFull = normalized
+ Return True
+
+ Catch ex As Exception When _
+ TypeOf ex Is ArgumentException OrElse _
+ TypeOf ex Is UnauthorizedAccessException OrElse _
+ TypeOf ex Is System.Security.SecurityException OrElse _
+ TypeOf ex Is NotSupportedException OrElse _
+ TypeOf ex Is PathTooLongException OrElse _
+ TypeOf ex Is IOException
+
+ opt.LogWarn($"[Materialize] Ungültiger Zielpfad: {ex.Message}")
+ destinationFull = Nothing
+ Return False
+
+ End Try
+
+ End Function
+
+ '''
+ ''' Bereitet den Materialisierungs-Target gemäß Overwrite-Regel vor.
+ '''
+ '''
+ ''' Hinweis:
+ ''' - In echten Implementierungen: Existenzprüfung, Overwrite-Policy, Zielvalidierung.
+ ''' - Darf keine Exceptions nach außen propagieren (fail-closed im Aufrufer).
+ '''
+ ''' Normalisierter Zielpfad.
+ ''' Overwrite-Regel.
+ ''' Options-/Logging-Kontext.
+ ''' True, wenn Ziel vorbereitet ist, sonst False.
+ Private Shared Function PrepareTarget _
+ (
+ destinationFull As String,
+ overwrite As Boolean,
+ opt As MaterializerOptions
+ ) As Boolean
+
+ ' Deklarationsblock
+ Dim isValid As Boolean = True
+
+ Return isValid
+
+ End Function
+
+ '''
+ ''' Versucht, Archiv-Metadaten/Typ aus zu bestimmen.
+ '''
+ '''
+ ''' Vertrag:
+ ''' - Setzt nur bei Erfolg.
+ ''' - Liefert False, wenn keine Archivstruktur erkannt wird.
+ '''
+ ''' Eingabebytes.
+ ''' Ausgabe: Descriptor oder Nothing.
+ ''' Options-/Logging-Kontext.
+ ''' True bei erkannter Archivstruktur, sonst False.
+ Private Shared Function TryDescribeArchive _
+ (
+ data As Byte(),
+ ByRef descriptor As String,
+ opt As MaterializerOptions
+ ) As Boolean
+
+ ' Deklarationsblock
+ Dim recognized As Boolean = False
+
+ descriptor = Nothing
+ Return recognized
+
+ End Function
+
+ '''
+ ''' Bewertet ein erkanntes Archiv als sicher oder unsicher.
+ '''
+ '''
+ ''' Security:
+ ''' - In echten Implementierungen: ZipSlip-Prüfung, Pfadtraversal, Größenlimits, Bomb-Detektion.
+ ''' - Fail-closed: unsicher => False.
+ '''
+ ''' Archivbytes.
+ ''' Archiv-Descriptor.
+ ''' Options-/Logging-Kontext.
+ ''' True wenn sicher, sonst False.
+ Private Shared Function IsArchiveSafe _
+ (
+ data As Byte(),
+ descriptor As String,
+ opt As MaterializerOptions
+ ) As Boolean
+
+ ' Deklarationsblock
+ Dim safe As Boolean = True
+
+ Return safe
+
+ End Function
+
+ '''
+ ''' Beispiel-Extraktion (Platzhalter).
+ '''
+ '''
+ ''' In realem Code delegiert dies an einen Archiv-Extraktor.
+ '''
+ ''' Archivstream.
+ ''' Zielordner.
+ ''' Archiv-Descriptor.
+ ''' Options-/Logging-Kontext.
+ ''' True bei Erfolg, sonst False.
+ Private Shared Function FakeExtract _
+ (
+ ms As MemoryStream,
+ destinationFull As String,
+ descriptor As String,
+ opt As MaterializerOptions
+ ) As Boolean
+
+ ' Deklarationsblock
+ Dim ok As Boolean = True
+
+ Return ok
+
+ End Function
+
+
+
+ ' =====================================================================
+ ' Minimaler Options-Typ (nur Beispiel)
+ ' =====================================================================
+
+ '''
+ ''' Minimaler Options-/Logging-Container (Beispiel).
+ '''
+ Private NotInheritable Class MaterializerOptions
+
+ '''
+ ''' Maximale akzeptierte Byte-Anzahl.
+ '''
+ Public ReadOnly MaxBytes As Long
+
+ '''
+ ''' Erstellt einen neuen Options-Container.
+ '''
+ ''' Maximale Byte-Anzahl.
+ Public Sub New(maxBytes As Long)
+ Me.MaxBytes = maxBytes
+ End Sub
+
+ '''
+ ''' Loggt eine Warnung.
+ '''
+ ''' Warntext.
+ Public Sub LogWarn(message As String)
+ ' placeholder
+ End Sub
+
+ '''
+ ''' Loggt einen Fehler inkl. Exception.
+ '''
+ ''' Fehlertext.
+ ''' Exception.
+ Public Sub LogError(message As String, ex As Exception)
+ ' placeholder
+ End Sub
+
+ End Class
+
+ End Class
+
+End Namespace
+```
+
+## 11. Policy/RoC-Mapping (CI)
+Diese Policy ist in der CI-RoC-Matrix auf folgende Regeldateien gemappt:
+- `tools/ci/policies/rules/artifact_contract.yaml`
+- `tools/ci/policies/rules/docs_drift.yaml`
+- `tools/ci/policies/rules/naming_snt.yaml`
+- `tools/ci/policies/rules/shell_safety.yaml`
+- `tools/ci/policies/rules/versioning_svt.yaml`
diff --git a/docs/governance/145_CODE_QUALITY_POLICY_DE.MD b/docs/governance/145_CODE_QUALITY_POLICY_DE.MD
new file mode 100644
index 00000000..41940479
--- /dev/null
+++ b/docs/governance/145_CODE_QUALITY_POLICY_DE.MD
@@ -0,0 +1,142 @@
+
+[DE](045_CODE_QUALITY_POLICY_DE.MD) | [EN](145_CODE_QUALITY_POLICY_DE.MD)
+
+
+# Code Quality & Documentation Policy (EN)
+Status: binding (project policy)
+Scope: `src/FileTypeDetection/*` (VB.NET and C#), public API + internal implementation
+
+## 1. Purpose
+This policy defines a consistent, auditable schema for:
+- code structure (readability, semantics, member ordering)
+- error handling (fail-closed, consistent logging)
+- documentation (German for public API, complete, with real umlauts)
+- reproducible Codex changes without behavioral drift
+
+## 2. Normative Orientation (DIN/ISO/IEC/IEEE)
+Note: there is no single “DIN for code formatting”. This is an internal rule set aligned with established standards for information quality and software quality:
+- ISO/IEC/IEEE 26514:2022-01
+- ISO/IEC 25010:2023
+- ISO/IEC/IEEE 15289:2019
+- optional: DIN EN IEC/IEEE 82079-1:2021-09
+
+## 3. Hard Principles
+- Never transliterate German umlauts: `ä ö ü Ä Ö Ü ß` (no `ae/oe/ue/ss`).
+- Files remain UTF-8.
+- No behavior changes through formatting/docs:
+ - no signature changes
+ - no semantic changes in exceptions/returns/side effects
+ - no new external dependencies
+
+## 4. Shared vs. Instance (Construction Rule)
+### 4.1 Shared (utility) is allowed only if all are true
+- type is stateless
+- no DI or swappable dependencies needed
+- no polymorphism/test doubles via interfaces needed
+- typically: `NotInheritable` + `Private Sub New()` + only shared members
+
+### 4.2 Instance/service type is mandatory if at least one applies
+- dependencies should be injectable/swappable (I/O, logger, policy, clock, provider, ...)
+- testability via DI/interfaces is required
+- per-instance state/configuration is meaningful
+
+Within style/docs-only updates, type kind must not be changed unless already clearly established as utility/service.
+
+## 5. File and Type Structure
+### 5.1 File order
+1) file header comment (policy/context block, not XML docs)
+2) `Option Strict On` / `Option Explicit On` (VB)
+3) imports
+4) namespace
+5) types
+
+### 5.2 Type layout (member order)
+1) XML docs on type (`summary` + `remarks`)
+2) constants (`Const`) / `Shared ReadOnly`
+3) fields/properties (only when type state exists)
+4) constructors
+5) public API (all public members, ordered)
+6) internal/private helpers
+7) nested types (only if needed; at end)
+
+### 5.3 Semantic blocks in methods
+Use visible block separation (empty line + block comment markers):
+- options/snapshot
+- guard clauses (fail-closed)
+- normalization/canonicalization
+- branches (for example secure extraction)
+- fallback
+- I/O helpers separated
+
+## 6. Variable Rule
+- All local variables are declared in a declaration block at the start of the function.
+- Placement:
+ - function-local when only needed there
+ - class-level only when shared across members by design
+- Alignment: column-style (`Dim` / name / `As` / initializer) using tabs/spaces.
+- Exception: `Using`/`For` headers may contain local variables when idiomatic and more readable.
+
+## 6.1 Naming Conventions (VB.NET + C#)
+- Public API is a contract and must be convention-compliant.
+- No umlauts in identifiers.
+- No underscores in public API names (except required interop contracts).
+- Avoid unclear abbreviations in public API.
+- Keep PascalCase for namespaces/types/public members.
+- Parameters/locals: camelCase.
+- Private fields: `_camelCase` (or existing repo SSOT if different).
+- Boolean names should be positive and use `is/has/can/should` where applicable.
+- `Async` suffix only for true async semantics.
+
+## 7. Exception Handling & Logging (Fail-Closed)
+- Prefer catch filter form in VB: `Catch ex As Exception When TypeOf ex Is ...`
+- Forbidden redundant pseudo-filter: `Catch ex As Exception When TypeOf ex Is Exception`
+ If all exceptions must be handled, use `Catch ex As Exception` instead.
+- No unfiltered catch-all unless technically required and documented.
+- No silent swallow: log (`Warn`/`Error`) and preserve prior fail-closed behavior.
+- Keep log wording consistent (German with proper umlauts in this project).
+- No exception semantics change (no new wrapping, no new throws).
+
+## 8. Documentation Standard (Public API)
+### 8.1 Language/characters
+- German language for public API docs.
+- Real umlauts, no transliteration.
+
+### 8.2 Minimum per public type/member
+- Type:
+ - ``: 1-3 sentences (purpose/scope)
+ - ``: structured sections (purpose, responsibilities, non-goals, side effects, error cases, security notes, threading if relevant)
+- Public methods/functions:
+ - ``, all ``, always ``
+ - `` only if actually propagated by API contract; otherwise describe fail-closed behavior in remarks
+ - `` when useful
+
+### 8.3 “DIN-/standard-oriented” means
+- precise wording
+- consistent terminology
+- explicit error paths and side effects
+
+## 9. Definition of Done (DoD)
+For each file in `src/FileTypeDetection/*`:
+- layout complies with sections 5-7
+- public API documented per section 8
+- umlauts preserved (no `ae/oe/ue` transliteration)
+- build/tests successful
+- no public signature changes
+- no behavior drift (no new dependencies, no semantic changes)
+
+## 10. Style Reference (SSOT)
+The authoritative style/semantics template is the reference block in `docs/governance/045_CODE_QUALITY_POLICY_DE.MD` section “10. STYLE REFERENCE (SSOT)”.
+Apply that schema to all files in `src/FileTypeDetection/*`.
+Deviations are allowed only when technically required and must be justified in diff summary.
+
+## Source of Truth Note
+This English edition is provided for accessibility. If wording differs, the German policy file
+`docs/governance/045_CODE_QUALITY_POLICY_DE.MD` is authoritative.
+
+## 11. Policy/RoC Mapping (CI)
+This policy is mapped in the CI RoC matrix to the following rule files:
+- `tools/ci/policies/rules/artifact_contract.yaml`
+- `tools/ci/policies/rules/docs_drift.yaml`
+- `tools/ci/policies/rules/naming_snt.yaml`
+- `tools/ci/policies/rules/shell_safety.yaml`
+- `tools/ci/policies/rules/versioning_svt.yaml`
diff --git a/docs/references/001_REFERENCES_CORE.MD b/docs/references/001_REFERENCES_CORE.MD
index 24037f24..9b0d8aca 100644
--- a/docs/references/001_REFERENCES_CORE.MD
+++ b/docs/references/001_REFERENCES_CORE.MD
@@ -66,7 +66,7 @@ flowchart LR
MIME["Mime (HeyRed.Mime)"]
RMS["Microsoft.IO.RecyclableMemoryStream"]
SHARP["SharpCompress"]
- LOG["Microsoft.Extensions.Logging via Microsoft.AspNetCore.App"]
+ LOG["Microsoft.Extensions.Logging.Abstractions"]
API --> INF
INF --> ZIP
@@ -83,7 +83,7 @@ flowchart LR
| `Mime` | `Infrastructure/MimeProvider.vb` | MIME-Auflösung aus Extension |
| `Microsoft.IO.RecyclableMemoryStream` | `Infrastructure/ArchiveManagedInternals.vb` | kontrollierte Memory-Streams |
| `SharpCompress` | `Infrastructure/ArchiveInternals.vb`, `FileMaterializer.vb` | Archive-Type-Erkennung, generische Archiv-Iteration, defensiver Lesbarkeits-Check |
-| `Microsoft.AspNetCore.App` (FrameworkReference) | Logging via `Microsoft.Extensions.Logging` | optionale Diagnostik |
+| `Microsoft.Extensions.Logging.Abstractions` | `Configuration/FileTypeProjectOptions.vb`, `FileTypeOptions.vb`, `Infrastructure/CoreInternals.vb` | Logging-Interfaces fuer optionale Diagnostik ohne ASP.NET-FrameworkReference |
## 6. Referenz-Index (wo finde ich was?)
| Thema | Primardokument |
diff --git a/docs/references/101_REFERENCES_CORE.MD b/docs/references/101_REFERENCES_CORE.MD
index d5981b0c..1032bc20 100644
--- a/docs/references/101_REFERENCES_CORE.MD
+++ b/docs/references/101_REFERENCES_CORE.MD
@@ -66,7 +66,7 @@ flowchart LR
MIME["Mime (HeyRed.Mime)"]
RMS["Microsoft.IO.RecyclableMemoryStream"]
SHARP["SharpCompress"]
- LOG["Microsoft.Extensions.Logging via Microsoft.AspNetCore.App"]
+ LOG["Microsoft.Extensions.Logging.Abstractions"]
API --> INF
INF --> ZIP
@@ -83,7 +83,7 @@ flowchart LR
| `Mime` | `Infrastructure/MimeProvider.vb` | MIME resolution from extension |
| `Microsoft.IO.RecyclableMemoryStream` | `Infrastructure/ArchiveManagedInternals.vb` | controlled memory streams |
| `SharpCompress` | `Infrastructure/ArchiveInternals.vb`, `FileMaterializer.vb` | archive type detection, generic archive iteration, defensive readability check |
-| `Microsoft.AspNetCore.App` (FrameworkReference) | logging via `Microsoft.Extensions.Logging` | optional diagnostics |
+| `Microsoft.Extensions.Logging.Abstractions` | `Configuration/FileTypeProjectOptions.vb`, `FileTypeOptions.vb`, `Infrastructure/CoreInternals.vb` | logging interfaces for optional diagnostics without ASP.NET framework reference |
## 6. Reference index (where to find what?)
| Topic | Primary document |
diff --git a/docs/versioning/002_HISTORY_VERSIONS.MD b/docs/versioning/002_HISTORY_VERSIONS.MD
index 5bfd2334..2f117d78 100644
--- a/docs/versioning/002_HISTORY_VERSIONS.MD
+++ b/docs/versioning/002_HISTORY_VERSIONS.MD
@@ -12,7 +12,7 @@ Heuristik fuer die Rueckwirkungs-Zuordnung:
- `docs|test|ci|chore|tooling|refactor|fix` => Patch
Aktueller Entwicklungsstand:
-- Aktuelle Entwicklungslinie enthaelt `5.x` (aktuell veroeffentlichtes Tag: `v5.1.4`; Details in `docs/versioning/003_CHANGELOG_RELEASES.MD`).
+- Aktuelle Entwicklungslinie enthaelt `5.x` (Release-Stand: `v5.1.4`, naechster Zielstand in Arbeit: `5.2.0`; Details in `docs/versioning/003_CHANGELOG_RELEASES.MD`).
Hinweis:
- Die Spalte `Keyword` verwendet den technischen Klassifizierungswert aus der Historie.
@@ -20,6 +20,7 @@ Hinweis:
| Version | Kurzbeschreibung | Commit | Keyword |
|---|---|---|---|
+| `5.2.0` | netstandard2.0-Compat-Layer eingefuehrt, Provider-Struktur konsolidiert und TFM-Multi-Targeting erweitert | n/a (branch: `codex/chore/netstandard2-compat-structure`) | minor |
| `5.1.4` | Refactor-Cluster 7C abgeschlossen + Qodana-Alerts auf 0 + Version-Bump fuer Release | [2adeb83](https://github.com/tomtastisch/FileClassifier/commit/2adeb83) | patch |
| `5.1.3` | PR-Governance-Haertung (DE-Naming, PR-Template, fail-closed Gate fuer `security/code-scanning/tools = 0`) | [0b488ac](https://github.com/tomtastisch/FileClassifier/commit/0b488ac) | patch |
| `5.1.2` | Gate4 Polling-Optimierung und Release-Haertung | [f12711d](https://github.com/tomtastisch/FileClassifier/commit/f12711d) | patch |
diff --git a/docs/versioning/102_HISTORY_VERSIONS.MD b/docs/versioning/102_HISTORY_VERSIONS.MD
index 3e55f398..b15d9c69 100644
--- a/docs/versioning/102_HISTORY_VERSIONS.MD
+++ b/docs/versioning/102_HISTORY_VERSIONS.MD
@@ -12,13 +12,14 @@ Heuristics for retroactive classification:
- `docs|test|ci|chore|tooling|refactor|fix` => patch
Current state:
-- Current release line contains `5.x` (latest published tag: `v5.1.4`; details in `docs/versioning/103_CHANGELOG_RELEASES.MD`).
+- Current release line contains `5.x` (release state: `v5.1.4`, next target in progress: `5.2.0`; details in `docs/versioning/103_CHANGELOG_RELEASES.MD`).
Note:
- The \"short description\" column follows the original commit/PR intent text for deterministic traceability and is not normalized to a single language.
| Version | Short description | Commit | Keyword |
|---|---|---|---|
+| `5.2.0` | Introduce netstandard2.0 compatibility layer, consolidate provider structure, and extend TFM multi-targeting | n/a (branch: `codex/chore/netstandard2-compat-structure`) | minor |
| `5.1.4` | Refactor-Cluster 7C abgeschlossen + Qodana-Alerts auf 0 + Version-Bump fuer Release | [2adeb83](https://github.com/tomtastisch/FileClassifier/commit/2adeb83) | patch |
| `5.1.3` | PR-Governance-Haertung (DE-Naming, PR-Template, fail-closed Gate fuer `security/code-scanning/tools = 0`) | [0b488ac](https://github.com/tomtastisch/FileClassifier/commit/0b488ac) | patch |
| `5.1.2` | Gate4 Polling-Optimierung und Release-Haertung | [f12711d](https://github.com/tomtastisch/FileClassifier/commit/f12711d) | patch |
diff --git a/src/FileClassifier.App/packages.lock.json b/src/FileClassifier.App/packages.lock.json
index eaa2758b..f915a5de 100644
--- a/src/FileClassifier.App/packages.lock.json
+++ b/src/FileClassifier.App/packages.lock.json
@@ -2,6 +2,11 @@
"version": 2,
"dependencies": {
"net10.0": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "10.0.0",
+ "contentHash": "L3AdmZ1WOK4XXT5YFPEwyt0ep6l8lGIPs7F5OOBZc77Zqeo01Of7XXICy47628sdVl0v/owxYJTe86DTgFwKCA=="
+ },
"MimeTypesMap": {
"type": "Transitive",
"resolved": "1.0.9",
@@ -15,12 +20,22 @@
"Tomtastisch.FileClassifier": {
"type": "Project",
"dependencies": {
+ "Microsoft.Extensions.Logging.Abstractions": "[10.0.0, )",
"Microsoft.IO.RecyclableMemoryStream": "[3.0.1, )",
"Mime": "[3.8.0, )",
"SharpCompress": "[0.39.0, )",
"System.IO.Hashing": "[10.0.2, )"
}
},
+ "Microsoft.Extensions.Logging.Abstractions": {
+ "type": "CentralTransitive",
+ "requested": "[10.0.0, )",
+ "resolved": "10.0.0",
+ "contentHash": "FU/IfjDfwaMuKr414SSQNTIti/69bHEMb+QKrskRb26oVqpx3lNFXMjs/RC9ZUuhBhcwDM2BwOgoMw+PZ+beqQ==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.0"
+ }
+ },
"Microsoft.IO.RecyclableMemoryStream": {
"type": "CentralTransitive",
"requested": "[3.0.1, )",
diff --git a/src/FileTypeDetection/Abstractions/Archive/ZipExtractedEntry.vb b/src/FileTypeDetection/Abstractions/Archive/ZipExtractedEntry.vb
index cad2e752..0f10558b 100644
--- a/src/FileTypeDetection/Abstractions/Archive/ZipExtractedEntry.vb
+++ b/src/FileTypeDetection/Abstractions/Archive/ZipExtractedEntry.vb
@@ -1,3 +1,12 @@
+' ============================================================================
+' FILE: ZipExtractedEntry.vb
+'
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' - Try/Catch konsistent im Catch-Filter-Schema
+' - Variablen im Deklarationsblock, spaltenartig ausgerichtet
+' ============================================================================
+
Option Strict On
Option Explicit On
diff --git a/src/FileTypeDetection/Abstractions/Detection/DetectionDetail.vb b/src/FileTypeDetection/Abstractions/Detection/DetectionDetail.vb
index 47c0ca54..3c8c0b78 100644
--- a/src/FileTypeDetection/Abstractions/Detection/DetectionDetail.vb
+++ b/src/FileTypeDetection/Abstractions/Detection/DetectionDetail.vb
@@ -1,3 +1,12 @@
+' ============================================================================
+' FILE: DetectionDetail.vb
+'
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' - Try/Catch konsistent im Catch-Filter-Schema
+' - Variablen im Deklarationsblock, spaltenartig ausgerichtet
+' ============================================================================
+
Option Strict On
Option Explicit On
diff --git a/src/FileTypeDetection/Abstractions/Detection/FileKind.vb b/src/FileTypeDetection/Abstractions/Detection/FileKind.vb
index 3e9a8544..b8aefb8c 100644
--- a/src/FileTypeDetection/Abstractions/Detection/FileKind.vb
+++ b/src/FileTypeDetection/Abstractions/Detection/FileKind.vb
@@ -1,3 +1,12 @@
+' ============================================================================
+' FILE: FileKind.vb
+'
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' - Try/Catch konsistent im Catch-Filter-Schema
+' - Variablen im Deklarationsblock, spaltenartig ausgerichtet
+' ============================================================================
+
Option Strict On
Option Explicit On
Option Infer On
diff --git a/src/FileTypeDetection/Abstractions/Detection/FileType.vb b/src/FileTypeDetection/Abstractions/Detection/FileType.vb
index 67f3a87a..04ed4c85 100644
--- a/src/FileTypeDetection/Abstractions/Detection/FileType.vb
+++ b/src/FileTypeDetection/Abstractions/Detection/FileType.vb
@@ -1,3 +1,12 @@
+' ============================================================================
+' FILE: FileType.vb
+'
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' - Try/Catch konsistent im Catch-Filter-Schema
+' - Variablen im Deklarationsblock, spaltenartig ausgerichtet
+' ============================================================================
+
Option Strict On
Option Explicit On
diff --git a/src/FileTypeDetection/Abstractions/Hashing/HashDigestSet.vb b/src/FileTypeDetection/Abstractions/Hashing/HashDigestSet.vb
index 8ba3059f..96cb9f82 100644
--- a/src/FileTypeDetection/Abstractions/Hashing/HashDigestSet.vb
+++ b/src/FileTypeDetection/Abstractions/Hashing/HashDigestSet.vb
@@ -1,3 +1,12 @@
+' ============================================================================
+' FILE: HashDigestSet.vb
+'
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' - Try/Catch konsistent im Catch-Filter-Schema
+' - Variablen im Deklarationsblock, spaltenartig ausgerichtet
+' ============================================================================
+
Option Strict On
Option Explicit On
diff --git a/src/FileTypeDetection/Abstractions/Hashing/HashEvidence.vb b/src/FileTypeDetection/Abstractions/Hashing/HashEvidence.vb
index ed8cf643..47804479 100644
--- a/src/FileTypeDetection/Abstractions/Hashing/HashEvidence.vb
+++ b/src/FileTypeDetection/Abstractions/Hashing/HashEvidence.vb
@@ -1,3 +1,12 @@
+' ============================================================================
+' FILE: HashEvidence.vb
+'
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' - Try/Catch konsistent im Catch-Filter-Schema
+' - Variablen im Deklarationsblock, spaltenartig ausgerichtet
+' ============================================================================
+
Option Strict On
Option Explicit On
@@ -33,12 +42,12 @@ Namespace Global.Tomtastisch.FileClassifier
'''
''' Optional mitgeführte komprimierte Bytes.
'''
- Public ReadOnly Property CompressedBytes As Global.System.Collections.Immutable.ImmutableArray(Of Byte)
+ Public ReadOnly Property CompressedBytes As Immutable.ImmutableArray(Of Byte)
'''
''' Optional mitgeführte unkomprimierte bzw. logische Bytes.
'''
- Public ReadOnly Property UncompressedBytes As Global.System.Collections.Immutable.ImmutableArray(Of Byte)
+ Public ReadOnly Property UncompressedBytes As Immutable.ImmutableArray(Of Byte)
'''
''' Anzahl berücksichtigter Entries im Nachweis.
@@ -98,11 +107,11 @@ Namespace Global.Tomtastisch.FileClassifier
notes:=notes)
End Function
- Private Shared Function ToImmutable(data As Byte()) As Global.System.Collections.Immutable.ImmutableArray(Of Byte)
+ Private Shared Function ToImmutable(data As Byte()) As Immutable.ImmutableArray(Of Byte)
If data Is Nothing OrElse data.Length = 0 Then
- Return Global.System.Collections.Immutable.ImmutableArray(Of Byte).Empty
+ Return Immutable.ImmutableArray(Of Byte).Empty
End If
- Return Global.System.Collections.Immutable.ImmutableArray.Create(data)
+ Return Immutable.ImmutableArray.Create(data)
End Function
End Class
End Namespace
diff --git a/src/FileTypeDetection/Abstractions/Hashing/HashOptions.vb b/src/FileTypeDetection/Abstractions/Hashing/HashOptions.vb
index 71741344..99201155 100644
--- a/src/FileTypeDetection/Abstractions/Hashing/HashOptions.vb
+++ b/src/FileTypeDetection/Abstractions/Hashing/HashOptions.vb
@@ -1,6 +1,17 @@
+' ============================================================================
+' FILE: HashOptions.vb
+'
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' - Try/Catch konsistent im Catch-Filter-Schema
+' - Variablen im Deklarationsblock, spaltenartig ausgerichtet
+' ============================================================================
+
Option Strict On
Option Explicit On
+Imports System.Diagnostics.CodeAnalysis
+
Namespace Global.Tomtastisch.FileClassifier
'''
''' Konfiguriert das Verhalten der öffentlichen deterministischen Hashing-APIs.
@@ -49,19 +60,20 @@ Namespace Global.Tomtastisch.FileClassifier
Return cloned
End Function
+
Private Shared Function NormalizeMaterializedFileName(candidate As String) As String
Dim normalized = If(candidate, String.Empty).Trim()
If String.IsNullOrWhiteSpace(normalized) Then Return "deterministic-roundtrip.bin"
Try
- normalized = Global.System.IO.Path.GetFileName(normalized)
+ normalized = IO.Path.GetFileName(normalized)
Catch
Return "deterministic-roundtrip.bin"
End Try
If String.IsNullOrWhiteSpace(normalized) Then Return "deterministic-roundtrip.bin"
- For Each invalidChar In Global.System.IO.Path.GetInvalidFileNameChars()
+ For Each invalidChar In IO.Path.GetInvalidFileNameChars()
If normalized.IndexOf(invalidChar) >= 0 Then
Return "deterministic-roundtrip.bin"
End If
diff --git a/src/FileTypeDetection/Abstractions/Hashing/HashRoundTripReport.vb b/src/FileTypeDetection/Abstractions/Hashing/HashRoundTripReport.vb
index b7cd8979..69cdd6b0 100644
--- a/src/FileTypeDetection/Abstractions/Hashing/HashRoundTripReport.vb
+++ b/src/FileTypeDetection/Abstractions/Hashing/HashRoundTripReport.vb
@@ -1,3 +1,12 @@
+' ============================================================================
+' FILE: HashRoundTripReport.vb
+'
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' - Try/Catch konsistent im Catch-Filter-Schema
+' - Variablen im Deklarationsblock, spaltenartig ausgerichtet
+' ============================================================================
+
Option Strict On
Option Explicit On
diff --git a/src/FileTypeDetection/Abstractions/Hashing/HashSourceType.vb b/src/FileTypeDetection/Abstractions/Hashing/HashSourceType.vb
index af02e2bb..63356781 100644
--- a/src/FileTypeDetection/Abstractions/Hashing/HashSourceType.vb
+++ b/src/FileTypeDetection/Abstractions/Hashing/HashSourceType.vb
@@ -1,3 +1,12 @@
+' ============================================================================
+' FILE: HashSourceType.vb
+'
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' - Try/Catch konsistent im Catch-Filter-Schema
+' - Variablen im Deklarationsblock, spaltenartig ausgerichtet
+' ============================================================================
+
Option Strict On
Option Explicit On
diff --git a/src/FileTypeDetection/Abstractions/Providers/IHashPrimitives.vb b/src/FileTypeDetection/Abstractions/Providers/IHashPrimitives.vb
new file mode 100644
index 00000000..8641aa6c
--- /dev/null
+++ b/src/FileTypeDetection/Abstractions/Providers/IHashPrimitives.vb
@@ -0,0 +1,55 @@
+' ============================================================================
+' FILE: IHashPrimitives.vb
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' ============================================================================
+
+Option Strict On
+Option Explicit On
+
+Namespace Global.Tomtastisch.FileClassifier
+ '''
+ ''' Interne Abstraktion für deterministische Lower-Hex-Kodierung von Bytefolgen.
+ '''
+ '''
+ ''' Zweck: Kapselt die TFM-sensitive Hex-Ausgabe hinter einem einheitlichen Vertrag.
+ '''
+ Friend Interface IHexCodec
+ Function EncodeLowerHex(data As Byte()) As String
+ End Interface
+
+ '''
+ ''' Interne Abstraktion für SHA256-Grundoperationen.
+ '''
+ '''
+ ''' Zweck: Vereinheitlicht Byte- und Hex-Ausgabe von SHA256 über alle TFMs.
+ '''
+ Friend Interface ISha256Primitives
+ Function ComputeHash(data As Byte()) As Byte()
+ Function ComputeHashHex(data As Byte()) As String
+ End Interface
+
+ '''
+ ''' Interne Abstraktion für deterministische 64-Bit-Fast-Hash-Operationen.
+ '''
+ '''
+ ''' Zweck: Entkoppelt FastHash64-Berechnung von TFM-spezifischen APIs.
+ '''
+ Friend Interface IFastHash64
+ Function ComputeHashUInt64(data As Byte()) As ULong
+ Function ComputeHashHex(data As Byte()) As String
+ End Interface
+
+ '''
+ ''' Aggregierter interner Vertrag für alle Hash-Primitive des Core-Hashings.
+ '''
+ '''
+ ''' Zweck: Stellt einen zentralen Zugriffspunkt für Hex, SHA256 und FastHash64 bereit.
+ '''
+ Friend Interface IHashPrimitives
+ ReadOnly Property ProviderMarker As String
+ ReadOnly Property HexCodec As IHexCodec
+ ReadOnly Property Sha256 As ISha256Primitives
+ ReadOnly Property FastHash64 As IFastHash64
+ End Interface
+End Namespace
diff --git a/src/FileTypeDetection/Abstractions/Providers/README.md b/src/FileTypeDetection/Abstractions/Providers/README.md
new file mode 100644
index 00000000..fcf15b59
--- /dev/null
+++ b/src/FileTypeDetection/Abstractions/Providers/README.md
@@ -0,0 +1,32 @@
+# Abstractions Providers Modul
+
+## 1. Zweck
+Dieses Verzeichnis enthält interne Verträge für TFM-sensitive Hashing-Primitive.
+
+## 2. Inhalt
+- `IHexCodec`
+- `ISha256Primitives`
+- `IFastHash64`
+- `IHashPrimitives`
+
+## 3. API und Verhalten
+- Die Interfaces sind intern (`Friend`) und gehören nicht zur Public API.
+- Core-/Fassadenlogik konsumiert nur diese Abstraktionen statt direkter TFM-APIs.
+
+## 4. Verifikation
+- Provider-Implementierungen müssen die gleichen Ausgabekontrakte je TFM einhalten.
+
+## 5. Diagramm
+```mermaid
+flowchart LR
+ A["EvidenceHashing"] --> B["HashPrimitives.Current"]
+ B --> C["IHashPrimitives"]
+ C --> D["IHexCodec"]
+ C --> E["ISha256Primitives"]
+ C --> F["IFastHash64"]
+```
+
+## 6. Verweise
+- [Abstractions Modul](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/Abstractions/README.md)
+- [Composition Modul](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/Composition/README.md)
+- [Providers Modul](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/Providers/README.md)
diff --git a/src/FileTypeDetection/Abstractions/README.md b/src/FileTypeDetection/Abstractions/README.md
index 7c05bd18..5b48e58b 100644
--- a/src/FileTypeDetection/Abstractions/README.md
+++ b/src/FileTypeDetection/Abstractions/README.md
@@ -27,3 +27,4 @@ flowchart LR
- [Detection-Modelle](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/Abstractions/Detection/README.md)
- [Archive-Modelle](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/Abstractions/Archive/README.md)
- [Hashing-Modelle](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/Abstractions/Hashing/README.md)
+- [Provider-Abstraktionen](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/Abstractions/Providers/README.md)
diff --git a/src/FileTypeDetection/ArchiveProcessing.vb b/src/FileTypeDetection/ArchiveProcessing.vb
index 7bf11181..e12a2ca5 100644
--- a/src/FileTypeDetection/ArchiveProcessing.vb
+++ b/src/FileTypeDetection/ArchiveProcessing.vb
@@ -1,3 +1,12 @@
+' ============================================================================
+' FILE: ArchiveProcessing.vb
+'
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' - Try/Catch konsistent im Catch-Filter-Schema
+' - Variablen im Deklarationsblock, spaltenartig ausgerichtet
+' ============================================================================
+
Option Strict On
Option Explicit On
diff --git a/src/FileTypeDetection/Composition/HashPrimitives.vb b/src/FileTypeDetection/Composition/HashPrimitives.vb
new file mode 100644
index 00000000..b480cca6
--- /dev/null
+++ b/src/FileTypeDetection/Composition/HashPrimitives.vb
@@ -0,0 +1,29 @@
+' ============================================================================
+' FILE: HashPrimitives.vb
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' ============================================================================
+
+Option Strict On
+Option Explicit On
+
+Namespace Global.Tomtastisch.FileClassifier
+ '''
+ ''' Interner Kompositionspunkt für TFM-spezifische Hash-Primitive.
+ '''
+ '''
+ ''' Zweck: Stellt genau eine compile-time gebundene Providerinstanz für den Core bereit.
+ '''
+ Friend NotInheritable Class HashPrimitives
+ Private Shared ReadOnly _current As IHashPrimitives = New HashPrimitivesProvider()
+
+ Private Sub New()
+ End Sub
+
+ Friend Shared ReadOnly Property Current As IHashPrimitives
+ Get
+ Return _current
+ End Get
+ End Property
+ End Class
+End Namespace
diff --git a/src/FileTypeDetection/Composition/README.md b/src/FileTypeDetection/Composition/README.md
new file mode 100644
index 00000000..2893426f
--- /dev/null
+++ b/src/FileTypeDetection/Composition/README.md
@@ -0,0 +1,25 @@
+# Composition Modul
+
+## 1. Zweck
+Dieses Verzeichnis kapselt den einzigen Kompositionspunkt für interne Hashing-Provider.
+
+## 2. Inhalt
+- `HashPrimitives.vb`
+
+## 3. API und Verhalten
+- `HashPrimitives.Current` liefert den compile-time gebundenen Provider.
+- Kein Runtime-Branching, keine Environment-Erkennung, keine DI-basierte Provider-Umschaltung.
+
+## 4. Verifikation
+- Reflection-Tests prüfen die Verfügbarkeit und den Provider-Marker.
+
+## 5. Diagramm
+```mermaid
+flowchart LR
+ A["EvidenceHashing"] --> B["HashPrimitives.Current"]
+ B --> C["HashPrimitivesProvider (compiled for TFM)"]
+```
+
+## 6. Verweise
+- [Abstractions Providers Modul](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/Abstractions/Providers/README.md)
+- [Providers Modul](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/Providers/README.md)
diff --git a/src/FileTypeDetection/Configuration/FileTypeProjectBaseline.vb b/src/FileTypeDetection/Configuration/FileTypeProjectBaseline.vb
index 79c0e6fa..255fa7e1 100644
--- a/src/FileTypeDetection/Configuration/FileTypeProjectBaseline.vb
+++ b/src/FileTypeDetection/Configuration/FileTypeProjectBaseline.vb
@@ -1,3 +1,12 @@
+' ============================================================================
+' FILE: FileTypeProjectBaseline.vb
+'
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' - Try/Catch konsistent im Catch-Filter-Schema
+' - Variablen im Deklarationsblock, spaltenartig ausgerichtet
+' ============================================================================
+
Option Strict On
Option Explicit On
diff --git a/src/FileTypeDetection/Configuration/FileTypeProjectOptions.vb b/src/FileTypeDetection/Configuration/FileTypeProjectOptions.vb
index cab4217c..20f6d2ee 100644
--- a/src/FileTypeDetection/Configuration/FileTypeProjectOptions.vb
+++ b/src/FileTypeDetection/Configuration/FileTypeProjectOptions.vb
@@ -1,3 +1,12 @@
+' ============================================================================
+' FILE: FileTypeProjectOptions.vb
+'
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' - Try/Catch konsistent im Catch-Filter-Schema
+' - Variablen im Deklarationsblock, spaltenartig ausgerichtet
+' ============================================================================
+
Option Strict On
Option Explicit On
@@ -75,7 +84,7 @@ Namespace Global.Tomtastisch.FileClassifier
Public Property AllowUnknownArchiveEntrySize As Boolean = False
''' Optionaler Logger für Diagnosezwecke.
- Public Property Logger As Global.Microsoft.Extensions.Logging.ILogger = Nothing
+ Public Property Logger As Microsoft.Extensions.Logging.ILogger = Nothing
'''
''' Optionen für deterministische Hash-/Evidence-Funktionen.
diff --git a/src/FileTypeDetection/Core/README.md b/src/FileTypeDetection/Core/README.md
new file mode 100644
index 00000000..6e9f73fe
--- /dev/null
+++ b/src/FileTypeDetection/Core/README.md
@@ -0,0 +1,22 @@
+# Core Modul
+
+## 1. Zweck
+Dieses Verzeichnis reserviert den Raum für gemeinsame, TFM-unabhängige Kernlogik ohne direkte TFM-spezifische API-Aufrufe.
+
+## 2. Inhalt
+- Derzeit nur Strukturanker für netstandard2.0-kompatible Refactorings.
+
+## 3. API und Verhalten
+- Core-Code darf keine direkten Aufrufe auf moderne TFM-spezifische APIs enthalten.
+- TFM-sensitive Primitive werden ausschließlich über Provider-Abstraktionen konsumiert.
+
+## 4. Verifikation
+- Nachweis erfolgt über Grep-Checks und Build-Matrix je TFM.
+
+## 5. Diagramm
+N/A
+
+## 6. Verweise
+- [Modulübersicht](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/README.md)
+- [Abstractions Modul](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/Abstractions/README.md)
+- [Providers Modul](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/Providers/README.md)
diff --git a/src/FileTypeDetection/Detection/FileTypeRegistry.vb b/src/FileTypeDetection/Detection/FileTypeRegistry.vb
index 5281cdfd..16107b96 100644
--- a/src/FileTypeDetection/Detection/FileTypeRegistry.vb
+++ b/src/FileTypeDetection/Detection/FileTypeRegistry.vb
@@ -1,3 +1,12 @@
+' ============================================================================
+' FILE: FileTypeRegistry.vb
+'
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' - Try/Catch konsistent im Catch-Filter-Schema
+' - Variablen im Deklarationsblock, spaltenartig ausgerichtet
+' ============================================================================
+
Option Strict On
Option Explicit On
@@ -6,9 +15,9 @@ Imports System.Linq
Namespace Global.Tomtastisch.FileClassifier
'''
- ''' Zentrale Registry als SSOT fuer Typmetadaten, Alias-Aufloesung und Magic-Patterns.
+ ''' Zentrale Registry als SSOT für Typmetadaten, Alias-Auflösung und Magic-Patterns.
''' Regeln:
- ''' - Neue Typen werden primaer ueber FileKind erweitert.
+ ''' - Neue Typen werden primär über FileKind erweitert.
''' - Metadaten werden deterministisch aus FileKind + zentralen Overrides aufgebaut.
''' - Unknown ist immer als fail-closed Fallback vorhanden.
'''
@@ -73,8 +82,8 @@ Namespace Global.Tomtastisch.FileClassifier
End Function
Private Shared Function OrderedKinds() As ImmutableArray(Of FileKind)
- Return [Enum].
- GetValues(Of FileKind)().
+ Dim values = [Enum].GetValues(GetType(FileKind)).Cast(Of FileKind)()
+ Return values.
OrderBy(Function(kind) CInt(kind)).
ToImmutableArray()
End Function
@@ -264,7 +273,7 @@ Namespace Global.Tomtastisch.FileClassifier
End Function
'''
- ''' Liefert den zugeordneten FileType fuer einen Enumwert.
+ ''' Liefert den zugeordneten FileType für einen Enumwert.
'''
''' Enumwert des Typs.
''' Registrierter Typ oder Unknown.
@@ -275,9 +284,9 @@ Namespace Global.Tomtastisch.FileClassifier
End Function
'''
- ''' Liefert den zugeordneten FileType fuer einen Aliaswert.
+ ''' Liefert den zugeordneten FileType für einen Aliaswert.
'''
- ''' Alias mit oder ohne fuehrenden Punkt.
+ ''' Alias mit oder ohne führenden Punkt.
''' Registrierter Typ oder Unknown.
Friend Shared Function ResolveByAlias(aliasKey As String) As FileType
Dim k = FileKind.Unknown
@@ -287,6 +296,9 @@ Namespace Global.Tomtastisch.FileClassifier
Return Resolve(FileKind.Unknown)
End Function
+ '''
+ ''' Interner, unveränderlicher Datenträger FileTypeDefinition für strukturierte Verarbeitungsschritte.
+ '''
Private Structure FileTypeDefinition
Friend ReadOnly Kind As FileKind
Friend ReadOnly CanonicalExtension As String
@@ -302,6 +314,9 @@ Namespace Global.Tomtastisch.FileClassifier
End Sub
End Structure
+ '''
+ ''' Interner, unveränderlicher Datenträger MagicRule für strukturierte Verarbeitungsschritte.
+ '''
Private Structure MagicRule
Friend ReadOnly Kind As FileKind
Friend ReadOnly Patterns As ImmutableArray(Of MagicPattern)
@@ -312,6 +327,9 @@ Namespace Global.Tomtastisch.FileClassifier
End Sub
End Structure
+ '''
+ ''' Interner, unveränderlicher Datenträger MagicPattern für strukturierte Verarbeitungsschritte.
+ '''
Private Structure MagicPattern
Friend ReadOnly Segments As ImmutableArray(Of MagicSegment)
@@ -320,6 +338,9 @@ Namespace Global.Tomtastisch.FileClassifier
End Sub
End Structure
+ '''
+ ''' Interner, unveränderlicher Datenträger MagicSegment für strukturierte Verarbeitungsschritte.
+ '''
Private Structure MagicSegment
Friend ReadOnly Offset As Integer
Friend ReadOnly Bytes As ImmutableArray(Of Byte)
diff --git a/src/FileTypeDetection/EvidenceHashing.vb b/src/FileTypeDetection/EvidenceHashing.vb
index 30151a4c..ecbb8d78 100644
--- a/src/FileTypeDetection/EvidenceHashing.vb
+++ b/src/FileTypeDetection/EvidenceHashing.vb
@@ -1,3 +1,12 @@
+' ============================================================================
+' FILE: EvidenceHashing.vb
+'
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' - Try/Catch konsistent im Catch-Filter-Schema
+' - Variablen im Deklarationsblock, spaltenartig ausgerichtet
+' ============================================================================
+
Option Strict On
Option Explicit On
@@ -151,7 +160,7 @@ Namespace Global.Tomtastisch.FileClassifier
If CLng(data.Length) > detectorOptions.MaxBytes Then
Return _
- HashEvidence.CreateFailure(HashSourceType.RawBytes, label, "Payload groesser als MaxBytes.")
+ HashEvidence.CreateFailure(HashSourceType.RawBytes, label, "Payload größer als MaxBytes.")
End If
Dim detectedType = New FileTypeDetector().Detect(data)
@@ -540,7 +549,7 @@ Namespace Global.Tomtastisch.FileClassifier
Dim normalizedPath As String = Nothing
If Not TryNormalizeEntryPath(entry.RelativePath, normalizedPath) Then
- errorMessage = $"Ungueltiger Entry-Pfad: '{entry.RelativePath}'."
+ errorMessage = $"Ungültiger Entry-Pfad: '{entry.RelativePath}'."
Return False
End If
@@ -574,7 +583,7 @@ Namespace Global.Tomtastisch.FileClassifier
For Each entry In entries
Dim pathBytes = Text.Encoding.UTF8.GetBytes(entry.RelativePath)
- Dim contentHash = Security.Cryptography.SHA256.HashData(entry.Content)
+ Dim contentHash = HashPrimitives.Current.Sha256.ComputeHash(entry.Content)
writer.Write(pathBytes.Length)
writer.Write(pathBytes)
writer.Write(CLng(entry.Content.LongLength))
@@ -588,7 +597,7 @@ Namespace Global.Tomtastisch.FileClassifier
Private Shared Function ComputeSha256Hex(payload As Byte()) As String
Dim data = If(payload, Array.Empty(Of Byte)())
- Return Convert.ToHexString(Security.Cryptography.SHA256.HashData(data)).ToLowerInvariant()
+ Return HashPrimitives.Current.Sha256.ComputeHashHex(data)
End Function
Private Shared Function TryResolveHmacKey(ByRef key As Byte(), ByRef note As String) As Boolean
@@ -626,15 +635,14 @@ Namespace Global.Tomtastisch.FileClassifier
Dim safeKey = If(key, Array.Empty(Of Byte)())
Dim data = If(payload, Array.Empty(Of Byte)())
Using hmac As New Security.Cryptography.HMACSHA256(safeKey)
- Return Convert.ToHexString(hmac.ComputeHash(data)).ToLowerInvariant()
+ Return HashPrimitives.Current.HexCodec.EncodeLowerHex(hmac.ComputeHash(data))
End Using
End Function
Private Shared Function ComputeFastHash(payload As Byte(), options As HashOptions) As String
If options Is Nothing OrElse Not options.IncludeFastHash Then Return String.Empty
Dim data = If(payload, Array.Empty(Of Byte)())
- Dim value = IO.Hashing.XxHash3.HashToUInt64(data)
- Return value.ToString("x16", Globalization.CultureInfo.InvariantCulture)
+ Return HashPrimitives.Current.FastHash64.ComputeHashHex(data)
End Function
Private Shared Function AppendNoteIfAny(baseNotes As String, toAppend As String) As String
@@ -688,7 +696,7 @@ Namespace Global.Tomtastisch.FileClassifier
End If
If fi.Length > detectorOptions.MaxBytes Then
- errorMessage = "Datei groesser als MaxBytes."
+ errorMessage = "Datei größer als MaxBytes."
Return False
End If
@@ -718,6 +726,9 @@ Namespace Global.Tomtastisch.FileClassifier
Return False
End Function
+ '''
+ ''' Interne Hilfsklasse NormalizedEntry zur kapselnden Umsetzung von Guard-, I/O- und Policy-Logik.
+ '''
Private NotInheritable Class NormalizedEntry
Friend ReadOnly Property RelativePath As String
Friend ReadOnly Property Content As Byte()
diff --git a/src/FileTypeDetection/FileMaterializer.vb b/src/FileTypeDetection/FileMaterializer.vb
index bbc4f02e..51daf36d 100644
--- a/src/FileTypeDetection/FileMaterializer.vb
+++ b/src/FileTypeDetection/FileMaterializer.vb
@@ -1,3 +1,12 @@
+' ============================================================================
+' FILE: FileMaterializer.vb
+'
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' - Try/Catch konsistent im Catch-Filter-Schema
+' - Variablen im Deklarationsblock, spaltenartig ausgerichtet
+' ============================================================================
+
Option Strict On
Option Explicit On
@@ -138,7 +147,6 @@ Namespace Global.Tomtastisch.FileClassifier
' Pfadnormalisierung: Absoluten Zielpfad auflösen.
Dim destinationFull As String
- Dim errorMessage As String = Nothing
Try
destinationFull = Path.GetFullPath(destinationPath)
@@ -146,12 +154,12 @@ Namespace Global.Tomtastisch.FileClassifier
Catch ex As Exception When _
TypeOf ex Is ArgumentException OrElse
TypeOf ex Is UnauthorizedAccessException OrElse
- TypeOf ex Is System.Security.SecurityException OrElse
+ TypeOf ex Is Security.SecurityException OrElse
TypeOf ex Is NotSupportedException OrElse
TypeOf ex Is PathTooLongException OrElse
TypeOf ex Is IOException
- LogGuard.Warn(opt.Logger, $"[Materialize] Ungueltiger Zielpfad: {errorMessage}")
+ LogGuard.Warn(opt.Logger, $"[Materialize] Ungueltiger Zielpfad: {ex.Message}")
Return False
End Try
@@ -206,7 +214,7 @@ Namespace Global.Tomtastisch.FileClassifier
Catch ex As Exception When _
TypeOf ex Is UnauthorizedAccessException OrElse _
- TypeOf ex Is System.Security.SecurityException OrElse _
+ TypeOf ex Is Security.SecurityException OrElse _
TypeOf ex Is IOException OrElse _
TypeOf ex Is InvalidDataException OrElse _
TypeOf ex Is NotSupportedException OrElse _
@@ -236,7 +244,7 @@ Namespace Global.Tomtastisch.FileClassifier
Catch ex As Exception When _
TypeOf ex Is UnauthorizedAccessException OrElse _
- TypeOf ex Is System.Security.SecurityException OrElse _
+ TypeOf ex Is Security.SecurityException OrElse _
TypeOf ex Is IOException OrElse _
TypeOf ex Is InvalidDataException OrElse _
TypeOf ex Is NotSupportedException OrElse _
diff --git a/src/FileTypeDetection/FileTypeDetectionLib.vbproj b/src/FileTypeDetection/FileTypeDetectionLib.vbproj
index 912f3b67..4003efc6 100644
--- a/src/FileTypeDetection/FileTypeDetectionLib.vbproj
+++ b/src/FileTypeDetection/FileTypeDetectionLib.vbproj
@@ -3,15 +3,15 @@
Tomtastisch.FileClassifier
Tomtastisch.FileClassifier
- net8.0;net10.0
+ netstandard2.0;net8.0;net10.0
true
false
Tomtastisch.FileClassifier
- 5.1.4
- 5.1.4
+ 5.2.0
+ 5.2.0
tomtastisch
Deterministic file type and MIME detection with fail-closed archive safety checks, secure extraction primitives, and reproducible hashing evidence for .NET.
- filetype;mime;detection;magic-bytes;sniffing;archive;zip;tar;7z;rar;zipslip;security;hashing;sha256;deterministic;dotnet;net8;net10
+ filetype;mime;detection;magic-bytes;sniffing;archive;zip;tar;7z;rar;zipslip;security;hashing;sha256;deterministic;dotnet;netstandard2.0;net8;net10
MIT
https://github.com/tomtastisch/FileClassifier
git
@@ -23,13 +23,24 @@
+
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/FileTypeDetection/FileTypeDetector.vb b/src/FileTypeDetection/FileTypeDetector.vb
index 7ab3a9b7..8d014ae4 100644
--- a/src/FileTypeDetection/FileTypeDetector.vb
+++ b/src/FileTypeDetection/FileTypeDetector.vb
@@ -1,3 +1,12 @@
+' ============================================================================
+' FILE: FileTypeDetector.vb
+'
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' - Try/Catch konsistent im Catch-Filter-Schema
+' - Variablen im Deklarationsblock, spaltenartig ausgerichtet
+' ============================================================================
+
Option Strict On
Option Explicit On
@@ -181,6 +190,7 @@ Namespace Global.Tomtastisch.FileClassifier
''' Kann bei ungültigen Datenzuständen intern auftreten und wird fail-closed behandelt.
''' Kann bei nicht unterstützten Pfadformaten intern auftreten und wird fail-closed behandelt.
''' Kann bei ungültigen Argumentzuständen intern auftreten und wird fail-closed behandelt.
+
Public Function Detect _
(
path As String,
@@ -896,6 +906,9 @@ Namespace Global.Tomtastisch.FileClassifier
Return New MemoryStream(data, 0, data.Length, writable:=False, publiclyVisible:=False)
End Function
+ '''
+ ''' Interner, unveränderlicher Datenträger DetectionTrace für strukturierte Verarbeitungsschritte.
+ '''
Private Structure DetectionTrace
Friend ReasonCode As String
Friend UsedZipContentCheck As Boolean
diff --git a/src/FileTypeDetection/FileTypeOptions.vb b/src/FileTypeDetection/FileTypeOptions.vb
index bae157e2..4de864d1 100644
--- a/src/FileTypeDetection/FileTypeOptions.vb
+++ b/src/FileTypeDetection/FileTypeOptions.vb
@@ -1,3 +1,12 @@
+' ============================================================================
+' FILE: FileTypeOptions.vb
+'
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' - Try/Catch konsistent im Catch-Filter-Schema
+' - Variablen im Deklarationsblock, spaltenartig ausgerichtet
+' ============================================================================
+
Option Strict On
Option Explicit On
diff --git a/src/FileTypeDetection/Infrastructure/ArchiveInternals.vb b/src/FileTypeDetection/Infrastructure/ArchiveInternals.vb
index c9d46e46..99ac0a27 100644
--- a/src/FileTypeDetection/Infrastructure/ArchiveInternals.vb
+++ b/src/FileTypeDetection/Infrastructure/ArchiveInternals.vb
@@ -1,9 +1,21 @@
+' ============================================================================
+' FILE: ArchiveInternals.vb
+'
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' - Try/Catch konsistent im Catch-Filter-Schema
+' - Variablen im Deklarationsblock, spaltenartig ausgerichtet
+' ============================================================================
+
Option Strict On
Option Explicit On
Imports System.IO
Namespace Global.Tomtastisch.FileClassifier
+ '''
+ ''' Interne Aufzählung ArchiveContainerType für deterministische Zustands- und Typkennzeichnung.
+ '''
Friend Enum ArchiveContainerType
Unknown = 0
Zip
@@ -13,9 +25,24 @@ Namespace Global.Tomtastisch.FileClassifier
Rar
End Enum
+ '''
+ ''' Unveränderlicher Deskriptor zur Beschreibung erkannter Archivtypen und Containerketten.
+ ''' Enthält Metadaten zu , und .
+ '''
Friend NotInheritable Class ArchiveDescriptor
+ '''
+ ''' Logischer Dateityp des erkannten Archivcontainers.
+ '''
Public ReadOnly Property LogicalKind As FileKind
+
+ '''
+ ''' Primärer physischer Containertyp der Erkennung.
+ '''
Public ReadOnly Property ContainerType As ArchiveContainerType
+
+ '''
+ ''' Deterministische Containerkette für verschachtelte Formate.
+ '''
Public ReadOnly Property ContainerChain As IReadOnlyList(Of ArchiveContainerType)
Private Sub New(logicalKind As FileKind, containerType As ArchiveContainerType,
@@ -42,6 +69,9 @@ Namespace Global.Tomtastisch.FileClassifier
End Function
End Class
+ '''
+ ''' Interner Vertrag IArchiveEntryModel für austauschbare Infrastrukturkomponenten.
+ '''
Friend Interface IArchiveEntryModel
ReadOnly Property RelativePath As String
ReadOnly Property IsDirectory As Boolean
@@ -51,6 +81,9 @@ Namespace Global.Tomtastisch.FileClassifier
Function OpenStream() As Stream
End Interface
+ '''
+ ''' Interner Vertrag IArchiveBackend für austauschbare Infrastrukturkomponenten.
+ '''
Friend Interface IArchiveBackend
ReadOnly Property ContainerType As ArchiveContainerType
@@ -63,9 +96,12 @@ Namespace Global.Tomtastisch.FileClassifier
) As Boolean
End Interface
+ '''
+ ''' Interne Hilfsklasse ArchiveBackendRegistry zur kapselnden Umsetzung von Guard-, I/O- und Policy-Logik.
+ '''
Friend NotInheritable Class ArchiveBackendRegistry
- Private Shared ReadOnly _managedArchiveBackend As New ArchiveManagedBackend()
- Private Shared ReadOnly _sharpCompressBackend As New SharpCompressArchiveBackend()
+ Private Shared ReadOnly ManagedArchiveBackend As New ArchiveManagedBackend()
+ Private Shared ReadOnly SharpCompressBackend As New SharpCompressArchiveBackend()
Private Sub New()
End Sub
@@ -73,16 +109,19 @@ Namespace Global.Tomtastisch.FileClassifier
Friend Shared Function Resolve(containerType As ArchiveContainerType) As IArchiveBackend
Select Case containerType
Case ArchiveContainerType.Zip
- Return _managedArchiveBackend
+ Return ManagedArchiveBackend
Case ArchiveContainerType.Tar, ArchiveContainerType.GZip, ArchiveContainerType.SevenZip,
ArchiveContainerType.Rar
- Return _sharpCompressBackend
+ Return SharpCompressBackend
Case Else
Return Nothing
End Select
End Function
End Class
+ '''
+ ''' Interne Hilfsklasse ArchiveTypeResolver zur kapselnden Umsetzung von Guard-, I/O- und Policy-Logik.
+ '''
Friend NotInheritable Class ArchiveTypeResolver
Private Sub New()
End Sub
@@ -149,6 +188,9 @@ Namespace Global.Tomtastisch.FileClassifier
End Function
End Class
+ '''
+ ''' Interne Hilfsklasse ArchiveProcessingEngine zur kapselnden Umsetzung von Guard-, I/O- und Policy-Logik.
+ '''
Friend NotInheritable Class ArchiveProcessingEngine
Private Sub New()
End Sub
@@ -175,8 +217,11 @@ Namespace Global.Tomtastisch.FileClassifier
End Function
End Class
+ '''
+ ''' Interne Hilfsklasse ArchiveExtractor zur kapselnden Umsetzung von Guard-, I/O- und Policy-Logik.
+ '''
Friend NotInheritable Class ArchiveExtractor
- Private Shared ReadOnly _recyclableStreams As New Microsoft.IO.RecyclableMemoryStreamManager()
+ Private Shared ReadOnly RecyclableStreams As New Microsoft.IO.RecyclableMemoryStreamManager()
Private Sub New()
End Sub
@@ -352,7 +397,7 @@ Namespace Global.Tomtastisch.FileClassifier
Try
Using source = entry.OpenStream()
If source Is Nothing OrElse Not source.CanRead Then Return False
- Using ms = _recyclableStreams.GetStream("ArchiveExtractor.MemoryEntry")
+ Using ms = RecyclableStreams.GetStream("ArchiveExtractor.MemoryEntry")
StreamBounds.CopyBounded(source, ms, opt.MaxZipEntryUncompressedBytes)
Dim payload As Byte() = Array.Empty(Of Byte)()
If ms.Length > 0 Then
@@ -424,6 +469,9 @@ Namespace Global.Tomtastisch.FileClassifier
End Function
End Class
+ '''
+ ''' Interne Hilfsklasse ArchiveEntryCollector zur kapselnden Umsetzung von Guard-, I/O- und Policy-Logik.
+ '''
Friend NotInheritable Class ArchiveEntryCollector
Private Sub New()
End Sub
@@ -474,15 +522,25 @@ Namespace Global.Tomtastisch.FileClassifier
End Function
End Class
+ '''
+ ''' SharpCompress-Backend zur Verarbeitung verschiedener Archivformate (z. B. TAR, RAR, 7z).
+ ''' Kapselt Guard-, I/O- und Policy-Logik für nicht-managed Container.
+ '''
Friend NotInheritable Class SharpCompressArchiveBackend
Implements IArchiveBackend
+ '''
+ ''' Liefert den vom Backend gemeldeten Containertyp.
+ '''
Public ReadOnly Property ContainerType As ArchiveContainerType Implements IArchiveBackend.ContainerType
Get
Return ArchiveContainerType.Unknown
End Get
End Property
+ '''
+ ''' Verarbeitet ein Archiv über SharpCompress fail-closed und optionalen Entry-Callback.
+ '''
Public Function Process(
stream As Stream,
opt As FileTypeProjectOptions,
@@ -661,6 +719,9 @@ Namespace Global.Tomtastisch.FileClassifier
End Function
End Class
+ '''
+ ''' Interne Hilfsklasse SharpCompressEntryModel zur kapselnden Umsetzung von Guard-, I/O- und Policy-Logik.
+ '''
Friend NotInheritable Class SharpCompressEntryModel
Implements IArchiveEntryModel
@@ -670,6 +731,9 @@ Namespace Global.Tomtastisch.FileClassifier
_entry = entry
End Sub
+ '''
+ ''' Liefert den relativen Archivpfad des Eintrags.
+ '''
Public ReadOnly Property RelativePath As String Implements IArchiveEntryModel.RelativePath
Get
If _entry Is Nothing Then Return String.Empty
@@ -677,12 +741,18 @@ Namespace Global.Tomtastisch.FileClassifier
End Get
End Property
+ '''
+ ''' Kennzeichnet, ob der Eintrag ein Verzeichnis repräsentiert.
+ '''
Public ReadOnly Property IsDirectory As Boolean Implements IArchiveEntryModel.IsDirectory
Get
Return _entry IsNot Nothing AndAlso _entry.IsDirectory
End Get
End Property
+ '''
+ ''' Liefert die unkomprimierte Größe, sofern verfügbar.
+ '''
Public ReadOnly Property UncompressedSize As Long? Implements IArchiveEntryModel.UncompressedSize
Get
If _entry Is Nothing Then Return Nothing
@@ -692,6 +762,9 @@ Namespace Global.Tomtastisch.FileClassifier
End Get
End Property
+ '''
+ ''' Liefert die komprimierte Größe, sofern verfügbar.
+ '''
Public ReadOnly Property CompressedSize As Long? Implements IArchiveEntryModel.CompressedSize
Get
If _entry Is Nothing Then Return Nothing
@@ -701,6 +774,9 @@ Namespace Global.Tomtastisch.FileClassifier
End Get
End Property
+ '''
+ ''' Liefert ein Linkziel bei Link-Einträgen, sonst eine leere Zeichenfolge.
+ '''
Public ReadOnly Property LinkTarget As String Implements IArchiveEntryModel.LinkTarget
Get
If _entry Is Nothing Then Return String.Empty
@@ -708,6 +784,9 @@ Namespace Global.Tomtastisch.FileClassifier
End Get
End Property
+ '''
+ ''' Öffnet einen lesbaren Stream für den Eintragsinhalt.
+ '''
Public Function OpenStream() As Stream Implements IArchiveEntryModel.OpenStream
If _entry Is Nothing Then Return Stream.Null
Return _entry.OpenEntryStream()
diff --git a/src/FileTypeDetection/Infrastructure/ArchiveManagedInternals.vb b/src/FileTypeDetection/Infrastructure/ArchiveManagedInternals.vb
index 27eda531..721f1439 100644
--- a/src/FileTypeDetection/Infrastructure/ArchiveManagedInternals.vb
+++ b/src/FileTypeDetection/Infrastructure/ArchiveManagedInternals.vb
@@ -1,3 +1,12 @@
+' ============================================================================
+' FILE: ArchiveManagedInternals.vb
+'
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' - Try/Catch konsistent im Catch-Filter-Schema
+' - Variablen im Deklarationsblock, spaltenartig ausgerichtet
+' ============================================================================
+
Option Strict On
Option Explicit On
@@ -6,11 +15,11 @@ Imports System.IO.Compression
Namespace Global.Tomtastisch.FileClassifier
'''
- ''' Zentrale SSOT-Engine fuer archivbasierte Verarbeitung.
- ''' Eine Iterationslogik fuer Validierung und sichere Extraktion.
+ ''' Zentrale SSOT-Engine für archivbasierte Verarbeitung.
+ ''' Eine Iterationslogik für Validierung und sichere Extraktion.
'''
Friend NotInheritable Class ArchiveStreamEngine
- Private Shared ReadOnly _recyclableStreams As New Microsoft.IO.RecyclableMemoryStreamManager()
+ Private Shared ReadOnly RecyclableStreams As New Microsoft.IO.RecyclableMemoryStreamManager()
Private Sub New()
End Sub
@@ -58,7 +67,7 @@ Namespace Global.Tomtastisch.FileClassifier
Try
Using es = e.Open()
- Using nestedMs = _recyclableStreams.GetStream("ArchiveStreamEngine.Nested")
+ Using nestedMs = RecyclableStreams.GetStream("ArchiveStreamEngine.Nested")
StreamBounds.CopyBounded(es, nestedMs, opt.MaxZipNestedBytes)
nestedMs.Position = 0
@@ -109,15 +118,25 @@ Namespace Global.Tomtastisch.FileClassifier
End Function
End Class
+ '''
+ ''' Managed-ZIP-Backend zur Verarbeitung von ZIP-Archiven über .
+ ''' Kapselt Guard-, I/O- und Policy-Logik und delegiert an die .
+ '''
Friend NotInheritable Class ArchiveManagedBackend
Implements IArchiveBackend
+ '''
+ ''' Liefert den vom Managed-Backend unterstützten Containertyp.
+ '''
Public ReadOnly Property ContainerType As ArchiveContainerType Implements IArchiveBackend.ContainerType
Get
Return ArchiveContainerType.Zip
End Get
End Property
+ '''
+ ''' Verarbeitet ZIP-Archive fail-closed über die Managed-Archive-Engine.
+ '''
Public Function Process(
stream As Stream,
opt As FileTypeProjectOptions,
@@ -141,6 +160,10 @@ Namespace Global.Tomtastisch.FileClassifier
End Function
End Class
+ '''
+ ''' Adapter-Modell für Managed-ZIP-Einträge () zur Bereitstellung einer
+ ''' einheitlichen -Schnittstelle im Managed-Archiv-Backend.
+ '''
Friend NotInheritable Class ArchiveManagedEntryModel
Implements IArchiveEntryModel
@@ -150,6 +173,9 @@ Namespace Global.Tomtastisch.FileClassifier
_entry = entry
End Sub
+ '''
+ ''' Liefert den relativen Archivpfad des Managed-Eintrags.
+ '''
Public ReadOnly Property RelativePath As String Implements IArchiveEntryModel.RelativePath
Get
If _entry Is Nothing Then Return String.Empty
@@ -157,6 +183,9 @@ Namespace Global.Tomtastisch.FileClassifier
End Get
End Property
+ '''
+ ''' Kennzeichnet, ob der Managed-Eintrag ein Verzeichnis repräsentiert.
+ '''
Public ReadOnly Property IsDirectory As Boolean Implements IArchiveEntryModel.IsDirectory
Get
If _entry Is Nothing Then Return False
@@ -165,6 +194,9 @@ Namespace Global.Tomtastisch.FileClassifier
End Get
End Property
+ '''
+ ''' Liefert die unkomprimierte Größe des Eintrags, sofern verfügbar.
+ '''
Public ReadOnly Property UncompressedSize As Long? Implements IArchiveEntryModel.UncompressedSize
Get
If _entry Is Nothing Then Return Nothing
@@ -172,6 +204,9 @@ Namespace Global.Tomtastisch.FileClassifier
End Get
End Property
+ '''
+ ''' Liefert die komprimierte Größe des Eintrags, sofern verfügbar.
+ '''
Public ReadOnly Property CompressedSize As Long? Implements IArchiveEntryModel.CompressedSize
Get
If _entry Is Nothing Then Return Nothing
@@ -179,12 +214,18 @@ Namespace Global.Tomtastisch.FileClassifier
End Get
End Property
+ '''
+ ''' Liefert für Managed-ZIP immer eine leere Zeichenfolge (keine Link-Metadaten).
+ '''
Public ReadOnly Property LinkTarget As String Implements IArchiveEntryModel.LinkTarget
Get
Return String.Empty
End Get
End Property
+ '''
+ ''' Öffnet einen lesbaren Stream auf den Eintragsinhalt.
+ '''
Public Function OpenStream() As Stream Implements IArchiveEntryModel.OpenStream
If _entry Is Nothing Then Return Stream.Null
Return _entry.Open()
diff --git a/src/FileTypeDetection/Infrastructure/CoreInternals.vb b/src/FileTypeDetection/Infrastructure/CoreInternals.vb
index ae9ace27..2c524230 100644
--- a/src/FileTypeDetection/Infrastructure/CoreInternals.vb
+++ b/src/FileTypeDetection/Infrastructure/CoreInternals.vb
@@ -1,3 +1,12 @@
+' ============================================================================
+' FILE: CoreInternals.vb
+'
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' - Try/Catch konsistent im Catch-Filter-Schema
+' - Variablen im Deklarationsblock, spaltenartig ausgerichtet
+' ============================================================================
+
Option Strict On
Option Explicit On
@@ -6,6 +15,9 @@ Imports System.IO.Compression
Imports Microsoft.Extensions.Logging
Namespace Global.Tomtastisch.FileClassifier
+ '''
+ ''' Interne Hilfsklasse InternalIoDefaults zur kapselnden Umsetzung von Guard-, I/O- und Policy-Logik.
+ '''
Friend NotInheritable Class InternalIoDefaults
Friend Const CopyBufferSize As Integer = 8192
Friend Const FileStreamBufferSize As Integer = 81920
@@ -16,7 +28,7 @@ Namespace Global.Tomtastisch.FileClassifier
End Class
'''
- ''' Zentrale IO-Helfer fuer harte Grenzen.
+ ''' Zentrale IO-Helfer für harte Grenzen.
''' SSOT-Regel: bounded copy wird nur hier gepflegt.
'''
Friend NotInheritable Class StreamBounds
@@ -57,7 +69,7 @@ Namespace Global.Tomtastisch.FileClassifier
End Class
'''
- ''' Sicherheits-Gate fuer Archive-Container.
+ ''' Sicherheits-Gate für Archive-Container.
'''
Friend NotInheritable Class ArchiveSafetyGate
Private Sub New()
@@ -88,7 +100,7 @@ Namespace Global.Tomtastisch.FileClassifier
End Class
'''
- ''' Gemeinsame Guards fuer signaturbasierte Archiv-Byte-Payloads.
+ ''' Gemeinsame Guards für signaturbasierte Archiv-Byte-Payloads.
'''
Friend NotInheritable Class ArchiveSignaturePayloadGuard
Private Sub New()
@@ -101,7 +113,7 @@ Namespace Global.Tomtastisch.FileClassifier
End Class
'''
- ''' Gemeinsame Guards fuer beliebige Archive-Byte-Payloads.
+ ''' Gemeinsame Guards für beliebige Archive-Byte-Payloads.
'''
Friend NotInheritable Class ArchivePayloadGuard
Private Sub New()
@@ -119,7 +131,7 @@ Namespace Global.Tomtastisch.FileClassifier
End Class
'''
- ''' Gemeinsame Zielpfad-Policy fuer Materialisierung und Archiv-Extraktion.
+ ''' Gemeinsame Zielpfad-Policy für Materialisierung und Archiv-Extraktion.
'''
Friend NotInheritable Class DestinationPathGuard
Private Sub New()
@@ -184,7 +196,7 @@ Namespace Global.Tomtastisch.FileClassifier
End Class
'''
- ''' Gemeinsame Normalisierung fuer relative Archiv-Entry-Pfade.
+ ''' Gemeinsame Normalisierung für relative Archiv-Entry-Pfade.
'''
Friend NotInheritable Class ArchiveEntryPathPolicy
Private Sub New()
@@ -306,7 +318,7 @@ Namespace Global.Tomtastisch.FileClassifier
'''
''' Defensiver Logger-Schutz.
- ''' Logging darf niemals zu Erkennungsfehlern oder Exceptions fuehren.
+ ''' Logging darf niemals zu Erkennungsfehlern oder Exceptions führen.
'''
Friend NotInheritable Class LogGuard
Private Sub New()
diff --git a/src/FileTypeDetection/Infrastructure/MimeProvider.vb b/src/FileTypeDetection/Infrastructure/MimeProvider.vb
index 3c7feede..094df5a5 100644
--- a/src/FileTypeDetection/Infrastructure/MimeProvider.vb
+++ b/src/FileTypeDetection/Infrastructure/MimeProvider.vb
@@ -1,3 +1,12 @@
+' ============================================================================
+' FILE: MimeProvider.vb
+'
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' - Try/Catch konsistent im Catch-Filter-Schema
+' - Variablen im Deklarationsblock, spaltenartig ausgerichtet
+' ============================================================================
+
Option Strict On
Option Explicit On
@@ -5,8 +14,8 @@ Namespace Global.Tomtastisch.FileClassifier
'''
''' Kapselt das MIME-Mapping als austauschbares Infrastrukturdetail.
''' SSOT-Regel:
- ''' - Alle MIME-Zuordnungen fuer die Registry laufen ausschliesslich ueber diese Klasse.
- ''' - Die eigentliche Dateityp-Erkennung darf niemals von MIME abhaengen.
+ ''' - Alle MIME-Zuordnungen für die Registry laufen ausschließlich über diese Klasse.
+ ''' - Die eigentliche Dateityp-Erkennung darf niemals von MIME abhängen.
'''
Friend NotInheritable Class MimeProvider
Friend Shared ReadOnly Instance As New MimeProvider()
@@ -15,10 +24,10 @@ Namespace Global.Tomtastisch.FileClassifier
End Sub
'''
- ''' Liefert den MIME-Typ fuer eine Endung (mit oder ohne fuehrenden Punkt).
- ''' Gibt bei Fehlern oder unbekannter Endung einen leeren String zurueck.
+ ''' Liefert den MIME-Typ für eine Endung (mit oder ohne führenden Punkt).
+ ''' Gibt bei Fehlern oder unbekannter Endung einen leeren String zurück.
'''
- ''' Dateiendung mit oder ohne fuehrenden Punkt.
+ ''' Dateiendung mit oder ohne führenden Punkt.
''' Kanonischer MIME-Typ oder leerer String.
Friend Shared Function GetMime(extWithDot As String) As String
If String.IsNullOrWhiteSpace(extWithDot) Then Return String.Empty
@@ -35,7 +44,7 @@ Namespace Global.Tomtastisch.FileClassifier
End Class
'''
- ''' Liefert Diagnose-Information fuer Tests ohne Oeffnung der oeffentlichen API.
+ ''' Liefert Diagnose-Information für Tests ohne Öffnung der öffentlichen API.
'''
Friend NotInheritable Class MimeProviderDiagnostics
Private Sub New()
diff --git a/src/FileTypeDetection/Providers/Net8_0Plus/HashPrimitivesProvider.vb b/src/FileTypeDetection/Providers/Net8_0Plus/HashPrimitivesProvider.vb
new file mode 100644
index 00000000..86051ea5
--- /dev/null
+++ b/src/FileTypeDetection/Providers/Net8_0Plus/HashPrimitivesProvider.vb
@@ -0,0 +1,111 @@
+' ============================================================================
+' FILE: HashPrimitivesProvider.vb
+' TFM: net8.0/net10.0
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' ============================================================================
+
+Option Strict On
+Option Explicit On
+
+Imports System.Globalization
+Imports System.Security.Cryptography
+
+Namespace Global.Tomtastisch.FileClassifier
+ '''
+ ''' Providerimplementierung der Hash-Primitive für `net8.0` und `net10.0`.
+ '''
+ '''
+ ''' Zweck: Kapselt moderne SHA256-, Hex- und FastHash64-APIs hinter stabilen internen Verträgen.
+ '''
+ Friend NotInheritable Class HashPrimitivesProvider
+ Implements IHashPrimitives
+
+ Private Shared ReadOnly _hexCodec As IHexCodec = New LowerHexCodec()
+ Private Shared ReadOnly _sha256 As ISha256Primitives = New Sha256Primitives(_hexCodec)
+ Private Shared ReadOnly _fastHash64 As IFastHash64 = New FastHash64Primitives()
+
+ Public ReadOnly Property ProviderMarker As String Implements IHashPrimitives.ProviderMarker
+ Get
+ Return "Net8_0Plus"
+ End Get
+ End Property
+
+ Public ReadOnly Property HexCodec As IHexCodec Implements IHashPrimitives.HexCodec
+ Get
+ Return _hexCodec
+ End Get
+ End Property
+
+ Public ReadOnly Property Sha256 As ISha256Primitives Implements IHashPrimitives.Sha256
+ Get
+ Return _sha256
+ End Get
+ End Property
+
+ Public ReadOnly Property FastHash64 As IFastHash64 Implements IHashPrimitives.FastHash64
+ Get
+ Return _fastHash64
+ End Get
+ End Property
+
+ '''
+ ''' Deterministische Lower-Hex-Kodierung über `Convert.ToHexString`.
+ '''
+ '''
+ ''' Zweck: Stellt die einheitliche Kleinschreibung der Hex-Ausgabe sicher.
+ '''
+ Private NotInheritable Class LowerHexCodec
+ Implements IHexCodec
+
+ Public Function EncodeLowerHex(data As Byte()) As String Implements IHexCodec.EncodeLowerHex
+ Dim safeData = If(data, Array.Empty(Of Byte)())
+ Return Convert.ToHexString(safeData).ToLowerInvariant()
+ End Function
+ End Class
+
+ '''
+ ''' SHA256-Primitive auf Basis von `SHA256.HashData`.
+ '''
+ '''
+ ''' Zweck: Liefert konsistente SHA256-Bytes und -Hex für aktuelle TFMs.
+ '''
+ Private NotInheritable Class Sha256Primitives
+ Implements ISha256Primitives
+
+ Private ReadOnly _codec As IHexCodec
+
+ Public Sub New(codec As IHexCodec)
+ _codec = codec
+ End Sub
+
+ Public Function ComputeHash(data As Byte()) As Byte() Implements ISha256Primitives.ComputeHash
+ Dim safeData = If(data, Array.Empty(Of Byte)())
+ Return Security.Cryptography.SHA256.HashData(safeData)
+ End Function
+
+ Public Function ComputeHashHex(data As Byte()) As String Implements ISha256Primitives.ComputeHashHex
+ Return _codec.EncodeLowerHex(ComputeHash(data))
+ End Function
+ End Class
+
+ '''
+ ''' FastHash64-Primitive auf Basis von `System.IO.Hashing.XxHash3`.
+ '''
+ '''
+ ''' Zweck: Liefert deterministische UInt64- und Hex-Werte für schnelle Hashvergleiche.
+ '''
+ Private NotInheritable Class FastHash64Primitives
+ Implements IFastHash64
+
+ Public Function ComputeHashUInt64(data As Byte()) As ULong Implements IFastHash64.ComputeHashUInt64
+ Dim safeData = If(data, Array.Empty(Of Byte)())
+ Return IO.Hashing.XxHash3.HashToUInt64(safeData)
+ End Function
+
+ Public Function ComputeHashHex(data As Byte()) As String Implements IFastHash64.ComputeHashHex
+ Return ComputeHashUInt64(data).ToString("x16", CultureInfo.InvariantCulture)
+ End Function
+ End Class
+ End Class
+End Namespace
diff --git a/src/FileTypeDetection/Providers/Net8_0Plus/README.md b/src/FileTypeDetection/Providers/Net8_0Plus/README.md
new file mode 100644
index 00000000..c85ab562
--- /dev/null
+++ b/src/FileTypeDetection/Providers/Net8_0Plus/README.md
@@ -0,0 +1,28 @@
+# Providers Net8_0Plus Modul
+
+## 1. Zweck
+Dieses Verzeichnis implementiert interne Hashing-Primitive für net8.0 und net10.0.
+
+## 2. Inhalt
+- `HashPrimitivesProvider.vb`
+
+## 3. API und Verhalten
+- SHA256 wird über `SHA256.HashData` berechnet.
+- Lower-Hex wird über `Convert.ToHexString(...).ToLowerInvariant()` ausgegeben.
+- FastHash64 wird über `System.IO.Hashing.XxHash3` als lower-hex ausgegeben.
+
+## 4. Verifikation
+- Build mit `-f net8.0` und `-f net10.0` muss diesen Provider kompilieren.
+
+## 5. Diagramm
+```mermaid
+flowchart LR
+ A["Payload"] --> B["SHA256.HashData"]
+ A --> C["XxHash3.HashToUInt64"]
+ B --> D["Convert.ToHexString Lower"]
+ C --> E["x16 Lower Hex"]
+```
+
+## 6. Verweise
+- [Providers Modul](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/Providers/README.md)
+- [Abstractions Providers Modul](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/Abstractions/Providers/README.md)
diff --git a/src/FileTypeDetection/Providers/NetStandard2_0/HashPrimitivesProvider.vb b/src/FileTypeDetection/Providers/NetStandard2_0/HashPrimitivesProvider.vb
new file mode 100644
index 00000000..81c9350f
--- /dev/null
+++ b/src/FileTypeDetection/Providers/NetStandard2_0/HashPrimitivesProvider.vb
@@ -0,0 +1,127 @@
+' ============================================================================
+' FILE: HashPrimitivesProvider.vb
+' TFM: netstandard2.0
+' INTERNE POLICY (DIN-/Norm-orientiert, verbindlich)
+' - Datei- und Type-Struktur gemäß docs/governance/045_CODE_QUALITY_POLICY_DE.MD
+' ============================================================================
+
+Option Strict On
+Option Explicit On
+
+Imports System.Globalization
+Imports System.Security.Cryptography
+
+Namespace Global.Tomtastisch.FileClassifier
+ '''
+ ''' Providerimplementierung der Hash-Primitive für `netstandard2.0`.
+ '''
+ '''
+ ''' Zweck: Kapselt kompatible SHA256-, Hex- und FastHash64-Operationen ohne moderne TFM-only APIs.
+ '''
+ Friend NotInheritable Class HashPrimitivesProvider
+ Implements IHashPrimitives
+
+ Private Shared ReadOnly _hexCodec As IHexCodec = New LowerHexCodec()
+ Private Shared ReadOnly _sha256 As ISha256Primitives = New Sha256Primitives(_hexCodec)
+ Private Shared ReadOnly _fastHash64 As IFastHash64 = New FastHash64Primitives()
+
+ Public ReadOnly Property ProviderMarker As String Implements IHashPrimitives.ProviderMarker
+ Get
+ Return "NetStandard2_0"
+ End Get
+ End Property
+
+ Public ReadOnly Property HexCodec As IHexCodec Implements IHashPrimitives.HexCodec
+ Get
+ Return _hexCodec
+ End Get
+ End Property
+
+ Public ReadOnly Property Sha256 As ISha256Primitives Implements IHashPrimitives.Sha256
+ Get
+ Return _sha256
+ End Get
+ End Property
+
+ Public ReadOnly Property FastHash64 As IFastHash64 Implements IHashPrimitives.FastHash64
+ Get
+ Return _fastHash64
+ End Get
+ End Property
+
+ '''
+ ''' Deterministische Lower-Hex-Kodierung per Nibble-Map.
+ '''
+ '''
+ ''' Zweck: Liefert eine TFM-unabhängige Hex-Ausgabe in Kleinbuchstaben.
+ '''
+ Private NotInheritable Class LowerHexCodec
+ Implements IHexCodec
+
+ Private Shared ReadOnly HexDigits As Char() = "0123456789abcdef".ToCharArray()
+
+ Public Function EncodeLowerHex(data As Byte()) As String Implements IHexCodec.EncodeLowerHex
+ Dim safeData = If(data, Array.Empty(Of Byte)())
+ Dim chars As Char() = Nothing
+ Dim index As Integer = 0
+
+ If safeData.Length = 0 Then Return String.Empty
+
+ chars = New Char(safeData.Length * 2 - 1) {}
+ For Each byteValue In safeData
+ chars(index) = HexDigits((byteValue >> 4) And &HF)
+ index += 1
+ chars(index) = HexDigits(byteValue And &HF)
+ index += 1
+ Next
+ Return New String(chars)
+ End Function
+ End Class
+
+ '''
+ ''' SHA256-Primitive auf Basis von `SHA256.Create()`.
+ '''
+ '''
+ ''' Zweck: Realisiert SHA256-Bytes und -Hex über `netstandard2.0`-kompatible Kryptografie-APIs.
+ '''
+ Private NotInheritable Class Sha256Primitives
+ Implements ISha256Primitives
+
+ Private ReadOnly _codec As IHexCodec
+
+ Public Sub New(codec As IHexCodec)
+ _codec = codec
+ End Sub
+
+ Public Function ComputeHash(data As Byte()) As Byte() Implements ISha256Primitives.ComputeHash
+ Dim safeData = If(data, Array.Empty(Of Byte)())
+ Using sha As Security.Cryptography.SHA256 = Security.Cryptography.SHA256.Create()
+ Return sha.ComputeHash(safeData)
+ End Using
+ End Function
+
+ Public Function ComputeHashHex(data As Byte()) As String Implements ISha256Primitives.ComputeHashHex
+ Return _codec.EncodeLowerHex(ComputeHash(data))
+ End Function
+ End Class
+
+ '''
+ ''' FastHash64-Primitive auf Basis von `System.IO.Hashing.XxHash3`.
+ '''
+ '''
+ ''' Zweck: Liefert deterministische UInt64- und Hex-Werte für schnelle Hashvergleiche.
+ '''
+ Private NotInheritable Class FastHash64Primitives
+ Implements IFastHash64
+
+ Public Function ComputeHashUInt64(data As Byte()) As ULong Implements IFastHash64.ComputeHashUInt64
+ Dim safeData = If(data, Array.Empty(Of Byte)())
+ Return IO.Hashing.XxHash3.HashToUInt64(safeData)
+ End Function
+
+ Public Function ComputeHashHex(data As Byte()) As String Implements IFastHash64.ComputeHashHex
+ Return ComputeHashUInt64(data).ToString("x16", CultureInfo.InvariantCulture)
+ End Function
+ End Class
+ End Class
+End Namespace
diff --git a/src/FileTypeDetection/Providers/NetStandard2_0/README.md b/src/FileTypeDetection/Providers/NetStandard2_0/README.md
new file mode 100644
index 00000000..f143f1b4
--- /dev/null
+++ b/src/FileTypeDetection/Providers/NetStandard2_0/README.md
@@ -0,0 +1,28 @@
+# Providers NetStandard2_0 Modul
+
+## 1. Zweck
+Dieses Verzeichnis implementiert interne Hashing-Primitive ohne moderne, net8/net10-exklusive APIs.
+
+## 2. Inhalt
+- `HashPrimitivesProvider.vb`
+
+## 3. API und Verhalten
+- SHA256 wird über `SHA256.Create()` berechnet.
+- Lower-Hex wird deterministisch über nibble-map kodiert.
+- FastHash64 wird über `System.IO.Hashing.XxHash3` als lower-hex ausgegeben.
+
+## 4. Verifikation
+- Build mit `-f netstandard2.0` muss diesen Provider kompilieren.
+
+## 5. Diagramm
+```mermaid
+flowchart LR
+ A["Payload"] --> B["SHA256.Create"]
+ A --> C["XxHash3.HashToUInt64"]
+ B --> D["LowerHexCodec"]
+ C --> E["x16 Lower Hex"]
+```
+
+## 6. Verweise
+- [Providers Modul](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/Providers/README.md)
+- [Abstractions Providers Modul](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/Abstractions/Providers/README.md)
diff --git a/src/FileTypeDetection/Providers/README.md b/src/FileTypeDetection/Providers/README.md
new file mode 100644
index 00000000..f89a56d7
--- /dev/null
+++ b/src/FileTypeDetection/Providers/README.md
@@ -0,0 +1,28 @@
+# Providers Modul
+
+## 1. Zweck
+Dieses Verzeichnis kapselt TFM-spezifische Implementierungen für interne Hashing-Primitive.
+
+## 2. Inhalt
+- `NetStandard2_0/`
+- `Net8_0Plus/`
+
+## 3. API und Verhalten
+- Die Provider-Auswahl ist compile-time und MSBuild-gesteuert.
+- Pro TFM wird exakt ein Provider-Set kompiliert.
+
+## 4. Verifikation
+- Build-Logs weisen je TFM die inkludierten Providerdateien nach.
+
+## 5. Diagramm
+```mermaid
+flowchart LR
+ A["TargetFramework"] --> B["MSBuild Compile Include"]
+ B --> C["NetStandard2_0 Provider"]
+ B --> D["Net8_0Plus Provider"]
+```
+
+## 6. Verweise
+- [FileTypeDetectionLib.vbproj](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/FileTypeDetectionLib.vbproj)
+- [Abstractions Providers Modul](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/Abstractions/Providers/README.md)
+- [Composition Modul](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/Composition/README.md)
diff --git a/src/FileTypeDetection/README.md b/src/FileTypeDetection/README.md
index c70c4c05..ead8d0af 100644
--- a/src/FileTypeDetection/README.md
+++ b/src/FileTypeDetection/README.md
@@ -5,7 +5,7 @@ Dieses Verzeichnis stellt die öffentliche Bibliotheksoberfläche für Dateitype
## 2. Inhalt
- Öffentliche API-Einstiegspunkte: `FileTypeDetector`, `ArchiveProcessing`, `FileMaterializer`, `FileTypeOptions`, `EvidenceHashing`.
-- Submodule für Modellklassen, Registry/Detection, Konfiguration und Infrastruktur.
+- Submodule für Modellklassen, Registry/Detection, Konfiguration, Infrastruktur, Provider-Abstraktionen und TFM-spezifische Provider.
## 3. API und Verhalten
- `FileTypeDetector`: Typdetektion aus Pfad/Bytes, Detailnachweise und sichere Archivpfade.
@@ -34,6 +34,8 @@ flowchart LR
- [Infrastruktur-Submodul](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/Infrastructure/README.md)
- [Konfiguration-Submodul](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/Configuration/README.md)
- [Abstractions-Submodul](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/Abstractions/README.md)
+- [Composition-Submodul](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/Composition/README.md)
+- [Providers-Submodul](https://github.com/tomtastisch/FileClassifier/blob/main/src/FileTypeDetection/Providers/README.md)
## 7. Provenance Verification
```bash
diff --git a/src/FileTypeDetection/packages.lock.json b/src/FileTypeDetection/packages.lock.json
index 07a43c9e..421c269a 100644
--- a/src/FileTypeDetection/packages.lock.json
+++ b/src/FileTypeDetection/packages.lock.json
@@ -1,7 +1,213 @@
{
"version": 2,
"dependencies": {
+ ".NETStandard,Version=v2.0": {
+ "Microsoft.Extensions.Logging.Abstractions": {
+ "type": "Direct",
+ "requested": "[10.0.0, )",
+ "resolved": "10.0.0",
+ "contentHash": "FU/IfjDfwaMuKr414SSQNTIti/69bHEMb+QKrskRb26oVqpx3lNFXMjs/RC9ZUuhBhcwDM2BwOgoMw+PZ+beqQ==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.0",
+ "System.Buffers": "4.6.1",
+ "System.Diagnostics.DiagnosticSource": "10.0.0",
+ "System.Memory": "4.6.3"
+ }
+ },
+ "Microsoft.IO.RecyclableMemoryStream": {
+ "type": "Direct",
+ "requested": "[3.0.1, )",
+ "resolved": "3.0.1",
+ "contentHash": "s/s20YTVY9r9TPfTrN5g8zPF1YhwxyqO6PxUkrYTGI2B+OGPe9AdajWZrLhFqXIvqIW23fnUE4+ztrUWNU1+9g==",
+ "dependencies": {
+ "System.Memory": "4.5.5"
+ }
+ },
+ "Mime": {
+ "type": "Direct",
+ "requested": "[3.8.0, )",
+ "resolved": "3.8.0",
+ "contentHash": "SG8QHXjnyLoVeIOSw4ym7orS5LIRPBpzFQYfkgSqyAkeog+eZNMj32UOEO1SxLNBASxNPgVBIacxOOZsenBImg==",
+ "dependencies": {
+ "MimeTypesMap": "1.0.9"
+ }
+ },
+ "NETStandard.Library": {
+ "type": "Direct",
+ "requested": "[2.0.3, )",
+ "resolved": "2.0.3",
+ "contentHash": "st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0"
+ }
+ },
+ "SharpCompress": {
+ "type": "Direct",
+ "requested": "[0.39.0, )",
+ "resolved": "0.39.0",
+ "contentHash": "0esqIUDlg68Z7+Weuge4QzEvNtawUO4obTJFL7xuf4DBHMxVRr+wbNgiX9arMrj3kGXQSvLe0zbZG3oxpkwJOA==",
+ "dependencies": {
+ "Microsoft.Bcl.AsyncInterfaces": "8.0.0",
+ "System.Buffers": "4.6.0",
+ "System.Memory": "4.6.0",
+ "System.Text.Encoding.CodePages": "8.0.0",
+ "ZstdSharp.Port": "0.8.4"
+ }
+ },
+ "System.Collections.Immutable": {
+ "type": "Direct",
+ "requested": "[10.0.0, )",
+ "resolved": "10.0.0",
+ "contentHash": "BHo23kBFvTFQa0tuDFXcb3Q8QInjm1Xrq+If/xuV8iMlxOOsylsa6sgRK25n5dlcMk8G2f0O/t5AdjZrdVBOXA==",
+ "dependencies": {
+ "System.Memory": "4.6.3",
+ "System.Runtime.CompilerServices.Unsafe": "6.1.2"
+ }
+ },
+ "System.IO.Hashing": {
+ "type": "Direct",
+ "requested": "[10.0.2, )",
+ "resolved": "10.0.2",
+ "contentHash": "AKJknIFi9O3+rGExxTry188JPvUoZAPcCtS2qdqyFhIzsxQ1Ap94BeGDG0VzVEHakhmRxmJtVih6TsHoghIt/g==",
+ "dependencies": {
+ "System.Buffers": "4.6.1",
+ "System.Memory": "4.6.3"
+ }
+ },
+ "System.Text.Json": {
+ "type": "Direct",
+ "requested": "[10.0.0, )",
+ "resolved": "10.0.0",
+ "contentHash": "1Dpjwq9peG/Wt5BNbrzIhTpclfOSqBWZsUO28vVr59yQlkvL5jLBWfpfzRmJ1OY+6DciaY0DUcltyzs4fuZHjw==",
+ "dependencies": {
+ "Microsoft.Bcl.AsyncInterfaces": "10.0.0",
+ "System.Buffers": "4.6.1",
+ "System.IO.Pipelines": "10.0.0",
+ "System.Memory": "4.6.3",
+ "System.Runtime.CompilerServices.Unsafe": "6.1.2",
+ "System.Text.Encodings.Web": "10.0.0",
+ "System.Threading.Tasks.Extensions": "4.6.3"
+ }
+ },
+ "Microsoft.Bcl.AsyncInterfaces": {
+ "type": "Transitive",
+ "resolved": "10.0.0",
+ "contentHash": "vFuwSLj9QJBbNR0NeNO4YVASUbokxs+i/xbuu8B+Fs4FAZg5QaFa6eGrMaRqTzzNI5tAb97T7BhSxtLckFyiRA==",
+ "dependencies": {
+ "System.Threading.Tasks.Extensions": "4.6.3"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "10.0.0",
+ "contentHash": "L3AdmZ1WOK4XXT5YFPEwyt0ep6l8lGIPs7F5OOBZc77Zqeo01Of7XXICy47628sdVl0v/owxYJTe86DTgFwKCA==",
+ "dependencies": {
+ "Microsoft.Bcl.AsyncInterfaces": "10.0.0",
+ "System.Threading.Tasks.Extensions": "4.6.3"
+ }
+ },
+ "Microsoft.NETCore.Platforms": {
+ "type": "Transitive",
+ "resolved": "1.1.0",
+ "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A=="
+ },
+ "MimeTypesMap": {
+ "type": "Transitive",
+ "resolved": "1.0.9",
+ "contentHash": "M0TuSCwL1a8QV0VKw8ysY4AIs6v/Aor3N7GXQeqgNlAvqjx9Kj9KxNd09Pg5RzpY1tCOU8mkrfYBi1Lxwj8quQ=="
+ },
+ "System.Buffers": {
+ "type": "Transitive",
+ "resolved": "4.6.1",
+ "contentHash": "N8GXpmiLMtljq7gwvyS+1QvKT/W2J8sNAvx+HVg4NGmsG/H+2k/y9QI23auLJRterrzCiDH+IWAw4V/GPwsMlw=="
+ },
+ "System.Diagnostics.DiagnosticSource": {
+ "type": "Transitive",
+ "resolved": "10.0.0",
+ "contentHash": "0KdBK+h7G13PuOSC2R/DalAoFMvdYMznvGRuICtkdcUMXgl/gYXsG6z4yUvTxHSMACorWgHCU1Faq0KUHU6yAQ==",
+ "dependencies": {
+ "System.Memory": "4.6.3",
+ "System.Runtime.CompilerServices.Unsafe": "6.1.2"
+ }
+ },
+ "System.IO.Pipelines": {
+ "type": "Transitive",
+ "resolved": "10.0.0",
+ "contentHash": "M1eb3nfXntaRJPrrMVM9EFS8I1bDTnt0uvUS6QP/SicZf/ZZjydMD5NiXxfmwW/uQwaMDP/yX2P+zQN1NBHChg==",
+ "dependencies": {
+ "System.Buffers": "4.6.1",
+ "System.Memory": "4.6.3",
+ "System.Threading.Tasks.Extensions": "4.6.3"
+ }
+ },
+ "System.Memory": {
+ "type": "Transitive",
+ "resolved": "4.6.3",
+ "contentHash": "qdcDOgnFZY40+Q9876JUHnlHu7bosOHX8XISRoH94fwk6hgaeQGSgfZd8srWRZNt5bV9ZW2TljcegDNxsf+96A==",
+ "dependencies": {
+ "System.Buffers": "4.6.1",
+ "System.Numerics.Vectors": "4.6.1",
+ "System.Runtime.CompilerServices.Unsafe": "6.1.2"
+ }
+ },
+ "System.Numerics.Vectors": {
+ "type": "Transitive",
+ "resolved": "4.6.1",
+ "contentHash": "sQxefTnhagrhoq2ReR0D/6K0zJcr9Hrd6kikeXsA1I8kOCboTavcUC4r7TSfpKFeE163uMuxZcyfO1mGO3EN8Q=="
+ },
+ "System.Runtime.CompilerServices.Unsafe": {
+ "type": "Transitive",
+ "resolved": "6.1.2",
+ "contentHash": "2hBr6zdbIBTDE3EhK7NSVNdX58uTK6iHW/P/Axmm9sl1xoGSLqDvMtpecn226TNwHByFokYwJmt/aQQNlO5CRw=="
+ },
+ "System.Text.Encoding.CodePages": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "OZIsVplFGaVY90G2SbpgU7EnCoOO5pw1t4ic21dBF3/1omrJFpAGoNAVpPyMVOC90/hvgkGG3VFqR13YgZMQfg==",
+ "dependencies": {
+ "System.Memory": "4.5.5",
+ "System.Runtime.CompilerServices.Unsafe": "6.0.0"
+ }
+ },
+ "System.Text.Encodings.Web": {
+ "type": "Transitive",
+ "resolved": "10.0.0",
+ "contentHash": "257hh1ep1Gqm1Lm0ulxf7vVBVMJuGN6EL4xSWjpi46DffXzm1058IiWsfSC06zSm7SniN+Tb5160UnXsSa8rRg==",
+ "dependencies": {
+ "System.Buffers": "4.6.1",
+ "System.Memory": "4.6.3",
+ "System.Runtime.CompilerServices.Unsafe": "6.1.2"
+ }
+ },
+ "System.Threading.Tasks.Extensions": {
+ "type": "Transitive",
+ "resolved": "4.6.3",
+ "contentHash": "7sCiwilJLYbTZELaKnc7RecBBXWXA+xMLQWZKWawBxYjp6DBlSE3v9/UcvKBvr1vv2tTOhipiogM8rRmxlhrVA==",
+ "dependencies": {
+ "System.Runtime.CompilerServices.Unsafe": "6.1.2"
+ }
+ },
+ "ZstdSharp.Port": {
+ "type": "Transitive",
+ "resolved": "0.8.4",
+ "contentHash": "eieSXq3kakCUXbgdxkKaRqWS6hF0KBJcqok9LlDCs60GOyrynLvPOcQ0pRw7shdPF7lh/VepJ9cP9n9HHc759g==",
+ "dependencies": {
+ "Microsoft.Bcl.AsyncInterfaces": "5.0.0",
+ "System.Memory": "4.5.5",
+ "System.Runtime.CompilerServices.Unsafe": "6.0.0"
+ }
+ }
+ },
"net10.0": {
+ "Microsoft.Extensions.Logging.Abstractions": {
+ "type": "Direct",
+ "requested": "[10.0.0, )",
+ "resolved": "10.0.0",
+ "contentHash": "FU/IfjDfwaMuKr414SSQNTIti/69bHEMb+QKrskRb26oVqpx3lNFXMjs/RC9ZUuhBhcwDM2BwOgoMw+PZ+beqQ==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.0"
+ }
+ },
"Microsoft.IO.RecyclableMemoryStream": {
"type": "Direct",
"requested": "[3.0.1, )",
@@ -32,6 +238,11 @@
"resolved": "10.0.2",
"contentHash": "AKJknIFi9O3+rGExxTry188JPvUoZAPcCtS2qdqyFhIzsxQ1Ap94BeGDG0VzVEHakhmRxmJtVih6TsHoghIt/g=="
},
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "10.0.0",
+ "contentHash": "L3AdmZ1WOK4XXT5YFPEwyt0ep6l8lGIPs7F5OOBZc77Zqeo01Of7XXICy47628sdVl0v/owxYJTe86DTgFwKCA=="
+ },
"MimeTypesMap": {
"type": "Transitive",
"resolved": "1.0.9",
@@ -44,6 +255,16 @@
}
},
"net8.0": {
+ "Microsoft.Extensions.Logging.Abstractions": {
+ "type": "Direct",
+ "requested": "[10.0.0, )",
+ "resolved": "10.0.0",
+ "contentHash": "FU/IfjDfwaMuKr414SSQNTIti/69bHEMb+QKrskRb26oVqpx3lNFXMjs/RC9ZUuhBhcwDM2BwOgoMw+PZ+beqQ==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.0",
+ "System.Diagnostics.DiagnosticSource": "10.0.0"
+ }
+ },
"Microsoft.IO.RecyclableMemoryStream": {
"type": "Direct",
"requested": "[3.0.1, )",
@@ -74,11 +295,21 @@
"resolved": "10.0.2",
"contentHash": "AKJknIFi9O3+rGExxTry188JPvUoZAPcCtS2qdqyFhIzsxQ1Ap94BeGDG0VzVEHakhmRxmJtVih6TsHoghIt/g=="
},
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "10.0.0",
+ "contentHash": "L3AdmZ1WOK4XXT5YFPEwyt0ep6l8lGIPs7F5OOBZc77Zqeo01Of7XXICy47628sdVl0v/owxYJTe86DTgFwKCA=="
+ },
"MimeTypesMap": {
"type": "Transitive",
"resolved": "1.0.9",
"contentHash": "M0TuSCwL1a8QV0VKw8ysY4AIs6v/Aor3N7GXQeqgNlAvqjx9Kj9KxNd09Pg5RzpY1tCOU8mkrfYBi1Lxwj8quQ=="
},
+ "System.Diagnostics.DiagnosticSource": {
+ "type": "Transitive",
+ "resolved": "10.0.0",
+ "contentHash": "0KdBK+h7G13PuOSC2R/DalAoFMvdYMznvGRuICtkdcUMXgl/gYXsG6z4yUvTxHSMACorWgHCU1Faq0KUHU6yAQ=="
+ },
"ZstdSharp.Port": {
"type": "Transitive",
"resolved": "0.8.4",
diff --git a/tests/FileTypeDetectionLib.Tests/Unit/HashingEvidenceTests.cs b/tests/FileTypeDetectionLib.Tests/Unit/HashingEvidenceTests.cs
index 0a2d94d2..a7e5abad 100644
--- a/tests/FileTypeDetectionLib.Tests/Unit/HashingEvidenceTests.cs
+++ b/tests/FileTypeDetectionLib.Tests/Unit/HashingEvidenceTests.cs
@@ -1144,6 +1144,38 @@ public void TryReadFileBounded_ReturnsFalse_WhenFileTooLarge()
}
}
+public sealed class HashPrimitivesCompositionTests
+{
+ [Fact]
+ public void HashPrimitives_Current_UsesExpectedProviderForCurrentTfm()
+ {
+ var assembly = typeof(EvidenceHashing).Assembly;
+ var compositionType = assembly.GetType("Tomtastisch.FileClassifier.HashPrimitives");
+ Assert.NotNull(compositionType);
+
+ var currentProperty = compositionType!.GetProperty(
+ "Current",
+ BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
+ Assert.NotNull(currentProperty);
+
+ var currentProvider = currentProperty!.GetValue(null);
+ Assert.NotNull(currentProvider);
+
+ var markerProperty = currentProvider!.GetType().GetProperty(
+ "ProviderMarker",
+ BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
+ Assert.NotNull(markerProperty);
+
+ var marker = TestGuard.NotNull(markerProperty!.GetValue(currentProvider) as string);
+#if NETSTANDARD2_0
+ const string expected = "NetStandard2_0";
+#else
+ const string expected = "Net8_0Plus";
+#endif
+ Assert.Equal(expected, marker);
+ }
+}
+
[Trait("Category", "ApiContract")]
public sealed class HashingEvidenceApiContractTests
{
diff --git a/tests/FileTypeDetectionLib.Tests/packages.lock.json b/tests/FileTypeDetectionLib.Tests/packages.lock.json
index dd4de631..31af74c7 100644
--- a/tests/FileTypeDetectionLib.Tests/packages.lock.json
+++ b/tests/FileTypeDetectionLib.Tests/packages.lock.json
@@ -109,6 +109,11 @@
"resolved": "18.0.1",
"contentHash": "O+utSr97NAJowIQT/OVp3Lh9QgW/wALVTP4RG1m2AfFP4IyJmJz0ZBmFJUsRQiAPgq6IRC0t8AAzsiPIsaUDEA=="
},
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "10.0.0",
+ "contentHash": "L3AdmZ1WOK4XXT5YFPEwyt0ep6l8lGIPs7F5OOBZc77Zqeo01Of7XXICy47628sdVl0v/owxYJTe86DTgFwKCA=="
+ },
"Microsoft.Extensions.DependencyModel": {
"type": "Transitive",
"resolved": "8.0.2",
@@ -235,12 +240,22 @@
"Tomtastisch.FileClassifier": {
"type": "Project",
"dependencies": {
+ "Microsoft.Extensions.Logging.Abstractions": "[10.0.0, )",
"Microsoft.IO.RecyclableMemoryStream": "[3.0.1, )",
"Mime": "[3.8.0, )",
"SharpCompress": "[0.39.0, )",
"System.IO.Hashing": "[10.0.2, )"
}
},
+ "Microsoft.Extensions.Logging.Abstractions": {
+ "type": "CentralTransitive",
+ "requested": "[10.0.0, )",
+ "resolved": "10.0.0",
+ "contentHash": "FU/IfjDfwaMuKr414SSQNTIti/69bHEMb+QKrskRb26oVqpx3lNFXMjs/RC9ZUuhBhcwDM2BwOgoMw+PZ+beqQ==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.0"
+ }
+ },
"Microsoft.IO.RecyclableMemoryStream": {
"type": "CentralTransitive",
"requested": "[3.0.1, )",