use alloc::vec::Vec;
use crate::block::Block;
use crate::drawing::Drawing;
use crate::entity::*;
use crate::error::Error;
use crate::reader::BinaryReader;
use crate::table::{Layer, Style};
use crate::value::GroupValue;
pub fn scan<'a>(data: &'a [u8]) -> Result<Drawing<'a>, Error> {
let mut reader = BinaryReader::new(data)?;
let mut drawing = Drawing::default();
let mut next = read_type_name(&mut reader)?;
while let Some(type_name) = next {
match type_name {
b"SECTION" => {
let section_name = read_section_name(&mut reader)?;
next = match section_name {
b"HEADER" => scan_header(&mut reader, &mut drawing)?,
b"TABLES" => scan_tables(&mut reader, &mut drawing)?,
b"BLOCKS" => scan_blocks(&mut reader, &mut drawing)?,
b"ENTITIES" => scan_entities(&mut reader, &mut drawing)?,
_ => skip_to_code0(&mut reader)?,
};
}
b"EOF" => break,
_ => {
next = read_type_name(&mut reader)?;
}
}
}
for (i, layer) in drawing.layers.iter().enumerate() {
drawing.layers_by_name.insert(layer.name, i);
}
for (i, style) in drawing.styles.iter().enumerate() {
drawing.styles_by_name.insert(style.name, i);
}
for (i, block) in drawing.blocks.iter().enumerate() {
drawing.blocks_by_name.insert(block.name, i);
}
for (i, entity) in drawing.entities.iter().enumerate() {
let handle = entity.common().handle;
if !handle.is_empty() {
drawing.entity_by_handle.insert(handle, i);
}
}
Ok(drawing)
}
fn read_type_name<'a>(reader: &mut BinaryReader<'a>) -> Result<Option<&'a [u8]>, Error> {
loop {
let Some((code, val)) = reader.next_pair()? else {
return Ok(None);
};
if code == 0 {
return Ok(val.as_str_bytes());
}
}
}
fn read_section_name<'a>(reader: &mut BinaryReader<'a>) -> Result<&'a [u8], Error> {
match reader.next_pair()? {
Some((2, GroupValue::String(name))) => Ok(name),
_ => Ok(b""),
}
}
fn skip_to_code0<'a>(reader: &mut BinaryReader<'a>) -> Result<Option<&'a [u8]>, Error> {
loop {
let Some((code, val)) = reader.next_pair()? else {
return Ok(None);
};
if code == 0 {
return Ok(val.as_str_bytes());
}
}
}
fn feed_entity_pairs<'a>(
reader: &mut BinaryReader<'a>,
common: &mut EntityCommon<'a>,
mut feed_specific: impl FnMut(u16, &GroupValue<'a>),
) -> Result<Option<&'a [u8]>, Error> {
loop {
let Some((code, val)) = reader.next_pair()? else {
return Ok(None);
};
if code == 0 {
return Ok(val.as_str_bytes());
}
if !common.feed(code, &val) {
feed_specific(code, &val);
}
}
}
fn scan_header<'a>(
reader: &mut BinaryReader<'a>,
drawing: &mut Drawing<'a>,
) -> Result<Option<&'a [u8]>, Error> {
let mut current_var: Option<&'a str> = None;
loop {
let Some((code, val)) = reader.next_pair()? else {
return Ok(None);
};
if code == 0 {
return Ok(val.as_str_bytes());
}
if code == 9 {
current_var = val
.as_str_bytes()
.and_then(|b| core::str::from_utf8(b).ok());
} else if let Some(name) = current_var.take() {
drawing.headers.insert(name, val);
}
}
}
fn scan_tables<'a>(
reader: &mut BinaryReader<'a>,
drawing: &mut Drawing<'a>,
) -> Result<Option<&'a [u8]>, Error> {
let mut next = read_type_name(reader)?;
loop {
let type_name = match next {
Some(t) => t,
None => return Ok(None),
};
match type_name {
b"ENDSEC" => return read_type_name(reader),
b"TABLE" => {
let table_name = read_section_name(reader)?;
next = scan_table(reader, drawing, table_name)?;
}
_ => {
next = read_type_name(reader)?;
}
}
}
}
fn scan_table<'a>(
reader: &mut BinaryReader<'a>,
drawing: &mut Drawing<'a>,
table_name: &[u8],
) -> Result<Option<&'a [u8]>, Error> {
let mut next = read_type_name(reader)?;
loop {
let type_name = match next {
Some(t) => t,
None => return Ok(None),
};
match type_name {
b"ENDTAB" => return read_type_name(reader),
b"LAYER" if table_name == b"LAYER" => {
let mut layer = Layer::default();
next = feed_pairs(reader, |c, v| layer.feed(c, v))?;
drawing.layers.push(layer);
}
b"STYLE" if table_name == b"STYLE" => {
let mut style = Style::default();
next = feed_pairs(reader, |c, v| style.feed(c, v))?;
drawing.styles.push(style);
}
_ => {
next = skip_to_code0(reader)?;
}
}
}
}
fn feed_pairs<'a>(
reader: &mut BinaryReader<'a>,
mut feed: impl FnMut(u16, &GroupValue<'a>),
) -> Result<Option<&'a [u8]>, Error> {
loop {
let Some((code, val)) = reader.next_pair()? else {
return Ok(None);
};
if code == 0 {
return Ok(val.as_str_bytes());
}
feed(code, &val);
}
}
fn scan_blocks<'a>(
reader: &mut BinaryReader<'a>,
drawing: &mut Drawing<'a>,
) -> Result<Option<&'a [u8]>, Error> {
let mut next = read_type_name(reader)?;
loop {
let type_name = match next {
Some(t) => t,
None => return Ok(None),
};
match type_name {
b"ENDSEC" => return read_type_name(reader),
b"BLOCK" => {
let (block, n) = scan_one_block(reader)?;
drawing.blocks.push(block);
next = n;
}
_ => {
next = skip_to_code0(reader)?;
}
}
}
}
fn scan_one_block<'a>(
reader: &mut BinaryReader<'a>,
) -> Result<(Block<'a>, Option<&'a [u8]>), Error> {
let mut block = Block::default();
let mut next = feed_entity_pairs(reader, &mut EntityCommon::new(), |code, val| match code {
2 => {
if let Some(s) = val.as_str_bytes() {
block.name = s;
}
}
10 => {
if let Some(f) = val.as_f64() {
block.base_point.x = f;
}
}
20 => {
if let Some(f) = val.as_f64() {
block.base_point.y = f;
}
}
30 => {
if let Some(f) = val.as_f64() {
block.base_point.z = f;
}
}
_ => {}
})?;
loop {
let type_name = match next {
Some(t) => t,
None => return Ok((block, None)),
};
if type_name == b"ENDBLK" {
next = skip_to_code0(reader)?;
return Ok((block, next));
}
next = scan_one_entity(reader, type_name, &mut block.entities)?;
}
}
fn scan_entities<'a>(
reader: &mut BinaryReader<'a>,
drawing: &mut Drawing<'a>,
) -> Result<Option<&'a [u8]>, Error> {
let mut next = read_type_name(reader)?;
loop {
let type_name = match next {
Some(t) => t,
None => return Ok(None),
};
if type_name == b"ENDSEC" {
return read_type_name(reader);
}
next = scan_one_entity(reader, type_name, &mut drawing.entities)?;
}
}
fn scan_one_entity<'a>(
reader: &mut BinaryReader<'a>,
type_name: &'a [u8],
dest: &mut Vec<Entity<'a>>,
) -> Result<Option<&'a [u8]>, Error> {
match type_name {
b"POLYLINE" => {
let mut common = EntityCommon::new();
let mut poly = Polyline::default();
let mut next = feed_entity_pairs(reader, &mut common, |c, v| poly.feed(c, v))?;
while let Some(tn) = next {
match tn {
b"VERTEX" => {
let mut vc = EntityCommon::new();
let mut v = Vertex::default();
next = feed_entity_pairs(reader, &mut vc, |c, val| v.feed(c, val))?;
poly.vertices.push(v);
}
b"SEQEND" => {
next = skip_to_code0(reader)?;
break;
}
_ => {
next = skip_to_code0(reader)?;
}
}
}
dest.push(Entity::Polyline(common, poly));
Ok(next)
}
_ => {
let (entity, next) = scan_typed_entity(reader, type_name)?;
if let Entity::Insert(_, ref ins) = entity
&& ins.has_attributes
{
let mut entity = entity;
let next = collect_insert_attributes(reader, &mut entity, next)?;
dest.push(entity);
return Ok(next);
}
dest.push(entity);
Ok(next)
}
}
}
fn scan_typed_entity<'a>(
reader: &mut BinaryReader<'a>,
type_name: &'a [u8],
) -> Result<(Entity<'a>, Option<&'a [u8]>), Error> {
let mut common = EntityCommon::new();
macro_rules! scan_entity {
($variant:ident, $ty:ty) => {{
let mut e = <$ty>::default();
let next = feed_entity_pairs(reader, &mut common, |c, v| e.feed(c, v))?;
Ok((Entity::$variant(common, e), next))
}};
($variant:ident, $ty:ty, finish) => {{
let mut e = <$ty>::default();
let next = feed_entity_pairs(reader, &mut common, |c, v| e.feed(c, v))?;
e.finish();
Ok((Entity::$variant(common, e), next))
}};
($variant:ident, $ty:ty, new) => {{
let mut e = <$ty>::new();
let next = feed_entity_pairs(reader, &mut common, |c, v| e.feed(c, v))?;
Ok((Entity::$variant(common, e), next))
}};
}
match type_name {
b"LINE" => scan_entity!(Line, Line),
b"CIRCLE" => scan_entity!(Circle, Circle),
b"ARC" => scan_entity!(Arc, Arc),
b"ELLIPSE" => scan_entity!(Ellipse, Ellipse),
b"LWPOLYLINE" => scan_entity!(LwPolyline, LwPolyline, finish),
b"SPLINE" => scan_entity!(Spline, Spline, finish),
b"SOLID" => scan_entity!(Solid, Solid),
b"TRACE" => scan_entity!(Trace, Trace),
b"3DFACE" => scan_entity!(Face3d, Face3d, finish),
b"POINT" => scan_entity!(Point, DxfPoint),
b"TEXT" => scan_entity!(Text, Text),
b"MTEXT" => scan_entity!(MText, MText),
b"INSERT" => scan_entity!(Insert, Insert, new),
b"DIMENSION" => scan_entity!(Dimension, Dimension),
b"LEADER" => scan_entity!(Leader, Leader, finish),
b"HATCH" => {
let mut builder = crate::entity::hatch::HatchBuilder::new();
let next = feed_entity_pairs(reader, &mut common, |c, v| builder.feed(c, v))?;
Ok((Entity::Hatch(common, builder.hatch), next))
}
b"WIPEOUT" => scan_entity!(Wipeout, Wipeout),
b"ATTRIB" => scan_entity!(Attrib, Attrib),
b"ATTDEF" => scan_entity!(AttDef, AttDef),
_ => {
let next = feed_entity_pairs(reader, &mut common, |_, _| {})?;
Ok((Entity::Unknown(common, type_name), next))
}
}
}
fn collect_insert_attributes<'a>(
reader: &mut BinaryReader<'a>,
entity: &mut Entity<'a>,
mut next: Option<&'a [u8]>,
) -> Result<Option<&'a [u8]>, Error> {
let attrs = match entity {
Entity::Insert(_, ins) => &mut ins.attributes,
_ => return Ok(next),
};
loop {
let tn = match next {
Some(t) => t,
None => return Ok(None),
};
match tn {
b"ATTRIB" => {
let mut common = EntityCommon::new();
let mut a = Attrib::default();
next = feed_entity_pairs(reader, &mut common, |c, v| a.feed(c, v))?;
attrs.push(a);
}
b"SEQEND" => {
next = skip_to_code0(reader)?;
return Ok(next);
}
_ => {
next = skip_to_code0(reader)?;
}
}
}
}