Archive Functions

build_vfs

Build a virtual filesystem from all matching catalogs in a directory. Later catalogs override earlier ones for the same path, matching X4’s load order.

from x4_catalog import build_vfs

vfs = build_vfs(Path("/path/to/X4 Foundations"))
# vfs is dict[str, CatEntry]

entry = vfs.get("libraries/wares.xml")
if entry:
    print(f"wares.xml is {entry.size} bytes, in {entry.cat_path}")

Signature:

def build_vfs(directory: Path, prefix: str = "") -> dict[str, CatEntry]: ...
Parameter Description
directory Path to game install or extension directory
prefix Catalog filename prefix ("" for NN.cat, "ext_" for ext_NN.cat)

build_vfs_multi

Build a merged VFS from multiple source directories. Later sources override earlier ones.

from x4_catalog import build_vfs_multi

vfs = build_vfs_multi([
    (Path("/path/to/X4 Foundations"), ""),
    (Path("/path/to/X4 Foundations/extensions/ego_dlc_boron"), "ext_"),
])

Signature:

def build_vfs_multi(sources: list[tuple[Path, str]]) -> dict[str, CatEntry]: ...

list_entries

Return deduplicated catalog entries, optionally filtered by glob and regex patterns.

from x4_catalog import list_entries

# List all MD scripts
entries = list_entries(Path("/path/to/X4 Foundations"), glob_pattern="md/*.xml")
for entry in entries:
    print(f"{entry.size:>10}  {entry.path}")

Signature:

def list_entries(
    directory: Path,
    glob_pattern: str | None = None,
    prefix: str = "",
    include_re: str | None = None,
    exclude_re: str | None = None,
) -> list[CatEntry]: ...

extract_to_disk

Extract files to disk, preserving directory structure and modification times. Verifies MD5 checksums during extraction.

from x4_catalog import extract_to_disk

written = extract_to_disk(
    Path("/path/to/X4 Foundations"),
    Path("./unpacked"),
    glob_pattern="libraries/wares.xml",
)
print(f"Extracted {len(written)} file(s)")

Signature:

def extract_to_disk(
    directory: Path,
    output_dir: Path,
    glob_pattern: str | None = None,
    prefix: str = "",
    include_re: str | None = None,
    exclude_re: str | None = None,
) -> list[Path]: ...

Returns a list of written file paths.

pack_catalog

Pack loose files from a directory into a .cat/.dat pair.

from x4_catalog import pack_catalog

count = pack_catalog(Path("./src"), Path("./dist/ext_01.cat"))
print(f"Packed {count} files")

# Append to an existing catalog
pack_catalog(Path("./extra"), Path("./dist/ext_01.cat"), append=True)

Signature:

def pack_catalog(source_dir: Path, cat_path: Path, append: bool = False) -> int: ...

Returns the number of files packed.

iter_cat_files

Return .cat files matching {prefix}NN.cat sorted by numeric ID. Signature catalogs (*_sig.cat) are excluded.

from x4_catalog import iter_cat_files

cats = iter_cat_files(Path("/path/to/X4 Foundations"))
# [Path('01.cat'), Path('02.cat'), ...]

Signature:

def iter_cat_files(directory: Path, prefix: str = "") -> list[Path]: ...

parse_cat_line

Parse a single .cat index line into a CatEntry. The cat_path and dat_offset fields are set to placeholders – this function is useful for parsing individual lines without full catalog context.

from x4_catalog import parse_cat_line

entry = parse_cat_line("libraries/wares.xml 790216 1775564527 1df31b1302a8db514139e40d6f975f30")
print(entry.path, entry.size, entry.md5)

Signature:

def parse_cat_line(line: str) -> CatEntry: ...

Raises ValueError on blank lines, malformed fields, negative sizes, or invalid MD5 hashes.

read_payload

Read the raw bytes for a single CatEntry from its .dat file, with MD5 integrity verification.

from x4_catalog import read_payload, build_vfs
from pathlib import Path

vfs = build_vfs(Path("/path/to/X4 Foundations"))
data = read_payload(vfs["libraries/wares.xml"])
def read_payload(entry: CatEntry) -> bytes: ...

Raises OSError on short reads or MD5 mismatches.


diff_and_pack

Compare two directories and pack changed files into a catalog.

from x4_catalog import diff_and_pack

changed, deleted = diff_and_pack(
    Path("./original"),
    Path("./modified"),
    Path("./dist/ext_01.cat"),
)
print(f"{changed} changed, {deleted} deleted")

Signature:

def diff_and_pack(base_dir: Path, mod_dir: Path, cat_path: Path) -> tuple[int, int]: ...

Returns (num_changed, num_deleted).

diff_file_sets

Compare two directories and identify changes without packing.

from x4_catalog import diff_file_sets

changed, deleted = diff_file_sets(Path("./original"), Path("./modified"))
for vpath, disk_path in changed.items():
    print(f"Changed: {vpath}")
for vpath in deleted:
    print(f"Deleted: {vpath}")

Signature:

def diff_file_sets(
    base_dir: Path, mod_dir: Path
) -> tuple[dict[str, Path], list[str]]: ...

Returns (changed, deleted) where changed maps virtual paths to disk paths and deleted is a list of virtual paths present in base but absent in mod.



x4cat — MIT License

This site uses Just the Docs, a documentation theme for Jekyll.