Skip to content
mindwork64 edited this page Oct 4, 2026 · 5 revisions

SLTextureDecoder

A decoder for the Second Life / Firestorm JPEG 2000 texture cache. It turns a viewer texture cache (texture.entries + texture.cache + the <uuid>.texture shards) into ordinary PNG files, and ships three front ends for it: a command line tool, a parallel batch engine and a Qt 6 desktop GUI.

Educational and research use only. The tool reads a cache that is already on your own machine, opens it read-only, decodes locally and never connects to the Second Life grid. Copyright in the textures stays with their creators; this project claims no rights in them and is not affiliated with, endorsed by or supported by Linden Research, Inc. or the Phoenix Firestorm Project. See the Legal notice before you use it.

Features

  • Reassembles the complete JPEG 2000 codestream of every cached texture (600 byte header block from texture.cache + body from <uuid>.texture).
  • Decodes through OpenJPEG, with a strict pass and a lenient best-effort pass for the records whose cached codestream is truncated.
  • Maps 1/2/3/4/5 component codestreams onto 8 bit RGBA and writes PNG through libpng, so 16 bit per component codestreams are normalised to 8 bit output.
  • Parallel batch conversion (worker pool, resume, cancel) reaching ~2.5x on a real 2 core / 4 thread CPU, with byte-identical output compared to a single threaded run.
  • Qt 6 GUI: cache/output pickers, live coloured log, progress, result list with PNG preview, and a headless --batch mode in the same binary for unattended runs.
  • Exit codes per failure category, so scripts can tell "no such cache" (2) from "decode failure" (6) without parsing log text.

Quick start

# build (MSYS2 mingw-w64 shell)
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=C:/msys64/mingw64
cmake --build build
ctest --test-dir build --output-on-failure

# build (Linux: GCC + distribution packages, no prefix path)
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build
ctest --test-dir build --output-on-failure
# 120 textures, four worker threads, no window
.\build\bin\SLTextureDecoderGUI.exe --batch --cache-dir "$env:APPDATA\Firestorm_x64\texturecache" `
    --out-dir D:\textures --jobs 4 --limit 120

# the same run with a window
.\build\bin\SLTextureDecoderGUI.exe

Documentation

Page Content
Installation requirements, MSYS2 packages, build, products, where the viewer keeps its cache
Usage every CLI option, output naming, exit codes, examples
GUI the Qt 6 window and the headless --batch mode
Cache format the reverse engineered texture.* layout, the two record populations, component mapping
Architecture module map, decoding pipeline, threading model, error handling
Performance measured throughput, memory and disk usage, tuning hints
Troubleshooting exit codes, truncated records, Qt runtime, slow runs
Legal notice scope of use, rights in the output, trademarks, licence

The complete reverse engineering notes with all measurements live in the repository: docs/format-notes.md.

Status

Stage Content State
0 Toolchain, dependency check done
1 Core library + CLI skeleton, CMake, gtest/ctest done
2 texture.entries parser, cache layout, frozen test slice done
3 Codestream assembler (header block + body) done
4 .texture body discovery / batch iteration done
5 JPEG 2000 decoding via OpenJPEG (strict + lenient) done
6 Component handling (1/2/3/4/5 components -> RGBA) done
7 PNG output via libpng done
8 CLI (--cache-dir, filters, progress) done
9 Batch conversion service (worker pool, resume) done
10 GUI (Qt 6 Widgets, dynamic) done
11 Robustness / error reporting done
12 Release build, static OpenJPEG deferred

Stage 11 closed the robustness work: atomic output (<name>.part + rename), Ctrl+C with exit code 10, sanity limits before any allocation, and --dry-run (see Usage). What it left open is tracked as GitHub issues: the negative corpus and a decoder fuzzer, a machine-readable error report, CI with sanitizers and a clang-format check, and the live-cache safety work (sharing violations, "the cache changed while it was read").

Requirements at a glance

Windows (MSYS2): mingw-w64-x86_64 toolchain with C++20, CMake >= 3.16, Ninja, OpenJPEG 2.5.4, libpng 1.6.58, gtest 1.17 and - for the GUI - Qt 6 (qt6-base).

pacman -S --needed mingw-w64-x86_64-{toolchain,cmake,ninja,openjpeg2,libpng,gtest,qt6-base}

Linux (Debian / Ubuntu): g++, cmake, ninja-build, libopenjp2-7-dev, libpng-dev, libgtest-dev and - for the GUI - qt6-base-dev.

sudo apt-get install -y g++ cmake ninja-build libopenjp2-7-dev libpng-dev libgtest-dev qt6-base-dev

See Installation for the details.

Clone this wiki locally