| include/teampandory/pandorydx/threepack | ||
| packaging | ||
| po | ||
| src | ||
| .clang-format | ||
| .gitignore | ||
| AGENTS.md | ||
| build.sh | ||
| LICENSE | ||
| meson.build | ||
| README.md | ||
threepack
threepack is a C++ library and CLI for inspecting, extracting, repacking,
and identifying Pandora DX/CX firmware asset archives.
License: GPL-2.0. See LICENSE.
It supports:
- top-level archive listing
- recursive archive listing
- full and shallow extraction
- targeted file extraction
- archive repacking
- firmware identification by SHA-1
- optional JSON CLI output
- gettext-based CLI translations
Dependencies
Required build dependencies:
- a C++20 compiler
mesonninjapkg-config- gettext
Optional build dependencies:
nlohmann-jsonfor--jsonwasi-sdkand a WASI runtime such aswasmtimeforwasibuilds
Install Dependencies
Debian/Ubuntu:
sudo apt-get update
sudo apt-get install -y \
build-essential meson ninja-build pkg-config \
gettext \
nlohmann-json3-dev
Fedora:
sudo dnf install -y \
gcc-c++ meson ninja-build pkgconf-pkg-config \
gettext \
nlohmann-json-devel
Arch Linux:
sudo pacman -S --needed \
base-devel meson ninja pkgconf \
gettext \
nlohmann-json
Build
Simple wrapper script:
./build.sh
With no arguments, build.sh prints its help.
Supported build.sh targets:
linux32linux64deb32deb64rpm32rpm64appimage32appimage64wasirpi32rpi64armv7armv8mingw32mingw64
MSYS2 notes:
- inside
MINGW64,UCRT64, orMINGW32shells,build.shprintspacmanpackage install commands instead of Debian/Fedora ones mingw64onUCRT64will suggestmingw-w64-ucrt-x86_64-*packagesmingw64onMINGW64will suggestmingw-w64-x86_64-*packages- under MSYS2, only
mingw32andmingw64targets are supported mingw32targets 32-bit Windows with an XP-era minimummingw64targets 64-bit Windows 10 and Windows 11
Examples:
./build.sh
./build.sh linux64
./build.sh linux32
./build.sh deb32
./build.sh deb64
./build.sh rpm32
./build.sh rpm64
./build.sh appimage64
./build.sh appimage32
./build.sh wasi
./build.sh rpi64
./build.sh mingw32
./build.sh mingw64
Debian/Ubuntu ARM cross-build note:
rpi32andarmv7use the Debian/Ubuntu cross toolchain packages such ascrossbuild-essential-armhf,libc6-dev-armhf-cross, andlinux-libc-dev-armhf-crossrpi64andarmv8use the matchingarm64cross toolchain packages such ascrossbuild-essential-arm64,libc6-dev-arm64-cross, andlinux-libc-dev-arm64-crossbuild.shattempts to install those automatically if they are missing
Linux 32-bit note:
linux32uses the host GCC toolchain with-m32- on Debian/Ubuntu this usually means
gcc-multilib,g++-multilib, andlibc6-dev-i386 build.shattempts to install these automatically if they are missing
Native package note:
deb32builds a 32-bit.debpackage anddeb64builds a 64-bit.debpackage for Debian-family systems such as Debian, Ubuntu, Linux Mint, and Pop!_OSrpm32builds a 32-bit.rpmpackage andrpm64builds a 64-bit.rpmpackage for RPM-family systems such as Fedora, RHEL, Rocky Linux, AlmaLinux, and openSUSE- package output defaults to
out/packages/ - both targets stage a normal
/usrinstall tree viameson installbefore producing the final package
AppImage note:
appimage64builds a 64-bit Linux AppImageappimage32builds a 32-bit Linux AppImage using the same-m32toolchain setup aslinux32- both targets download
appimagetoolfromhttps://github.com/AppImage/appimagetoolbefore the Meson build starts - on systems without
curl,build.shattempts to install it automatically - packaged output defaults to
out/threepack-x86_64.AppImageorout/threepack-i686.AppImage
Direct Meson usage:
meson setup build
meson compile -C build
Install:
meson install -C build
Installed artifacts:
libthreepack.sothreepack- C++ header:
teampandory/pandorydx/threepack/threepack.hpp - C header:
teampandory/pandorydx/threepack/threepack.h - public headers under
include/teampandory/... - gettext catalogs
threepack.pc
Library Usage
The C++ API exposes the reusable archive logic through
teampandory::pandorydx::threepack::ArchiveTool.
For extract and repack operations, callers may supply a progress callback to
receive coarse-grained status updates while archive entries, nested image
packages, libcfg archives, matched files, and the final outer package are
processed.
Example:
#include <iostream>
#include <teampandory/pandorydx/threepack/threepack.hpp>
using namespace teampandory::pandorydx::threepack;
int main() {
ArchiveTool archiveTool;
archiveTool.extractAssetFile(
"rads.zip",
"rads-out",
[](const ProgressInfo &progress) {
std::cout << "[extract] " << progress.message;
if (!progress.path.empty()) {
std::cout << ": " << progress.path.string();
}
if (progress.total > 0) {
std::cout << " (" << progress.current << "/" << progress.total << ")";
}
std::cout << '\n';
});
archiveTool.packAssetFile(
"rads.zip",
"rads-repacked.zip",
[](const ProgressInfo &progress) {
std::cout << "[pack] ";
std::cout << progress.message;
if (!progress.path.empty()) {
std::cout << ": " << progress.path.string();
}
if (progress.total > 0) {
std::cout << " (" << progress.current << "/" << progress.total << ")";
}
std::cout << '\n';
});
}
Progress phases currently include:
ProgressPhase::scanningProgressPhase::extractingOuterEntryProgressPhase::extractingImageProgressPhase::extractingLibcfgProgressPhase::copyingMatchProgressPhase::packingImageProgressPhase::packingLibcfgProgressPhase::packingOuterArchiveProgressPhase::finished
Build output notes:
threepacknow uses internal AES-256-ECB, SHA-1, and CRC32 logic instead of OpenSSL and zlibthreepackbuilds as the normal dynamically linked CLI
WASI
threepack can also be built as a command-line WebAssembly binary for WASI
runtimes such as wasmtime.
Build a WASI binary:
./build.sh wasi
Run it with a WASI runtime:
wasmtime run ./out/wasi/threepack -- --help
wasmtime run ./out/wasi/threepack -- l /path/to/rads.zip
Notes:
- the
wasitarget expectswasm32-wasi-clang,wasm32-wasi-clang++,llvm-ar, andllvm-strip build.sh wasinow tries to installwasi-sdkfrom the package manager when the platform provides it- if that still does not provide
wasm32-wasi-clang, it falls back to a matching upstreamwasi-sdkrelease from GitHub - the GitHub fallback follows the upstream
wasi-sdkinstall layout usingbin/clang,bin/clang++, andshare/wasi-sysroot - when using that SDK layout,
build.shinjects the matching--sysroot=...arguments into the Meson cross file automatically WASI_SDK_PATHis honored when it already points at an installed SDK- override the bootstrap location with
THREEPACK_WASI_SDK_ROOT - override the release version or URL with
THREEPACK_WASI_SDK_VERSIONorTHREEPACK_WASI_SDK_VERSION_FULL/THREEPACK_WASI_SDK_URL build.sh wasinow stagesnlohmann/json.hppautomatically for the WASI compiler include path- it first tries distro packages and then falls back to downloading the pinned upstream release tarball from GitHub
- the output is a command-line WebAssembly binary intended for WASI, not a browser build
CLI Usage
Show help:
threepack --help
List top-level entries:
threepack l /path/to/asset_zip_file.zip
Example:
Listing archive: ./cx1.2jamma/rads.zip
Size Packed CRC HdrOff Off Name
---------- ---------- -------- ------ -------- ------------------------------
3368960 3368976 4d599dbf 16 32784 libcfg_me4.so
4065280 4065296 0eecb9ea 28 3401760 libcfg_mk.so
3734880 3734880 98af8143 40 7467056 imagesce.so
List recursively:
threepack lr /path/to/asset_zip_file.zip
Example:
Recursive listing: ./cx1.2jamma/rads.zip
Size Packed CRC HdrOff Off Name
---------- ---------- -------- ------ -------- ------------------------------
3368960 3368976 4d599dbf 16 32784 libcfg_me4.so
---------- ---------- -------- ------ -------- ------------------------------
[libcfg_me4.so <tar archive>]
26952 26952 credit.bmp
8904 8904 cursor_coin.bmp
Extract recursively:
threepack x /path/to/rads.zip /tmp/out
Extract top level only:
threepack e /path/to/rads.zip /tmp/out
Extract one matching file recursively:
threepack xf /path/to/rads.zip config_fav.png /tmp/out
Extract one matching top-level file only:
threepack ef /path/to/rads.zip imagesce.so /tmp/out
Repack:
threepack a /tmp/out/rads.zip /tmp/repacked-rads.zip
Test readability:
threepack t /path/to/rads.zip
Example:
Testing archive: /path/to/asset_zip_file.zip
Entries: 29
Everything is Ok
Identify firmware:
threepack id /path/to/had.zip
Example:
cx1.2jamma - CX, Jamma variant, Firmware 1.2
CLI Output Formats
JSON:
threepack l /path/to/rads.zip --json
Example:
{
"files": 29,
"rows": [
{
"crc": 1297718719,
"depth": 0,
"file_offset": 32784,
"header_offset": 16,
"kind": "entry",
"name": "libcfg_me4.so",
"packed": 3368976,
"size": 3368976
}
],
"title": "Listing archive: /path/to/asset_zip_file.zip",
"total_packed": 86887808
}
If JSON support was not compiled in, threepack prints a runtime error when
--json is used.
Localization
By default, the CLI uses the process locale from the environment, like a normal gettext application.
Standard gettext precedence applies:
LC_ALLLC_MESSAGESLANG
Examples:
LANG=ja_JP.UTF-8 threepack --help
LC_MESSAGES=de_DE.UTF-8 threepack id /path/to/rade.zip
You can still override the language explicitly:
threepack --lang ja --help
Supported catalogs:
endefresitptzh_CNjacy
Library Usage
Public header:
#include <teampandory/pandorydx/threepack/threepack.hpp>
Namespace:
teampandory::pandorydx::threepack
Basic example:
#include <filesystem>
#include <iostream>
#include <teampandory/pandorydx/threepack/threepack.hpp>
int main() {
namespace fs = std::filesystem;
using teampandory::pandorydx::threepack::ArchiveTool;
ArchiveTool archiveTool;
const auto entries = archiveTool.inspectZipPackage("/work/original/cx1.2jamma/rads.zip");
for (const auto &entry : entries) {
std::cout << std::hex << entry.crc << " " << std::dec << entry.len << '\n';
}
archiveTool.extractAssetFile("/work/original/cx1.2jamma/rads.zip", "/tmp/threepack-out");
archiveTool.packAssetFile("/tmp/threepack-out/rads.zip", "/tmp/rads-repacked.zip");
}
Compile with pkg-config:
c++ -std=c++20 example.cpp $(pkg-config --cflags --libs threepack) -o example
For C callers, include the C ABI header:
#include <teampandory/pandorydx/threepack/threepack.h>
Meson consumer example:
project('example', 'cpp', default_options: ['cpp_std=c++20'])
threepack_dep = dependency('threepack')
executable(
'example',
'example.cpp',
dependencies: [threepack_dep],
)
Using the build tree directly:
c++ -std=c++20 example.cpp \
-I/work/threepack/include \
-L/work/threepack/build -lthreepack \
-Wl,-rpath,/work/threepack/build \
-o example
C Projects
The public API is C++, not C. A plain C project will need a thin C++ wrapper layer or a dedicated C API.
Notes
- unknown archive entries not present in the embedded names table are preserved and repacked using metadata sidecars
- CRC
0x312ffb03is blacklisted and repacked as an empty payload. - unchanged supported archives are expected to round-trip byte-for-byte