diff --git a/Cargo.lock b/Cargo.lock index 5a7daf6..130964f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,14 +3,152 @@ version = 3 [[package]] -name = "byteorder" -version = "1.4.3" +name = "atty" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "clap" +version = "4.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91b9970d7505127a162fdaa9b96428d28a479ba78c9ec7550a63a5d9863db682" +dependencies = [ + "atty", + "bitflags", + "clap_lex", + "once_cell", + "strsim", + "termcolor", +] + +[[package]] +name = "clap_lex" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "itoa" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" + +[[package]] +name = "libc" +version = "0.2.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" [[package]] name = "losteden" version = "0.1.0" dependencies = [ - "byteorder", + "clap", + "serde", + "serde_json", ] + +[[package]] +name = "once_cell" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" + +[[package]] +name = "os_str_bytes" +version = "6.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3baf96e39c5359d2eb0dd6ccb42c62b91d9678aa68160d261b9e0ccbf9e9dea9" + +[[package]] +name = "ryu" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + +[[package]] +name = "serde" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" + +[[package]] +name = "serde_json" +version = "1.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 13bcb8b..d2111c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -byteorder = "1.4.3" \ No newline at end of file +clap = { version = "4.0.22", features = ["cargo"] } +serde = "1.0.147" +serde_json = "1.0.87" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 6ddb3a1..543bffb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,6 @@ use std::fs::File; -use std::io::{Read, Seek, Write}; - -// https://gist.github.com/falsovsky/da9a2de2c9a65282527fbd462bd92914 -// https://github.com/scummvm/scummvm/blob/90f2ff2532ca71033b4393b9ce604c9b0e6cafa0/engines/cryo/defs.h#L761 -// https://github.com/scummvm/scummvm/blob/master/engines/cryo/resource.cpp#L73 +use std::fs; +use std::io::{BufWriter, Read, Seek, SeekFrom, Write}; #[derive(Debug)] struct DatHeader { @@ -12,8 +9,22 @@ struct DatHeader { } impl DatHeader { - fn new(total: u16) -> Self { - Self { total, files: Vec::new() } + fn new(filename: &str) -> Self { + let mut f = File::open(filename).unwrap(); + // Read Total Files + let mut file_dat: [u8; 2] = [0; 2]; + let _ = f.read(&mut file_dat); + let mut result = DatHeader::from_bytes(file_dat); + for _ in 0..result.total { + let mut file_dat: [u8; 25] = [0; 25]; + let _ = f.read(&mut file_dat); + if file_dat[0] == 0 { + continue + } + let my_file = DatFile::from_bytes(file_dat); + result.files.push(my_file); + } + result } fn from_bytes(buffer: [u8; 2]) -> Self { @@ -69,33 +80,112 @@ impl DatFile { } } -fn main() -> std::io::Result<()> { - let mut f = File::open("EDEN.DAT")?; +#[derive(Debug)] +struct JsonFile { + name: String, + padding: u32, +} - // Read Total Files - let mut file_dat: [u8; 2] = [0; 2]; - let _ = f.read(&mut file_dat); - let mut dat = DatHeader::from_bytes(file_dat); +fn extract_file(rec: &DatFile) { + let mut source = File::open("EDEN.DAT").unwrap(); + let _ = source.seek(SeekFrom::Start(rec.offset as u64)).unwrap(); - println!("Valor: {:?} - Hex: {:02X?}", dat.total, dat.to_bytes()); + let filename = format!("extract/{}", rec.name); + let mut destination = File::create(filename).unwrap(); - for _ in 0..dat.total { - let mut file_dat: [u8; 25] = [0; 25]; - let _ = f.read(&mut file_dat); + let mut contents: Vec = Vec::new(); + let _ = source.take(rec.size as u64).read_to_end(&mut contents); + let _ = destination.write(&*contents); +} - if file_dat[0] == 0 { - continue - } - let my_file = DatFile::from_bytes(file_dat); - println!("{:?} - {:02X?}", my_file, my_file.to_bytes()); - dat.files.push(my_file); +fn create_json(dat: &DatHeader) { + let mut file_list: Vec = Vec::new(); + for f in &dat.files { + file_list.push(format!("extract/{}", f.name.clone())); } + let mut w = BufWriter::new(File::create("list.json").unwrap()); + serde_json::to_writer_pretty(&mut w, &file_list).unwrap(); + w.flush().unwrap(); +} - let mut f = File::create("NOVO.DAT")?; +fn read_json() -> Vec { + let data = fs::read_to_string("list.json").expect("Unable to read file"); + serde_json::from_str(&data).expect("Unable to parse") +} + +fn create_dat(files: Vec) { + let mut f = File::create("NOVO.DAT").unwrap(); + let dat: DatHeader = DatHeader { total: 2621, files: Vec::new() }; let _ = f.write(&dat.to_bytes()); - for file in dat.files { - let _ = f.write(&file.to_bytes()); + let mut jsonfiles : Vec = Vec::new(); + let mut address: i32 = 65536; + for file in files { + // Obter tamanho do ficheiro + let file_size: i32 = fs::metadata(&file).unwrap().len() as i32; + // Separar o Nome da Path + let split: Vec<_> = file.split('/').collect(); + let file_name = split[1].clone(); + // Gravar info da Header + let datfile = DatFile::new(file_name.to_string(), file_size as u32, address as u32, 0); + let _ = f.write(&datfile.to_bytes()); + // Ver se o final do ficheiro está alinhado a 16 + address += file_size; + address += (-address).checked_rem_euclid(16).unwrap(); + jsonfiles.push(JsonFile { name: file.to_string(), padding: address as u32 }); } - Ok(()) + // Preencher ate 65535 com 0 + let new_position = f.seek(SeekFrom::Current(0)).unwrap(); + if new_position < 65536 { + for _ in new_position..65536 { + let _ = f.write(&[0]); + } + } + + // Gravar conteudo dos ficheiros no DAT + for file in jsonfiles { + let mut source = File::open(file.name).unwrap(); + let mut contents: Vec = Vec::new(); + let _ = source.read_to_end(&mut contents); + let _ = f.write(&*contents); + let current_position= f.seek(SeekFrom::Current(0)).unwrap() as u32; + if current_position < file.padding { + for _ in current_position..file.padding { + let _ = f.write(&[0]); + } + } + } +} + +fn main() { + let cmd = clap::Command::new(env!("CARGO_CRATE_NAME")) + .multicall(false) + .arg_required_else_help(true) + .subcommand_value_name("COMMAND") + .subcommand_help_heading("COMMAND") + .subcommand(clap::Command::new("extract").about("Extracts all files from EDEN.DAT")) + .subcommand( + clap::Command::new("json").about("Creates a JSON with the list of files inside EDEN.DAT") + ) + .subcommand(clap::Command::new("generate").about("Creates a new EDEN.DAT based on list.json")); + + match cmd.get_matches().subcommand_name() { + Some("extract") => { + let dat = DatHeader::new("EDEN.DAT"); + for f in dat.files { + extract_file(&f); + println!("Extracting {} - Size: {}, Offset: {}", &f.name, &f.size, &f.offset) + } + } + Some("json") => { + let dat = DatHeader::new("EDEN.DAT"); + create_json(&dat); + println!("Created {}", "list.json"); + } + Some("generate") => { + let files = read_json(); + create_dat(files); + } + _ => unreachable!("parser should ensure only valid subcommand names are used"), + } } \ No newline at end of file