add more compact output to bytediff
This commit is contained in:
		
							parent
							
								
									a01fdc7de7
								
							
						
					
					
						commit
						9e62430e2d
					
				
					 1 changed files with 110 additions and 28 deletions
				
			
		|  | @ -1,7 +1,53 @@ | ||||||
| use std::fs::File; | use std::fs::File; | ||||||
| use std::io::{prelude::*, BufReader}; | use std::io::{prelude::*, BufReader}; | ||||||
|  | use std::path::PathBuf; | ||||||
| 
 | 
 | ||||||
| use anyhow::{anyhow, Context, Result}; | use anyhow::{Context, Result}; | ||||||
|  | use clap::Parser; | ||||||
|  | 
 | ||||||
|  | #[derive(Parser, Debug)] | ||||||
|  | #[clap(author, version)] | ||||||
|  | /// diff binary files
 | ||||||
|  | ///
 | ||||||
|  | /// bytediff checks whether binary files match, and prints out
 | ||||||
|  | /// a list of differences at the byte level if they don't.
 | ||||||
|  | struct Cli { | ||||||
|  |     /// Print out a full hexdump of differing bytes, not just a summary of differences
 | ||||||
|  |     #[arg(short, long)] | ||||||
|  |     detailed: bool, | ||||||
|  | 
 | ||||||
|  |     /// First file to diff
 | ||||||
|  |     #[arg(required = true)] | ||||||
|  |     file1: PathBuf, | ||||||
|  | 
 | ||||||
|  |     /// Second file to diff
 | ||||||
|  |     #[arg(required = true)] | ||||||
|  |     file2: PathBuf, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(PartialEq, Eq)] | ||||||
|  | enum DiffState { | ||||||
|  |     Same, | ||||||
|  |     DifferNonZero, | ||||||
|  |     DifferAZero, | ||||||
|  |     DifferBZero, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn is_byte_vec_zero(v: &[u8]) -> bool { | ||||||
|  |     v.iter().all(|c| *c == 0u8) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn compare_byte_vecs(a: &[u8], b: &[u8]) -> DiffState { | ||||||
|  |     if a == b { | ||||||
|  |         DiffState::Same | ||||||
|  |     } else if is_byte_vec_zero(a) { | ||||||
|  |         DiffState::DifferAZero | ||||||
|  |     } else if is_byte_vec_zero(b) { | ||||||
|  |         DiffState::DifferBZero | ||||||
|  |     } else { | ||||||
|  |         DiffState::DifferNonZero | ||||||
|  |     } | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| struct ZipLonger<A: Iterator, B: Iterator> { | struct ZipLonger<A: Iterator, B: Iterator> { | ||||||
|     a: A, |     a: A, | ||||||
|  | @ -83,47 +129,45 @@ fn color_byte_display(this: &[u8], that: &[u8], color: u8) -> String { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn main() -> Result<()> { | fn main() -> Result<()> { | ||||||
|     let mut args = std::env::args(); |     let cli = Cli::parse(); | ||||||
|     let name = args | 
 | ||||||
|         .next() |     let a = cli.file1; | ||||||
|         .ok_or_else(|| anyhow!("Missing executable name in args"))?; |     let b = cli.file2; | ||||||
|     let (a, b) = match (args.next(), args.next()) { |  | ||||||
|         (Some(a), Some(b)) => (a, b), |  | ||||||
|         _ => return Err(anyhow!("Usage: {} file file", name)), |  | ||||||
|     }; |  | ||||||
| 
 | 
 | ||||||
|     let a_bytes = BufReader::new( |     let a_bytes = BufReader::new( | ||||||
|         File::open(a.clone()).with_context(|| format!("Failed to open input file {}", a))?, |         File::open(a.clone()) | ||||||
|  |             .with_context(|| format!("Failed to open input file {}", a.display()))?, | ||||||
|     ) |     ) | ||||||
|     .bytes(); |     .bytes(); | ||||||
|     let b_bytes = BufReader::new( |     let b_bytes = BufReader::new( | ||||||
|         File::open(b.clone()).with_context(|| format!("Failed to open input file {}", b))?, |         File::open(b.clone()) | ||||||
|  |             .with_context(|| format!("Failed to open input file {}", b.display()))?, | ||||||
|     ) |     ) | ||||||
|     .bytes(); |     .bytes(); | ||||||
| 
 | 
 | ||||||
|     let mut in_differing_region = false; |     let mut diff_state = DiffState::Same; | ||||||
|  |     let mut region_start: usize = 0; | ||||||
| 
 | 
 | ||||||
|     for (i, (rva, rvb)) in |     for (i, (rva, rvb)) in | ||||||
|         ZipLonger::new(Chunks::new(a_bytes, 16), Chunks::new(b_bytes, 16)).enumerate() |         ZipLonger::new(Chunks::new(a_bytes, 16), Chunks::new(b_bytes, 16)).enumerate() | ||||||
|     { |     { | ||||||
|         let va: Vec<u8> = rva |         let va: Vec<u8> = rva | ||||||
|             .transpose() |             .transpose() | ||||||
|             .with_context(|| format!("Error reading from input file {}", a))? |             .with_context(|| format!("Error reading from input file {}", a.display()))? | ||||||
|             .unwrap_or_default(); |             .unwrap_or_default(); | ||||||
|         let vb: Vec<u8> = rvb |         let vb: Vec<u8> = rvb | ||||||
|             .transpose() |             .transpose() | ||||||
|             .with_context(|| format!("Error reading from input file {}", b))? |             .with_context(|| format!("Error reading from input file {}", b.display()))? | ||||||
|             .unwrap_or_default(); |             .unwrap_or_default(); | ||||||
| 
 | 
 | ||||||
|         if va == vb { |         let new_diff_state = compare_byte_vecs(&va, &vb); | ||||||
|             if in_differing_region { | 
 | ||||||
|                 in_differing_region = false; |         if cli.detailed { | ||||||
|  |             if new_diff_state == DiffState::Same { | ||||||
|  |                 if diff_state != DiffState::Same { | ||||||
|                     println!("---"); |                     println!("---"); | ||||||
|                 } |                 } | ||||||
|             continue; |             } else { | ||||||
|         } |  | ||||||
|         in_differing_region = true; |  | ||||||
| 
 |  | ||||||
|                 println!( |                 println!( | ||||||
|                     "{0:08x}: {1}\n{0:08x}: {2}", |                     "{0:08x}: {1}\n{0:08x}: {2}", | ||||||
|                     i * 16, |                     i * 16, | ||||||
|  | @ -131,6 +175,44 @@ fn main() -> Result<()> { | ||||||
|                     color_byte_display(&vb, &va, 32), |                     color_byte_display(&vb, &va, 32), | ||||||
|                 ); |                 ); | ||||||
|             } |             } | ||||||
|  |         } else { | ||||||
|  |             if new_diff_state != diff_state { | ||||||
|  |                 if diff_state != DiffState::Same { | ||||||
|  |                     print!("{0:08x} to {1:08x}: ", region_start, i * 16); | ||||||
|  |                 } | ||||||
|  |                 match diff_state { | ||||||
|  |                     DiffState::Same => (), | ||||||
|  |                     DiffState::DifferAZero => { | ||||||
|  |                         println!("First file is zero bytes"); | ||||||
|  |                     } | ||||||
|  |                     DiffState::DifferBZero => { | ||||||
|  |                         println!("Second file is zero bytes"); | ||||||
|  |                     } | ||||||
|  |                     DiffState::DifferNonZero => { | ||||||
|  |                         println!("Files differ"); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 region_start = i * 16; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         diff_state = new_diff_state; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     match diff_state { | ||||||
|  |         DiffState::Same => (), | ||||||
|  |         DiffState::DifferAZero => { | ||||||
|  |             println!("First file is zero bytes from {0:08x} to end", region_start); | ||||||
|  |         } | ||||||
|  |         DiffState::DifferBZero => { | ||||||
|  |             println!( | ||||||
|  |                 "Second file is zero bytes from {0:08x} to end", | ||||||
|  |                 region_start | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |         DiffState::DifferNonZero => { | ||||||
|  |             println!("Files differ from {0:08x} to end", region_start); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     Ok(()) |     Ok(()) | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue