use crate::types::{Color, DxfVersion, Vector2, Vector3};
use crate::types::Transparency;
use crate::io::dwg::dwg_version::DwgVersion;
use crate::io::dwg::dwg_reference_type::DwgReferenceType;
use super::bit_writer::DwgBitWriter;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum MergeMode {
TwoStream,
ThreeStream,
}
pub struct DwgMergedWriter {
main: DwgBitWriter,
text: DwgBitWriter,
handle: DwgBitWriter,
mode: MergeMode,
saved_position: bool,
position_in_bits: i64,
handle_start_bits: i64,
}
impl DwgMergedWriter {
pub fn new(version: DwgVersion, dxf_version: DxfVersion) -> Self {
let mode = if version >= DwgVersion::AC21 {
MergeMode::ThreeStream
} else {
MergeMode::TwoStream
};
Self {
main: DwgBitWriter::new(version, dxf_version),
text: DwgBitWriter::new(version, dxf_version),
handle: DwgBitWriter::new(version, dxf_version),
mode,
saved_position: false,
position_in_bits: -1,
handle_start_bits: -1,
}
}
pub fn with_encoding(
version: DwgVersion,
dxf_version: DxfVersion,
encoding: &'static encoding_rs::Encoding,
) -> Self {
let mode = if version >= DwgVersion::AC21 {
MergeMode::ThreeStream
} else {
MergeMode::TwoStream
};
Self {
main: DwgBitWriter::with_encoding(version, dxf_version, encoding),
text: DwgBitWriter::with_encoding(version, dxf_version, encoding),
handle: DwgBitWriter::with_encoding(version, dxf_version, encoding),
mode,
saved_position: false,
position_in_bits: -1,
handle_start_bits: -1,
}
}
pub fn version(&self) -> DwgVersion {
self.main.version()
}
pub fn dxf_version(&self) -> DxfVersion {
self.main.dxf_version()
}
pub fn main(&self) -> &DwgBitWriter {
&self.main
}
pub fn main_mut(&mut self) -> &mut DwgBitWriter {
&mut self.main
}
pub fn text(&self) -> &DwgBitWriter {
&self.text
}
pub fn text_mut(&mut self) -> &mut DwgBitWriter {
&mut self.text
}
pub fn handle_writer(&self) -> &DwgBitWriter {
&self.handle
}
pub fn main_ref(&self) -> &DwgBitWriter {
&self.main
}
pub fn is_saved(&self) -> bool {
self.saved_position
}
pub fn saved_pos_bits(&self) -> i64 {
self.position_in_bits
}
pub fn handle_mut(&mut self) -> &mut DwgBitWriter {
&mut self.handle
}
pub fn reset(&mut self) {
self.main.reset();
self.text.reset();
self.handle.reset();
self.saved_position = false;
self.position_in_bits = -1;
self.handle_start_bits = -1;
}
pub fn save_position_for_size(&mut self) {
self.saved_position = true;
self.position_in_bits = self.main.position_in_bits();
self.main.write_int(0);
}
pub fn write_bit(&mut self, value: bool) {
self.main.write_bit(value);
}
pub fn write_2bits(&mut self, value: u8) {
self.main.write_2bits(value);
}
pub fn write_byte(&mut self, value: u8) {
self.main.write_byte(value);
}
pub fn write_bytes(&mut self, data: &[u8]) {
self.main.write_bytes(data);
}
pub fn write_raw_short(&mut self, value: i16) {
self.main.write_raw_short(value);
}
pub fn write_raw_long(&mut self, value: i32) {
self.main.write_raw_long(value);
}
pub fn write_raw_double(&mut self, value: f64) {
self.main.write_raw_double(value);
}
pub fn write_int(&mut self, value: i32) {
self.main.write_int(value);
}
pub fn write_bit_short(&mut self, value: i16) {
self.main.write_bit_short(value);
}
pub fn write_bit_long(&mut self, value: i32) {
self.main.write_bit_long(value);
}
pub fn write_bit_long_unsigned(&mut self, value: u32) {
self.main.write_bit_long_unsigned(value);
}
pub fn write_bit_double(&mut self, value: f64) {
self.main.write_bit_double(value);
}
pub fn write_bit_long_long(&mut self, value: i64) {
self.main.write_bit_long_long(value);
}
pub fn write_bit_double_with_default(&mut self, def: f64, value: f64) {
self.main.write_bit_double_with_default(def, value);
}
pub fn write_2bit_double(&mut self, value: Vector2) {
self.main.write_2bit_double(value);
}
pub fn write_3bit_double(&mut self, value: Vector3) {
self.main.write_3bit_double(value);
}
pub fn write_2raw_double(&mut self, value: Vector2) {
self.main.write_2raw_double(value);
}
pub fn write_2bit_double_with_default(&mut self, def: Vector2, value: Vector2) {
self.main.write_2bit_double_with_default(def, value);
}
pub fn write_3bit_double_with_default(&mut self, def: Vector3, value: Vector3) {
self.main.write_3bit_double_with_default(def, value);
}
pub fn write_bit_thickness(&mut self, thickness: f64) {
self.main.write_bit_thickness(thickness);
}
pub fn write_bit_extrusion(&mut self, normal: Vector3) {
self.main.write_bit_extrusion(normal);
}
pub fn write_object_type(&mut self, value: i16) {
self.main.write_object_type(value);
}
pub fn write_cm_color(&mut self, color: &Color) {
self.main.write_cm_color(color);
}
pub fn write_en_color(&mut self, color: &Color, transparency: &Transparency) {
self.main.write_en_color(color, transparency);
}
pub fn write_en_color_with_book(
&mut self,
color: &Color,
transparency: &Transparency,
is_book_color: bool,
) {
self.main.write_en_color_with_book(color, transparency, is_book_color);
}
pub fn write_datetime(&mut self, julian_day: i32, milliseconds: i32) {
self.main.write_datetime(julian_day, milliseconds);
}
pub fn write_8bit_julian_date(&mut self, julian_day: i32, milliseconds: i32) {
self.main.write_8bit_julian_date(julian_day, milliseconds);
}
pub fn write_timespan(&mut self, days: i32, milliseconds: i32) {
self.main.write_timespan(days, milliseconds);
}
pub fn write_variable_text(&mut self, value: &str) {
match self.mode {
MergeMode::ThreeStream => self.text.write_variable_text(value),
MergeMode::TwoStream => self.main.write_variable_text(value),
}
}
pub fn write_text_unicode(&mut self, value: &str) {
match self.mode {
MergeMode::ThreeStream => self.text.write_text_unicode(value),
MergeMode::TwoStream => self.main.write_text_unicode(value),
}
}
pub fn write_handle(&mut self, ref_type: DwgReferenceType, handle: u64) {
self.handle.write_handle(ref_type, handle);
}
pub fn write_handle_undefined(&mut self, handle: u64) {
self.handle.write_handle_undefined(handle);
}
pub fn merge(&mut self) -> Vec<u8> {
match self.mode {
MergeMode::TwoStream => self.merge_two_stream(),
MergeMode::ThreeStream => self.merge_three_stream(),
}
}
fn merge_two_stream(&mut self) -> Vec<u8> {
let main_size_bits = self.main.position_in_bits();
self.main.write_spear_shift();
if self.saved_position {
let saved_pos = self.position_in_bits;
self.main.set_position_in_bits(saved_pos);
self.main.write_raw_long(main_size_bits as i32);
self.main.write_shift_value();
self.main.set_position_in_bits(main_size_bits);
}
self.handle.write_spear_shift();
self.handle_start_bits = self.main.position_in_bits();
let handle_bytes = self.handle.to_bytes();
self.main.write_bytes(&handle_bytes);
self.main.write_spear_shift();
self.main.to_bytes()
}
fn merge_three_stream(&mut self) -> Vec<u8> {
let main_size_bits = self.main.position_in_bits();
let text_size_bits = self.text.position_in_bits();
self.main.write_spear_shift();
if self.saved_position {
let saved_pos = self.position_in_bits;
let mut total_bits = main_size_bits + text_size_bits + 1;
if text_size_bits > 0 {
total_bits += 16;
if text_size_bits >= 0x8000 {
total_bits += 16;
if text_size_bits >= 0x40000000 {
total_bits += 16;
}
}
}
self.main.set_position_in_bits(saved_pos);
self.main.write_raw_long(total_bits as i32);
self.main.write_shift_value();
}
self.main.set_position_in_bits(main_size_bits);
if text_size_bits > 0 {
self.text.write_spear_shift();
let text_bytes = self.text.to_bytes();
self.main.write_bytes(&text_bytes);
self.main.write_spear_shift();
self.main.set_position_in_bits(main_size_bits + text_size_bits);
self.main.set_position_by_flag(text_size_bits);
self.main.write_bit(true); } else {
self.main.write_bit(false); }
self.handle.write_spear_shift();
self.handle_start_bits = self.main.position_in_bits();
let handle_bytes = self.handle.to_bytes();
self.main.write_bytes(&handle_bytes);
self.main.write_spear_shift();
self.main.to_bytes()
}
pub fn handle_start_bits(&self) -> i64 {
self.handle_start_bits
}
pub fn last_saved_position_in_bits(&self) -> i64 {
self.main.saved_position_in_bits()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_two_stream_basic() {
let mut w = DwgMergedWriter::new(DwgVersion::AC15, DxfVersion::AC1015);
w.write_bit_short(42);
w.write_handle(DwgReferenceType::SoftPointer, 0x10);
w.write_variable_text("Hello");
let bytes = w.merge();
assert!(!bytes.is_empty());
}
#[test]
fn test_three_stream_basic() {
let mut w = DwgMergedWriter::new(DwgVersion::AC24, DxfVersion::AC1024);
w.write_bit_short(42);
w.write_handle(DwgReferenceType::SoftPointer, 0x10);
w.write_variable_text("Hello");
let bytes = w.merge();
assert!(!bytes.is_empty());
}
#[test]
fn test_two_stream_with_size() {
let mut w = DwgMergedWriter::new(DwgVersion::AC18, DxfVersion::AC1018);
w.save_position_for_size();
w.write_bit_short(100);
w.write_handle(DwgReferenceType::HardPointer, 0x20);
let bytes = w.merge();
assert!(!bytes.is_empty());
}
#[test]
fn test_three_stream_with_size() {
let mut w = DwgMergedWriter::new(DwgVersion::AC24, DxfVersion::AC1024);
w.save_position_for_size();
w.write_bit_short(100);
w.write_variable_text("Test");
w.write_handle(DwgReferenceType::SoftOwnership, 0x30);
let bytes = w.merge();
assert!(!bytes.is_empty());
}
#[test]
fn test_three_stream_no_text() {
let mut w = DwgMergedWriter::new(DwgVersion::AC24, DxfVersion::AC1024);
w.save_position_for_size();
w.write_bit_short(7);
w.write_handle(DwgReferenceType::SoftPointer, 0x01);
let bytes = w.merge();
assert!(!bytes.is_empty());
}
#[test]
fn test_reset() {
let mut w = DwgMergedWriter::new(DwgVersion::AC15, DxfVersion::AC1015);
w.write_byte(0xFF);
w.write_handle(DwgReferenceType::Undefined, 1);
w.reset();
assert_eq!(w.main().position_in_bits(), 0);
assert_eq!(w.text().position_in_bits(), 0);
assert_eq!(w.handle_writer().position_in_bits(), 0);
}
}