#!/usr/bin/env bash # Extract a user-owned Mario Kart Wii PAL (RMCP01) disc image for a local build. # This script deliberately contains no game data and is intended for the macOS # setup application and for maintainers testing that setup path. set -euo pipefail readonly EXPECTED_DOL_SHA256=80d18895b39c63bd80f457398bfcbb91b7d16ac116a41a88967e954080155b05 readonly EXPECTED_REL_SHA256=16d9d146112541fefea701ecb5bc1a496f9d50e4a752fbb5b6778e7c6399f67d fail() { printf 'extract-disc.command: error: %s\n' "$*" >&2; exit 1; } sha256() { shasum -a 256 "$1" | awk '{ print $1 }'; } usage() { cat <<'EOF' Usage: extract-disc.command --game IMAGE --assets-dir DIR --nodtool PATH Extracts a user-owned Mario Kart Wii PAL RMCP01 image into DIR. The final layout is DIR/main.dol, DIR/StaticR.rel, and DIR/DATA. Existing data is left untouched unless the complete new extraction passes both content hash checks. EOF } game="" assets_dir="" nodtool="" while (($#)); do case "$1" in --game) game=${2:-}; shift 2 ;; --assets-dir) assets_dir=${2:-}; shift 2 ;; --nodtool) nodtool=${2:-}; shift 2 ;; -h|--help) usage; exit 0 ;; *) fail "unknown option: $1" ;; esac done [[ -f "$game" ]] || fail "disc image does not exist: $game" [[ -n "$assets_dir" ]] || fail "--assets-dir is required" [[ -x "$nodtool" ]] || fail "nodtool is not executable: $nodtool" assets_dir=$(mkdir -p "$assets_dir" && cd "$assets_dir" && pwd) scratch=$(mktemp -d "${TMPDIR:-/tmp}/wiicompiled-disc.XXXXXX") cleanup() { rm -rf "$scratch"; } trap cleanup EXIT printf 'MKWCBUILD:STEP:validate-disc Checking the selected disc image\n' "$nodtool" info "$game" >/dev/null printf 'MKWCBUILD:STEP:extract-disc Extracting the user-owned disc image\n' "$nodtool" extract "$game" "$scratch/extracted" dol=$(find "$scratch/extracted" -type f -path '*/sys/main.dol' -print -quit) rel=$(find "$scratch/extracted" -type f -path '*/files/rel/StaticR.rel' -print -quit) [[ -n "$dol" ]] || fail 'nodtool extraction did not contain sys/main.dol' [[ -n "$rel" ]] || fail 'nodtool extraction did not contain files/rel/StaticR.rel' [[ $(sha256 "$dol") == "$EXPECTED_DOL_SHA256" ]] || fail 'disc is not the supported clean PAL RMCP01 Mario Kart Wii image' [[ $(sha256 "$rel") == "$EXPECTED_REL_SHA256" ]] || fail 'disc has an unexpected StaticR.rel; use a clean PAL RMCP01 image' data_root=$(dirname "$(dirname "$dol")") [[ -d "$data_root/files" ]] || fail 'nodtool extraction did not contain the Wii files directory' # Stage beside the destination so the final replacement stays on one volume. stage="$assets_dir/.extract-stage-$$" rm -rf "$stage" mkdir -p "$stage" ditto "$data_root" "$stage/DATA" ditto "$dol" "$stage/main.dol" ditto "$rel" "$stage/StaticR.rel" backup="$assets_dir/.previous-extraction-$(date +%Y%m%d-%H%M%S)" if [[ -e "$assets_dir/DATA" || -e "$assets_dir/main.dol" || -e "$assets_dir/StaticR.rel" ]]; then mkdir -p "$backup" for item in DATA main.dol StaticR.rel; do [[ -e "$assets_dir/$item" ]] && mv "$assets_dir/$item" "$backup/$item" done fi mv "$stage/DATA" "$assets_dir/DATA" mv "$stage/main.dol" "$assets_dir/main.dol" mv "$stage/StaticR.rel" "$assets_dir/StaticR.rel" rmdir "$stage" rm -rf "$backup" printf 'MKWCBUILD:STEP:disc-ready Verified and extracted clean PAL RMCP01 game assets\n'