pub mod common;
pub mod tables;
pub mod entities;
pub mod objects;
use std::collections::HashMap;
use crate::error::{DxfError, Result};
use crate::io::dwg::dwg_version::DwgVersion;
use crate::io::dwg::dwg_stream_readers::merged_reader::DwgMergedReader;
use crate::types::{DxfVersion, Color, Transparency};
const MAX_ARRAY_COUNT: i32 = 100_000;
#[inline]
fn safe_count(raw: i32) -> i32 {
raw.max(0).min(MAX_ARRAY_COUNT)
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ObjectCommonData {
pub type_code: i16,
pub handle: u64,
#[cfg_attr(feature = "serde", serde(skip))]
pub eed_raw: Vec<(u64, Vec<u8>)>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EntityCommonData {
pub common: ObjectCommonData,
pub has_graphic: bool,
#[cfg_attr(feature = "serde", serde(skip))]
pub graphic_data: Option<Vec<u8>>,
pub entity_mode: u8,
pub owner_handle: u64,
pub reactors: Vec<u64>,
pub xdictionary_handle: Option<u64>,
pub color: Color,
pub transparency: Transparency,
pub line_weight: u8,
pub linetype_scale: f64,
pub invisible: bool,
pub layer_handle: u64,
pub linetype_flags: u8,
pub linetype_handle: u64,
pub prev_entity_handle: Option<u64>,
pub next_entity_handle: Option<u64>,
pub material_flags: u8,
pub material_handle: Option<u64>,
pub shadow_flags: u8,
pub plotstyle_flags: u8,
pub plotstyle_handle: Option<u64>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct NonEntityCommonData {
pub common: ObjectCommonData,
pub owner_handle: u64,
pub reactors: Vec<u64>,
pub xdictionary_handle: Option<u64>,
}
pub struct DwgObjectReader {
data: Vec<u8>,
version: DwgVersion,
dxf_version: DxfVersion,
handle_map: HashMap<u64, i64>,
}
impl DwgObjectReader {
pub fn new(
data: Vec<u8>,
dxf_version: DxfVersion,
handle_map: HashMap<u64, i64>,
) -> Result<Self> {
let version = DwgVersion::from_dxf_version(dxf_version)?;
Ok(DwgObjectReader {
data,
version,
dxf_version,
handle_map,
})
}
pub fn read_record_at(&self, offset: usize) -> Result<(i16, DwgMergedReader)> {
if offset >= self.data.len() {
return Err(DxfError::Parse(format!(
"Object offset {} out of range (data len {})",
offset, self.data.len()
)));
}
let mut pos = offset;
let (size, ms_len) = read_modular_short(&self.data[pos..]);
pos += ms_len;
let handle_bits = if self.version.r2010_plus() {
let (hb, mc_len) = read_modular_char(&self.data[pos..]);
pos += mc_len;
hb as i64
} else {
0
};
if pos + size > self.data.len() {
return Err(DxfError::Parse(format!(
"Object record extends past data: offset={}, size={}, data_len={}",
offset, size, self.data.len()
)));
}
let merged_data = self.data[pos..pos + size].to_vec();
if self.version.r2007_plus() {
let dwg = DwgVersion::from_dxf_version(self.dxf_version)
.unwrap_or(DwgVersion::AC15);
let mut temp = crate::io::dwg::dwg_stream_readers::bit_reader::DwgBitReader::new(
merged_data.clone(), dwg, self.dxf_version,
);
let type_code = temp.read_object_type();
let (flag_position, handle_start, data_start_bits);
if !self.version.r2010_plus() {
let total_size_bits = temp.read_raw_long() as i64;
data_start_bits = temp.position_in_bits();
flag_position = total_size_bits - 1;
handle_start = total_size_bits;
} else {
data_start_bits = temp.position_in_bits();
let total_data_bits = (size as i64) * 8;
handle_start = total_data_bits - handle_bits;
flag_position = handle_start - 1;
}
let mut main_reader = crate::io::dwg::dwg_stream_readers::bit_reader::DwgBitReader::new(
merged_data.clone(), dwg, self.dxf_version,
);
main_reader.set_position_in_bits(data_start_bits);
let mut text_reader = crate::io::dwg::dwg_stream_readers::bit_reader::DwgBitReader::new(
merged_data.clone(), dwg, self.dxf_version,
);
text_reader.set_position_by_flag(flag_position);
let mut handle_reader = crate::io::dwg::dwg_stream_readers::bit_reader::DwgBitReader::new(
merged_data.clone(), dwg, self.dxf_version,
);
handle_reader.set_position_in_bits(handle_start);
let mut reader = DwgMergedReader::from_readers(
main_reader,
Some(text_reader),
Some(handle_reader),
self.dxf_version,
);
reader.set_handle_bits(handle_bits);
reader.set_handle_start(handle_start);
return Ok((type_code, reader));
}
let dwg = DwgVersion::from_dxf_version(self.dxf_version)
.unwrap_or(DwgVersion::AC15);
let handle_start_bits = if self.version.r2000_plus() {
let mut temp = crate::io::dwg::dwg_stream_readers::bit_reader::DwgBitReader::new(
merged_data.clone(), dwg, self.dxf_version,
);
let _tc = temp.read_object_type(); temp.read_raw_long() as i64 } else {
0
};
let main_reader = crate::io::dwg::dwg_stream_readers::bit_reader::DwgBitReader::new(
merged_data.clone(), dwg, self.dxf_version,
);
let mut handle_reader = crate::io::dwg::dwg_stream_readers::bit_reader::DwgBitReader::new(
merged_data, dwg, self.dxf_version,
);
handle_reader.set_position_in_bits(handle_start_bits);
let mut reader = DwgMergedReader::from_readers(
main_reader,
None, Some(handle_reader),
self.dxf_version,
);
let type_code = reader.read_object_type();
Ok((type_code, reader))
}
pub fn read_common_data(
&self,
reader: &mut DwgMergedReader,
type_code: i16,
) -> ObjectCommonData {
if self.version.r2000_plus() && !self.version.r2007_plus() {
let _size_in_bits = reader.read_raw_long();
}
let handle = reader.main_mut().read_handle();
reader.set_ref_handle(handle);
let eed_raw = self.read_extended_data_raw(reader);
ObjectCommonData {
type_code,
handle,
eed_raw,
}
}
pub fn read_common_entity_data(
&self,
reader: &mut DwgMergedReader,
type_code: i16,
) -> EntityCommonData {
let common = self.read_common_data(reader, type_code);
let has_graphic = reader.read_bit();
let graphic_data = if has_graphic {
let graphic_size = if self.version.r2010_plus() {
reader.read_bit_long_long()
} else {
reader.read_raw_long() as i64
};
let mut gdata = Vec::with_capacity(graphic_size.max(0) as usize);
for _ in 0..graphic_size.max(0) {
gdata.push(reader.read_byte());
}
Some(gdata)
} else {
None
};
if self.version.r13_14_only() {
let main_size_bits = reader.read_raw_long();
reader.reposition_handle_reader(main_size_bits);
}
let entity_mode = reader.main_mut().read_2bits();
let owner_handle = if entity_mode == 0 {
reader.read_handle()
} else {
0
};
let reactor_count = safe_count(reader.read_bit_long());
let mut reactors = Vec::new();
for _ in 0..reactor_count {
reactors.push(reader.read_handle());
}
let xdictionary_handle = if self.version.r2004_plus() {
let no_xdic = reader.read_bit();
if !no_xdic {
Some(reader.read_handle())
} else {
None
}
} else {
let h = reader.read_handle();
if h != 0 { Some(h) } else { None }
};
if self.version.r2013_plus(self.dxf_version) {
let _has_binary_data = reader.read_bit();
}
let mut layer_handle = 0u64;
let mut linetype_flags = 0u8;
if self.version.r13_14_only() {
layer_handle = reader.read_handle();
let is_bylayer_lt = reader.read_bit();
if !is_bylayer_lt {
let _linetype_handle = reader.read_handle();
}
}
let mut prev_entity_handle = None;
let mut next_entity_handle = None;
if !self.version.r2004_plus() {
let nolinks = reader.read_bit();
if !nolinks {
prev_entity_handle = Some(reader.read_handle());
next_entity_handle = Some(reader.read_handle());
}
}
let (color, transparency, has_color_handle) = if self.version.r2000_plus() {
reader.read_en_color()
} else {
(reader.read_cm_color(), Transparency::default(), false)
};
if self.version.r2004_plus() && has_color_handle {
let _color_book_handle = reader.read_handle();
}
let linetype_scale = reader.read_bit_double();
let invisible;
if self.version.r13_14_only() {
invisible = reader.read_bit_short() != 0;
return EntityCommonData {
common,
has_graphic,
graphic_data,
entity_mode,
owner_handle,
reactors,
xdictionary_handle,
color,
transparency,
line_weight: 0,
linetype_scale,
invisible,
layer_handle,
linetype_flags,
linetype_handle: 0,
prev_entity_handle,
next_entity_handle,
material_flags: 0,
material_handle: None,
shadow_flags: 0,
plotstyle_flags: 0,
plotstyle_handle: None,
};
}
if self.version.r2000_plus() {
layer_handle = reader.read_handle();
}
let mut linetype_handle = 0u64;
linetype_flags = reader.main_mut().read_2bits();
if linetype_flags == 0b11 {
linetype_handle = reader.read_handle();
}
let mut material_flags = 0u8;
let mut material_handle: Option<u64> = None;
let mut shadow_flags = 0u8;
if self.version.r2007_plus() {
material_flags = reader.main_mut().read_2bits();
if material_flags == 0b11 {
material_handle = Some(reader.read_handle());
}
shadow_flags = reader.read_byte();
}
let mut plotstyle_flags = 0u8;
let mut plotstyle_handle: Option<u64> = None;
if self.version.r2000_plus() {
plotstyle_flags = reader.main_mut().read_2bits();
if plotstyle_flags == 0b11 {
plotstyle_handle = Some(reader.read_handle());
}
}
if self.version.r2010_plus() {
if reader.read_bit() {
let _full_visual_style_handle = reader.read_handle();
}
if reader.read_bit() {
let _face_visual_style_handle = reader.read_handle();
}
if reader.read_bit() {
let _edge_visual_style_handle = reader.read_handle();
}
}
invisible = reader.read_bit_short() != 0;
let line_weight = if self.version.r2000_plus() {
reader.read_byte()
} else {
0
};
EntityCommonData {
common,
has_graphic,
graphic_data,
entity_mode,
owner_handle,
reactors,
xdictionary_handle,
color,
transparency,
line_weight,
linetype_scale,
invisible,
layer_handle,
linetype_flags,
linetype_handle,
prev_entity_handle,
next_entity_handle,
material_flags,
material_handle,
shadow_flags,
plotstyle_flags,
plotstyle_handle,
}
}
pub fn read_common_non_entity_data(
&self,
reader: &mut DwgMergedReader,
type_code: i16,
) -> NonEntityCommonData {
let common = self.read_common_data(reader, type_code);
if self.version.r13_14_only() {
let main_size_bits = reader.read_raw_long();
reader.reposition_handle_reader(main_size_bits);
}
let owner_handle = reader.read_handle();
let reactor_count = safe_count(reader.read_bit_long());
let mut reactors = Vec::new();
for _ in 0..reactor_count {
reactors.push(reader.read_handle());
}
let xdictionary_handle = if self.version.r2004_plus() {
let no_xdic = reader.read_bit();
if !no_xdic {
Some(reader.read_handle())
} else {
None
}
} else {
let h = reader.read_handle();
if h != 0 { Some(h) } else { None }
};
if self.version.r2013_plus(self.dxf_version) {
let _has_binary_data = reader.read_bit();
}
NonEntityCommonData {
common,
owner_handle,
reactors,
xdictionary_handle,
}
}
fn read_extended_data_raw(&self, reader: &mut DwgMergedReader) -> Vec<(u64, Vec<u8>)> {
let mut result: Vec<(u64, Vec<u8>)> = Vec::new();
loop {
let size = reader.read_bit_short();
if size <= 0 {
break;
}
let size_u = size as usize;
let app_handle = reader.main_mut().read_handle();
let mut data = Vec::with_capacity(size_u);
for _ in 0..size_u {
data.push(reader.read_byte());
}
result.push((app_handle, data));
}
result
}
pub fn handles(&self) -> Vec<u64> {
self.handle_map.keys().copied().collect()
}
pub fn offset_for(&self, handle: u64) -> Option<i64> {
self.handle_map.get(&handle).copied()
}
pub fn version(&self) -> DwgVersion {
self.version
}
pub fn dxf_version(&self) -> DxfVersion {
self.dxf_version
}
}
fn read_modular_short(data: &[u8]) -> (usize, usize) {
let mut value: usize = 0;
let mut shift = 0;
let mut i = 0;
loop {
if i + 1 >= data.len() {
break;
}
let word = u16::from_le_bytes([data[i], data[i + 1]]);
i += 2;
value |= ((word & 0x7FFF) as usize) << shift;
shift += 15;
if (word & 0x8000) == 0 {
break;
}
}
(value, i)
}
fn read_modular_char(data: &[u8]) -> (usize, usize) {
let mut value: usize = 0;
let mut shift = 0;
let mut i = 0;
loop {
if i >= data.len() {
break;
}
let b = data[i];
i += 1;
value |= ((b & 0x7F) as usize) << shift;
shift += 7;
if (b & 0x80) == 0 {
break;
}
}
(value, i)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_modular_short_read() {
let data = [0x2A, 0x00];
let (val, len) = read_modular_short(&data);
assert_eq!(val, 42);
assert_eq!(len, 2);
}
#[test]
fn test_modular_short_multi_word() {
let data = [0x01, 0x80, 0x01, 0x00];
let (val, len) = read_modular_short(&data);
assert_eq!(val, 32769);
assert_eq!(len, 4);
}
#[test]
fn test_modular_char_read() {
let data = [42u8];
let (val, len) = read_modular_char(&data);
assert_eq!(val, 42);
assert_eq!(len, 1);
}
#[test]
fn test_modular_char_multi_byte() {
let data = [0x81, 0x01];
let (val, len) = read_modular_char(&data);
assert_eq!(val, 129);
assert_eq!(len, 2);
}
#[test]
fn test_modular_short_roundtrip() {
use crate::io::dwg::dwg_stream_writers::object_writer::common::{
write_modular_short_bytes, write_modular_char_bytes,
};
for &val in &[0, 1, 42, 127, 128, 255, 1000, 32767, 32768, 65535, 100000] {
let mut buf = Vec::new();
write_modular_short_bytes(&mut buf, val);
let (read_val, _) = read_modular_short(&buf);
assert_eq!(read_val, val, "MS roundtrip failed for {}", val);
}
for &val in &[0, 1, 42, 127, 128, 255, 1000, 32767, 65535, 100000] {
let mut buf = Vec::new();
write_modular_char_bytes(&mut buf, val);
let (read_val, _) = read_modular_char(&buf);
assert_eq!(read_val, val, "MC roundtrip failed for {}", val);
}
}
#[test]
fn test_read_record_roundtrip() {
use crate::io::dwg::dwg_stream_writers::object_writer::common::write_modular_short_bytes;
use crate::io::dwg::dwg_stream_writers::merged_writer::DwgMergedWriter;
use crate::io::dwg::crc;
let dwg_ver = DwgVersion::AC15;
let dxf_ver = DxfVersion::AC1015;
let mut writer = DwgMergedWriter::new(dwg_ver, dxf_ver);
writer.write_object_type(common::OBJ_LINE); writer.save_position_for_size();
writer.main_mut().write_handle_undefined(0x42);
writer.write_bit_short(0);
let merged = writer.merge();
let mut record = Vec::new();
write_modular_short_bytes(&mut record, merged.len());
record.extend_from_slice(&merged);
let crc_val = crc::crc16(crc::CRC16_SEED, &record);
record.extend_from_slice(&crc_val.to_le_bytes());
let handle_map = HashMap::new();
let reader = DwgObjectReader::new(record, dxf_ver, handle_map).unwrap();
let (type_code, mut merged_reader) = reader.read_record_at(0).unwrap();
assert_eq!(type_code, common::OBJ_LINE);
let common_data = reader.read_common_data(&mut merged_reader, type_code);
assert_eq!(common_data.type_code, common::OBJ_LINE);
assert_eq!(common_data.handle, 0x42);
assert!(common_data.eed_raw.is_empty());
}
}