diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 91dafc6..b2f2d49 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1074,15 +1074,15 @@ jobs: name: rb-cli-linux-${{ matrix.arch }}-${{ needs.generate-version.outputs.version }} path: rb-cli-linux-${{ matrix.arch }}-${{ needs.generate-version.outputs.version }}.tar.gz - # `rb-cli` for Windows on ARM (aarch64-pc-windows-msvc), cross-compiled on the - # x64 Windows runner (its Visual Studio carries the ARM64 MSVC libs). CLI only: - # a full ARM64 desktop build can't link because the `chd`/`optical` core - # (libchdman-rs) publishes no aarch64-pc-windows-msvc prebuilt — only - # x86_64 / i686 Windows — so the GUI lane is shipped from the same pure-Rust - # slim feature set as the PowerPC/RISC-V builds. Build-only: an ARM64 exe can't - # execute on the x64 runner, so the test legs stay on the x64/x86 Windows jobs. - build-rb-cli-win-arm64: - name: Build rb-cli (Windows ARM64) + # Full desktop app + `rb-cli` for Windows on ARM64 (aarch64-pc-windows-msvc), + # cross-compiled on the x64 Windows runner (its Visual Studio carries the ARM64 + # MSVC libs). First-class GUI build: libchdman-rs 0.288.8 publishes an + # aarch64-pc-windows-msvc prebuilt, so the `chd`/`optical` core links and the + # app ships the same default feature set as the x64/x86 Windows builds. + # Build-only (continue-on-error): an ARM64 exe can't execute on the x64 runner, + # so the test legs stay on the x64/x86 Windows jobs. + build-windows-arm64: + name: Build Windows ARM64 (GUI + rb-cli) # Skipped only when a manual run unticks "desktop"; every push builds it. if: ${{ github.event_name != 'workflow_dispatch' || inputs.desktop }} needs: generate-version @@ -1118,8 +1118,26 @@ jobs: path: target key: ${{ runner.os }}-aarch64-pc-windows-msvc-cargo-build-${{ hashFiles('**/Cargo.lock') }} - - name: Build rb-cli (pure-Rust slim — no GUI / CHD / optical) - run: cargo build --release --bin rb-cli --no-default-features --features pure-zstd,remote --target aarch64-pc-windows-msvc + # Default features (GUI + chd + optical + native-zstd/zlib + remote) — one + # build produces both rusty-backup.exe and rb-cli.exe, like build-windows. + - name: Build (GUI + rb-cli, default features) + run: cargo build --release --target aarch64-pc-windows-msvc + + - name: Package app + shell: bash + run: | + cd target/aarch64-pc-windows-msvc/release + if [ -f "../../../assets/icons/icon.ico" ]; then + 7z a ../../../Rusty-Backup-windows-arm64-${{ needs.generate-version.outputs.version }}.zip rusty-backup.exe ../../../assets/icons/icon.ico + else + 7z a ../../../Rusty-Backup-windows-arm64-${{ needs.generate-version.outputs.version }}.zip rusty-backup.exe + fi + + - name: Upload app artifact + uses: actions/upload-artifact@v7 + with: + name: Rusty-Backup-windows-arm64-${{ needs.generate-version.outputs.version }} + path: Rusty-Backup-windows-arm64-${{ needs.generate-version.outputs.version }}.zip - name: Stage CLI binary shell: bash @@ -1135,6 +1153,121 @@ jobs: name: rb-cli-windows-arm64-${{ needs.generate-version.outputs.version }} path: rb-cli-windows-arm64-${{ needs.generate-version.outputs.version }}.zip + # Full desktop GUI for Linux RISC-V 64 (riscv64gc-unknown-linux-gnu), + # cross-compiled on x64. There is no GitHub-hosted riscv64 runner, so unlike + # the x64/arm64 AppImage jobs this can't build/package natively: we cross-link + # the default feature set (GUI + CHD + optical) against a riscv64 GTK/GL sysroot + # pulled in via dpkg multiarch (ubuntu-ports), then ship a plain dynamically- + # linked tarball — NOT a self-contained AppImage; it uses the user's system + # GTK3 at runtime. libchdman-rs 0.288.8 publishes the riscv64gc prebuilt that + # makes the CHD core link. continue-on-error: best-effort, can't block release. + build-gui-linux-riscv64: + name: Build Linux RISC-V 64 GUI (rusty-backup) + # Skipped only when a manual run unticks "desktop"; every push builds it. + if: ${{ github.event_name != 'workflow_dispatch' || inputs.desktop }} + needs: generate-version + runs-on: ubuntu-latest + continue-on-error: true + env: + RELEASE_VERSION: ${{ needs.generate-version.outputs.version }} + # libchdman is C++; link through g++ so libstdc++ is pulled in. + CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER: riscv64-linux-gnu-g++ + # cc-rs (cd-da-reader's C shim) — the riscv64gc triple doesn't auto-map to + # the riscv64-linux-gnu-* cross tools, so point it at them explicitly. + CC_riscv64gc_unknown_linux_gnu: riscv64-linux-gnu-gcc + CXX_riscv64gc_unknown_linux_gnu: riscv64-linux-gnu-g++ + # gtk-sys/glib-sys (system-deps) must read the riscv64 multiarch .pc files + # and accept a cross build. + PKG_CONFIG_ALLOW_CROSS: "1" + PKG_CONFIG_LIBDIR: /usr/lib/riscv64-linux-gnu/pkgconfig:/usr/share/pkgconfig + PKG_CONFIG_SYSROOT_DIR: / + steps: + - uses: actions/checkout@v6 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + targets: riscv64gc-unknown-linux-gnu + + - name: Add riscv64 as a foreign dpkg architecture (ubuntu-ports) + run: | + set -euxo pipefail + # riscv64 lives in ubuntu-ports, not the amd64 archive. Pin every + # existing source to amd64 so `apt-get update` doesn't 404 trying to + # fetch riscv64 indexes from archive.ubuntu.com / PPAs, then add one + # riscv64-only ports source. + sudo dpkg --add-architecture riscv64 + for f in /etc/apt/sources.list.d/*.sources; do + [ -f "$f" ] || continue + grep -q '^Architectures:' "$f" || sudo sed -i '/^Types:/a Architectures: amd64' "$f" + done + for f in /etc/apt/sources.list /etc/apt/sources.list.d/*.list; do + [ -f "$f" ] || continue + sudo sed -i -E 's|^deb (http)|deb [arch=amd64] \1|; s|^deb-src (http)|deb-src [arch=amd64] \1|' "$f" + done + printf '%s\n' \ + 'Types: deb' \ + 'URIs: http://ports.ubuntu.com/ubuntu-ports' \ + 'Suites: noble noble-updates noble-backports noble-security' \ + 'Components: main universe' \ + 'Architectures: riscv64' \ + 'Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg' \ + | sudo tee /etc/apt/sources.list.d/riscv64-ports.sources >/dev/null + sudo apt-get update + + - name: Install riscv64 cross toolchain + GTK/GL sysroot + run: | + set -euxo pipefail + sudo apt-get install -y \ + g++-riscv64-linux-gnu binutils-riscv64-linux-gnu file \ + libgtk-3-dev:riscv64 libglib2.0-dev:riscv64 \ + libgl1-mesa-dev:riscv64 libegl1-mesa-dev:riscv64 \ + libxkbcommon-dev:riscv64 libxkbcommon-x11-dev:riscv64 \ + libx11-dev:riscv64 libxcb1-dev:riscv64 libxcursor-dev:riscv64 \ + libxi-dev:riscv64 libxrandr-dev:riscv64 libwayland-dev:riscv64 + + - name: Cache cargo registry + uses: actions/cache@v5 + with: + path: ~/.cargo/registry + key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} + + - name: Cache cargo index + uses: actions/cache@v5 + with: + path: ~/.cargo/git + key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} + + - name: Cache cargo build + uses: actions/cache@v5 + with: + path: target + key: ${{ runner.os }}-riscv64gc-gui-cargo-build-${{ hashFiles('**/Cargo.lock') }} + + - name: Build (default features = GUI + CHD + optical) + run: cargo build --release --target riscv64gc-unknown-linux-gnu + + - name: Strip + verify ELF + run: | + set -e + ELF=target/riscv64gc-unknown-linux-gnu/release/rusty-backup + riscv64-linux-gnu-strip "$ELF" + file "$ELF" + ls -lh "$ELF" + riscv64-linux-gnu-objdump -p "$ELF" | grep -E 'NEEDED|GLIBC_' || true + + - name: Package app + run: | + TGZ="Rusty-Backup-linux-riscv64-${{ needs.generate-version.outputs.version }}.tar.gz" + tar -C target/riscv64gc-unknown-linux-gnu/release -czf "$TGZ" rusty-backup + ls -lh "$TGZ" + + - name: Upload app artifact + uses: actions/upload-artifact@v7 + with: + name: Rusty-Backup-linux-riscv64-${{ needs.generate-version.outputs.version }} + path: Rusty-Backup-linux-riscv64-${{ needs.generate-version.outputs.version }}.tar.gz + # Turn the `appliance` choice input into a JSON arch list for the matrix # below. A manual dispatch honours none / i586 / i686 / both. A push to # main/master builds both arches automatically (the full Buildroot build is @@ -1350,11 +1483,13 @@ jobs: - build-linux-appimage - build-linux-packages - build-rb-cli-mini-armv7 - # CLI-only cross-builds for extra CPU arches (PowerPC BE 32/64, RISC-V 64, - # Windows ARM64). continue-on-error like mini-armv7: listed here so the - # release waits for their tarballs/zips, but a failure can't block it. + # Cross-builds for extra CPU arches: PowerPC BE 32/64 (rb-cli only), plus + # full GUI + rb-cli for Windows ARM64 and Linux RISC-V 64. continue-on-error + # like mini-armv7: listed here so the release waits for their tarballs/zips, + # but a failure can't block the desktop release. - build-rb-cli-extra-arch - - build-rb-cli-win-arm64 + - build-windows-arm64 + - build-gui-linux-riscv64 # build-appliance is skipped on feature branches and on a manual # appliance=none run. A skipped `needs` job would normally skip the whole # release, so the release `if` below uses `!cancelled()` + explicit @@ -1406,6 +1541,7 @@ jobs: "Rusty-Backup-linux-x64-${VER}.rpm" "Rusty-Backup-linux-x64-${VER}.pkg.tar.zst" \ "Rusty-Backup-linux-arm64-${VER}.AppImage" "Rusty-Backup-linux-arm64-${VER}.deb" \ "Rusty-Backup-linux-arm64-${VER}.rpm" "Rusty-Backup-linux-arm64-${VER}.pkg.tar.zst" \ + "Rusty-Backup-windows-arm64-${VER}.zip" "Rusty-Backup-linux-riscv64-${VER}.tar.gz" \ "rb-cli-windows-x64-${VER}.zip" "rb-cli-windows-x86-${VER}.zip" \ "rb-cli-macos-arm64-${VER}.zip" "rb-cli-macos-x64-${VER}.zip" \ "rb-cli-linux-x64-${VER}.tar.gz" "rb-cli-linux-arm64-${VER}.tar.gz" \ @@ -1429,13 +1565,15 @@ jobs: |---|---|---|---| | **Windows 11 / 10** | x64 (64-bit) | [Installer](${BASE}/Rusty-Backup-Setup-windows-x64-${VER}.exe) · [Portable zip](${BASE}/Rusty-Backup-windows-x64-${VER}.zip) | [rb-cli](${BASE}/rb-cli-windows-x64-${VER}.zip) | | **Windows 10** | x86 (32-bit) | [Installer](${BASE}/Rusty-Backup-Setup-windows-x86-${VER}.exe) · [Portable zip](${BASE}/Rusty-Backup-windows-x86-${VER}.zip) | [rb-cli](${BASE}/rb-cli-windows-x86-${VER}.zip) | + | **Windows 11** | ARM64 (AArch64) | [Portable zip](${BASE}/Rusty-Backup-windows-arm64-${VER}.zip) | [rb-cli](${BASE}/rb-cli-windows-arm64-${VER}.zip) | | **macOS 10.13+** | Apple Silicon (arm64) | [.dmg](${BASE}/Rusty-Backup-macos-arm64-${VER}.dmg) | [rb-cli](${BASE}/rb-cli-macos-arm64-${VER}.zip) | | **macOS 10.13+** | Intel (x64) | [.dmg](${BASE}/Rusty-Backup-macos-x64-${VER}.dmg) | [rb-cli](${BASE}/rb-cli-macos-x64-${VER}.zip) | | **Linux** (glibc >= 2.39) | x64 | [AppImage](${BASE}/Rusty-Backup-linux-x64-${VER}.AppImage) · [deb](${BASE}/Rusty-Backup-linux-x64-${VER}.deb) · [rpm](${BASE}/Rusty-Backup-linux-x64-${VER}.rpm) · [pkg](${BASE}/Rusty-Backup-linux-x64-${VER}.pkg.tar.zst) | [rb-cli](${BASE}/rb-cli-linux-x64-${VER}.tar.gz) | | **Linux** (glibc >= 2.39) | arm64 | [AppImage](${BASE}/Rusty-Backup-linux-arm64-${VER}.AppImage) · [deb](${BASE}/Rusty-Backup-linux-arm64-${VER}.deb) · [rpm](${BASE}/Rusty-Backup-linux-arm64-${VER}.rpm) · [pkg](${BASE}/Rusty-Backup-linux-arm64-${VER}.pkg.tar.zst) | [rb-cli](${BASE}/rb-cli-linux-arm64-${VER}.tar.gz) | + | **Linux** (glibc >= 2.39) | RISC-V 64-bit (\`riscv64gc\`) | [tar.gz](${BASE}/Rusty-Backup-linux-riscv64-${VER}.tar.gz) | [rb-cli](${BASE}/rb-cli-linux-riscv64-${VER}.tar.gz) | | **MiSTer FPGA** (Cortex-A9, glibc 2.31) | armv7 hardfloat | _(GUI not built for this target)_ | [rb-cli-mini](${BASE}/rb-cli-mini-armv7-linux-${VER}.tar.gz) | - **Windows:** x86 = 32-bit (Windows 10, the last Windows with 32-bit support). · **macOS:** requires 10.13 High Sierra or later. · **Linux:** deb = Debian/Ubuntu, rpm = Fedora/RHEL/openSUSE, pkg = Arch/Manjaro; the packages and \`rb-cli\` are built against **glibc 2.39** (Ubuntu 24.04), while the **AppImage** is self-contained and runs on most distributions regardless of glibc. · **MiSTer FPGA:** \`rb-cli-mini\` is a slim \`rb-cli\` cross-compiled for the MiSTer's armv7 hardfloat Intel Cyclone V SoC against Ubuntu 20.04 glibc 2.31 — same baseline as the MiSTer Buildroot rootfs and the upstream \`libchdman-rs\` armv7 prebuilt. GUI/optical features are off; CHD is in. Drop it onto the SD at \`/media/fat/Scripts/rb-cli\`. · Every **rb-cli** download contains a single \`rb-cli\` executable (\`rb-cli.exe\` on Windows). + **Windows:** x86 = 32-bit (Windows 10, the last Windows with 32-bit support). · **macOS:** requires 10.13 High Sierra or later. · **Linux:** deb = Debian/Ubuntu, rpm = Fedora/RHEL/openSUSE, pkg = Arch/Manjaro; the packages and \`rb-cli\` are built against **glibc 2.39** (Ubuntu 24.04), while the **AppImage** is self-contained and runs on most distributions regardless of glibc. · **Windows ARM64 / RISC-V 64:** cross-compiled, build-only legs — the Windows ARM64 app is a portable zip and the RISC-V 64 app is a plain dynamically-linked tarball that uses your system GTK3 (not a self-contained AppImage like x64/arm64). · **MiSTer FPGA:** \`rb-cli-mini\` is a slim \`rb-cli\` cross-compiled for the MiSTer's armv7 hardfloat Intel Cyclone V SoC against Ubuntu 20.04 glibc 2.31 — same baseline as the MiSTer Buildroot rootfs and the upstream \`libchdman-rs\` armv7 prebuilt. GUI/optical features are off; CHD is in. Drop it onto the SD at \`/media/fat/Scripts/rb-cli\`. · Every **rb-cli** download contains a single \`rb-cli\` executable (\`rb-cli.exe\` on Windows). ### Command-line (\`rb-cli\`) for other CPU architectures @@ -1445,10 +1583,8 @@ jobs: |---|---|---| | **Linux** (glibc >= 2.39) | PowerPC 64-bit, big-endian (G5 / POWER) | [rb-cli](${BASE}/rb-cli-linux-ppc64-${VER}.tar.gz) | | **Linux** (glibc >= 2.39) | PowerPC 32-bit, big-endian (G3 / G4) | [rb-cli](${BASE}/rb-cli-linux-ppc32-${VER}.tar.gz) | - | **Linux** (glibc >= 2.39) | RISC-V 64-bit (\`riscv64gc\`) | [rb-cli](${BASE}/rb-cli-linux-riscv64-${VER}.tar.gz) | - | **Windows 11** | ARM64 (AArch64) | [rb-cli](${BASE}/rb-cli-windows-arm64-${VER}.zip) | - The Linux builds use the same **glibc 2.39** (Ubuntu 24.04) baseline as the x64/arm64 \`rb-cli\`. **Windows ARM64 is the CLI only** — a full ARM64 desktop app can't be built yet because the CHD core (\`libchdman-rs\`) publishes no \`aarch64-pc-windows-msvc\` prebuilt. Each download contains a single \`rb-cli\` executable (\`rb-cli.exe\` on Windows). + These PowerPC builds use the same **glibc 2.39** (Ubuntu 24.04) baseline as the x64/arm64 \`rb-cli\`, and each download contains a single \`rb-cli\` executable. (Windows ARM64 and RISC-V 64 now ship a full desktop app — see the main table above.) ### Install on a MiSTer FPGA (one line, auto-updating) diff --git a/Cargo.lock b/Cargo.lock index 7fd35a4..88a26f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -305,7 +305,7 @@ dependencies = [ "objc2-foundation 0.3.2", "parking_lot", "percent-encoding", - "windows-sys 0.52.0", + "windows-sys 0.60.2", "x11rb", ] @@ -1317,7 +1317,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1650,7 +1650,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2773,9 +2773,9 @@ checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libchdman-rs" -version = "0.288.5" +version = "0.288.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f23c6f7338dec4f8dd7ae07e2956b5d9633be9b0dd81782aa28b6db3b9239534" +checksum = "f9e349d24a5de45ed8a8c9f01db055d0f393771881169c39ae39707618cffd22" dependencies = [ "cc", "hex", @@ -3545,9 +3545,9 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "opticaldiscs" -version = "0.4.5" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91726e09312bbe825916a5c1589e9a080d91e6e1fa4f43995c2941c8812f12ab" +checksum = "ee8945c35cfd0e2364cea3597617e0e9c74e09d7a0c62df4bdc381903ae88ec4" dependencies = [ "cue_sheet", "libchdman-rs", @@ -3985,7 +3985,7 @@ dependencies = [ "once_cell", "socket2", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] @@ -4366,7 +4366,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -4425,7 +4425,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -5029,7 +5029,7 @@ dependencies = [ "getrandom 0.4.2", "once_cell", "rustix 1.1.4", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -6044,7 +6044,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -6405,7 +6405,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d6f32a0ff4a9f6f01231eb2059cc85479330739333e0e58cadf03b6af2cca10" dependencies = [ "cfg-if", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e62d51e..d6723da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,7 +97,7 @@ chd = ["dep:libchdman-rs"] # Physical optical-drive I/O (rip / data-track read) plus optical-image # convert/browse. Builds on armv7 (MiSTer) too: cd-da-reader is cc+libc # (a self-compiled SG_IO shim — NO system libcdio link), and opticaldiscs -# (>=0.4.5) reuses the SAME libchdman-rs 0.288.5 prebuilt as the `chd` feature +# (>=0.4.5) reuses the SAME libchdman-rs 0.288.8 prebuilt as the `chd` feature # — which ships an armv7-gnueabihf-glibc2.31 build — so the two dedupe to one # libchdman. At runtime it needs a drive present (e.g. /dev/sr0); harmless to # include when none is attached. @@ -116,13 +116,13 @@ remote = [] eframe = { version = "0.34", features = ["glow"], optional = true } egui = { version = "0.34", optional = true } rfd = { version = "0.17", default-features = false, features = ["gtk3"], optional = true } -libchdman-rs = { version = "0.288.5", features = ["prebuilt"], optional = true } +libchdman-rs = { version = "0.288.8", features = ["prebuilt"], optional = true } # rustls-tls keeps reqwest off openssl-sys so the gui-feature build doesn't drag # in OpenSSL native libs; the cross/armv7 path doesn't need reqwest at all # (it's behind `gui`). reqwest = { version = "0.13", default-features = false, features = ["blocking", "json", "rustls"], optional = true } webbrowser = { version = "1.0", optional = true } -opticaldiscs = { version = "0.4.2", features = ["drives"], optional = true } +opticaldiscs = { version = "0.5", features = ["drives"], optional = true } cd-da-reader = { git = "https://github.com/danifunker/rust-cd-da-reader", branch = "add-data-support-0-4-1", optional = true } # Always-on dependencies — used by rb-cli (mini included). diff --git a/src/cli/verbs/optical.rs b/src/cli/verbs/optical.rs index e0c9522..15d5fcd 100644 --- a/src/cli/verbs/optical.rs +++ b/src/cli/verbs/optical.rs @@ -393,9 +393,9 @@ fn walk_tree( out.push_str(&format!(" (rsrc: {})", format_size(rs))); } } - if let Some(tc) = &child.type_code { + if let Some(tc) = child.type_code_string() { out.push_str(&format!(" {tc}")); - if let Some(cc) = &child.creator_code { + if let Some(cc) = child.creator_code_string() { out.push_str(&format!("/{cc}")); } } @@ -528,8 +528,8 @@ fn extract( .read_resource_fork(entry) .map_err(|e| anyhow::anyhow!("read_resource_fork: {e}"))? .unwrap_or_default(); - let type_code = fourcc(entry.type_code.as_deref()); - let creator_code = fourcc(entry.creator_code.as_deref()); + let type_code = entry.type_code.unwrap_or([0; 4]); + let creator_code = entry.creator_code.unwrap_or([0; 4]); let mb = resource_fork::build_macbinary( &safe_name, &type_code, @@ -550,8 +550,8 @@ fn extract( f.write_all(&data)?; f.flush()?; if has_rsrc && mode != M::DataForkOnly { - let type_code = fourcc(entry.type_code.as_deref()); - let creator_code = fourcc(entry.creator_code.as_deref()); + let type_code = entry.type_code.unwrap_or([0; 4]); + let creator_code = entry.creator_code.unwrap_or([0; 4]); let rsrc = fs .read_resource_fork(entry) .map_err(|e| anyhow::anyhow!("read_resource_fork: {e}"))? @@ -597,16 +597,6 @@ fn extract( Ok(()) } -fn fourcc(s: Option<&str>) -> [u8; 4] { - let mut out = [0u8; 4]; - if let Some(code) = s { - let bytes = code.as_bytes(); - let n = bytes.len().min(4); - out[..n].copy_from_slice(&bytes[..n]); - } - out -} - fn parse_resource_fork_mode(s: &str) -> Option { match s.to_ascii_lowercase().replace('-', "").as_str() { "dataonly" | "data" => Some(CliResourceForkMode::DataOnly), diff --git a/src/optical/browse_view.rs b/src/optical/browse_view.rs index bc76778..01f7419 100644 --- a/src/optical/browse_view.rs +++ b/src/optical/browse_view.rs @@ -364,10 +364,10 @@ impl OpticalDiscBrowseView { ui.label(egui::RichText::new(&entry.name).strong()); ui.horizontal(|ui| { ui.label(format!("Size: {}", entry.size_string())); - if let Some(ref tc) = entry.type_code { + if let Some(tc) = entry.type_code_string() { ui.label(format!("Type: {tc}")); } - if let Some(ref cc) = entry.creator_code { + if let Some(cc) = entry.creator_code_string() { ui.label(format!("Creator: {cc}")); } if let Some(rsrc) = entry.resource_fork_size { @@ -684,9 +684,9 @@ fn walk_optical_tree( out.push_str(&format!(" (rsrc: {})", format_size(rsrc))); } } - if let Some(ref tc) = child.type_code { + if let Some(tc) = child.type_code_string() { out.push_str(&format!(" {tc}")); - if let Some(ref cc) = child.creator_code { + if let Some(cc) = child.creator_code_string() { out.push_str(&format!("/{cc}")); } } @@ -768,16 +768,8 @@ fn extract_entry( let data = fs.read_file(entry)?; let rsrc_data = fs.read_resource_fork(entry)?.unwrap_or_default(); - let type_code = entry - .type_code - .as_ref() - .map(|s| fourcc_bytes(s)) - .unwrap_or([0; 4]); - let creator_code = entry - .creator_code - .as_ref() - .map(|s| fourcc_bytes(s)) - .unwrap_or([0; 4]); + let type_code = entry.type_code.unwrap_or([0; 4]); + let creator_code = entry.creator_code.unwrap_or([0; 4]); let mb = resource_fork::build_macbinary( &safe_name, @@ -809,16 +801,8 @@ fn extract_entry( // Handle resource fork if has_rsrc && resource_fork_mode != ResourceForkMode::DataForkOnly { - let type_code = entry - .type_code - .as_ref() - .map(|s| fourcc_bytes(s)) - .unwrap_or([0; 4]); - let creator_code = entry - .creator_code - .as_ref() - .map(|s| fourcc_bytes(s)) - .unwrap_or([0; 4]); + let type_code = entry.type_code.unwrap_or([0; 4]); + let creator_code = entry.creator_code.unwrap_or([0; 4]); let rsrc_data = fs.read_resource_fork(entry)?.unwrap_or_default(); @@ -873,16 +857,6 @@ fn extract_entry( Ok(()) } -/// Convert a 4-character type/creator string to a byte array. -fn fourcc_bytes(s: &str) -> [u8; 4] { - let bytes = s.as_bytes(); - let mut result = [b' '; 4]; - for (i, &b) in bytes.iter().take(4).enumerate() { - result[i] = b; - } - result -} - /// Human-friendly size string. fn format_size(bytes: u64) -> String { match bytes {