use num_traits::Zero;
use libreda_db as db;
use db::layout::prelude::*;
use db::prelude::WithProperties;
use std::io::Read;
use byteorder::{ReadBytesExt, LittleEndian};
use std::collections::{HashMap, HashSet};
use crate::base_types::*;
use crate::base_types::RegularRepetition;
use crate::base_types::Repetition;
use crate::{Modal, XYMode, NameOrRef};
use std::rc::Rc;
#[derive(Default, Debug)]
struct MutableState {
m_expect_strict_mode: bool,
m_table_cell_name: Option<UInt>,
m_cell_names: HashMap<UInt, String>,
m_cell_names_forward_references: HashMap<UInt, CellIndex>,
m_property_name_forward_references: HashMap<UInt, Vec<(PropertyParent, Vec<PropertyValue>)>>,
m_propnames: HashMap<UInt, String>,
m_propstrings: HashMap<UInt, Vec<u8>>,
m_textstrings: HashMap<UInt, String>,
}
#[derive(Debug, Clone)]
enum PropertyParent {
None,
Cell(Rc<Cell<SInt>>),
CellName(String),
Geometry(Vec<Rc<Shape<SInt>>>),
Placement(Vec<Rc<CellInstance<SInt>>>),
XElement,
XGeometry,
}
fn read_offset_table<R: Read>(reader: &mut R) -> Result<(), OASISReadError> {
let _cellname_flag = read_unsigned_integer(reader)?;
let _cellname_offset = read_unsigned_integer(reader)?;
let _textstring_flag = read_unsigned_integer(reader)?;
let _textstring_offset = read_unsigned_integer(reader)?;
let _propname_flag = read_unsigned_integer(reader)?;
let _propname_offset = read_unsigned_integer(reader)?;
let _propstring_flag = read_unsigned_integer(reader)?;
let _propstring_offset = read_unsigned_integer(reader)?;
let _layername_flag = read_unsigned_integer(reader)?;
let _layername_offset = read_unsigned_integer(reader)?;
let _xname_flag = read_unsigned_integer(reader)?;
let _xname_offset = read_unsigned_integer(reader)?;
Ok(())
}
fn _read_properties<R: Read>(_reader: &mut R) -> Result<(), OASISReadError> {
unimplemented!()
}
fn read_repetition_conditional<R: Read>(reader: &mut R,
is_present: bool,
modal_value: &mut Option<Repetition>) -> Result<Repetition, OASISReadError> {
if is_present {
let repetition = read_repetition(reader)?;
let repetition = match repetition {
Repetition::ReusePrevious => {
modal_value.as_ref().cloned().ok_or(OASISReadError::ModalRepetitionNotDefined)?
}
_ => repetition
};
assert_ne!(&repetition, &Repetition::ReusePrevious, "`modal.repetition` should never be set to `ReusePrevious`.");
*modal_value = Some(repetition.clone());
Ok(repetition)
} else {
Ok(Repetition::Regular(
RegularRepetition::new(Vector::zero(), Vector::zero(), 1, 1)
))
}
}
fn repetition_to_offsets(rep: &Repetition, first_position: Vector<SInt>) -> Vec<Vector<SInt>> {
match &rep {
Repetition::ReusePrevious => {
panic!("`modal.repetition` should never be set to `ReusePrevious`.")
}
Repetition::Regular(r) => {
r.iter().map(|offset| first_position + offset).collect()
}
Repetition::Irregular(r) => {
r.iter().map(|offset| first_position + *offset).collect()
}
}
}
fn read_coordinate_conditional<R: Read>(reader: &mut R,
is_present: bool,
xy_mode: XYMode,
modal_value: &mut SInt) -> Result<SInt, OASISReadError> {
let c = if is_present {
let c = read_signed_integer(reader)?;
match xy_mode {
XYMode::Absolute => c,
XYMode::Relative => *modal_value + c
}
} else {
*modal_value
};
*modal_value = c;
Ok(c)
}
fn read_layernum_datatype<R: Read>(reader: &mut R,
is_layer_present: bool,
is_datatype_present: bool,
modal: &mut Modal) -> Result<(UInt, UInt), OASISReadError> {
let layer = if is_layer_present {
read_unsigned_integer(reader)?
} else {
modal.layer.ok_or(OASISReadError::NoImplicitLayerDefined)?
};
modal.layer = Some(layer);
let datatype = if is_datatype_present {
read_unsigned_integer(reader)?
} else {
modal.datatype.ok_or(OASISReadError::NoImplicitDataTypeDefined)?
};
modal.datatype = Some(datatype);
Ok((layer, datatype))
}
pub fn read_layout<R: Read>(reader: &mut R, layout: &mut Layout) -> Result<(), OASISReadError> {
let mut modal = Modal::default();
read_magic(reader)?;
let record_id = read_unsigned_integer(reader)?;
if record_id != 1 {
return Err(OASISReadError::UnexpectedRecord(record_id));
}
let version_string = read_ascii_string(reader)?;
if !version_string.eq("1.0") {
return Err(OASISReadError::WrongVersionString);
}
let resolution = read_real(reader)?;
{
let r = resolution.to_f64();
if f64::is_sign_negative(r) || f64::is_infinite(r) || f64::is_nan(r) {
return Err(OASISReadError::InvalidResolution(resolution));
}
}
let dbu = match resolution.try_to_int() {
Some(r) if r > 0 => r as UInt,
_ => unimplemented!("Resolution must be a positive non-zero integer.")
};
assert!(dbu >= 1);
layout.dbu = dbu;
let offset_flag = read_unsigned_integer(reader)?;
debug!("offset flag = {}", offset_flag);
let table_offsets_at_start = offset_flag == 0;
if table_offsets_at_start {
read_offset_table(reader)?;
}
#[derive(Eq, PartialEq, Debug)]
enum IdMode {
Any,
Impl,
Expl,
}
let mut state = MutableState::default();
let mut current_cell = None;
let mut placement_cell_forward_references = HashSet::new();
let mut property_parent = PropertyParent::None;
let mut cellname_id_mode = IdMode::Any;
let mut cellname_id_counter = (0..).into_iter();
let mut textstrings_id_mode = IdMode::Any;
let mut textstrings_id_counter = (0..).into_iter();
let mut propname_id_mode = IdMode::Any;
let mut propname_id_counter = (0..).into_iter();
let mut propstrings_id_mode = IdMode::Any;
let mut propstrings_id_counter = (0..).into_iter();
let set_property = |layout: &Layout,
property_parent: &PropertyParent,
property_name: &String,
property_values: &Vec<PropertyValue>,
property_strings: &HashMap<UInt, Vec<u8>>| {
let property_values: Vec<db::property_storage::PropertyValue> = property_values.iter()
.map(|v| {
use db::property_storage::PropertyValue as PV;
match v {
PropertyValue::SInt(v) => (*v).into(),
PropertyValue::UInt(v) => (*v).into(),
PropertyValue::Real(v) => match v {
Real::IEEEFloat32(v) => PV::Float(*v as f64),
Real::IEEEFloat64(v) => PV::Float(*v),
Real::PositiveWholeNumber(v) => (*v).into(),
Real::NegativeWholeNumber(v) => (0 - *v as i32).into(),
x => {
dbg!(&property_name, x);
unimplemented!();
}
},
PropertyValue::AString(s) => s.clone().into(),
PropertyValue::NString(s) => s.clone().into(),
PropertyValue::BString(s) => s.clone().into(),
PropertyValue::NStringRef(propstring_id) => {
let bstring = property_strings.get(propstring_id)
.expect("AString forward references are not supported yet.");
let s = bytes_to_name_string(bstring.clone())
.expect("Failed to convert bytes to name string.");
s.into()
}
PropertyValue::AStringRef(propstring_id) => {
let bstring = property_strings.get(propstring_id)
.expect("NString forward references are not supported yet.");
let s = bytes_to_ascii_string(bstring.clone())
.expect("Failed to convert bytes to ascii string.");
s.into()
}
PropertyValue::BStringRef(propstring_id) => {
let bstring = property_strings.get(propstring_id)
.expect("BString forward references are not supported yet.");
bstring.clone().into()
}
}
})
.collect();
match &property_parent {
PropertyParent::None => {
for v in &property_values {
layout.set_property(property_name.clone(),
v.clone());
}
}
PropertyParent::Geometry(shapes) => {
for shape in shapes {
for v in &property_values {
shape.set_property(property_name.clone(),
v.clone());
}
}
}
PropertyParent::Cell(cell) => {
for v in &property_values {
cell.set_property(property_name.clone(),
v.clone());
}
}
PropertyParent::CellName(cell_name) => {
let cell = layout.cell_by_name(cell_name).expect("Cell name not found.");
for v in &property_values {
cell.set_property(property_name.clone(),
v.clone());
}
}
PropertyParent::Placement(instances) => {
for instance in instances {
for v in &property_values {
instance.set_property(property_name.clone(),
v.clone());
}
}
}
x => debug!("Storing properties to this type is not supported yet: {:?}", x)
}
};
loop {
let record_id = read_unsigned_integer(reader)?;
debug!("record_id = {}", record_id);
match record_id {
0 => {
debug!("PAD record");
}
1 => {
debug!("START record");
return Err(OASISReadError::UnexpectedRecord(record_id));
}
2 => {
debug!("END record");
if !table_offsets_at_start {
read_offset_table(reader)?;
}
let _padding_string = read_byte_string(reader)?;
let validation_scheme = read_unsigned_integer(reader)?;
match validation_scheme {
0 => {
debug!("No integrity validation.");
}
1 => {
let crc32_expected = reader.read_u32::<LittleEndian>()?;
debug!("CRC32 (from file): {:x}", crc32_expected);
}
2 => {
let checksum32_expected = reader.read_u32::<LittleEndian>()?;
debug!("CHECKSUM32 (from file): {:x}", checksum32_expected);
}
v => {
return Err(OASISReadError::UnknownValidationScheme(v));
}
}
break;
}
3 | 4 => {
debug!("CELLNAME record");
let cell_name = read_name_string(reader)?;
debug!("cell name = {}", &cell_name);
let id = if record_id == 3 {
if cellname_id_mode == IdMode::Expl {
return Err(OASISReadError::MixedImplExplCellnameModes);
};
cellname_id_mode = IdMode::Impl;
cellname_id_counter.next().unwrap()
} else {
if cellname_id_mode == IdMode::Impl {
return Err(OASISReadError::MixedImplExplCellnameModes);
};
cellname_id_mode = IdMode::Expl;
read_unsigned_integer(reader)?
};
if let Some(_) = state.m_cell_names.insert(id, cell_name.clone()) {
return Err(OASISReadError::CellnameIdAlreadyPresent(id));
}
modal.reset();
if let Some(idx) = state.m_cell_names_forward_references.remove(&id) {
layout.rename_cell(idx, Some(cell_name.clone()))?;
}
property_parent = PropertyParent::CellName(cell_name);
}
5 | 6 => {
debug!("TEXTSTRING record");
let textstring = read_ascii_string(reader)?;
let id = if record_id == 5 {
if textstrings_id_mode == IdMode::Expl {
return Err(OASISReadError::MixedImplExplTextstringModes);
};
textstrings_id_mode = IdMode::Impl;
textstrings_id_counter.next().unwrap()
} else {
if textstrings_id_mode == IdMode::Impl {
return Err(OASISReadError::MixedImplExplTextstringModes);
};
textstrings_id_mode = IdMode::Expl;
read_unsigned_integer(reader)?
};
if let Some(_) = state.m_textstrings.insert(id, textstring) {
return Err(OASISReadError::TextStringAlreadyPresent(id));
}
modal.reset();
}
7 | 8 => {
debug!("PROPNAME record");
let property_name = read_name_string(reader)?;
debug!("property_name = {}", &property_name);
let prop_name_id = if record_id == 7 {
if propname_id_mode == IdMode::Expl {
return Err(OASISReadError::MixedImplExplPropnameModes);
};
propname_id_mode = IdMode::Impl;
propname_id_counter.next().unwrap()
} else {
if propname_id_mode == IdMode::Impl {
return Err(OASISReadError::MixedImplExplPropnameModes);
};
propname_id_mode = IdMode::Expl;
read_unsigned_integer(reader)?
};
debug!("prop_id = {}", prop_name_id);
if let Some(_existing_name) = state.m_propnames.insert(prop_name_id, property_name) {
return Err(OASISReadError::PropnameIdAlreadyPresent(prop_name_id));
}
modal.reset();
}
9 | 10 => {
debug!("PROPSTRING record");
let propstring = read_byte_string(reader)?;
debug!("propstring = {:?}", &propstring);
let id = if record_id == 9 {
if propstrings_id_mode == IdMode::Expl {
return Err(OASISReadError::MixedImplExplPropstringModes);
};
propstrings_id_mode = IdMode::Impl;
propstrings_id_counter.next().unwrap()
} else {
if propstrings_id_mode == IdMode::Impl {
return Err(OASISReadError::MixedImplExplPropstringModes);
};
propstrings_id_mode = IdMode::Expl;
read_unsigned_integer(reader)?
};
if let Some(_existing_name) = state.m_propstrings.insert(id, propstring) {
return Err(OASISReadError::PropStringAlreadyPresent(id));
}
modal.reset();
}
11 | 12 => {
debug!("LAYERNAME record");
let layer_name = read_name_string(reader)?;
debug!("layer_name = {}", &layer_name);
let read_interval = |reader: &mut R| {
let interval_type = read_unsigned_integer(reader)?;
let max = UInt::MAX;
match interval_type {
0 => Ok((0, max)),
1 => Ok((0, read_unsigned_integer(reader)?)),
2 => Ok((read_unsigned_integer(reader)?, max)),
3 => {
let a = read_unsigned_integer(reader)?;
Ok((a, a))
}
4 => Ok((read_unsigned_integer(reader)?, read_unsigned_integer(reader)?)),
t => return Err(OASISReadError::IllegalIntervalType(t))
}
};
let (layer_start, layer_end) = read_interval(reader)?;
let (dtype_start, dtype_end) = read_interval(reader)?;
for l in layer_start..layer_end {
for d in dtype_start..dtype_end {
let idx = layout.find_or_create_layer(l, d);
layout.set_layer_name(idx, Some(layer_name.clone()));
}
}
modal.reset();
warn!("LAYERNAME record is not implemented: '{}'", &layer_name);
}
13 | 14 => {
debug!("CELL record");
let cell_name = if record_id == 13 {
let cell_name_reference = read_unsigned_integer(reader)?;
let cell_name = state.m_cell_names.get(&cell_name_reference);
if let Some(cell_name) = cell_name {
NameOrRef::Name(cell_name.clone())
} else {
NameOrRef::NameRef(cell_name_reference)
}
} else {
NameOrRef::Name(read_name_string(reader)?)
};
debug!("cell_name = {:?}", &cell_name);
let cell_idx = match cell_name {
NameOrRef::Name(n) => {
if let Some(cell_idx) = layout.cell_index_by_name(&n) {
if placement_cell_forward_references.remove(&cell_idx) {
cell_idx
} else {
return Err(OASISReadError::CellnameAlreadyPresent(n));
}
} else {
layout.create_cell(Some(n))
}
}
NameOrRef::NameRef(r) => {
if let Some(&cell_idx) = state.m_cell_names_forward_references.get(&r) {
if placement_cell_forward_references.remove(&cell_idx) {
cell_idx
} else {
return Err(OASISReadError::CellnameIdAlreadyPresent(r));
}
} else {
let cell_idx = layout.create_cell::<String>(None);
state.m_cell_names_forward_references.insert(r, cell_idx);
cell_idx
}
}
};
current_cell = Some(layout.cell_by_index(cell_idx)
.unwrap()
);
property_parent = PropertyParent::Cell(current_cell.clone().unwrap());
modal.reset();
}
15 => {
debug!("XYABSOLUTE record");
modal.xy_mode = XYMode::Absolute;
}
16 => {
debug!("XYRELATIVE record");
modal.xy_mode = XYMode::Relative;
}
17 | 18 => {
debug!("PLACEMENT record");
let placement_info_byte = read_byte(reader)?;
let b = |index| { (placement_info_byte >> index) & 1u8 == 1u8 };
let is_cell_reference_explicit = b(7);
let is_cell_reference_number_present = b(6);
let is_x_present = b(5);
let is_y_present = b(4);
let is_repetition_present = b(3);
let is_flip = b(0);
let instance_ref = if is_cell_reference_explicit {
let cell_name = if is_cell_reference_number_present {
let cell_name_ref = read_unsigned_integer(reader)?;
if let Some(cell_name) = state.m_cell_names.get(&cell_name_ref) {
NameOrRef::Name(cell_name.clone())
} else {
NameOrRef::NameRef(cell_name_ref)
}
} else {
NameOrRef::Name(read_name_string(reader)?)
};
match cell_name {
NameOrRef::Name(n) => {
if let Some(cell) = layout.cell_by_name(&n) {
cell
} else {
let cell = layout.create_and_get_cell(Some(n));
placement_cell_forward_references.insert(cell.index());
cell
}
}
NameOrRef::NameRef(r) => {
state.m_cell_names_forward_references.get(&r)
.map(|&i| layout.cell_by_index(i)
.expect("Could not find cell even tough it must have been created.")
)
.unwrap_or_else(|| {
let cell = layout.create_and_get_cell::<String>(None);
let idx = cell.index();
state.m_cell_names_forward_references.insert(r, idx);
placement_cell_forward_references.insert(idx);
cell
})
}
}
} else {
modal.placement_cell.clone()
.ok_or(OASISReadError::ModalPlacementCellNotDefined)?
};
modal.placement_cell = Some(instance_ref.clone());
let (magnification, angle_degrees) = if record_id == 17 {
let aa = (placement_info_byte >> 1) & 3u8;
let angle_degrees = 90 * (aa as u16);
let magnification = 1;
(Real::PositiveWholeNumber(magnification), Real::PositiveWholeNumber(angle_degrees.into()))
} else {
let is_magnification_present = b(2);
let is_angle_present = b(1);
let magnification = if is_magnification_present {
read_real(reader)?
} else {
Real::PositiveWholeNumber(1)
};
let angle_degrees = if is_angle_present {
read_real(reader)?
} else {
Real::PositiveWholeNumber(0)
};
(magnification, angle_degrees)
};
let x = read_coordinate_conditional(reader, is_x_present, modal.xy_mode, &mut modal.placement_x)?;
let y = read_coordinate_conditional(reader, is_y_present, modal.xy_mode, &mut modal.placement_y)?;
let displacement = Vector::new(x, y);
let repetition = read_repetition_conditional(reader,
is_repetition_present,
&mut modal.repetition)?;
let angle90 = match angle_degrees.try_to_int() {
Some(0) => Some(Angle::R0),
Some(90) => Some(Angle::R90),
Some(180) => Some(Angle::R180),
Some(270) => Some(Angle::R270),
_ => None
}.expect("Rotation angle must be a multiple of 90 degree.");
let magnification = magnification.try_to_int().expect("Magnification mut be an integer.");
let positions = repetition_to_offsets(&repetition, displacement);
let parent_cell = current_cell.as_ref().ok_or(OASISReadError::NoCellRecordPresent)?;
let mut instances = Vec::new();
for pos in positions {
let trans = SimpleTransform::new(is_flip, angle90,
magnification, pos);
let instance = parent_cell.create_instance(&instance_ref, trans);
instances.push(instance);
}
property_parent = PropertyParent::Placement(instances);
}
19 => {
debug!("TEXT record");
let text_info_byte = read_byte(reader)?;
let b = |index| { (text_info_byte >> index) & 1u8 == 1u8 };
let is_text_reference_explicit = b(6);
let text_string = if is_text_reference_explicit {
let reference_number_present = b(5);
if reference_number_present {
let ref_number = read_unsigned_integer(reader)?;
let text_string = state.m_textstrings.get(&ref_number);
text_string.cloned().ok_or(OASISReadError::PropStringIdNotFound(ref_number))?
} else {
read_ascii_string(reader)?
}
} else {
modal.text_string.as_ref().cloned().ok_or(OASISReadError::NoImplicitTextStringDefined)?
};
debug!("text_string = {}", &text_string);
modal.text_string = Some(text_string.clone());
let is_explicit_textlayer = b(0);
let is_explicit_texttype = b(1);
let is_repetition_present = b(2);
let is_x_present = b(4);
let is_y_present = b(3);
let textlayer = if is_explicit_textlayer {
read_unsigned_integer(reader)?
} else {
modal.textlayer.ok_or(OASISReadError::ModalTextLayerDefined)?
};
modal.textlayer = Some(textlayer);
let texttype = if is_explicit_texttype {
read_unsigned_integer(reader)?
} else {
modal.texttype.ok_or(OASISReadError::ModalTextTypeDefined)?
};
modal.texttype = Some(texttype);
let x = read_coordinate_conditional(reader, is_x_present, modal.xy_mode, &mut modal.text_x)?;
let y = read_coordinate_conditional(reader, is_y_present, modal.xy_mode, &mut modal.text_y)?;
let pos = Vector::new(x, y);
let repetition = read_repetition_conditional(reader,
is_repetition_present,
&mut modal.repetition)?;
let positions = repetition_to_offsets(&repetition, pos);
let parent_cell = current_cell.as_ref()
.ok_or(OASISReadError::NoCellRecordPresent)?;
let layer = layout.find_or_create_layer(textlayer, texttype);
let shapes = parent_cell.shapes_get_or_create(layer);
let mut shape_instances = Vec::new();
for pos in positions {
let text = Text::new(text_string.clone(), pos.into());
let shape = shapes.insert(text);
shape_instances.push(shape);
}
property_parent = PropertyParent::Geometry(shape_instances);
}
20 => {
debug!("RECTANGLE record");
let rectangle_info_byte = read_byte(reader)?;
let b = |index| { (rectangle_info_byte >> index) & 1u8 == 1u8 };
let is_layer_number_present = b(0);
let is_datatype_number_present = b(1);
let is_width_present = b(6);
let is_height_present = b(5);
let is_x_present = b(4);
let is_y_present = b(3);
let is_repetition_present = b(2);
let is_square = b(7);
let (layer, datatype) = read_layernum_datatype(reader, is_layer_number_present,
is_datatype_number_present, &mut modal)?;
let width = if is_width_present {
read_unsigned_integer(reader)?
} else {
modal.geometry_w.ok_or(OASISReadError::ModalGeometryWNotDefined)?
};
modal.geometry_w = Some(width);
let height = if is_square {
if is_height_present {
return Err(OASISReadError::HeightIsPresentForSquare);
} else {
width
}
} else {
if is_height_present {
read_unsigned_integer(reader)?
} else {
modal.geometry_h.ok_or(OASISReadError::ModalGeometryHNotDefined)?
}
};
modal.geometry_h = Some(height);
let x = read_coordinate_conditional(reader, is_x_present,
modal.xy_mode,
&mut modal.geometry_x)?;
let y = read_coordinate_conditional(reader,
is_y_present, modal.xy_mode,
&mut modal.geometry_y)?;
let pos = Vector::new(x, y);
let repetition = read_repetition_conditional(reader,
is_repetition_present,
&mut modal.repetition)?;
let positions = repetition_to_offsets(&repetition, pos);
let diagonal = Vector::new(width as SInt, height as SInt);
let lower_left = Point::zero();
let rect = Rect::new(lower_left, lower_left + diagonal);
if let Some(parent_cell) = ¤t_cell {
let layer_id = layout.find_or_create_layer(layer, datatype);
let shapes = parent_cell.shapes_get_or_create(layer_id);
let mut shape_instances = Vec::new();
for pos in positions {
let r = rect.translate(pos);
let shape = shapes.insert(r);
shape_instances.push(shape);
}
property_parent = PropertyParent::Geometry(shape_instances);
} else {
return Err(OASISReadError::NoCellRecordPresent);
}
}
21 => {
debug!("POLYGON record");
let polygon_info_byte = read_byte(reader)?;
let b = |index| { (polygon_info_byte >> index) & 1u8 == 1u8 };
let is_layer_number_present = b(0);
let is_datatype_number_present = b(1);
let is_repetition_present = b(2);
let is_y_present = b(3);
let is_x_present = b(4);
let is_pointlist_present = b(5);
let (layer, datatype) = read_layernum_datatype(reader, is_layer_number_present,
is_datatype_number_present, &mut modal)?;
if is_pointlist_present {
let p = read_point_list(reader)?;
modal.polygon_point_list = Some(p);
}
let x = read_coordinate_conditional(reader, is_x_present, modal.xy_mode, &mut modal.geometry_x)?;
let y = read_coordinate_conditional(reader, is_y_present, modal.xy_mode, &mut modal.geometry_y)?;
let point0 = Vector::new(x, y);
let points: Vec<_> = modal.polygon_point_list.as_ref()
.ok_or(OASISReadError::ModalPolygonPointListNotDefined)
.map(|pointlist| pointlist.points(Vector::zero(), true))?;
let repetition = read_repetition_conditional(reader,
is_repetition_present,
&mut modal.repetition)?;
let positions = repetition_to_offsets(&repetition, point0);
let polygon = SimplePolygon::new(points);
if let Some(parent_cell) = ¤t_cell {
let layer_id = layout.find_or_create_layer(layer, datatype);
let shapes = parent_cell.shapes_get_or_create(layer_id);
let mut shape_instances = Vec::new();
for pos in positions {
let p = polygon.translate(pos);
let shape = shapes.insert(p);
shape_instances.push(shape);
}
property_parent = PropertyParent::Geometry(shape_instances);
} else {
return Err(OASISReadError::NoCellRecordPresent);
}
}
22 => {
debug!("PATH record");
let path_info_byte = read_byte(reader)?;
let b = |index| { (path_info_byte >> index) & 1u8 == 1u8 };
let is_layer_number_present = b(0);
let is_datatype_number_present = b(1);
let is_repetition_present = b(2);
let is_y_present = b(3);
let is_x_present = b(4);
let is_pointlist_present = b(5);
let is_half_width_present = b(6);
let is_extension_scheme_present = b(7);
let (layer, datatype) = read_layernum_datatype(reader, is_layer_number_present,
is_datatype_number_present, &mut modal)?;
let half_width = if is_half_width_present {
let hw = read_unsigned_integer(reader)?;
modal.path_halfwidth = Some(hw);
hw
} else {
modal.path_halfwidth.ok_or(OASISReadError::ModalPathHalfWidthNotDefined)?
};
let (start_ext, end_ext) = if is_extension_scheme_present {
let ext_scheme = read_unsigned_integer(reader)?;
let ss = (ext_scheme >> 2) & 0b11;
let ee = ext_scheme & 0b11;
let start_ext = match ss {
0 => modal.path_start_extension.ok_or(OASISReadError::ModalPathStartExtensionNotDefined)?,
1 => 0,
2 => half_width as SInt,
3 => read_signed_integer(reader)?,
_ => panic!()
};
let end_ext = match ee {
0 => modal.path_end_extension.ok_or(OASISReadError::ModalPathEndExtensionNotDefined)?,
1 => 0,
2 => half_width as SInt,
3 => read_signed_integer(reader)?,
_ => panic!()
};
(start_ext, end_ext)
} else {
let s = modal.path_start_extension.ok_or(OASISReadError::ModalPathStartExtensionNotDefined)?;
let e = modal.path_end_extension.ok_or(OASISReadError::ModalPathEndExtensionNotDefined)?;
(s, e)
};
modal.path_start_extension = Some(start_ext);
modal.path_end_extension = Some(end_ext);
if is_pointlist_present {
let p = read_point_list(reader)?;
modal.path_point_list = Some(p);
}
let x = read_coordinate_conditional(reader, is_x_present, modal.xy_mode, &mut modal.geometry_x)?;
let y = read_coordinate_conditional(reader, is_y_present, modal.xy_mode, &mut modal.geometry_y)?;
let point0 = Vector::new(x, y);
let repetition = read_repetition_conditional(reader,
is_repetition_present,
&mut modal.repetition)?;
let positions = repetition_to_offsets(&repetition, point0);
let points: Vec<_> = modal.path_point_list.as_ref()
.ok_or(OASISReadError::ModalPathPointListNotDefined)
.map(|pointlist| pointlist.points(Vector::zero(), false))?;
let path = Path::new_extended(points, half_width as SInt * 2, start_ext, end_ext);
if let Some(parent_cell) = ¤t_cell {
let layer_id = layout.find_or_create_layer(layer, datatype);
let shapes = parent_cell.shapes_get_or_create(layer_id);
let mut shape_instances = Vec::new();
for pos in positions {
let p = path.translate(pos);
let shape = shapes.insert(p);
shape_instances.push(shape);
}
property_parent = PropertyParent::Geometry(shape_instances);
} else {
return Err(OASISReadError::NoCellRecordPresent);
}
}
28 | 29 => {
debug!("PROPERTY record");
let (property_name_or_ref, property_values) = if record_id == 28 {
let prop_info_byte = read_byte(reader)?;
let b = |index| { (prop_info_byte >> index) & 1u8 == 1u8 };
let is_name_reference_explicit = b(2);
let use_last_value_list = b(3);
let _is_standard_property = b(0);
let uuuu = ((prop_info_byte >> 4) & 0xF).into();
let property_name_or_ref = if is_name_reference_explicit {
let is_ref_number_present = b(1);
if is_ref_number_present {
let ref_number = read_unsigned_integer(reader)?;
let property_name = state.m_propnames.get(&ref_number);
debug!("ref_number = {}", ref_number);
match property_name {
Some(name) => NameOrRef::Name(name.clone()),
None => NameOrRef::NameRef(ref_number)
}
} else {
NameOrRef::Name(read_name_string(reader)?)
}
} else {
modal.last_property_name
.ok_or(OASISReadError::ModalLastPropertyNameNotDefined)?
};
let values = if !use_last_value_list {
let num_values = if uuuu == 15 {
read_unsigned_integer(reader)?
} else {
uuuu
};
let mut prop_value_list = Vec::new();
for _i in 0..num_values {
let prop = read_property_value(reader)?;
prop_value_list.push(prop)
}
prop_value_list
} else {
if uuuu != 0 {
return Err(OASISReadError::FormatError);
}
modal.last_value_list.ok_or(OASISReadError::ModalLastValueListNotDefined)?
};
modal.last_property_name = Some(property_name_or_ref.clone());
modal.last_value_list = Some(values.clone());
(property_name_or_ref, values)
} else {
(
modal.last_property_name.clone().ok_or(OASISReadError::ModalLastPropertyNameNotDefined)?,
modal.last_value_list.clone().ok_or(OASISReadError::ModalLastValueListNotDefined)?
)
};
debug!("property name or reference = {:?}", &property_name_or_ref);
debug!("property values = {:?}", &property_values);
match property_name_or_ref {
NameOrRef::Name(property_name) => {
debug!("property name = {}", &property_name);
set_property(&layout,
&property_parent,
&property_name,
&property_values,
&state.m_propstrings);
}
NameOrRef::NameRef(property_name_ref) => {
debug!("Property name is a forward reference = {}", &property_name_ref);
state.m_property_name_forward_references.entry(property_name_ref)
.or_insert(Vec::new())
.push((property_parent.clone(), property_values))
}
}
}
30 | 31 => {
debug!("XNAME record");
let _xname_attribute = read_unsigned_integer(reader)?;
let _xname_string = read_byte_string(reader)?;
if record_id == 31 {
let _reference_number = read_unsigned_integer(reader)?;
}
modal.reset();
unimplemented!("XNAME record is not supported yet.")
}
32 => {
debug!("XELEMENT record");
let _xelement_attribute = read_unsigned_integer(reader)?;
let _xelement_string = read_byte_string(reader)?;
property_parent = PropertyParent::XElement;
}
33 => {
debug!("XGEOMETRY record");
property_parent = PropertyParent::XGeometry;
unimplemented!("XGEOMETRY record is not supported yet.")
}
_ => unimplemented!("Unsupported record type.")
}
}
for (prop_name_id, forward_references) in state.m_property_name_forward_references.drain() {
let property_name = state.m_propnames.get(&prop_name_id).unwrap();
debug!("Resolve {} forward references '{}=>{}'.",
forward_references.len(),
prop_name_id,
&property_name);
for (property_parent, property_values) in forward_references {
set_property(&layout, &property_parent, &property_name, &property_values,
&state.m_propstrings);
}
}
if !state.m_cell_names_forward_references.is_empty() {
error!("Some cell name forward references where not resolved.");
return Err(OASISReadError::UnresolvedForwardReferences(
state.m_cell_names_forward_references.keys().copied().collect()
));
}
debug_assert!(placement_cell_forward_references.is_empty(),
"Some forward references have never been resolved.");
if !state.m_property_name_forward_references.is_empty() {
error!("Some property name forward references where not resolved.");
return Err(OASISReadError::UnresolvedForwardReferences(
state.m_property_name_forward_references.keys().copied().collect()
));
}
Ok(())
}