{"id":19916693,"url":"https://github.com/encounter/nod","last_synced_at":"2026-03-10T03:03:59.755Z","repository":{"id":57645320,"uuid":"399103494","full_name":"encounter/nod","owner":"encounter","description":"Rust crate for reading GameCube and Wii disc images","archived":false,"fork":false,"pushed_at":"2026-03-09T07:48:00.000Z","size":977,"stargazers_count":37,"open_issues_count":6,"forks_count":4,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-03-09T12:08:07.058Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/encounter.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-08-23T12:56:19.000Z","updated_at":"2026-03-09T07:48:03.000Z","dependencies_parsed_at":"2024-02-24T20:33:14.355Z","dependency_job_id":"739cf7f7-2e27-40bd-bfaf-cd80f088d875","html_url":"https://github.com/encounter/nod","commit_stats":{"total_commits":10,"total_committers":2,"mean_commits":5.0,"dds":0.09999999999999998,"last_synced_commit":"50f171dcf5bc13c579039fbf3f41e27769ce82bb"},"previous_names":["encounter/nod-rs"],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/encounter/nod","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/encounter%2Fnod","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/encounter%2Fnod/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/encounter%2Fnod/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/encounter%2Fnod/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/encounter","download_url":"https://codeload.github.com/encounter/nod/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/encounter%2Fnod/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30322648,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-10T01:36:58.598Z","status":"online","status_checked_at":"2026-03-10T02:00:06.579Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-12T21:47:18.555Z","updated_at":"2026-03-10T03:03:59.749Z","avatar_url":"https://github.com/encounter.png","language":"Rust","funding_links":[],"categories":["🔧 Middleware \u0026 SDKs"],"sub_categories":["Nintendo SDKs \u0026 Hardware"],"readme":"# nod [![Build Status]][actions] [![Latest Version]][crates.io] [![Api Rustdoc]][rustdoc] ![Rust Version]\n\n[Build Status]: https://github.com/encounter/nod/actions/workflows/build.yaml/badge.svg\n[actions]: https://github.com/encounter/nod/actions\n[Latest Version]: https://img.shields.io/crates/v/nod.svg\n[crates.io]: https://crates.io/crates/nod\n[Api Rustdoc]: https://img.shields.io/badge/api-rustdoc-blue.svg\n[rustdoc]: https://docs.rs/nod\n[Rust Version]: https://img.shields.io/badge/rust-1.85+-blue.svg?maxAge=3600\n\nLibrary for reading and writing Nintendo Optical Disc (GameCube and Wii) images.\n\nPrimarily a Rust crate with a [C API](#c-api) for integration with C and C++ projects.\n\nOriginally based on the C++ library [nod](https://github.com/AxioDL/nod),\nbut with extended format support and many additional features.\n\nCurrently supported file formats:\n\n- ISO (GCM)\n- WIA / RVZ\n- WBFS (+ NKit 2 lossless)\n- CISO (+ NKit 2 lossless)\n- NFS (Wii U VC, read-only)\n- GCZ\n- TGC\n\n## CLI tool\n\nThis crate includes a command-line tool called `nodtool`.\n\nDownload the latest release from the [releases page](https://github.com/encounter/nod-rs/releases),\nor install it using Cargo:\n\n```shell\ncargo install --locked nodtool\n```\n\n### info\n\nDisplays information about a disc image.\n\n```shell\nnodtool info /path/to/game.iso\n```\n\n### extract\n\nExtracts the contents of a disc image to a directory.\n\n```shell\nnodtool extract /path/to/game.iso [outdir]\n```\n\nFor Wii U VC titles, use `content/hif_000000.nfs`:\n\n```shell\nnodtool extract /path/to/game/content/hif_000000.nfs [outdir]\n```\n\n### convert\n\nConverts a disc image to any supported format.\n\nSee `nodtool convert --help` for more information.\n\n```shell\nnodtool convert /path/to/game.iso /path/to/game.rvz\n```\n\n### verify\n\nVerifies a disc image against an internal Redump database.\n\n```shell\nnodtool verify /path/to/game.iso\n```\n\n## Library example\n\nOpening a disc image and reading a file:\n\n```rust\nuse std::io::Read;\n\nuse nod::{\n    common::PartitionKind,\n    read::{DiscOptions, DiscReader, PartitionOptions},\n};\n\n// Open a disc image and the first data partition.\nlet disc =\n    DiscReader::new(\"path/to/file.iso\", \u0026DiscOptions::default()).expect(\"Failed to open disc\");\nlet mut partition = disc\n    .open_partition_kind(PartitionKind::Data, \u0026PartitionOptions::default())\n    .expect(\"Failed to open data partition\");\n\n// Read partition metadata and the file system table.\nlet meta = partition.meta().expect(\"Failed to read partition metadata\");\nlet fst = meta.fst().expect(\"File system table is invalid\");\n\n// Find a file by path and read it into a string.\nif let Some((_, node)) = fst.find(\"/MP3/Worlds.txt\") {\n    let mut s = String::new();\n    partition\n        .open_file(node)\n        .expect(\"Failed to open file stream\")\n        .read_to_string(\u0026mut s)\n        .expect(\"Failed to read file\");\n    println!(\"{}\", s);\n}\n```\n\nConverting a disc image to raw ISO:\n\n```rust\nuse nod::read::{DiscOptions, DiscReader, PartitionEncryption};\n\nlet options = DiscOptions {\n    partition_encryption: PartitionEncryption::Original,\n    // Use 4 threads to preload data as the disc is read. This can speed up sequential reads,\n    // especially when the disc image format uses compression.\n    preloader_threads: 4,\n};\n// Open a disc image.\nlet mut disc = DiscReader::new(\"path/to/file.rvz\", \u0026options).expect(\"Failed to open disc\");\n\n// Create a new output file.\nlet mut out = std::fs::File::create(\"output.iso\").expect(\"Failed to create output file\");\n// Read directly from the DiscReader and write to the output file.\n// NOTE: Any copy method that accepts `Read` and `Write` can be used here,\n// such as `std::io::copy`. This example utilizes `BufRead` for efficiency,\n// since `DiscReader` has its own internal buffer.\nnod::util::buf_copy(\u0026mut disc, \u0026mut out).expect(\"Failed to write data\");\n```\n\nConverting a disc image to RVZ:\n\n```rust\nuse std::fs::File;\nuse std::io::{Seek, Write};\nuse nod::common::{Compression, Format};\nuse nod::read::{DiscOptions, DiscReader, PartitionEncryption};\nuse nod::write::{DiscWriter, DiscWriterWeight, FormatOptions, ProcessOptions};\n\nlet open_options = DiscOptions {\n    partition_encryption: PartitionEncryption::Original,\n    // Use 4 threads to preload data as the disc is read. This can speed up sequential reads,\n    // especially when the disc image format uses compression.\n    preloader_threads: 4,\n};\n// Open a disc image.\nlet disc = DiscReader::new(\"path/to/file.iso\", \u0026open_options)\n    .expect(\"Failed to open disc\");\n// Create a new output file.\nlet mut output_file = File::create(\"output.rvz\")\n    .expect(\"Failed to create output file\");\n\nlet options = FormatOptions {\n    format: Format::Rvz,\n    compression: Compression::Zstandard(19),\n    block_size: Format::Rvz.default_block_size(),\n};\n// Create a disc writer with the desired output format.\nlet mut writer = DiscWriter::new(disc, \u0026options)\n    .expect(\"Failed to create writer\");\n\n// Ideally we'd base this on the actual number of CPUs available.\n// This is just an example.\nlet num_threads = match writer.weight() {\n    DiscWriterWeight::Light =\u003e 0,\n    DiscWriterWeight::Medium =\u003e 4,\n    DiscWriterWeight::Heavy =\u003e 12,\n};\nlet process_options = ProcessOptions {\n    processor_threads: num_threads,\n    // Enable checksum calculation for the _original_ disc data.\n    // Digests will be stored in the output file for verification, if supported.\n    // They will also be returned in the finalization result.\n    digest_crc32: true,\n    digest_md5: false, // MD5 is slow, skip it\n    digest_sha1: true,\n    digest_xxh64: true,\n};\n// Start processing the disc image.\nlet finalization = writer.process(\n    |data, _progress, _total| {\n        output_file.write_all(data.as_ref())?;\n        // One could display progress here, if desired.\n        Ok(())\n    },\n    \u0026process_options\n)\n.expect(\"Failed to process disc image\");\n\n// Some disc writers calculate data during processing.\n// If the finalization returns header data, seek to the beginning of the file and write it.\nif !finalization.header.is_empty() {\n    output_file.rewind()\n        .expect(\"Failed to seek\");\n    output_file.write_all(finalization.header.as_ref())\n        .expect(\"Failed to write header\");\n}\noutput_file.flush().expect(\"Failed to flush output file\");\n\n// Display the calculated digests.\nprintln!(\"CRC32: {:08X}\", finalization.crc32.unwrap());\n// ...\n```\n\n## C API\n\nThis repository also provides a [C API](nod-ffi/include/nod.h) for interfacing with other languages.\n\nFor a full end-to-end example of using the C API, see [SDL3 IOStream Demo](nod-ffi/examples/sdl3-stream-demo/README.md).\n\n### Integration with CMake\n\nThe top-level `CMakeLists.txt` builds the Rust library via [Corrosion](https://github.com/corrosion-rs/corrosion) and exports the target `nod::nod`.\n\nFeatures can be toggled with CMake options:\n\n- `NOD_COMPRESS_BZIP2` (default `ON`)\n- `NOD_COMPRESS_LZMA` (default `ON`)\n- `NOD_COMPRESS_ZLIB` (default `ON`)\n- `NOD_COMPRESS_ZSTD` (default `ON`)\n- `NOD_THREADING` (default `ON`)\n\nExample:\n\n```cmake\ncmake_minimum_required(VERSION 3.23)\nproject(my_app C CXX)\n\ninclude(FetchContent)\n\nFetchContent_Declare(\n  nod\n  GIT_REPOSITORY https://github.com/encounter/nod.git\n  GIT_TAG [tag]\n)\n\n# Optional feature toggles\nset(NOD_COMPRESS_BZIP2 ON CACHE INTERNAL \"Enable BZIP2 support\")\nset(NOD_COMPRESS_LZMA ON CACHE INTERNAL \"Enable LZMA/LZMA2 support\")\nset(NOD_COMPRESS_ZLIB ON CACHE INTERNAL \"Enable zlib/deflate support\")\nset(NOD_COMPRESS_ZSTD ON CACHE INTERNAL \"Enable Zstandard support\")\nset(NOD_THREADING ON CACHE INTERNAL \"Enable threaded processing support\")\n\nFetchContent_MakeAvailable(nod)\n\nadd_executable(my_app main.cpp)\ntarget_link_libraries(my_app PRIVATE nod::nod)\n```\n\n## License\n\nLicensed under either of\n\n- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or \u003chttp://www.apache.org/licenses/LICENSE-2.0\u003e)\n- MIT license ([LICENSE-MIT](LICENSE-MIT) or \u003chttp://opensource.org/licenses/MIT\u003e)\n\nat your option.\n\n### Contribution\n\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any\nadditional terms or conditions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fencounter%2Fnod","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fencounter%2Fnod","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fencounter%2Fnod/lists"}