|
@@ -6,11 +6,11 @@ use std::{
|
|
|
};
|
|
|
|
|
|
use binrw::{BinRead, BinWrite, BinWriterExt};
|
|
|
-use clap::Parser;
|
|
|
+use clap::{Args, Parser, Subcommand};
|
|
|
use clap_verbosity_flag::{InfoLevel, Verbosity};
|
|
|
use diff::Diff;
|
|
|
use env_logger::Target;
|
|
|
-use ezcad::file::EzCadHeader;
|
|
|
+use ezcad::{file::EzCadHeader, layer::Layer, objects::Object};
|
|
|
use log::{info, trace, warn};
|
|
|
|
|
|
use crate::config::{Config, Operations};
|
|
@@ -19,24 +19,58 @@ mod config;
|
|
|
|
|
|
#[derive(Debug, Parser)]
|
|
|
struct Cli {
|
|
|
- /// Input file to parse
|
|
|
+ #[command(subcommand)]
|
|
|
+ command: SubCommands,
|
|
|
+
|
|
|
+ /// Input .mlp file to parse
|
|
|
#[arg(short, long)]
|
|
|
input: PathBuf,
|
|
|
|
|
|
+ #[command(flatten)]
|
|
|
+ verbose: Verbosity<InfoLevel>,
|
|
|
+}
|
|
|
+
|
|
|
+#[derive(Debug, Subcommand)]
|
|
|
+enum SubCommands {
|
|
|
+ Diff(DiffCmd),
|
|
|
+ Query(QueryCmd),
|
|
|
+ Apply(ApplyConfig),
|
|
|
+}
|
|
|
+
|
|
|
+/// Diff two .mlp files and print differences between the two
|
|
|
+#[derive(Debug, Args)]
|
|
|
+struct DiffCmd {
|
|
|
/// File to diff input against
|
|
|
#[arg(short, long)]
|
|
|
- diff: Option<PathBuf>,
|
|
|
+ diff_file: PathBuf,
|
|
|
+}
|
|
|
|
|
|
- /// Output file to write to
|
|
|
+/// Queries input .mlp file for pen or object info
|
|
|
+#[derive(Debug, Args)]
|
|
|
+struct QueryCmd {
|
|
|
+ /// Print pen info
|
|
|
#[arg(short, long)]
|
|
|
- output: Option<PathBuf>,
|
|
|
+ pen: Option<Vec<usize>>,
|
|
|
+
|
|
|
+ /// Print object info
|
|
|
+ #[arg(short, long)]
|
|
|
+ object: Option<usize>,
|
|
|
+
|
|
|
+ /// Object layer to query object on
|
|
|
+ #[arg(short = 'b', long)]
|
|
|
+ object_layer: Option<usize>,
|
|
|
+}
|
|
|
|
|
|
+/// Applies configuration YAML to input .mlp file
|
|
|
+#[derive(Debug, Args)]
|
|
|
+struct ApplyConfig {
|
|
|
/// Configuration file
|
|
|
#[arg(short, long)]
|
|
|
- config: Option<PathBuf>,
|
|
|
+ config: PathBuf,
|
|
|
|
|
|
- #[command(flatten)]
|
|
|
- verbose: Verbosity<InfoLevel>,
|
|
|
+ /// Output file to write to
|
|
|
+ #[arg(short, long)]
|
|
|
+ output: Option<PathBuf>,
|
|
|
}
|
|
|
|
|
|
fn main() {
|
|
@@ -77,84 +111,127 @@ fn main() {
|
|
|
warn!("Re-encoded input file does not match original file!");
|
|
|
}
|
|
|
|
|
|
- // Print info on pens with non-default settings
|
|
|
- for (index, pen) in file
|
|
|
- .pens_offset
|
|
|
- .data
|
|
|
- .pens
|
|
|
- .iter()
|
|
|
- .filter(|x| *x.use_default == 0)
|
|
|
- .enumerate()
|
|
|
- {
|
|
|
- trace!("Pen {}: {:#?}", index, pen);
|
|
|
- }
|
|
|
+ match cli.command {
|
|
|
+ SubCommands::Diff(args) => {
|
|
|
+ info!(
|
|
|
+ "Processing diff file '{}'",
|
|
|
+ args.diff_file.to_string_lossy()
|
|
|
+ );
|
|
|
+ let mut diff: File = File::open(args.diff_file).expect("Failed to open diff file");
|
|
|
+ let diff_file: EzCadHeader =
|
|
|
+ EzCadHeader::read_le(&mut diff).expect("Failed to parse diff file as EZCAD format");
|
|
|
+
|
|
|
+ // Diff pens
|
|
|
+ info!(
|
|
|
+ "{:#?}",
|
|
|
+ file.pens_offset
|
|
|
+ .data
|
|
|
+ .pens
|
|
|
+ .diff(&diff_file.pens_offset.data.pens)
|
|
|
+ );
|
|
|
|
|
|
- // Print all objects
|
|
|
- for (layer_index, layer) in file.layers_offset.iter().enumerate() {
|
|
|
- for (object_index, object) in layer.objects.iter().enumerate() {
|
|
|
- trace!(
|
|
|
- "Layer {}, Object {}: {:#?}",
|
|
|
- layer_index,
|
|
|
- object_index,
|
|
|
- object
|
|
|
+ // Diff objects
|
|
|
+ info!(
|
|
|
+ "{:#?}",
|
|
|
+ file.layers_offset
|
|
|
+ .value
|
|
|
+ .diff(&diff_file.layers_offset.value)
|
|
|
);
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- // Process diff
|
|
|
- cli.diff.map(|diff| {
|
|
|
- info!("Processing diff file '{}'", diff.to_string_lossy());
|
|
|
- let mut diff: File = File::open(diff).expect("Failed to open diff file");
|
|
|
- let diff_file: EzCadHeader =
|
|
|
- EzCadHeader::read_le(&mut diff).expect("Failed to parse diff file as EZCAD format");
|
|
|
-
|
|
|
- // Diff pens
|
|
|
- info!(
|
|
|
- "{:#?}",
|
|
|
- file.pens_offset
|
|
|
+ SubCommands::Query(args) => {
|
|
|
+ // Print info on pens with non-default settings
|
|
|
+ for (index, pen) in file
|
|
|
+ .pens_offset
|
|
|
.data
|
|
|
.pens
|
|
|
- .diff(&diff_file.pens_offset.data.pens)
|
|
|
- );
|
|
|
-
|
|
|
- // Diff objects
|
|
|
- info!(
|
|
|
- "{:#?}",
|
|
|
- file.layers_offset
|
|
|
- .value
|
|
|
- .diff(&diff_file.layers_offset.value)
|
|
|
- );
|
|
|
- });
|
|
|
-
|
|
|
- // Process config
|
|
|
- cli.config.map(|config| {
|
|
|
- info!("Processing config file '{}'", config.to_string_lossy());
|
|
|
- let config: String = std::fs::read_to_string(config).expect("Failed to open config file");
|
|
|
- let config: Config = serde_yaml::from_str(&config).expect("Failed to parse config file");
|
|
|
-
|
|
|
- // Patch pen settings
|
|
|
- let time: Instant = Instant::now();
|
|
|
- config
|
|
|
- .ops
|
|
|
- .apply(&mut file.pens_offset.data.pens, &mut file.layers_offset);
|
|
|
- trace!("Config processing time: {:?}", time.elapsed());
|
|
|
- });
|
|
|
-
|
|
|
- // Process output
|
|
|
- cli.output.map(|output| {
|
|
|
- info!("Writing output file '{}'", output.to_string_lossy());
|
|
|
- // Serialize to memory buffer for perf
|
|
|
- let mut buffer: Cursor<Vec<u8>> = Cursor::new(vec![]);
|
|
|
- let time: Instant = Instant::now();
|
|
|
- buffer
|
|
|
- .write_le(&file)
|
|
|
- .expect("Failed to serialize contents as EZCAD format");
|
|
|
- trace!("Output file encode time: {:?}", time.elapsed());
|
|
|
-
|
|
|
- // Write buffer to output file
|
|
|
- let mut output: File = File::create(output).expect("Failed to open output file");
|
|
|
- output
|
|
|
- .write_all(buffer.into_inner().as_slice())
|
|
|
- .expect("Failed to write to output file");
|
|
|
- });
|
|
|
+ .iter()
|
|
|
+ .filter(|x| *x.use_default == 0)
|
|
|
+ .enumerate()
|
|
|
+ {
|
|
|
+ trace!("Pen {}: {:#?}", index, pen);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Print all objects
|
|
|
+ for (layer_index, layer) in file.layers_offset.iter().enumerate() {
|
|
|
+ for (object_index, object) in layer.objects.iter().enumerate() {
|
|
|
+ trace!(
|
|
|
+ "Layer {}, Object {}: {:#?}",
|
|
|
+ layer_index,
|
|
|
+ object_index,
|
|
|
+ object
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Process pen query
|
|
|
+ args.pen.map(|pens| {
|
|
|
+ for pen in pens {
|
|
|
+ info!(
|
|
|
+ "Pen #{}: {}",
|
|
|
+ pen,
|
|
|
+ file.pens_offset
|
|
|
+ .data
|
|
|
+ .pens
|
|
|
+ .get(pen)
|
|
|
+ .expect("Invalid pen index")
|
|
|
+ );
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // Process object query
|
|
|
+ args.object.map(|obj_index| {
|
|
|
+ let layer_index: usize = args.object_layer.unwrap_or(0);
|
|
|
+ let layer: &Layer = file
|
|
|
+ .layers_offset
|
|
|
+ .get(layer_index)
|
|
|
+ .expect("Invalid layer index");
|
|
|
+ let object: &Object = layer.objects.get(obj_index).expect("Invalid object index");
|
|
|
+ info!("Layer {}, Object {}: {:?}", layer_index, obj_index, object);
|
|
|
+ let pen_index: u32 = *object.core().pen;
|
|
|
+ trace!(
|
|
|
+ "Pen #{}: {}",
|
|
|
+ pen_index,
|
|
|
+ file.pens_offset
|
|
|
+ .data
|
|
|
+ .pens
|
|
|
+ .get(pen_index as usize)
|
|
|
+ .expect("Invalid pen index in object")
|
|
|
+ );
|
|
|
+ // TODO: object info
|
|
|
+ });
|
|
|
+ }
|
|
|
+ SubCommands::Apply(args) => {
|
|
|
+ // Process config
|
|
|
+ info!("Processing config file '{}'", args.config.to_string_lossy());
|
|
|
+ let config: String =
|
|
|
+ std::fs::read_to_string(args.config).expect("Failed to open config file");
|
|
|
+ let config: Config =
|
|
|
+ serde_yaml::from_str(&config).expect("Failed to parse config file");
|
|
|
+
|
|
|
+ // Patch pen settings
|
|
|
+ let time: Instant = Instant::now();
|
|
|
+ config
|
|
|
+ .ops
|
|
|
+ .apply(&mut file.pens_offset.data.pens, &mut file.layers_offset);
|
|
|
+ trace!("Config processing time: {:?}", time.elapsed());
|
|
|
+
|
|
|
+ // Process output
|
|
|
+ args.output.map(|output| {
|
|
|
+ info!("Writing output file '{}'", output.to_string_lossy());
|
|
|
+ // Serialize to memory buffer for perf
|
|
|
+ let mut buffer: Cursor<Vec<u8>> = Cursor::new(vec![]);
|
|
|
+ let time: Instant = Instant::now();
|
|
|
+ buffer
|
|
|
+ .write_le(&file)
|
|
|
+ .expect("Failed to serialize contents as EZCAD format");
|
|
|
+ trace!("Output file encode time: {:?}", time.elapsed());
|
|
|
+
|
|
|
+ // Write buffer to output file
|
|
|
+ let mut output: File = File::create(output).expect("Failed to open output file");
|
|
|
+ output
|
|
|
+ .write_all(buffer.into_inner().as_slice())
|
|
|
+ .expect("Failed to write to output file");
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|