lsdj_tools/
import.rs

1//! The `import` subcommand
2
3use crate::utils::{check_for_overwrite, has_extension, iter_files};
4use anyhow::{Context, Error, Result};
5use clap::Args;
6use lsdj::{
7    fs::{File, Filesystem, Index},
8    lsdsng::LsdSng,
9    name::Name,
10    serde::CompressBlockError,
11    song::SongMemory,
12    sram::SRam,
13};
14use std::path::PathBuf;
15
16/// Arguments for the `import` subcommand
17#[derive(Args)]
18#[clap(author, version, about = "Import .lsdsng's into a .sav file", long_about = None)]
19pub struct ImportArgs {
20    /// Paths to the songs that should be imported into a save
21    song: Vec<PathBuf>,
22
23    /// The output path
24    #[clap(short, long)]
25    output: PathBuf,
26}
27
28/// Import .lsdsng's into a .sav file
29pub fn import(args: ImportArgs) -> Result<()> {
30    let mut index = 0u8;
31    let mut sram = SRam::new();
32
33    for entry in iter_files(&args.song, true, &["lsdsng", "sav"]) {
34        let path = entry.path();
35
36        if index == Filesystem::FILES_CAPACITY as u8 {
37            return Err(Error::msg(
38                "Reached the maximum file limit. Aborting import.",
39            ));
40        }
41
42        if has_extension(path, "lsdsng") {
43            let lsdsng = LsdSng::from_path(path).context("Could not load {path}")?;
44            let song = lsdsng
45                .decompress()
46                .context(format!("Could not decompress {}", path.to_string_lossy()))?;
47
48            insert(&mut sram, index, &lsdsng.name()?, lsdsng.version(), &song)?;
49
50            println!("{:02} => {}", index, path.to_string_lossy());
51
52            index += 1;
53        } else if has_extension(path, "sav") {
54            let sav = SRam::from_path(path)
55                .context(format!("Could not open {}", path.to_string_lossy()))?;
56
57            for (source_index, file) in sav.filesystem.files().enumerate() {
58                if let Some(file) = file {
59                    let song = file.decompress().context(format!(
60                        "Could not decompress file {} from {}",
61                        source_index,
62                        path.to_string_lossy()
63                    ))?;
64
65                    let name = file.name()?;
66
67                    insert(&mut sram, index, &name, file.version(), &song)?;
68
69                    println!(
70                        "{:02} => {} - {}",
71                        index,
72                        path.to_string_lossy(),
73                        name.as_str(),
74                    );
75
76                    index += 1;
77                }
78            }
79        }
80    }
81
82    if check_for_overwrite(&args.output)? {
83        sram.to_path(&args.output).context(format!(
84            "Could not write SRAM to {}",
85            args.output.to_string_lossy()
86        ))?;
87
88        println!("Wrote {}", args.output.to_string_lossy());
89    }
90
91    Ok(())
92}
93
94fn insert(
95    sram: &mut SRam,
96    index: u8,
97    name: &Name<8>,
98    version: u8,
99    song: &SongMemory,
100) -> Result<()> {
101    match sram
102        .filesystem
103        .insert_file(Index::new(index), name, version, song)
104    {
105        Err(CompressBlockError::NoBlockLeft) => {
106            Err(Error::msg("Ran out of space in the SRAM memory"))
107        }
108        result => {
109            result.context("Could not insert song")?;
110            Ok(())
111        }
112    }
113}