RiptOPL DOCS

ZSO Format

ZSO is a compressed variant of the standard ISO disc image. OPL decompresses each sector on the fly using LZ4, so the PS2 sees a normal disc โ€” but your storage device holds a smaller file. Support was added in OPL 1.2.0 and works across all storage backends that use OPL's built-in core.

โ„น Neutrino does not support ZSO
If a game is configured to launch via the Neutrino core but its image is a .zso file, OPL shows an on-screen warning. For most backends (USB, MX4SIO, iLink, MMCE, SMB, and the internal HDD) it then falls back to its own built-in core and the game still launches โ€” just via the OPL core instead of Neutrino. Exception: for games sourced from UDPBD or UDPFS the launch is aborted entirely rather than falling back, because those network transports have no built-in OPL core โ€” Neutrino is their only launch path. To use Neutrino for a game on any backend you must first decompress the image back to .iso (see below).

Requirements

ZSO conversion is done on your PC before copying files to the PS2's storage device. You need:

Compressing an ISO to ZSO

Pass -c 2 to compress. The 2 selects high-compression mode (LZ4 HC), which gives the best ratio. Values 1โ€“12 all compress; values above 1 use LZ4 high-compression. Compression level 1 uses standard LZ4 (faster, slightly larger output).

python ziso.py -c 2 "input.iso" "output.zso"

The script prints a running percentage and a final summary showing the compressed size and compression ratio. Blocks that do not compress well (within 5% of the original size) are stored uncompressed inside the ZSO file automatically โ€” no manual tuning needed.

Optional flags

FlagDefaultEffect
-c <1โ€“12>requiredCompression level. 1 = standard LZ4, 2โ€“12 = LZ4 high-compression.
-c 0โ€”Decompress a ZSO back to ISO.
-b <size>2048Block size in bytes. Must be a multiple of 2048. Default matches a CD/DVD sector.
-moffEnable multiprocessing โ€” uses all CPU cores; significantly faster on large ISOs.
-t <percent>95Compression threshold. If a compressed block is larger than this percentage of the original, it is stored uncompressed.
-a <align>0Padding alignment. 0 = smallest output (slower seek). 6 = faster random access (slightly larger file).
-hโ€”Print usage help.

Decompressing a ZSO back to ISO

Pass -c 0 to decompress. This is the only way to use the image with Neutrino or any other tool that does not understand the ZSO container.

python ziso.py -c 0 "input.zso" "output.iso"

Using ZSO files on your PS2

USB, MMCE, MX4SIO, iLink, and SMB

Place the .zso file in the same folder as your ISOs โ€” OPL scans for both .iso and .zso extensions in the same directory sweep. No extra configuration is required; OPL detects the ZSO magic header at launch time and initialises the LZ4 decompressor automatically.

โ„น File naming
ZSO files follow the same naming conventions as ISO files. A game named SLES_123.45.GameTitle.zso (OPL legacy GameID format) or a free-form name ending in .zso are both recognised. The extension comparison is case-insensitive, so .ZSO and .zso are treated identically by the file scanner.

Internal HDD (APA)

Use the latest version of HDL-Dump to install a ZSO image to the internal HDD in the same way you would install a plain ISO. The APA partition will contain the compressed data; OPL reads the ZSO magic from the partition header and initialises the decompressor before any sector reads.

Internal HDD (exFAT / BDM)

Copy the .zso file to the mass storage area of the exFAT drive exactly as you would a plain ISO. OPL's BDM path scans for .iso and .zso together.

Neutrino and ZSO

The Neutrino external core does not implement ZSO decompression. When a game is set to use Neutrino in per-game settings and the image is a .zso file, OPL detects this before launch and:

The per-game Neutrino setting is not permanently changed โ€” it will still show as enabled next time you open per-game settings. To use Neutrino for the game permanently, decompress the image to ISO first (see above), then copy the .iso in place of the .zso.

The same fallback applies on the internal HDD: a ZSO partition that has Neutrino selected will fall back to OPL with a warning.

Quick reference

TaskCommand
Install dependencypip install lz4
Compress ISO โ†’ ZSOpython ziso.py -c 2 game.iso game.zso
Compress, multicorepython ziso.py -c 2 -m game.iso game.zso
Decompress ZSO โ†’ ISOpython ziso.py -c 0 game.zso game.iso
HDD installUse HDL-Dump (same as ISO)
How does the on-the-fly decompression work?

A ZSO file starts with a 24-byte header (magic ZISO, total uncompressed size, block size, version, and alignment). Following the header is an index table โ€” one 32-bit entry per 2048-byte sector โ€” that stores the file offset of each compressed block. The MSB of each index entry is a "plain" flag: when set, that block is stored uncompressed (it did not meet the compression threshold).

OPL's IOP-side ZSO module reads the header and index table at mount time. On every sector read request from cdvdman, it looks up the block offset in the index, reads the compressed bytes, and decompresses them with LZ4 into a per-sector buffer before handing the data to the EE. Because LZ4 decompression is fast, the impact on load times is typically small โ€” and the smaller file size can reduce seek times on slower devices, partially offsetting the decompression cost.

For images larger than 2 GB, the script automatically sets the alignment field so that block offsets shifted by the alignment value still fit in the 31-bit non-flag portion of each index entry.