use clap::{Parser, Subcommand};
use std::fs;
use std::path::PathBuf;
use std::str::FromStr;
use png_rusty::chunk::Chunk;
use png_rusty::chunk_type::ChunkType;
use png_rusty::errors::{Error, Result};
use png_rusty::png::Png;
#[derive(Parser, Debug)]
#[command(version, about, long_about=None)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand, Debug)]
enum Commands {
Encode {
file: PathBuf,
chunk_type: String,
secret_message: String,
},
Decode {
file: PathBuf,
chunk_type: String,
},
Remove {
file: PathBuf,
chunk_type: String,
},
Print {
file: PathBuf,
},
}
fn main() -> Result<()> {
let cli = Cli::parse();
match &cli.command {
Commands::Encode {
file,
chunk_type,
secret_message,
} => {
let file_bytes = fs::read(file)?;
let mut png = Png::try_from(file_bytes.as_slice())?;
let chunk_type = ChunkType::from_str(chunk_type)?;
let new_chunk = Chunk::new(chunk_type, secret_message.as_bytes().to_vec());
png.append_chunk(new_chunk);
fs::write("img/hidden.png", png.as_bytes())?;
}
Commands::Decode { file, chunk_type } => {
let file_bytes = fs::read(file)?;
let png = Png::try_from(file_bytes.as_slice())?;
let chunk = match png.chunk_by_type(chunk_type) {
Some(chunk) => chunk,
None => {
return Err(Error::from("No chunk found for specified chunk type"));
}
};
let hidden_string = chunk.data_as_string()?;
println!("Hidden message:'{hidden_string}'");
}
Commands::Remove { file, chunk_type } => {
let file_bytes = fs::read(file)?;
let mut png = Png::try_from(file_bytes.as_slice())?;
let chunk = png.remove_first_chunk(chunk_type.as_str())?;
println!("Removed chunk : {chunk}");
fs::write("img/removed_chunk.png", png.as_bytes())?;
}
Commands::Print { file } => {
let file_bytes = fs::read(file)?;
let png = Png::try_from(file_bytes.as_slice())?;
println!("PNG file content : {png}");
}
}
Ok(())
}