Chem O’DunReferences and Guides

X Catalog Tool

This page is also published as X Catalog Tool on the Egosoft wiki.

Everything X4 ships is inside a .cat / .dat pair, and everything a mod ships may be. The X Catalog Tool is the official way in and out of that format: XRCatTool.exe on the command line, XRCatToolGUI.exe in a window. Neither has ever had more documentation than the twenty lines in its own Readme.txt, which leaves the parts that actually bite - how the filters combine, what a diff considers changed, what a folder import quietly swallows - to be found the hard way.

This page is what those two programs do, checked against the binaries rather than the readme.

The Steam package that carries the tool carries WorkshopTool.exe as well, which publishes an extension to the Steam Workshop. That one is not covered here; it is described in Steam Workshop for X Rebirth and X4.

XRCatTool is not the only way in and out of the format. X4 Cat Suite by z1ppeh(z1p) - Nexus Mods, source on GitHub:

Contents

Getting the tool

The tool is free to anyone who owns the game, and both routes to it need the same two things: an Egosoft account, logged in, and X Rebirth or X4: Foundations owned and registered to that account.

From Egosoft it comes with the bonus material, at https://www.egosoft.com/download/x4/bonus_en.php. That download is the catalog tool by itself.

On Steam it is X Tools, in the Tools section of the library, and it installs to steamapps\common\X Tools. That is the larger of the two, since it carries the Workshop tool as well, and the folder is:

X Tools\
    WorkshopTool.exe        publishes an extension to the Steam Workshop
    XRCatTool.exe           the catalog tool, command line
    XRCatToolGUI.exe        the catalog tool, window
    Readme.txt              usage for both tools, and their version history
    startcmd.bat            opens a command prompt in this folder
    startreadme.bat         opens Readme.txt
    steam_api64.dll         used by WorkshopTool only
    steam_appid.txt         282160 - the depot is shared with X Rebirth

The catalog tool has not changed since 1.11 (2019-12-15), and does not need to: the format is the same for X Rebirth and X4, and the tool also reads the older X/X2/X3 one. WorkshopTool is the part that keeps moving, most recently 1.15 (2025-08-26).

Nothing in the package needs installing, and XRCatTool.exe has no dependency on the two DLLs beside it. Copying that single executable into a mod's build folder is enough to run it from a script.

↑ Contents

What a catalog is

A .cat is a plain text index, one line per file, and the .dat beside it is those file bodies concatenated in index order. The two are paired by name, so ext_01.cat needs ext_01.dat next to it and renaming one without the other breaks the archive.

The format in full, the kinds of catalog an extension can hold, what their paths are relative to and the order the game applies them are on Catalogs. This page is the two programs that read and write that format.

↑ Contents

XRCatTool: the command line

XRCatTool -in <paths> -out <path> [-diff <paths>] [-include <patterns>] [-exclude <patterns>] [flags]

There is no verb. What the tool does is decided by what -in and -out are, and a <path> is a catalog if it ends in .cat and a folder otherwise:

-in -out What happens
folder *.cat pack the folder into a catalog
*.cat folder extract the catalog into the folder
*.cat *.cat repack, filter, or convert format
several inputs *.cat merge, with later inputs overriding earlier ones
folder folder a filtered copy

Two consequences of that rule are easy to trip over. The output folder has to exist already: given a path that is neither an existing folder nor a .cat name, the tool prints Output ... is neither a catalog nor a folder, aborting and stops. And only an explicit .cat argument is read as an archive - a .cat file that happens to sit inside an input folder is packed as an ordinary file, bytes and all.

Switches

Switch What it does
-in <paths> Input paths, any mix of folders and catalogs. Later paths override earlier ones for the same entry.
-out <path> The single output, a folder or a .cat name.
-diff <paths> Treat the input as a change against these, and write only what differs.
-include <patterns> Put matching entries into the working set.
-exclude <patterns> Take matching entries out of it.
-append Add to an existing output catalog instead of overwriting it.
-x3cat Write the old X/X2/X3 catalog format. On -append the format is detected from the file.
-dump Print the resulting entry list. It does not suppress the write.

Each of -in, -diff, -include and -exclude takes a list, so several patterns follow one switch rather than repeating it.

How the filters actually work

The readme's one line about -include and -exclude describes neither the matching nor the combination correctly, and both matter.

They are regular expressions, matched as a substring, against the lowercased path. Not globs, and not a full match: -include md selects md/test.xml and v900/md/test.xml and anything else with md anywhere in its path. Anchor with ^ and $ to mean the whole path. Paths inside the tool always use forward slashes and are relative to the input root, so ^v[0-9]+/ is a top level folder and \.xml$ is an extension. The pattern is lowercased too, which is why matching is effectively case insensitive: -include README is echoed back as Filtering with -include readme and matches README.txt.

They form an ordered pipeline, and the order on the command line is the order applied. The working set starts as every scanned file - unless the first filter is an -include, in which case it starts empty. Each -exclude then removes its matches, and each -include puts its matches back.

That last part is the useful one, because it means a late -include is an exception to an earlier -exclude. This is exactly how WorkshopTool -buildcat builds the catalog it uploads; it shells out to XRCatTool with:

-exclude "\.(txt|pdf|cur|mkv|exe|bat|bak)$" "^[^/]*\.(xml|cat|dat|jpg|png)$" "^v[0-9]+/" "Thumbs\.db" "desktop\.ini" -include "ui.xml"

Five excludes drop the files that are uploaded loose or not at all, including every .xml in the extension's root folder - which is what keeps content.xml out of the catalog - and then one -include puts ui.xml back, because a UI mod needs it inside.

Reverse those two and nothing survives: with the -include first the set starts empty, and the -exclude that follows takes its one entry straight back out.

One side effect is worth having: an exclude that matches a folder prefix prunes the scan, which the tool reports as Skipping v900/... On a mod with a large assets tree, -exclude "^assets/" is much faster than filtering the entries afterwards.

Packing and extracting

Pack a mod folder, leaving out the things that are not part of the mod:

XRCatTool.exe -out C:\dev\mymod\ext_01.cat -in C:\dev\mymod ^
  -exclude "^\.git/" "^\.github/" "^dist/" "\.(md|txt|bak)$" "^[^/]*\.(xml|cat|dat|jpg|png)$" ^
  -include "ui.xml"

Unpack a game catalog, into a folder that already exists:

XRCatTool.exe -in "C:\Program Files (x86)\Steam\steamapps\common\X4 Foundations\01.cat" -out C:\x4\extracted

Vanilla is spread over 01.cat upwards with later catalogs overriding earlier ones, and each DLC has its own numbered set under extensions\ego_dlc_*. Extracting them into the same output folder in ascending order reproduces what the game sees. A batch file with one line per catalog, written in that order, is the way to keep it repeatable.

Pull one subtree out of a large catalog rather than all of it:

XRCatTool.exe -in 01.cat -out C:\x4\md-only -include "^md/" "^libraries/"

-dump prints what would land, in index order, with both the stored path and the lowercased sort key. It still writes the output, so point -out somewhere harmless when using it to inspect an archive.

Diffs, and version catalogs

-diff names a base. The input is then read as a change against it, and only the differences are written:

XRCatTool.exe -in C:\dev\mymod -diff C:\dev\mymod-1.00 -out ext_v900.cat

What lands in the result:

A file whose content is unchanged is left out even if its timestamp moved, which is what makes this usable against a fresh checkout or a copied tree. The base may be a folder or a catalog, and both sides may be several paths.

Three things about it are not obvious:

From X4 9.00 there is a catalog type built for this output. ext_NN_diff_v###.cat is loaded as a layer over ext_NN, on the version in its name and on every version above it, so a -diff taken against the previous release packs straight into one. Its naming and loading rules are on Multi-version extensions.

Appending

-append adds to an existing catalog rather than replacing it, and it is blunter than it looks: the new entries are sorted among themselves and written after the existing block, with no merge, no re-sort and no removal of a path that is already in there. The readme's own note is that an appended entry overrides all earlier occurrences of the same file.

The paths in the appended block are relative to that -in root, so appending mymod\aiscripts to a catalog that already holds aiscripts/foo.xml adds a second entry called plain foo.xml, not an override. Append with the same root you packed with.

The X3 format

-x3cat writes the catalog format of X, X2 and X3 - obfuscated rather than plain text, and with no reliable file dates. It exists so the tool can serve the older games; nothing in X Rebirth or X4 reads it. On -append the flag is ignored and the format is taken from the file being appended to.

Exit codes

0 on success, 1 for a usage error or -help, 2 for a real failure such as a missing input path or an unwritable output.

The gap in that is worth planning around: a .cat whose .dat is missing or truncated still exits 0. The tool prints Failed reading file <name> from <path>.dat per entry and carries on, so a build script that only checks the exit code will happily produce a catalog with holes in it. Check the output for Failed reading as well.

↑ Contents

XRCatToolGUI: the window

XRCatToolGUI [<catalog> [<catalog2> ...]]

Catalogs named on the command line are imported at startup, in the order given, later ones overriding earlier ones. Started with no arguments it comes up empty:

The X Catalog Tool window, empty: an Input group, a Diff group, an empty Content list, and a row of buttons
The whole program. Nothing is enabled until there is content to act on.

Four areas, and the window is a fixed size:

Everything on the window applies to the selected side only. Switching between Old and New swaps the list, and leaves the other side untouched. The window has no resize border and no maximize button, so on a large catalog the list shows about fourteen rows however much screen there is.

Getting content in

Set the root folder, then import. There is no filtering here at all - what is in the folder is what comes in:

The window after importing a mod folder: 45 files, 476 KB, the Content list showing paths relative to the root folder
A mod folder imported. Paths are relative to the root folder, which is what makes them right for an ext_ catalog.

Working on a selection

Selecting rows enables the four controls under the list, and the status line on the left counts what is selected:

One row selected; the status line reads Selected: 1 file, 0 deleted, 13,271 Bytes and the Extract, Remove and Keep folder hierarchy controls are now enabled
With a selection, Extract writes just those entries and Remove drops them from the set.

Old, New, and Create diff

To build a version catalog or check what a release actually changed, load the previous build into Old and the new one into New. Either side takes catalogs, folders or files, in any combination:

Both sides loaded: Old 43 files 455 KB, New 43 files 452 KB, and the Create diff button now enabled
Both sides loaded. Create diff stays disabled until each side has something in it.

Create diff replaces the New content with the difference and leaves Old alone. Deleted entries stay in the list as rows with no size, no date and no source:

After Create diff: New reads 2 files, 1 deleted, 43.4 KB, and the list holds one added file, one changed file, and a deletion row with no size or date
One added file, one changed file, and one deletion. Saving this as ext_v900.cat is the version catalog.

The comparison is the command line tool's, so the same two notes apply: content decides, not the timestamp, and an empty file is the exception.

Writing it out

The Save as catalog split button menu, offering Save as XR/X4 Catalog and Save as X/X2/X3 Catalog
The arrow on Save as catalog is where the format choice lives.

Two warnings from the readme are real. Do not save over a catalog that is currently imported - it is the live source for the entries being written. And the window stops responding while it extracts or saves; a large catalog is a wait, not a hang.

What the GUI cannot do

No -include or -exclude. Nothing beyond the initial catalogs is scriptable. No -dump. For a repeatable build - which is what packing a mod is - the command line is the tool and the GUI is the inspector.

↑ Contents

Traps

A folder import takes the whole folder. There is no ignore list, no dotfile rule and no default exclusion of anything. Pointed at a working copy, the tool packs .git too:

The same mod folder imported from its git working copy: 589 files, 264 MB, the list full of .git/hooks and .git/objects entries
The same mod as further up: 45 files and 476 KB became 589 files and 264 MB, all of it repository internals.

WorkshopTool -buildcat has the same blind spot - its exclude list is by file extension, and the files under .git/objects have none - so a Workshop upload built straight from a working copy carries the repository inside it. Build from an export, or pass -exclude "^\.git/".

content.xml does not belong in the catalog. The game reads it from the extension folder before it opens any catalog. Packing it in is harmless but pointless; publishing it in is worse, because the copy in the archive is then a second, stale version of the file the Workshop maintains.

Case is not preserved in the sort, only in the store. A tool that lists a catalog's entries in raw byte order will disagree with the tool that wrote it. Sort on the lowercased path.

-append is not a merge. It duplicates rather than replaces, and the paths follow the -in root of that append, not of the original pack.

An output folder is never created. -out C:\new\folder fails outright rather than making it.

Read failures do not fail the run. A missing or truncated .dat produces per-file messages and exit code 0.

↑ Contents