use gcn_disk::DirectoryEntry;
use gcn_disk::Entry;
use gcn_disk::Fst;
use gcn_disk::Metadata;
use std::fs::File;
use std::io;
use std::io::Read;
use std::io::Seek;
use std::io::SeekFrom;
use std::path::PathBuf;
use clap::Parser;
use rvz::HeaderRead;
use rvz::Rvz;
#[derive(Parser)]
struct Cli {
#[arg(short, long)]
fetch_icon: bool,
files: Vec<PathBuf>,
}
enum Io {
File(File),
Rvz(Box<Rvz<File>>),
}
impl Read for Io {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self {
Self::File(file) => file.read(buf),
Self::Rvz(file) => file.read(buf),
}
}
}
impl Seek for Io {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
match self {
Self::File(file) => file.seek(pos),
Self::Rvz(file) => file.seek(pos),
}
}
}
fn ls_file<T: Read + Seek>(fst: &Fst, io: &mut T, entry: &Entry, cwd: &str) {
match entry {
Entry::File(file) => {
println!(
"index: {}, filename_offset: {}, offset: 0x{:X}, size: {}, filename: {cwd}/{}",
file.index,
file.filename_offset,
file.offset,
file.size,
fst.get_entry_filename(io, entry).unwrap()
);
}
Entry::Directory(_) => {}
}
}
fn ls_dir<T: Read + Seek>(fst: &Fst, io: &mut T, directory: &DirectoryEntry, cwd: &str) -> u32 {
let mut index = directory.index + 1;
while index != directory.end_index {
let entry = &fst.entries[index as usize];
match entry {
Entry::File(_) => {
ls_file(fst, io, entry, cwd);
index += 1;
}
Entry::Directory(directory) => {
println!(
"index: {}, filename_offset: {}, parent_index: {}, end_index: {}, dirname: {}",
directory.index,
directory.filename_offset,
directory.parent_index,
directory.end_index,
fst.get_entry_filename(io, entry).unwrap()
);
let dir_name = fst.get_entry_filename(io, entry).unwrap();
index += ls_dir(fst, io, directory, &format!("{cwd}/{dir_name}"));
}
}
}
index - directory.index
}
pub fn main() {
let args = Cli::parse();
if args.files.is_empty() {
return;
}
println!("[");
for path in args.files {
let mut f = File::open(path).unwrap();
let mut io = if f.has_rvz_magic() {
let io = Rvz::new(f);
if let Err(err) = io {
eprintln!("Error: {err}");
continue;
}
Io::Rvz(Box::new(io.unwrap()))
} else {
Io::File(f)
};
let disk = Metadata::try_from(&mut io);
if let Err(ref err) = disk {
eprintln!("Error: {err}");
continue;
}
let disk = disk.unwrap();
let fst = &disk.filesystem;
let root = &fst.entries[0];
if !matches!(root, Entry::Directory(_)) {
eprintln!("Error: root directory is not a directory");
continue;
}
if let Entry::Directory(root) = root {
ls_dir(fst, &mut io, root, "");
}
}
println!("]");
}