Browse Source

Add support for serialization

Kevin Lee 1 year ago
parent
commit
5a0722f76d
5 changed files with 101 additions and 16 deletions
  1. 1 1
      src/ezcad/field_of.rs
  2. 67 6
      src/ezcad/file.rs
  3. 19 0
      src/ezcad/pen.rs
  4. 1 1
      src/ezcad/types.rs
  5. 13 8
      src/main.rs

+ 1 - 1
src/ezcad/field_of.rs

@@ -5,7 +5,7 @@ use std::{
     ops::{Deref, DerefMut},
 };
 
-/// Wrapper to prefix arbitrary structs with size of struct as u32
+/// Wrapper to prefix arbitrary types with size of type as u32
 #[binrw]
 #[derive(PartialEq)]
 pub struct FieldOf<T>

+ 67 - 6
src/ezcad/file.rs

@@ -1,18 +1,74 @@
-use binrw::{BinRead, BinWrite, FilePtr64};
+use std::io::{Seek, SeekFrom, Write};
 
-use crate::{array_of::ArrayOf, layer::Layer, pen::PenHeader};
+use binrw::{BinRead, BinResult, BinWrite, BinWriterExt, Endian, FilePtr64};
+
+use crate::{
+    array_of::ArrayOf,
+    layer::{self, Layer},
+    pen::PenHeader,
+};
 
 #[derive(BinRead, Debug)]
 pub struct Header {
     _magic: [u16; 8],
     _unknown_1: [u8; 0x150],
-    pub thumbnail: FilePtr64<Thumbnail>,
-    pub pens: FilePtr64<PenHeader>,
-    _unknown_offset: FilePtr64<()>,
-    pub layers: FilePtr64<ArrayOf<Layer>>,
+    pub thumbnail_offset: FilePtr64<Thumbnail>,
+    pub pens_offset: FilePtr64<PenHeader>,
+    _unknown_offset: FilePtr64<Unknown>,
+    pub layers_offset: FilePtr64<ArrayOf<Layer>>,
     _unknown_2: [u8; 0x1A8],
 }
 
+impl BinWrite for Header {
+    type Args<'a> = ();
+
+    fn write_options<W: Write + Seek>(
+        &self,
+        writer: &mut W,
+        endian: Endian,
+        args: Self::Args<'_>,
+    ) -> BinResult<()> {
+        self._magic.write_options(writer, endian, args)?;
+        self._unknown_1.write_options(writer, endian, args)?;
+
+        // Save address and write placeholder (zeros) for now
+        let thumbnail_save_offset: u64 = writer.stream_position().unwrap();
+        0u64.write_options(writer, endian, args)?;
+        let pens_save_offset: u64 = writer.stream_position().unwrap();
+        0u64.write_options(writer, endian, args)?;
+        let unknown_save_offset: u64 = writer.stream_position().unwrap();
+        0u64.write_options(writer, endian, args)?;
+        let layers_save_offset: u64 = writer.stream_position().unwrap();
+        0u64.write_options(writer, endian, args)?;
+
+        self._unknown_2.write_options(writer, endian, args)?;
+
+        let write_offset = |writer: &mut W, offset: u64| -> BinResult<()> {
+            let current_offset: u64 = writer.stream_position().unwrap();
+            writer.seek(SeekFrom::Start(offset)).unwrap();
+            writer.write_type(&current_offset, endian)?;
+            writer.seek(SeekFrom::Start(current_offset)).unwrap();
+            Ok(())
+        };
+
+        // Write thumbnail contents
+        write_offset(writer, thumbnail_save_offset)?;
+        self.thumbnail_offset.write_options(writer, endian, args)?;
+
+        // Write unknown contents
+        write_offset(writer, unknown_save_offset)?;
+        self._unknown_offset.write_options(writer, endian, args)?;
+
+        // Write pens
+        write_offset(writer, pens_save_offset)?;
+        self.pens_offset.write_options(writer, endian, args)?;
+
+        // Write layers
+        write_offset(writer, layers_save_offset)?;
+        self.layers_offset.write_options(writer, endian, args)
+    }
+}
+
 #[derive(BinRead, BinWrite, Debug)]
 pub struct Thumbnail {
     _zeros_1: u32,
@@ -26,3 +82,8 @@ pub struct Thumbnail {
     // pub pixels: Vec<Rgba>, // Takes ~1s longer
     pub pixels: Vec<u32>,
 }
+
+#[derive(BinRead, BinWrite, Debug)]
+pub struct Unknown {
+    _zeros: u32,
+}

+ 19 - 0
src/ezcad/pen.rs

@@ -16,6 +16,25 @@ pub struct PenHeader {
     pub data: FilePtr64<Pens>,
 }
 
+impl BinWrite for PenHeader {
+    type Args<'a> = ();
+
+    fn write_options<W: std::io::prelude::Write + std::io::prelude::Seek>(
+        &self,
+        writer: &mut W,
+        endian: binrw::Endian,
+        args: Self::Args<'_>,
+    ) -> binrw::prelude::BinResult<()> {
+        let pen_count: u32 = self.data.pens.len().try_into().unwrap();
+        pen_count.write_options(writer, endian, args)?;
+
+        let position: u64 = writer.stream_position().unwrap() + 8;
+        position.write_options(writer, endian, args)?;
+
+        self.data.pens.write_options(writer, endian, args)
+    }
+}
+
 #[derive(BinRead, BinWrite, Debug)]
 #[br(import {pen_count: u32})]
 pub struct Pens {

+ 1 - 1
src/ezcad/types.rs

@@ -18,7 +18,7 @@ pub type F64 = FieldOf<f64>;
 pub struct WString {
     // Temporary variable that holds number of elements
     #[br(temp)]
-    #[bw(try_calc(u32::try_from(value.len())))]
+    #[bw(try_calc(u32::try_from(value.len() * core::mem::size_of::<u16>())))]
     size: u32,
 
     #[br(count = size / core::mem::size_of::<u16>() as u32)]

+ 13 - 8
src/main.rs

@@ -4,7 +4,7 @@ use std::{
     time::Instant,
 };
 
-use binrw::BinRead;
+use binrw::{BinRead, BinWriterExt};
 use clap::Parser;
 use ezcad::file::Header;
 use log::info;
@@ -15,9 +15,9 @@ struct Cli {
     #[arg(short, long)]
     input: PathBuf,
 
-    // /// Output file to write to
-    // #[arg(short, long)]
-    // output: PathBuf,
+    /// Output file to write to
+    #[arg(short, long)]
+    output: Option<PathBuf>,
 
     // /// Configuration file
     // #[arg(short, long)]
@@ -43,13 +43,18 @@ fn main() {
 
     info!("Execution time: {:?}", time.elapsed());
 
-    // for pen in file.pens.data.pens.iter().take(1) {
-    //     dbg!(pen);
-    // }
+    for pen in file.pens_offset.data.pens.iter().take(1) {
+        dbg!(pen);
+    }
 
-    for layer in file.layers.iter() {
+    for layer in file.layers_offset.iter() {
         for object in layer.objects.iter() {
             dbg!(object);
         }
     }
+
+    if let Some(output) = args.output {
+        let mut output = fs::File::create(output).unwrap();
+        output.write_le(&file).unwrap();
+    }
 }