ESA — EA Installer Archive (.ESA)¶
SETUP.ESA is the single archive on the FA Disc 1 root that carries every file
the EA installer copies to disk: the game executable and symbols (FA.EXE,
FA.SMS), the installed LIB archives (FA_1/2/4B/4D.LIB), the sound and comms
drivers, the tech-support tool, and the loose install text. The installer
(SETUP.EXE) reads it under the direction of the .SSF scripts
(SSF.md), whose INSTALL_FILES directives select entries by the
label each carries. There is one .ESA in FA; the CD-resident FA_4C.LIB and
FA_7.LIB sit loose beside it and are not packed in.
The container is a flat directory of variable-length records followed by the
payloads back to back — no index, no padding, no per-payload header. PKWA
entries are raw PKWare DCL streams and NULL entries are stored; the four LIB
archives are stored, so extracting them yields byte-identical LIBs that parse
straight through the LIB codec.
Tools¶
fx¶
fx esa ls <SETUP.ESA> # directory: name, label, flags, method, sizes
fx esa info <SETUP.ESA> # entry/method counts, directory size, repack check
fx esa extract <SETUP.ESA> <NAME> [-o] # one entry (PKWA decoded, NULL copied)
fx esa unpack <SETUP.ESA> [-o dir] # every entry
fx esa repack <SETUP.ESA> <out.ESA> # container round-trip (byte-identical)
fx esa is a thin front-end over fx::esa_read_dir / esa_extract / esa_repack
(api.md). The PKWare DCL decode reuses
fx::blast_decompress — the same decoder the LIB codec uses — because a .ESA
PKWA stream is raw DCL.
File Layout¶
magic char[29] "ELECTRONIC_ARTS_ARCHIVE_FILE\0"
dir record[] variable-length records, back to back
term u8 0x00 — an empty (zero-length) name ends the directory
data blob[] payloads, contiguous, in directory order; the first begins
at the byte after the terminator, the last ends at EOF
Directory record — confirmed¶
All integers are little-endian; strings are NUL-terminated and are not 8.3 —
names may hold spaces and apostrophes (JANE'S HOME PAGE.URL).
| Field | Type | Description |
|---|---|---|
name |
char[] |
file name, NUL-terminated |
label |
char[] |
archive label — the token .SSF INSTALL_FILES selects on |
flags |
u32 |
see below |
usize |
u32 |
uncompressed size |
mtime |
u32 |
modification time (Unix epoch) |
method |
char[] |
"PKWA" (PKWare DCL) or "NULL" (stored), NUL-terminated |
csize |
u32 |
stored size; for NULL, csize == usize |
offset |
u32 |
absolute payload offset within the archive |
The directory self-terminates on an empty name, so there is no count field: the
byte after the terminator is the first payload offset. Two invariants hold across
a well-formed archive and are enforced on read — the directory does not overlap
any payload (offset >= directory_size), and the payloads exactly fill the file
(max(offset + csize) == file size). On the retail SETUP.ESA the last entry
ends at byte 109,979,167, the archive's exact length.
Entry flags — inferred¶
Every retail entry is 0x0211, except EAREMOVE.EXE and EAEXEC.EXE, which are
0x0221 — and those are exactly the two the .SSF scripts install with
INSTALL_SYSFILES (to the Windows system directory) rather than INSTALL_FILES
(to the app directory). The differing bit (0x10 vs 0x20) therefore reads as a
destination-class selector. The remaining low bits (0x001, 0x200) are
unexplained. Confirming the bitfield is a target of the SETUP.EXE reconstruction
(#54); the codec preserves flags verbatim regardless.
Compression — confirmed¶
PKWA payloads are raw PKWare DCL streams: a litmode byte, a dictbits
byte, then the LSB-first bitstream. Unlike a flags=4 LIB entry
(LIB.md § EA Compression Wrapper), a
.ESA stream carries no 4-byte EA decompressed-size prefix — the size is the
directory's usize — so it is decoded with blast_decompress, never
blast_decompress_ea. NULL payloads are stored verbatim.
File Inventory¶
The retail SETUP.ESA (Disc 1, v1.00F) — 23 entries, in directory order:
| Name | Label | Flags | Method | Usize | Csize |
|---|---|---|---|---|---|
| FA.EXE | FA_EXECUTABLE_FILES | 0x0211 | PKWA | 1,299,968 | 677,707 |
| FA.SMS | FA_EXECUTABLE_FILES | 0x0211 | PKWA | 104,452 | 50,077 |
| JANE'S HOME PAGE.URL | FA_INTERNET | 0x0211 | NULL | 49 | 49 |
| EAHELP.HLP | FA_README | 0x0211 | PKWA | 305,783 | 73,849 |
| README.TXT | FA_README | 0x0211 | PKWA | 27,816 | 10,512 |
| IP.EXE | FA_README | 0x0211 | PKWA | 708,096 | 314,488 |
| IP.CFG | FA_README | 0x0211 | NULL | 27 | 27 |
| FA_1.LIB | FA_LIBS | 0x0211 | NULL | 28,501,531 | 28,501,531 |
| FA_2.LIB | FA_LIBS | 0x0211 | NULL | 31,546,576 | 31,546,576 |
| FA_4B.LIB | FA_LIBS | 0x0211 | NULL | 34,670,738 | 34,670,738 |
| FA_4D.LIB | FA_LIBS | 0x0211 | NULL | 13,756,838 | 13,756,838 |
| CHAT.TXT | FA_MISC | 0x0211 | PKWA | 591 | 336 |
| BRIEFING.TXT | FA_MISC | 0x0211 | PKWA | 8,793 | 3,140 |
| EXAMPLE.MT | FA_MISC | 0x0211 | PKWA | 1,178 | 645 |
| LICENSE.TXT | FA_MISC | 0x0211 | PKWA | 4,672 | 2,279 |
| WAIL32.DLL | FA_SOUND_DRIVER_FILES | 0x0211 | PKWA | 135,680 | 64,347 |
| CDRVDL32.DLL | COMMDRV_DLLS_FILES | 0x0211 | PKWA | 28,672 | 12,760 |
| CDRVHF32.DLL | COMMDRV_DLLS_FILES | 0x0211 | PKWA | 29,184 | 14,121 |
| CDRVXF32.DLL | COMMDRV_DLLS_FILES | 0x0211 | PKWA | 39,424 | 20,704 |
| COMMSC32.DLL | COMMDRV_DLLS_FILES | 0x0211 | PKWA | 18,432 | 8,248 |
| EAREMOVE.EXE | REMOVER_EXECUTABLE_FILE | 0x0221 | PKWA | 325,632 | 163,684 |
| EAEXEC.EXE | EXEC_EXECUTABLE_FILE | 0x0221 | PKWA | 132,608 | 65,360 |
| PKCOMP.IDKDECODLL | SETUP_SPECIAL_FILES | 0x0211 | NULL | 19,968 | 19,968 |
Four members are also present loose on the Disc 1 root — README.TXT,
EAHELP.HLP, IP.EXE (all PKWA) and IP.CFG (NULL). Extracting them from the
archive reproduces the loose files byte-for-byte, which proves the codec from the
disc alone, with no installed game.
Build note. This is the v1.00F disc build. The official v1.02F patch
(fae102.exe) later rewrites FA.EXE, FA.SMS, FA_1.LIB
and FA_2.LIB and adds msapi.dll; the reconstruction database describes that
patched build, so a from-disc install is the earlier binary. FA.SMS here
declares 3,753 symbols versus 3,829 after the patch.
Round-Trip Notes¶
fx esa repack reads the directory and rebuilds the archive: metadata is copied
verbatim, payloads are kept stored (still PKWA where they were PKWA), offsets
are recomputed, and the terminator is rewritten. Because the records re-encode to
the same bytes, the recomputed offsets equal the originals for a contiguous,
in-order source, so the output is byte-identical — the proof the layout is fully
accounted for. A non-contiguous or reordered source normalises instead.
fx esa pack builds a fresh archive with every entry stored (method
"NULL"): fx_lib has a PKWare DCL decoder, not an encoder — the same asymmetry
as ealib_build writing flags=0. It is used to synthesise fixtures,
not to re-create a shipped SETUP.ESA.
Both claims are checked against the retail archive by the fa_disc_install
integration test (development.md § Real-media install mode):
the 110 MB SETUP.ESA repacks byte-for-byte, and every extracted entry is hashed
against a committed manifest. The decoder also has a self-oracle on the disc
itself — README.TXT, IP.EXE, IP.CFG and EAHELP.HLP are shipped both
inside the archive and loose on disc 1, and the extracted bytes must equal the
loose ones. Three of the four are PKWA, so the DCL path is proven without
reference to anything we recorded ourselves.
Open Questions¶
Entry flags bitfield¶
The flags field is 0x0211 on app-directory entries and 0x0221 on the two
INSTALL_SYSFILES entries, so one bit clearly selects the destination class, but
the low bits are unexplained and the mapping is inferred from correlation rather
than read out of SETUP.EXE.
Status: open — re-static (#54)
The malformed member name PKCOMP.IDKDECODLL¶
One entry carries a 17-character name that is not valid 8.3 and is referenced by
no .SSF directive; its payload is a single stored PE image, and its label
SETUP_SPECIAL_FILES appears nowhere in the scripts. It looks like a
name-concatenation bug in EA's archive builder (PKCOMP.IDK + …DECO.DLL?). The
codec preserves it verbatim; what consumes it is a question for the SETUP.EXE
reconstruction.
Status: open — re-static (#54)
Related¶
Formats: LIB — the four .LIB archives ESA carries, and the DCL
contrast (LIB entries wrap the stream in a 6-byte EA header; ESA does not).
SSF — the installer script whose INSTALL_FILES directives select ESA
entries by label. RGN — the other Disc 1 installer-only format.
Program: reconstruction.md — the SETUP.EXE
reconstruction that will confirm the flags bitfield and the PKCOMP member.