nod

Library for reading and writing Nintendo Optical Disc (GameCube and Wii) images.
Primarily a Rust crate with a C API for integration with C and C++ projects.
Originally based on the C++ library nod, but with extended format support and many additional features.
Currently supported file formats:
- ISO (GCM)
- WIA / RVZ
- WBFS (+ NKit 2 lossless)
- CISO (+ NKit 2 lossless)
- NFS (Wii U VC, read-only)
- GCZ
- TGC
CLI tool
This crate includes a command-line tool called nodtool.
Download the latest release from the releases page, or install it using Cargo:
cargo install --locked nodtool
info
Displays information about a disc image.
nodtool info /path/to/game.iso
extract
Extracts the contents of a disc image to a directory.
nodtool extract /path/to/game.iso [outdir]
For Wii U VC titles, use content/hif_000000.nfs:
nodtool extract /path/to/game/content/hif_000000.nfs [outdir]
convert
Converts a disc image to any supported format.
See nodtool convert --help for more information.
nodtool convert /path/to/game.iso /path/to/game.rvz
verify
Verifies a disc image against an internal Redump database.
nodtool verify /path/to/game.iso
Library example
Opening a disc image and reading a file:
use Read;
use ;
// Open a disc image and the first data partition.
let disc =
new.expect;
let mut partition = disc
.open_partition_kind
.expect;
// Read partition metadata and the file system table.
let meta = partition.meta.expect;
let fst = meta.fst.expect;
// Find a file by path and read it into a string.
if let Some = fst.find
Converting a disc image to raw ISO:
use ;
let options = DiscOptions ;
// Open a disc image.
let mut disc = new.expect;
// Create a new output file.
let mut out = create.expect;
// Read directly from the DiscReader and write to the output file.
// NOTE: Any copy method that accepts `Read` and `Write` can be used here,
// such as `std::io::copy`. This example utilizes `BufRead` for efficiency,
// since `DiscReader` has its own internal buffer.
buf_copy.expect;
Converting a disc image to RVZ:
use File;
use ;
use ;
use ;
use ;
let open_options = DiscOptions ;
// Open a disc image.
let disc = new
.expect;
// Create a new output file.
let mut output_file = create
.expect;
let options = FormatOptions ;
// Create a disc writer with the desired output format.
let mut writer = new
.expect;
// Ideally we'd base this on the actual number of CPUs available.
// This is just an example.
let num_threads = match writer.weight ;
let process_options = ProcessOptions ;
// Start processing the disc image.
let finalization = writer.process
.expect;
// Some disc writers calculate data during processing.
// If the finalization returns header data, seek to the beginning of the file and write it.
if !finalization.header.is_empty
output_file.flush.expect;
// Display the calculated digests.
println!;
// ...
C API
This repository also provides a C API for interfacing with other languages.
For a full end-to-end example of using the C API, see SDL3 IOStream Demo.
Integration with CMake
The top-level CMakeLists.txt builds the Rust library via Corrosion and exports the target nod::nod.
Features can be toggled with CMake options:
NOD_COMPRESS_BZIP2(defaultON)NOD_COMPRESS_LZMA(defaultON)NOD_COMPRESS_ZLIB(defaultON)NOD_COMPRESS_ZSTD(defaultON)NOD_THREADING(defaultON)
Example:
cmake_minimum_required(VERSION 3.23)
project(my_app C CXX)
include(FetchContent)
FetchContent_Declare(
nod
GIT_REPOSITORY https://github.com/encounter/nod.git
GIT_TAG [tag]
)
# Optional feature toggles
set(NOD_COMPRESS_BZIP2 ON CACHE INTERNAL "Enable BZIP2 support")
set(NOD_COMPRESS_LZMA ON CACHE INTERNAL "Enable LZMA/LZMA2 support")
set(NOD_COMPRESS_ZLIB ON CACHE INTERNAL "Enable zlib/deflate support")
set(NOD_COMPRESS_ZSTD ON CACHE INTERNAL "Enable Zstandard support")
set(NOD_THREADING ON CACHE INTERNAL "Enable threaded processing support")
FetchContent_MakeAvailable(nod)
add_executable(my_app main.cpp)
target_link_libraries(my_app PRIVATE nod::nod)
License
Licensed under either of
- Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.