whfmt.FileFormatCatalog

May 1, 2026 · View on GitHub

Table of Contents

  1. Architecture
  2. API Reference
  3. Utility Layer
  4. Integration Guide — Level 1: Basic Detection
  5. Integration Guide — Level 2: Routing and Syntax
  6. Integration Guide — Level 3: Full Pipeline
  7. Integration Guide — Level 4: Rich Metadata
  8. The .whfmt Format

Architecture

Assembly structure

The package ships two assemblies:

whfmt.FileFormatCatalog.nupkg
└── lib/net8.0/
    ├── WpfHexEditor.Core.Definitions.dll   — catalog engine + 675+ embedded resources
    └── WpfHexEditor.Core.Contracts.dll     — public types (interfaces, records, enums)

Consumers only need to reference WpfHexEditor.Core.Definitions. WpfHexEditor.Core.Contracts is bundled and flows transitively — no separate package reference needed.

Type ownership

TypeAssemblyPurpose
EmbeddedFormatCatalogCore.DefinitionsSingleton — catalog engine
IEmbeddedFormatCatalogCore.ContractsInterface — injectable abstraction
EmbeddedFormatEntryCore.ContractsImmutable record — one format definition
FormatSignatureCore.ContractsImmutable record — one magic-byte signature
FormatMatchResultCore.ContractsImmutable record — scored detection result
MatchSourceCore.ContractsFlags enum — Extension / MagicBytes / MimeType / Combined
FormatCategoryCore.ContractsEnum — 27 known categories
SchemaNameCore.ContractsEnum — 5 known embedded schemas
FormatMatcherCore.DefinitionsStateless detection façade with confidence scoring
FormatFileAnalyzerCore.DefinitionsI/O helper — file path / FileInfo / Stream / async
CatalogQueryCore.DefinitionsFluent query builder
FormatMetadataExtensionsCore.DefinitionsExtension methods — forensic, AI hints, assertions…
FormatSummaryBuilderCore.DefinitionsHuman-readable summaries — plain text / Markdown / dump

Initialization and caching

First call to EmbeddedFormatCatalog.Instance
    └── LazyInitializer creates the singleton (thread-safe)
        └── First call to GetAll()
            └── Scans all manifest resource names in the assembly
                └── Filters *.whfmt and *.grammar resources
                    └── LoadHeader() / LoadGrammarHeader() per resource
                        └── Extracts: name, category, extensions, MIME,
                                      signatures, preferredEditor, flags
                    └── Sorted by category then name
                    └── Stored as FrozenSet<EmbeddedFormatEntry>

GetJson(resourceKey) uses a separate Dictionary<string, string> cache — each resource is read from the embedded stream exactly once, then served from memory on all subsequent calls.

Consequence: the first call to GetAll() is the expensive one (~10–50 ms depending on hardware). All subsequent calls are O(1). Call PreWarm() on a background thread at startup to absorb this cost before the first user action.

Thread safety

  • Instance — safe to access from any thread (backed by LazyInitializer)
  • GetAll() / GetCategories() — safe; backed by immutable FrozenSet<T>
  • GetJson() — safe; uses lock + TryAdd pattern
  • DetectFromBytes() — safe; read-only enumeration over immutable entries
  • FormatMatcher, FormatFileAnalyzer, CatalogQuery — stateless; safe by construction
  • All other methods — safe; delegate to the above

Dependency graph

Your app
  └── WpfHexEditor.Core.Definitions   (net8.0)
        └── WpfHexEditor.Core.Contracts  (net8.0)
              └── [BCL only — System.*]

Zero external NuGet dependencies. No WPF, no platform-specific APIs.


API Reference

EmbeddedFormatCatalog

MemberReturnsDescription
InstanceEmbeddedFormatCatalogSingleton — thread-safe, lazy
GetAll()IReadOnlySet<EmbeddedFormatEntry>All entries, sorted by category then name
GetCategories()IReadOnlySet<string>Distinct category names, alphabetical
GetByExtension(string)EmbeddedFormatEntry?First match by extension (case-insensitive, leading dot optional)
GetByMimeType(string)EmbeddedFormatEntry?First match by MIME type (case-insensitive)
GetByCategory(string)IReadOnlyList<EmbeddedFormatEntry>All entries in a category (string overload)
GetByCategory(FormatCategory)IReadOnlyList<EmbeddedFormatEntry>All entries in a category (enum overload)
DetectFromBytes(ReadOnlySpan<byte>)EmbeddedFormatEntry?Best match by magic-byte scoring
GetCompatibleEditorIds(string)IReadOnlyList<string>Compatible editor IDs for a file path
GetJson(string)stringFull .whfmt JSON for a resource key (cached)
GetSyntaxDefinitionJson(string)string?Raw syntaxDefinition block JSON
GetSchemaJson(string)string?Embedded schema JSON (string overload)
GetSchemaJson(SchemaName)string?Embedded schema JSON (enum overload)
PreWarm()voidPre-load all JSON into memory cache
.Query()CatalogQueryBegin a fluent query (extension method)

EmbeddedFormatEntry

Immutable positional record. All fields populated from the .whfmt header at catalog load time.

FieldTypeNotes
ResourceKeystringAssembly manifest resource name — pass to GetJson() / GetSyntaxDefinitionJson()
NamestringHuman-readable format name, e.g. "ZIP Archive"
CategorystringLogical category, e.g. "Archives"
DescriptionstringShort description of the format
ExtensionsIReadOnlyList<string>File extensions with leading dot, e.g. [".zip", ".jar"]
MimeTypesIReadOnlyList<string>?MIME types, e.g. ["application/zip"]. Null when not declared.
SignaturesIReadOnlyList<FormatSignature>?Magic-byte signatures. Null when not declared.
QualityScoreint0–100 completeness score from QualityMetrics.CompletenessScore
VersionstringFormat spec version, e.g. "1.14". Empty when not specified.
AuthorstringAuthor/organization. Empty when not specified.
PlatformstringTarget platform for ROM/game formats, e.g. "Nintendo Entertainment System". Empty otherwise.
PreferredEditorstring?Recommended editor ID. Null when not declared. Typical values: "hex-editor", "code-editor", "structure-editor".
IsTextFormatboolTrue when detection.isTextFormat is set in the .whfmt file
HasSyntaxDefinitionboolTrue when the .whfmt file contains a syntaxDefinition block
DiffModestring?Preferred diff algorithm: "text", "semantic", "binary". Null when absent.

FormatMatchResult

Immutable scored detection result. Produced by FormatMatcher and FormatFileAnalyzer.

MemberTypeDescription
EntryEmbeddedFormatEntryThe matched format
ConfidencedoubleNormalised 0.0–1.0 confidence score
SourceMatchSourceWhich strategy produced this match
RawScoredoubleAccumulated signature weight before normalisation
IsConfirmedboolTrue when Source == Combined (extension + magic bytes both matched)

MatchSource flags enum

ValueMeaning
ExtensionMatched by file extension
MagicBytesMatched by magic-byte signature scoring
MimeTypeMatched by MIME type string
CombinedExtension + MagicBytes — highest confidence

FormatCategory enum

ValueCategory string
Archives"Archives"
Audio"Audio"
CAD"CAD"
Certificates"Certificates"
Crypto"Crypto"
Data"Data"
Database"Database"
Disk"Disk"
Documents"Documents"
Executables"Executables"
Firmware"Firmware"
Fonts"Fonts"
GIS"GIS"
Game"Game"
Images"Images"
MachineLearning"MachineLearning"
Medical"Medical"
Network"Network"
Programming"Programming"
RomHacking"RomHacking"
Science"Science"
Subtitles"Subtitles"
Synalysis"Synalysis"
System"System"
Text"Text"
Video"Video"
_3D"3D"
Other"Other"

FormatCategory._3D maps to the string "3D" — the enum overload handles this automatically.

SchemaName enum

ValueSchema fileUse case
Whfmtwhfmt.schema.jsonValidate .whfmt format definitions
Whcdwhcd.schema.jsonClass diagram visual state
Whdbgwhdbg.schema.jsonDebug launch configuration
Whidewswhidews.schema.jsonWorkspace archive manifest
Whscdwhscd.schema.jsonSolution-wide class diagram

Utility Layer

The utility layer sits on top of IEmbeddedFormatCatalog and covers four concerns: matching with confidence scores, I/O-free file analysis, fluent filtering, and rich metadata extraction. All utilities are cross-platform (net8.0, zero external dependencies).

Namespaces

using WpfHexEditor.Core.Definitions.Matching;   // FormatMatcher, FormatFileAnalyzer
using WpfHexEditor.Core.Definitions.Query;      // CatalogQuery, CatalogQueryExtensions
using WpfHexEditor.Core.Definitions.Metadata;   // FormatMetadataExtensions, FormatSummaryBuilder

FormatMatcher — Scored detection façade

FormatMatcher is a stateless class whose methods combine extension + magic-byte + MIME-type detection into a single FormatMatchResult with a normalised confidence score.

Confidence scale

ConfidenceSourceMeaning
1.0CombinedExtension + magic bytes both agree
0.51–0.99MagicBytesByte scoring only (no extension, or extension disagreed)
0.5ExtensionExtension matched, no signatures to confirm
0.4MimeTypeMIME type matched only

Single best match

using WpfHexEditor.Core.Definitions.Matching;

var catalog = EmbeddedFormatCatalog.Instance;
byte[] header = File.ReadAllBytes("myfile.zip")[..512];

var result = FormatMatcher.Match(catalog, ".zip", header);
// result.Entry.Name    → "ZIP Archive"
// result.Confidence    → 1.0
// result.Source        → MatchSource.Combined
// result.IsConfirmed   → true

Match from a full file path (extension extracted automatically):

var result = FormatMatcher.Match(catalog, @"C:\uploads\archive.zip", header);

Top-N ranked candidates

Useful when debugging ambiguous files or building a "pick format" UI:

var candidates = FormatMatcher.GetTopMatches(catalog, header, maxResults: 5);

foreach (var match in candidates)
    Console.WriteLine(match); // "ZIP Archive [MagicBytes] 99% (raw=1.00)"

All entries for an extension

Some extensions map to multiple formats (e.g. .bin). Get all candidates ranked by quality:

var all = FormatMatcher.GetMatchesByExtension(catalog, ".bin");
// Returns multiple FormatMatchResult sorted by QualityScore descending

MIME-type match

var result = FormatMatcher.MatchMime(catalog, "application/pdf");
// result.Entry.Name   → "PDF Document"
// result.Confidence   → 0.4   (MIME types are often ambiguous)
// result.Source       → MatchSource.MimeType

FormatFileAnalyzer — I/O without boilerplate

FormatFileAnalyzer reads the first 512 bytes from a file (or stream) and delegates to FormatMatcher. It eliminates the byte-reading boilerplate from every call site.

From a file path

using WpfHexEditor.Core.Definitions.Matching;

var catalog = EmbeddedFormatCatalog.Instance;

var result = FormatFileAnalyzer.Analyze(catalog, @"C:\files\document.pdf");
Console.WriteLine(result?.Entry.Name);      // "PDF Document"
Console.WriteLine(result?.Confidence);      // 1.0
Console.WriteLine(result?.IsConfirmed);     // true

From a FileInfo

var fi = new FileInfo(@"C:\files\archive.7z");
var result = FormatFileAnalyzer.Analyze(catalog, fi);

From a Stream (extension hint optional)

using var stream = assembly.GetManifestResourceStream("MyApp.Resources.data.bin")!;
var result = FormatFileAnalyzer.Analyze(catalog, stream, extension: ".bin");

Async — from a file path

var result = await FormatFileAnalyzer.AnalyzeAsync(catalog, @"C:\uploads\file.unknown");
if (result is null)
    Console.WriteLine("Format not recognised.");
else
    Console.WriteLine($"{result.Entry.Name} ({result.Source}, {result.Confidence:P0})");

Async — from a stream

await using var fs = File.OpenRead(uploadedFile);
var result = await FormatFileAnalyzer.AnalyzeAsync(catalog, fs,
    extension: Path.GetExtension(uploadedFile),
    cancellationToken: ct);

Batch — scan a directory

var catalog = EmbeddedFormatCatalog.Instance;

foreach (var (path, match) in FormatFileAnalyzer.AnalyzeDirectory(
    catalog,
    directory: @"C:\Data",
    searchPattern: "*.*",
    recursive: true))
{
    var name = match?.Entry.Name ?? "Unknown";
    var conf = match?.Confidence.ToString("P0") ?? "—";
    Console.WriteLine($"{Path.GetFileName(path),-30}  {name,-25}  {conf}");
}

CatalogQuery — Fluent filtering

CatalogQuery is a composable query builder. Obtain one via the .Query() extension method on any IEmbeddedFormatCatalog instance.

Basic example

using WpfHexEditor.Core.Definitions.Query;

var catalog = EmbeddedFormatCatalog.Instance;

var highQualityDiskFormats = catalog
    .Query()
    .InCategory(FormatCategory.Disk)
    .WithMinQuality(80)
    .HasMagicBytes()
    .OrderByQuality()
    .Execute();

foreach (var fmt in highQualityDiskFormats)
    Console.WriteLine($"{fmt.Name,30}  {fmt.QualityScore}%");

Filter methods

MethodDescription
.InCategory(FormatCategory)Restrict to a category (enum — compile-time safe)
.InCategory(string)Restrict to a category (string overload)
.WithMinQuality(int)Keep entries with QualityScore ≥ threshold
.PriorityOnly()Shortcut: QualityScore ≥ 85
.HasMagicBytes()Only entries with at least one signature
.WithExtension(string)Only entries that handle a given extension (leading dot optional)
.TextFormatsOnly()Only text-based formats
.BinaryFormatsOnly()Only binary formats
.HasSyntaxDefinition()Only entries with a grammar block
.WithPreferredEditor(string)Exact editor ID match, e.g. "code-editor"
.HasPreferredEditor()Any non-null, non-empty preferred editor (v1.1.1)
.HasMimeType()Only entries that declare a MIME type
.HasPlatform()Only entries with a non-empty platform field
.ForPlatform(string)Platform substring match, e.g. "Nintendo"
.WithDiffMode(string)"text", "binary", or "semantic"
.WithName(string)Exact name match (case-insensitive) (v1.1.1)
.Containing(string)Full-text search in name + description
.Where(predicate)Custom predicate

Ordering methods

MethodDescription
.OrderByQuality()Highest quality score first
.OrderByName()Alphabetical by name
.OrderByCategoryThenName()Category, then name within category

Terminal methods

MethodReturnsDescription
.Execute()IReadOnlyList<EmbeddedFormatEntry>All matching entries
.First()EmbeddedFormatEntry?First match or null
.Count()intCount without materialising the list
.Any()boolTrue when at least one entry matches (v1.1.1)
.Select<T>(selector)IReadOnlyList<T>Project each entry (v1.1.1)
.ToDictionary<K,V>(keySelector, valueSelector)Dictionary<K,V>Build a dictionary; auto OrdinalIgnoreCase for string keys (v1.1.1)
.ToExtensionDictionary()Dictionary<string, EmbeddedFormatEntry>Flat extension→entry map (v1.1.1)
.ToExtensionDictionary<V>(valueSelector)Dictionary<string, V>Extension→value routing map (v1.1.1)
.GroupByCategory()IReadOnlyDictionary<string, IReadOnlyList<EmbeddedFormatEntry>>Alphabetically sorted category groups (v1.1.1)

Real-world examples

All code-editor grammars with a syntax definition:

var grammars = catalog
    .Query()
    .InCategory(FormatCategory.Programming)
    .HasSyntaxDefinition()
    .OrderByName()
    .Execute();

Console.WriteLine($"{grammars.Count} language grammars available.");

ROM formats for Nintendo platforms:

var nintendoRoms = catalog
    .Query()
    .InCategory(FormatCategory.RomHacking)
    .ForPlatform("Nintendo")
    .OrderByQuality()
    .Execute();

Extension→editor routing map (one line):

// Build a lookup: file extension → preferred editor ID
var editorMap = catalog.Query()
    .HasPreferredEditor()
    .ToExtensionDictionary(e => e.PreferredEditor!);

var editor = editorMap.GetValueOrDefault(".cs"); // "code-editor"

Group by category for a tree view:

foreach (var (category, entries) in catalog.Query().OrderByName().GroupByCategory())
{
    Console.WriteLine($"[{category}]");
    foreach (var e in entries)
        Console.WriteLine($"  {e.Name}");
}

Check if a name exists in the catalog:

bool exists = catalog.Query().WithName("ZIP Archive").Any();

High-risk crypto formats:

var cryptoFormats = catalog.Query()
    .InCategory(FormatCategory.Crypto)
    .WithMinQuality(50)
    .Execute();

var highRisk = cryptoFormats
    .Where(e => e.IsHighRisk(catalog))
    .ToList();

Structure-editor formats with export templates:

var structured = catalog
    .Query()
    .WithPreferredEditor("structure-editor")
    .WithMinQuality(70)
    .Execute()
    .Where(e => e.GetExportTemplates(catalog).Count > 0)
    .ToList();

FormatMetadataExtensions — Rich whfmt metadata

These extension methods on EmbeddedFormatEntry surface the deep metadata blocks from the full .whfmt JSON — forensic, AI hints, navigation, assertions, inspector groups, export templates, and technical details.

All methods take the catalog as a second parameter to load the JSON on demand. The JSON is cached by the catalog after the first call.

Bulk parse — GetAllMetadata() (v1.1.1)

When you need two or more metadata blocks for the same entry, use GetAllMetadata() — it parses the .whfmt JSON exactly once and returns a FormatMetadata record with all blocks.

var meta = entry.GetAllMetadata(catalog);
// meta.Forensic          → ForensicSummary?
// meta.AiHints           → AiHints?
// meta.Bookmarks         → IReadOnlyList<NavigationBookmark>
// meta.Assertions        → IReadOnlyList<AssertionRule>
// meta.InspectorGroups   → IReadOnlyList<InspectorGroup>
// meta.ExportTemplates   → IReadOnlyList<ExportTemplate>
// meta.TechnicalDetails  → TechnicalDetails?
// meta.IsHighRisk        → bool (shortcut)
// meta.SupportsEncryption→ bool (shortcut)

// Much more efficient than chaining individual calls:
// ❌ entry.GetForensicSummary(catalog) + entry.GetAiHints(catalog)  → 2 JSON parses
// ✅ entry.GetAllMetadata(catalog)                                    → 1 JSON parse

Forensic data

using WpfHexEditor.Core.Definitions.Metadata;

var catalog = EmbeddedFormatCatalog.Instance;
var entry = catalog.GetByExtension(".jks")!;  // Java KeyStore

var forensic = entry.GetForensicSummary(catalog);
// forensic.Category           → "crypto"
// forensic.RiskLevel          → "medium"
// forensic.IsHighRisk         → false
// forensic.SuspiciousPatterns → list of SuspiciousPattern records

foreach (var p in forensic!.SuspiciousPatterns)
    Console.WriteLine($"⚠ {p.Name}: {p.Description}  (condition: {p.Condition})");

// Quick boolean check:
bool dangerous = entry.IsHighRisk(catalog);

AI analysis hints

var ai = entry.GetAiHints(catalog);
// ai.AnalysisContext       → "Java KeyStore format..."
// ai.SuggestedInspections  → ["Check version field", "Inspect alias count", ...]
// ai.KnownVulnerabilities  → []

Console.WriteLine(ai?.AnalysisContext);
foreach (var hint in ai?.SuggestedInspections ?? [])
    Console.WriteLine($"  → {hint}");
var apfs = catalog.GetByExtension("")
    ?? catalog.Query().InCategory(FormatCategory.Disk).Containing("APFS").First()!;

var bookmarks = apfs.GetNavigationBookmarks(catalog);
// [
//   NavigationBookmark("Object Header",        Offset=null, OffsetVar="currentOffset", Icon="header"),
//   NavigationBookmark("NXSB Magic",           Offset=32,   OffsetVar=null,            Icon="signature"),
//   NavigationBookmark("Container UUID",       Offset=72,   OffsetVar=null,            Icon="id"),
// ]

foreach (var b in bookmarks)
    Console.WriteLine($"  [{b.Icon}] {b.Name} @ {b.Offset?.ToString("X4") ?? b.OffsetVar}");

Validation assertions

var assertions = apfs.GetAssertions(catalog);
// [
//   AssertionRule("NXSB magic valid", "nxMagic == 'NXSB'", "error", "Invalid APFS magic"),
//   AssertionRule("block size is power of 2", "nxBlockSize >= 512 && ...", "warning", null),
// ]

foreach (var a in assertions)
    Console.WriteLine($"  [{a.Severity.ToUpperInvariant()}] {a.Name}: {a.Expression}");

Inspector groups

var groups = apfs.GetInspectorGroups(catalog);
// [
//   InspectorGroup("Object Header",      "header", ["objChecksum","objOid","objXid",...]),
//   InspectorGroup("Container Superblock","disk",  ["nxMagic","nxBlockSize",...]),
//   InspectorGroup("Feature Flags",      "flag",  ["nxFeatures",...]),
// ]

foreach (var g in groups)
    Console.WriteLine($"  [{g.Icon}] {g.Title}: {string.Join(", ", g.Fields)}");

Export templates

var templates = apfs.GetExportTemplates(catalog);
// [
//   ExportTemplate("APFS Container Header (JSON)", "json", ["nxMagic","nxBlockSize",...]),
//   ExportTemplate("APFS Summary (CSV)",           "csv",  ["nxMagic","nxBlockSize",...]),
// ]

foreach (var t in templates)
    Console.WriteLine($"  Export as {t.Format.ToUpperInvariant()}: {t.Name}  ({t.Fields.Count} fields)");

Technical details

var td = apfs.GetTechnicalDetails(catalog);
// td.Endianness         → "little"
// td.DataStructure      → "Copy-on-write B-tree filesystem..."
// td.SupportsEncryption → true
// td.Encryption         → "Per-file or per-volume encryption..."

Console.WriteLine($"Endianness: {td?.Endianness}");
Console.WriteLine($"Encrypted : {td?.SupportsEncryption}");

// Quick boolean check:
bool encrypted = apfs.SupportsEncryption(catalog);

FormatSummaryBuilder — Human-readable summaries

Generates formatted summaries without any WPF or MVVM dependency.

One-liner (status bar / tooltip)

using WpfHexEditor.Core.Definitions.Metadata;

var entry = EmbeddedFormatCatalog.Instance.GetByExtension(".zip")!;

string label = FormatSummaryBuilder.BuildOneLiner(entry);
// "ZIP Archive (Archives) — .zip .jar .apk — Quality: 92%"

Plain text (multi-line)

string text = FormatSummaryBuilder.BuildPlainText(entry);
// Name        : ZIP Archive
// Category    : Archives
// Description : ZIP archive format (PKZIP)...
// Extensions  : .zip  .jar  .apk
// MIME        : application/zip
// Quality     : 92/100
// Signatures  :
//    @   0  50 4B 03 04  weight=1.00
//    @   0  50 4B 05 06  weight=0.80

Pass the catalog to include rich metadata in the output:

string richText = FormatSummaryBuilder.BuildPlainText(entry, catalog);
// … includes Forensic, AI context, TechnicalDetails

Markdown card

string md = FormatSummaryBuilder.BuildMarkdown(entry, catalog);
// ## ZIP Archive
// > ZIP archive format (PKZIP)...
// | Field | Value |
// |---|---|
// | Category | `Archives` |
// | Extensions | `.zip` `.jar` `.apk` |
// | MIME | `application/zip` |
// | Quality | 92/100 |
// ...
// ### Magic Bytes
// | Offset | Signature | Weight |
// |---|---|---|
// | `0x0000` | `50 4B 03 04` | 1.00 |
// ...
// ### Forensic (low risk)
// ### Navigation Bookmarks
// ### Validation Assertions

Diagnostic dump (debugging)

string dump = FormatSummaryBuilder.BuildDiagnosticDump(entry, catalog);
// === FORMAT DIAGNOSTIC DUMP ===
// ResourceKey         : WpfHexEditor.Core.Definitions.FormatDefinitions.Archives.ZIP.whfmt
// Name                : ZIP Archive
// QualityScore        : 92
// Forensic.RiskLevel  : low  (high=False)
// Assertions (3):
//   [ERROR] NXSB magic valid: nxMagic == 'NXSB'
// Bookmarks (3):
//   Object Header  offset=currentOffset  icon=header
// ==============================

Signature formatting utility

string hex = FormatSummaryBuilder.FormatHex("504B0304");
// "50 4B 03 04"

Level 1: Basic Detection

This level covers the most common scenario: identifying a file and deciding what to do with it.

Extension lookup

The fastest lookup — no I/O, pure in-memory scan.

using WpfHexEditor.Core.Definitions;
using WpfHexEditor.Core.Contracts;

var catalog = EmbeddedFormatCatalog.Instance;

var entry = catalog.GetByExtension(".zip");
// entry.Name          → "ZIP Archive"
// entry.Category      → "Archives"
// entry.Description   → "ZIP archive format (PKZIP)..."
// entry.PreferredEditor → "hex-editor"
// entry.MimeTypes[0]  → "application/zip"

Extensions are case-insensitive and the leading dot is optional:

catalog.GetByExtension(".ZIP");  // same result
catalog.GetByExtension("zip");   // same result

Magic-byte detection

Use when the extension is missing, untrusted, or ambiguous. Pass as many bytes as you can — at least 16, ideally 512.

byte[] header = new byte[512];
using (var fs = File.OpenRead(filePath))
    fs.Read(header, 0, header.Length);

var entry = catalog.DetectFromBytes(header);
if (entry is not null)
    Console.WriteLine($"Detected: {entry.Name}");

How scoring works

Each entry's Signatures list is evaluated. For every signature where the bytes match at the declared offset, its Weight (0.0–1.0) is added to a running score. The entry with the highest total score wins. Entries with no signatures are skipped entirely.

ZIP has 3 signatures:
  "504B0304" offset 0  weight 1.0  ← Local File Header
  "504B0506" offset 0  weight 0.8  ← End of Central Directory
  "504B0708" offset 0  weight 0.5  ← Data Descriptor

A normal .zip file matches the first → score 1.0 → wins if no other format scores higher.

MIME type lookup

var entry = catalog.GetByMimeType("image/png");
// entry.Name       → "PNG Image"
// entry.Extensions → [".png"]

Category browsing

// Enum overload — recommended
var archives = catalog.GetByCategory(FormatCategory.Archives);

// Iterate
foreach (var fmt in archives)
    Console.WriteLine($"{fmt.Name}: {string.Join(", ", fmt.Extensions)}");

Level 2: Routing and Syntax

This level covers editor routing and syntax highlighting integration.

Editor routing

GetCompatibleEditorIds returns all editor IDs that can open a given file. "hex-editor" is always included as the universal fallback.

var editors = catalog.GetCompatibleEditorIds("report.pdf");
// ["hex-editor", "structure-editor"]

var editors2 = catalog.GetCompatibleEditorIds("main.cs");
// ["hex-editor", "code-editor", "text-editor"]

Routing logic applied internally:

ConditionEditor added
Always"hex-editor"
PreferredEditor is setthat value
IsTextFormat == true"code-editor", "text-editor"
Category == "Images""image-viewer"
Category == "Audio""audio-viewer"
DiffMode == "text""diff-viewer"

Registering grammars for a syntax engine

GetSyntaxDefinitionJson returns the raw syntaxDefinition JSON block from the .whfmt file. Feed it into your tokenizer or highlighter.

var catalog = EmbeddedFormatCatalog.Instance;

// Load all programming language grammars
foreach (var entry in catalog.GetByCategory(FormatCategory.Programming)
                              .Where(e => e.HasSyntaxDefinition))
{
    string? grammar = catalog.GetSyntaxDefinitionJson(entry.ResourceKey);
    if (grammar is null) continue;

    // Example: register with a hypothetical tokenizer registry
    // MyTokenizer.Register(entry.Name, grammar);
    Console.WriteLine($"  {entry.Name} → {entry.Extensions.FirstOrDefault()}");
}

Available language grammars (35): Assembly, Batch, C, C++, C#, C# Script, CSS, Dart, F#, Go, HTML, Java, JavaScript, JSON, Kotlin, Lua, Markdown, PHP, Perl, PowerShell, Python, Ruby, Rust, Shell, SQL, Swift, TOML, TypeScript, VB.NET, WHFMT, XAML, XML, XMLMarkup, YAML.

Detecting extension spoofing

bool IsExtensionSpoofed(string filePath)
{
    var byExtension = catalog.GetByExtension(Path.GetExtension(filePath));
    if (byExtension is null) return false;

    using var fs = File.OpenRead(filePath);
    var header = new byte[512];
    int read = fs.Read(header, 0, header.Length);
    var byBytes = catalog.DetectFromBytes(header.AsSpan(0, read));

    return byBytes is not null && byBytes.ResourceKey != byExtension.ResourceKey;
}

if (IsExtensionSpoofed(@"uploads\document.pdf"))
    throw new SecurityException("File content does not match declared extension.");

Or use the confidence-aware version via FormatMatcher:

using WpfHexEditor.Core.Definitions.Matching;

byte[] header = File.ReadAllBytes(filePath)[..512];
var result = FormatMatcher.Match(catalog, filePath, header);

bool spoofed = result is not null
    && result.Source == MatchSource.MagicBytes
    && !result.IsConfirmed;

MIME negotiation for HTTP

// Extension → MIME (Content-Type header)
string? GetContentType(string extension)
    => catalog.GetByExtension(extension)?.MimeTypes?.FirstOrDefault()
       ?? "application/octet-stream";

// MIME → extension (download filename)
string GetExtensionForMime(string mimeType)
    => catalog.GetByMimeType(mimeType)?.Extensions.FirstOrDefault()
       ?? ".bin";

// In an ASP.NET controller:
Response.ContentType = GetContentType(Path.GetExtension(fileName));

Accessing embedded JSON schemas

Use SchemaName enum for compile-time safety:

// Get the whfmt schema to validate user-provided format definitions
string? schema = catalog.GetSchemaJson(SchemaName.Whfmt);

// Pass to a JSON schema validator (e.g. JsonSchema.Net)
// var jsonSchema = JsonSchema.FromText(schema);
// var result = jsonSchema.Evaluate(JsonNode.Parse(userWhfmt));

Level 3: Full Pipeline

This level covers production-grade integration patterns.

using WpfHexEditor.Core.Definitions.Matching;

var catalog = EmbeddedFormatCatalog.Instance;

// One line — no byte-reading boilerplate
var result = FormatFileAnalyzer.Analyze(catalog, filePath);

if (result is null)
{
    Console.WriteLine("Format not recognised.");
}
else
{
    Console.WriteLine($"Format    : {result.Entry.Name}");
    Console.WriteLine($"Category  : {result.Entry.Category}");
    Console.WriteLine($"Confidence: {result.Confidence:P0}");
    Console.WriteLine($"Source    : {result.Source}");
    Console.WriteLine($"Confirmed : {result.IsConfirmed}");
}

File identification pipeline with fallback chain (low-level)

public sealed class FileIdentifier
{
    private readonly IEmbeddedFormatCatalog _catalog;

    public FileIdentifier(IEmbeddedFormatCatalog catalog) => _catalog = catalog;

    public EmbeddedFormatEntry? Identify(string filePath)
    {
        // 1 — Fast path: extension lookup
        var byExt = _catalog.GetByExtension(Path.GetExtension(filePath));
        if (byExt?.Signatures is { Count: > 0 })
        {
            // Confirm with magic bytes when signatures are available
            using var fs = File.OpenRead(filePath);
            var header = new byte[512];
            int read = fs.Read(header, 0, header.Length);
            var byBytes = _catalog.DetectFromBytes(header.AsSpan(0, read));
            if (byBytes is not null) return byBytes;
        }

        // 2 — Extension match without signatures (text formats, config files)
        if (byExt is not null) return byExt;

        // 3 — Pure magic-byte scan (no extension, or unknown extension)
        {
            using var fs = File.OpenRead(filePath);
            var header = new byte[512];
            int read = fs.Read(header, 0, header.Length);
            return _catalog.DetectFromBytes(header.AsSpan(0, read));
        }
    }
}

Dependency injection setup

IEmbeddedFormatCatalog is the injectable interface. Register the singleton in your DI container:

// Microsoft.Extensions.DependencyInjection
services.AddSingleton<IEmbeddedFormatCatalog>(EmbeddedFormatCatalog.Instance);

// Then inject normally
public class MyService(IEmbeddedFormatCatalog catalog) { ... }

Background pre-warming

public static class AppStartup
{
    public static Task PreWarmCatalogAsync()
        => Task.Run(() =>
        {
            // Forces singleton creation + full entry scan + JSON cache fill
            EmbeddedFormatCatalog.Instance.PreWarm();
        });
}

// In Program.cs or App.xaml.cs — fire and forget, don't await
_ = AppStartup.PreWarmCatalogAsync();

Batch folder scanner with parallel processing

using WpfHexEditor.Core.Definitions.Matching;

var catalog = EmbeddedFormatCatalog.Instance;

var results = Directory
    .EnumerateFiles(@"C:\Data", "*.*", SearchOption.AllDirectories)
    .AsParallel()
    .WithDegreeOfParallelism(Environment.ProcessorCount)
    .Select(path =>
    {
        FormatMatchResult? match = null;
        try { match = FormatFileAnalyzer.Analyze(catalog, path); }
        catch { /* skip locked / inaccessible files */ }

        return new
        {
            Path      = path,
            Name      = match?.Entry.Name ?? "Unknown",
            Category  = match?.Entry.Category ?? "Unknown",
            Confidence= match?.Confidence ?? 0,
            IsSpoofed = match?.Source == MatchSource.MagicBytes && !match.IsConfirmed,
        };
    })
    .ToList();

// Summary by category
foreach (var g in results.GroupBy(r => r.Category).OrderByDescending(g => g.Count()))
    Console.WriteLine($"{g.Key,-20} {g.Count(),5} file(s)  spoofed: {g.Count(f => f.IsSpoofed)}");

Full syntax engine bootstrap

using WpfHexEditor.Core.Definitions.Query;

public sealed class SyntaxEngineBootstrapper
{
    private readonly IEmbeddedFormatCatalog _catalog;
    private readonly Dictionary<string, string> _grammarsByExtension = new(StringComparer.OrdinalIgnoreCase);

    public SyntaxEngineBootstrapper(IEmbeddedFormatCatalog catalog)
    {
        _catalog = catalog;
        LoadAll();
    }

    private void LoadAll()
    {
        // Fluent query — all programming language grammars
        var entries = _catalog
            .Query()
            .InCategory(FormatCategory.Programming)
            .HasSyntaxDefinition()
            .Execute();

        foreach (var entry in entries)
        {
            var grammar = _catalog.GetSyntaxDefinitionJson(entry.ResourceKey);
            if (grammar is null) continue;
            foreach (var ext in entry.Extensions)
                _grammarsByExtension.TryAdd(ext, grammar);
        }
    }

    public string? GetGrammar(string fileExtension)
        => _grammarsByExtension.GetValueOrDefault(fileExtension);

    public string GetWhfmtSchema()
        => _catalog.GetSchemaJson(SchemaName.Whfmt) ?? throw new InvalidOperationException("Schema not found.");
}

Level 4: Rich Metadata

This level covers access to the deep metadata blocks embedded in each .whfmt file — forensic intelligence, AI hints, navigation, assertions, inspector groups, and export templates.

Security scanner — detect high-risk formats

using WpfHexEditor.Core.Definitions.Metadata;
using WpfHexEditor.Core.Definitions.Matching;
using WpfHexEditor.Core.Definitions.Query;

var catalog = EmbeddedFormatCatalog.Instance;

// Identify file
var result = FormatFileAnalyzer.Analyze(catalog, filePath);
if (result is null) return;

var entry = result.Entry;

// Forensic check
var forensic = entry.GetForensicSummary(catalog);
if (forensic?.IsHighRisk == true)
{
    Console.WriteLine($"⛔ HIGH RISK: {entry.Name} ({forensic.RiskLevel})");
    foreach (var p in forensic.SuspiciousPatterns)
        Console.WriteLine($"   ⚠ {p.Name}: {p.Description}");
}

// AI-assisted inspection hints
var ai = entry.GetAiHints(catalog);
if (ai?.SuggestedInspections.Count > 0)
{
    Console.WriteLine("Suggested inspections:");
    foreach (var hint in ai.SuggestedInspections)
        Console.WriteLine($"   → {hint}");
}

Binary validator — run format assertions

// Get assertion rules for the detected format
var assertions = entry.GetAssertions(catalog);

Console.WriteLine($"Validation rules for {entry.Name} ({assertions.Count} assertions):");
foreach (var a in assertions)
    Console.WriteLine($"  [{a.Severity,-7}] {a.Name}: {a.Expression}");

// assertions can be passed to a rule-engine / expression evaluator
// e.g. MyRuleEngine.Evaluate(parsedFields, assertions);

Structure viewer — build inspector groups

// Inspector groups define how parsed fields are visually organised
var groups = entry.GetInspectorGroups(catalog);

foreach (var group in groups)
{
    Console.WriteLine($"[{group.Icon}] {group.Title}");
    foreach (var field in group.Fields)
        Console.WriteLine($"    {field}");
}

Export pipeline — enumerate available templates

var templates = entry.GetExportTemplates(catalog);

foreach (var tmpl in templates)
{
    Console.WriteLine($"Export: {tmpl.Name} [{tmpl.Format.ToUpperInvariant()}]");
    Console.WriteLine($"  Fields: {string.Join(", ", tmpl.Fields)}");
}
var bookmarks = entry.GetNavigationBookmarks(catalog);

foreach (var b in bookmarks)
{
    var position = b.Offset.HasValue
        ? $"0x{b.Offset:X4}"
        : $"${b.OffsetVar}";
    Console.WriteLine($"  [{b.Icon,-12}] {b.Name,-25} @ {position}");
}

Diagnostic report — full entry dump

using WpfHexEditor.Core.Definitions.Metadata;

var entry = catalog.GetByExtension(".jks")!;
string dump = FormatSummaryBuilder.BuildDiagnosticDump(entry, catalog);
Console.WriteLine(dump);

Format report — Markdown card for documentation

var entry = catalog.Query()
    .InCategory(FormatCategory.Disk)
    .Containing("APFS")
    .First()!;

string markdown = FormatSummaryBuilder.BuildMarkdown(entry, catalog);
File.WriteAllText("apfs-format-card.md", markdown);

All-in-one: catalogue of high-quality formats with rich metadata

using WpfHexEditor.Core.Definitions.Query;
using WpfHexEditor.Core.Definitions.Metadata;

var catalog = EmbeddedFormatCatalog.Instance;

var formats = catalog
    .Query()
    .WithMinQuality(80)
    .HasMagicBytes()
    .OrderByQuality()
    .Execute();

Console.WriteLine($"{"Format",-30} {"Category",-15} {"Q",3}  {"Risk",-8}  {"Assertions",10}  {"Exports",7}");
Console.WriteLine(new string('-', 85));

foreach (var fmt in formats)
{
    var forensic   = fmt.GetForensicSummary(catalog);
    var assertions = fmt.GetAssertions(catalog);
    var exports    = fmt.GetExportTemplates(catalog);

    Console.WriteLine(
        $"{fmt.Name,-30} {fmt.Category,-15} {fmt.QualityScore,3}  " +
        $"{(forensic?.RiskLevel ?? "—"),-8}  {assertions.Count,10}  {exports.Count,7}");
}

The .whfmt Format

A .whfmt file is a JSONC document (JSON with // comments and trailing commas allowed) that describes a binary or text file format. Here is an annotated example:

{
  // Root identification fields
  "formatName": "ZIP Archive",           // Human-readable name
  "version": "1.14",                     // Format spec version
  "category": "Archives",               // Must match a FormatCategory value
  "description": "...",                 // Short description
  "author": "WPFHexaEditor Team",
  "preferredEditor": "hex-editor",      // "hex-editor" | "code-editor" | "structure-editor" | etc.
  "diffMode": "binary",                 // "text" | "semantic" | "binary"

  // File association
  "extensions": [ ".zip", ".jar", ".apk" ],
  "MimeTypes":  [ "application/zip" ],

  // Detection rules
  "detection": {
    "signatures": [
      { "value": "504B0304", "offset": 0, "weight": 1.0 },  // hex bytes, byte offset, confidence
      { "value": "504B0506", "offset": 0, "weight": 0.8 }
    ],
    "matchMode": "any",                  // "any" | "all"
    "required": true,                   // whether a signature match is mandatory
    "EntropyHint": { "min": 5.0, "max": 8.0 },
    "isTextFormat": false               // true for plain-text formats (CSV, INI, etc.)
  },

  // Quality metadata
  "QualityMetrics": {
    "CompletenessScore": 90             // 0–100
  },

  // Forensic intelligence
  "forensic": {
    "category": "archive",
    "riskLevel": "low",                 // "low" | "medium" | "high" | "critical"
    "suspiciousPatterns": [
      {
        "name": "Zip bomb",
        "description": "Deeply nested archives with extreme compression ratio",
        "condition": "compressionRatio > 1000"
      }
    ]
  },

  // AI-assisted analysis hints
  "aiHints": {
    "analysisContext": "ZIP is a widely-used container format...",
    "suggestedInspections": [
      "Check local file header counts",
      "Verify central directory offset"
    ]
  },

  // Navigation bookmarks
  "navigation": {
    "bookmarks": [
      { "name": "Local File Header", "offset": 0,  "icon": "signature" },
      { "name": "Central Directory", "offsetVar": "cdOffset", "icon": "directory" }
    ]
  },

  // Validation assertions
  "assertions": [
    {
      "name": "Magic bytes valid",
      "expression": "signature == 'PK'",
      "severity": "error",
      "message": "Missing ZIP magic bytes"
    }
  ],

  // Inspector layout (field grouping for UI)
  "inspector": {
    "groups": [
      {
        "title": "File Header",
        "icon": "header",
        "fields": ["signature", "version", "flags", "compression"]
      }
    ]
  },

  // Export templates
  "exportTemplates": [
    {
      "name": "ZIP Summary (JSON)",
      "format": "json",
      "fields": ["signature", "version", "compression", "crc32"]
    }
  ],

  // Technical details
  "TechnicalDetails": {
    "endianness": "little",
    "compressionMethod": "DEFLATE / Store / BZip2 / LZMA",
    "supportsEncryption": true,
    "encryption": "Traditional PKWARE, AES-256"
  },

  // Optional: syntax grammar block (only for text/code formats)
  "syntaxDefinition": {
    "name": "...",
    "scopeName": "source.example",
    "patterns": [ ]                     // tokenizer rules
  }
}

Key fields used by the catalog API

FieldAPI surface
formatNameEmbeddedFormatEntry.Name
categoryEmbeddedFormatEntry.Category / GetByCategory() / .Query().InCategory()
extensionsEmbeddedFormatEntry.Extensions / GetByExtension() / .Query().WithExtension()
MimeTypesEmbeddedFormatEntry.MimeTypes / GetByMimeType() / FormatMatcher.MatchMime()
detection.signaturesEmbeddedFormatEntry.Signatures / DetectFromBytes() / FormatMatcher.Match()
preferredEditorEmbeddedFormatEntry.PreferredEditor / GetCompatibleEditorIds()
detection.isTextFormatEmbeddedFormatEntry.IsTextFormat / .Query().TextFormatsOnly()
syntaxDefinitionEmbeddedFormatEntry.HasSyntaxDefinition / GetSyntaxDefinitionJson() / .Query().HasSyntaxDefinition()
diffModeEmbeddedFormatEntry.DiffMode / .Query().WithDiffMode()
QualityMetrics.CompletenessScoreEmbeddedFormatEntry.QualityScore / .Query().WithMinQuality()
forensicentry.GetForensicSummary(catalog) / entry.IsHighRisk(catalog)
aiHintsentry.GetAiHints(catalog)
navigation.bookmarksentry.GetNavigationBookmarks(catalog)
assertionsentry.GetAssertions(catalog)
inspector.groupsentry.GetInspectorGroups(catalog)
exportTemplatesentry.GetExportTemplates(catalog)
TechnicalDetailsentry.GetTechnicalDetails(catalog) / entry.SupportsEncryption(catalog)

Validating your own .whfmt files

string? schema = EmbeddedFormatCatalog.Instance.GetSchemaJson(SchemaName.Whfmt);
// Pass to JsonSchema.Net, Newtonsoft.Json.Schema, or any JSON Schema validator

The embedded schema (whfmt.schema.json) is the authoritative v2.4 schema used internally to validate all 675+ bundled definitions at build time.