diff --git a/Cargo.lock b/Cargo.lock index ca6c04c..d2ae7bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aho-corasick" version = "1.1.2" @@ -59,12 +74,53 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "async-trait" +version = "0.1.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + [[package]] name = "bytestream" version = "0.4.1" @@ -74,6 +130,18 @@ dependencies = [ "byteorder", ] +[[package]] +name = "cc" +version = "1.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "clap" version = "4.5.1" @@ -120,12 +188,57 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + [[package]] name = "hashbrown" version = "0.14.3" @@ -138,6 +251,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "indexmap" version = "2.2.5" @@ -148,12 +267,27 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + [[package]] name = "memchr" version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +[[package]] +name = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", +] + [[package]] name = "msbt" version = "0.1.0" @@ -162,10 +296,26 @@ dependencies = [ "clap", "regex", "serde", + "sha256", "thiserror", "toml", ] +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + [[package]] name = "proc-macro2" version = "1.0.78" @@ -213,6 +363,12 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "serde" version = "1.0.197" @@ -242,6 +398,30 @@ dependencies = [ "serde", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha256" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18278f6a914fa3070aa316493f7d2ddfb9ac86ebc06fa3b83bffda487e9065b0" +dependencies = [ + "async-trait", + "bytes", + "hex", + "sha2", + "tokio", +] + [[package]] name = "strsim" version = "0.11.0" @@ -279,6 +459,17 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio" +version = "1.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +dependencies = [ + "backtrace", + "bytes", + "pin-project-lite", +] + [[package]] name = "toml" version = "0.8.10" @@ -313,6 +504,12 @@ dependencies = [ "winnow", ] +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -325,6 +522,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "windows-sys" version = "0.52.0" diff --git a/Cargo.toml b/Cargo.toml index c246082..d8d0bc6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,5 +14,6 @@ bytestream = "0.4.1" clap = { version = "4.5.1", features = ["derive"] } regex = "1.10.3" serde = { version = "1.0.197", features = ["derive"] } +sha256 = "1.5.0" thiserror = "1.0.56" toml = "0.8.10" diff --git a/src/diff_utils.rs b/src/diff_utils.rs index 2758e2b..457f985 100644 --- a/src/diff_utils.rs +++ b/src/diff_utils.rs @@ -1,21 +1,41 @@ use crate::msbt::MSBTString; -pub fn get_added(original: Vec, edited: Vec) -> Vec { +pub fn get_added(original: Vec, vec_edited: Vec>) -> Vec { let mut result = Vec::::new(); - for string in edited { - let index = original.iter().position(|s| s.label == string.label); - if index.is_none(){ - result.push(string); + for edited in vec_edited{ + for string in edited { + let index = original.iter().position(|s| s.label == string.label); + if index.is_none(){ + result.push(string); + } } } return result; } -pub fn get_deleted(original: Vec, edited: Vec) -> Vec { +pub fn get_deleted(original: Vec, vec_edited: Vec>) -> Vec { let mut result = Vec::::new(); - for string in original { - let index = edited.iter().position(|s| s.label == string.label); - if index.is_none(){ - result.push(string); + for edited in vec_edited{ + for string in &original { + let index = edited.iter().position(|s| s.label == string.label); + if index.is_none(){ + result.push(string.to_owned()); + } + } + } + return result; +} + +pub fn get_edited(original: Vec, vec_edited: Vec>) -> Vec { + let mut result = Vec::::new(); + for edited in vec_edited{ + for string in edited { + let index = original.iter().position(|s| s.label == string.label); + if !index.is_none(){ + let string_original = original.get(index.unwrap()).unwrap(); + if string_original.string != string.string{ + result.push(string); + } + } } } return result; diff --git a/src/main.rs b/src/main.rs index 8685d3c..d13a70e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,19 +1,16 @@ use std::{ - collections::HashMap, - ffi::OsStr, - fs::File, - io::{Read, Write}, - path::Path, - string, + collections::HashMap, convert, ffi::OsStr, fs::{self, File}, io::{Read, Write}, path::Path, string }; -use ::msbt::msbt::MSBTString; +use ::msbt::msbt::{MSBTString, MSBT}; use bytestream::ByteOrder; use clap::{Parser, ValueEnum}; use msbt::msbt; use serde::{Deserialize, Serialize}; use toml; +mod diff_utils; + #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] struct Args { @@ -47,7 +44,7 @@ fn main() -> ::msbt::Result<()> { match args.action { Actions::EXTRACT => return extract_msbt(args), Actions::CREATE => return create_msbt(args), - Actions::DIFF => todo!(), + Actions::DIFF => return diff_msbt(args), Actions::PATCH => todo!(), } } @@ -103,6 +100,93 @@ fn create_msbt(args: Args) -> ::msbt::Result<()> { Ok(()) } +fn diff_msbt(args: Args) -> ::msbt::Result<()> { + let arg_filename = args.original.clone(); + let path = Path::new(&arg_filename); + let filename = path.file_stem().unwrap().to_str().unwrap(); + let extension = path.extension().unwrap().to_str().unwrap().to_lowercase(); + + //Getting original strings... + let mut orig_strings = Vec::::new(); + let mut hash; + let mut endianness; + if extension == "msbt" { + let bytes = fs::read(args.original.clone()).unwrap(); + hash = sha256::digest(&bytes); + let mut file = File::open(args.original)?; + let msbt = msbt::from_binary(&mut file)?; + endianness = msbt.endianness; + orig_strings = msbt::get_strings(msbt.clone())?; + } else { //Just assume it's toml + let file = File::open(args.original)?; + let toml = get_toml(file)?; + endianness = get_endianness_toml(&toml)?; + orig_strings = get_strings_toml(&toml)?; + hash = "".to_owned(); + } + + //Getting edited strings... + let mut edited_strings = Vec::>::new(); + for path_edited in args.edited { + let mut edited_string_single = Vec::::new(); + let arg_filename = path_edited.clone(); + let path = Path::new(&arg_filename); + let extension = path.extension().unwrap().to_str().unwrap().to_lowercase(); + if extension == "msbt" { + let mut file = File::open(path_edited)?; + let msbt = msbt::from_binary(&mut file)?; + edited_string_single = msbt::get_strings(msbt.clone())?; + } else { //Just assume it's toml + let file = File::open(path_edited)?; + let toml = get_toml(file)?; + edited_string_single = get_strings_toml(&toml)?; + } + edited_strings.push(edited_string_single); + } + let added_strings = diff_utils::get_added(orig_strings.clone(), edited_strings.clone()); + let deleted_strings = diff_utils::get_deleted(orig_strings.clone(), edited_strings.clone()); + let edited_strings = diff_utils::get_edited(orig_strings, edited_strings); + let mut diff_file = File::create(filename.to_owned()+".msbd.txt")?; + + //Writing file + let _ = diff_file.write((filename.to_owned()+"\n").as_bytes()); + let _ = diff_file.write((filename.to_owned()+"\n").as_bytes()); + if hash != ""{ + let _ = diff_file.write((hash+"\n").as_bytes()); + } + let _ = diff_file.write("\n".as_bytes()); + + //Writing added strings... + for string in added_strings{ + let label = "+".to_owned()+&string.label+"\n"; + let _ = diff_file.write(label.as_bytes()); + let mut parsed_string = ::msbt::structs::TXT2::parse_binary(string.string, endianness); + parsed_string.truncate(parsed_string.len() - 1); + parsed_string = parsed_string.replace("\n", "\n>"); + let _ = diff_file.write((">".to_owned()+&parsed_string+"\n").as_bytes()); + let _ = diff_file.write("\n".as_bytes()); + } + + //Writing deleted strings... + for string in deleted_strings{ + let label = "-".to_owned()+&string.label+"\n"; + let _ = diff_file.write(label.as_bytes()); + let _ = diff_file.write("\n".as_bytes()); + } + + //Writing edits... + for string in edited_strings{ + let label = "~".to_owned()+&string.label+"\n"; + let _ = diff_file.write(label.as_bytes()); + let mut parsed_string = ::msbt::structs::TXT2::parse_binary(string.string, endianness); + parsed_string.truncate(parsed_string.len() - 1); + parsed_string = parsed_string.replace("\n", "\n>"); + let _ = diff_file.write((">".to_owned()+&parsed_string+"\n").as_bytes()); + let _ = diff_file.write("\n".as_bytes()); + } + Ok(()) +} + fn get_toml(mut file: File) -> ::msbt::Result{ let mut toml_string = "".to_owned(); let _ = file.read_to_string(&mut toml_string);