1use std::collections::HashMap;
6use std::fs::File;
7use std::io::{BufReader, BufWriter, Cursor, Read, Write};
8use std::path::Path;
9
10#[derive(Debug, Clone)]
12pub struct OASISFile {
13 pub version: String,
14 pub unit: f64,
15 pub offset_flag: bool,
16 pub names: NameTable,
17 pub cells: Vec<OASISCell>,
18 pub layers: Vec<LayerInfo>,
19 pub properties: Vec<PropertyDefinition>,
20}
21
22#[derive(Debug, Clone)]
23pub struct NameTable {
24 pub cell_names: HashMap<u32, String>,
25 pub text_strings: HashMap<u32, String>,
26 pub prop_names: HashMap<u32, String>,
27 pub prop_strings: HashMap<u32, String>,
28 pub layer_names: HashMap<u32, String>,
29}
30
31#[derive(Debug, Clone)]
32pub struct OASISCell {
33 pub name: String,
34 pub elements: Vec<OASISElement>,
35}
36
37#[derive(Debug, Clone)]
38pub struct LayerInfo {
39 pub layer: u32,
40 pub datatype: u32,
41 pub name: Option<String>,
42}
43
44#[derive(Debug, Clone)]
45pub enum OASISElement {
46 Rectangle(Rectangle),
47 Polygon(Polygon),
48 Path(OPath),
49 Trapezoid(Trapezoid),
50 CTrapezoid(CTrapezoid),
51 Circle(Circle),
52 Text(OText),
53 Placement(Placement),
54}
55
56#[derive(Debug, Clone)]
57pub struct Rectangle {
58 pub layer: u32,
59 pub datatype: u32,
60 pub x: i64,
61 pub y: i64,
62 pub width: u64,
63 pub height: u64,
64 pub repetition: Option<Repetition>,
65 pub properties: Vec<Property>,
66}
67
68#[derive(Debug, Clone)]
69pub struct Polygon {
70 pub layer: u32,
71 pub datatype: u32,
72 pub x: i64,
73 pub y: i64,
74 pub points: Vec<(i64, i64)>,
75 pub repetition: Option<Repetition>,
76 pub properties: Vec<Property>,
77}
78
79#[derive(Debug, Clone)]
80pub struct OPath {
81 pub layer: u32,
82 pub datatype: u32,
83 pub x: i64,
84 pub y: i64,
85 pub half_width: u64,
86 pub extension_scheme: ExtensionScheme,
87 pub points: Vec<(i64, i64)>,
88 pub repetition: Option<Repetition>,
89 pub properties: Vec<Property>,
90}
91
92#[derive(Debug, Clone)]
93pub struct Trapezoid {
94 pub layer: u32,
95 pub datatype: u32,
96 pub x: i64,
97 pub y: i64,
98 pub width: u64,
99 pub height: u64,
100 pub delta_a: i64,
101 pub delta_b: i64,
102 pub orientation: bool, pub repetition: Option<Repetition>,
104 pub properties: Vec<Property>,
105}
106
107#[derive(Debug, Clone)]
108pub struct CTrapezoid {
109 pub layer: u32,
110 pub datatype: u32,
111 pub x: i64,
112 pub y: i64,
113 pub trap_type: u8,
114 pub width: u64,
115 pub height: u64,
116 pub repetition: Option<Repetition>,
117 pub properties: Vec<Property>,
118}
119
120#[derive(Debug, Clone)]
121pub struct Circle {
122 pub layer: u32,
123 pub datatype: u32,
124 pub x: i64,
125 pub y: i64,
126 pub radius: u64,
127 pub repetition: Option<Repetition>,
128 pub properties: Vec<Property>,
129}
130
131#[derive(Debug, Clone)]
132pub struct OText {
133 pub layer: u32,
134 pub texttype: u32,
135 pub x: i64,
136 pub y: i64,
137 pub string: String,
138 pub repetition: Option<Repetition>,
139 pub properties: Vec<Property>,
140}
141
142#[derive(Debug, Clone)]
143pub struct Placement {
144 pub cell_name: String,
145 pub x: i64,
146 pub y: i64,
147 pub magnification: Option<f64>,
148 pub angle: Option<f64>,
149 pub mirror: bool,
150 pub repetition: Option<Repetition>,
151 pub properties: Vec<Property>,
152}
153
154#[derive(Debug, Clone)]
155pub enum Repetition {
156 ReusePrevious,
157 Matrix {
158 x_count: u32,
159 y_count: u32,
160 x_space: u64,
161 y_space: u64,
162 },
163 Arbitrary {
164 x_displacements: Vec<i64>,
165 y_displacements: Vec<i64>,
166 },
167 Grid {
168 count: u32,
169 grid_space: u64,
170 },
171}
172
173#[derive(Debug, Clone)]
174pub enum ExtensionScheme {
175 Flush,
176 HalfWidth,
177 Custom { start: i64, end: i64 },
178}
179
180#[derive(Debug, Clone)]
181pub struct Property {
182 pub name: String,
183 pub values: Vec<PropertyValue>,
184}
185
186#[derive(Debug, Clone)]
187pub struct PropertyDefinition {
188 pub name: String,
189 pub is_standard: bool,
190}
191
192#[derive(Debug, Clone)]
193pub enum PropertyValue {
194 Integer(i64),
195 Real(f64),
196 String(String),
197 Reference(u32),
198 Boolean(bool),
199}
200
201#[allow(dead_code)]
204mod record_ids {
205 pub const PAD: u8 = 0;
206 pub const START: u8 = 1;
207 pub const END: u8 = 2;
208 pub const CELLNAME: u8 = 3;
209 pub const TEXTSTRING: u8 = 5;
210 pub const PROPNAME: u8 = 7;
211 pub const LAYERNAME: u8 = 11;
212 pub const CELL: u8 = 13;
213 pub const XYABSOLUTE: u8 = 14;
214 pub const XYRELATIVE: u8 = 15;
215 pub const PLACEMENT: u8 = 16;
216 pub const TEXT: u8 = 18;
217 pub const RECTANGLE: u8 = 19;
218 pub const POLYGON: u8 = 20;
219 pub const PATH: u8 = 21;
220 pub const TRAPEZOID: u8 = 22;
221 pub const CTRAPEZOID: u8 = 23;
222 pub const CIRCLE: u8 = 24;
223}
224
225impl Default for OASISFile {
226 fn default() -> Self {
227 OASISFile {
228 version: "1.0".to_string(),
229 unit: 1e-9, offset_flag: false,
231 names: NameTable {
232 cell_names: HashMap::new(),
233 text_strings: HashMap::new(),
234 prop_names: HashMap::new(),
235 prop_strings: HashMap::new(),
236 layer_names: HashMap::new(),
237 },
238 cells: Vec::new(),
239 layers: Vec::new(),
240 properties: Vec::new(),
241 }
242 }
243}
244
245impl OASISFile {
246 pub fn new() -> Self {
248 Self::default()
249 }
250
251 pub fn read_from_file<P: AsRef<Path>>(path: P) -> Result<Self, Box<dyn std::error::Error>> {
253 let file = File::open(path)?;
254 let mut reader = BufReader::new(file);
255 Self::read_from_reader(&mut reader)
256 }
257
258 pub fn read_from_reader<R: Read>(reader: &mut R) -> Result<Self, Box<dyn std::error::Error>> {
260 let mut buffer = Vec::new();
261 reader.read_to_end(&mut buffer)?;
262
263 let mut cursor = Cursor::new(buffer);
264 let mut oasis = OASISFile::new();
265
266 let magic = Self::read_bytes(&mut cursor, 13)?;
268 if &magic != b"%SEMI-OASIS\r\n" {
269 return Err("Invalid OASIS file magic".into());
270 }
271
272 loop {
274 let record_id = match Self::read_u8(&mut cursor) {
275 Ok(id) => id,
276 Err(_) => break,
277 };
278
279 if record_id == 0 {
281 continue;
282 }
283
284 match record_id {
285 1 => {
286 oasis.version = Self::read_string(&mut cursor)?;
288 oasis.unit = Self::read_real(&mut cursor)?;
289 oasis.offset_flag = Self::read_u8(&mut cursor)? != 0;
290 }
291 2 => {
292 let _ = Self::read_unsigned(&mut cursor);
296 break;
297 }
298 3 | 4 => {
299 let name = Self::read_string(&mut cursor)?;
301 let ref_num = Self::read_unsigned(&mut cursor)? as u32;
302 oasis.names.cell_names.insert(ref_num, name);
303 }
304 5 | 6 => {
305 let string = Self::read_string(&mut cursor)?;
307 let ref_num = Self::read_unsigned(&mut cursor)? as u32;
308 oasis.names.text_strings.insert(ref_num, string);
309 }
310 7 | 8 => {
311 let name = Self::read_string(&mut cursor)?;
313 let ref_num = Self::read_unsigned(&mut cursor)? as u32;
314 oasis.names.prop_names.insert(ref_num, name);
315 }
316 9 | 10 => {
317 let string = Self::read_string(&mut cursor)?;
319 let ref_num = Self::read_unsigned(&mut cursor)? as u32;
320 oasis.names.prop_strings.insert(ref_num, string);
321 }
322 11 | 12 => {
323 let name = Self::read_string(&mut cursor)?;
325 let layer_interval = Self::read_layer_interval(&mut cursor)?;
326 let _datatype_interval = Self::read_layer_interval(&mut cursor)?;
327 if let Some(layer) = layer_interval.first() {
329 oasis.names.layer_names.insert(*layer, name);
330 }
331 }
332 13 => {
333 let cell = Self::read_cell(&mut cursor, &oasis.names)?;
335 oasis.cells.push(cell);
336 }
337 14 => { }
340 15 => { }
343 19 => { }
346 20 => { }
349 21 => { }
352 _ => {
353 }
355 }
356 }
357
358 Ok(oasis)
359 }
360
361 pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> Result<(), Box<dyn std::error::Error>> {
363 let file = File::create(path)?;
364 let mut writer = BufWriter::new(file);
365 self.write_to_writer(&mut writer)
366 }
367
368 pub fn write_to_writer<W: Write>(
370 &self,
371 writer: &mut W,
372 ) -> Result<(), Box<dyn std::error::Error>> {
373 writer.write_all(b"%SEMI-OASIS\r\n")?;
375
376 Self::write_u8(writer, 1)?;
378 Self::write_string(writer, &self.version)?;
379 Self::write_real(writer, self.unit)?;
380 Self::write_u8(writer, if self.offset_flag { 1 } else { 0 })?;
381
382 for (ref_num, name) in &self.names.cell_names {
384 Self::write_u8(writer, 3)?; Self::write_string(writer, name)?;
386 Self::write_unsigned(writer, *ref_num as u64)?;
387 }
388
389 for (ref_num, string) in &self.names.text_strings {
390 Self::write_u8(writer, 5)?; Self::write_string(writer, string)?;
392 Self::write_unsigned(writer, *ref_num as u64)?;
393 }
394
395 for (ref_num, name) in &self.names.prop_names {
396 Self::write_u8(writer, 7)?; Self::write_string(writer, name)?;
398 Self::write_unsigned(writer, *ref_num as u64)?;
399 }
400
401 for cell in &self.cells {
403 cell.write(writer, &self.names)?;
404 }
405
406 Self::write_u8(writer, 2)?;
408
409 Self::write_unsigned(writer, 0)?; Ok(())
413 }
414
415 fn read_cell(
416 cursor: &mut Cursor<Vec<u8>>,
417 names: &NameTable,
418 ) -> Result<OASISCell, Box<dyn std::error::Error>> {
419 let name_ref_or_string = Self::read_unsigned(cursor)?;
420
421 let name = if name_ref_or_string & 1 == 0 {
422 let ref_num = (name_ref_or_string >> 1) as u32;
424 names
425 .cell_names
426 .get(&ref_num)
427 .ok_or("Cell name reference not found")?
428 .clone()
429 } else {
430 Self::read_string(cursor)?
432 };
433
434 let mut cell = OASISCell {
435 name,
436 elements: Vec::new(),
437 };
438
439 loop {
441 let position = cursor.position();
443 let record_id = match Self::read_u8(cursor) {
444 Ok(id) => id,
445 Err(_) => break, };
447
448 match record_id {
450 2 | 13 => {
451 cursor.set_position(position);
453 break;
454 }
455 14 | 15 => {
456 continue;
458 }
459 16 => {
460 if let Ok(elem) = Self::read_placement(cursor, names) {
462 cell.elements.push(OASISElement::Placement(elem));
463 }
464 }
465 18 => {
466 if let Ok(elem) = Self::read_text(cursor, names) {
468 cell.elements.push(OASISElement::Text(elem));
469 }
470 }
471 19 => {
472 if let Ok(elem) = Self::read_rectangle(cursor) {
474 cell.elements.push(OASISElement::Rectangle(elem));
475 }
476 }
477 20 => {
478 if let Ok(elem) = Self::read_polygon(cursor) {
480 cell.elements.push(OASISElement::Polygon(elem));
481 }
482 }
483 21 => {
484 if let Ok(elem) = Self::read_path(cursor) {
486 cell.elements.push(OASISElement::Path(elem));
487 }
488 }
489 22 => {
490 if let Ok(elem) = Self::read_trapezoid(cursor) {
492 cell.elements.push(OASISElement::Trapezoid(elem));
493 }
494 }
495 23 => {
496 if let Ok(elem) = Self::read_ctrapezoid(cursor) {
498 cell.elements.push(OASISElement::CTrapezoid(elem));
499 }
500 }
501 24 => {
502 if let Ok(elem) = Self::read_circle(cursor) {
504 cell.elements.push(OASISElement::Circle(elem));
505 }
506 }
507 28 | 29 => {
508 let _ = Self::read_unsigned(cursor); let values_count = Self::read_unsigned(cursor).unwrap_or(0);
511 for _ in 0..values_count {
512 let _ = Self::read_unsigned(cursor); }
514 }
515 30 | 31 | 34 => {
516 let _ = Self::read_unsigned(cursor);
518 let _ = Self::read_string(cursor);
519 }
520 32 | 33 => {
521 let _comp_type = Self::read_unsigned(cursor)?;
523 let _uncomp_byte_count = Self::read_unsigned(cursor)?;
524 let comp_byte_count = Self::read_unsigned(cursor)?;
525 let _ = Self::read_bytes(cursor, comp_byte_count as usize);
527 }
528 _ => {
529 cursor.set_position(position);
531 break;
532 }
533 }
534 }
535
536 Ok(cell)
537 }
538
539 fn read_rectangle(
540 cursor: &mut Cursor<Vec<u8>>,
541 ) -> Result<Rectangle, Box<dyn std::error::Error>> {
542 let _info_byte = Self::read_u8(cursor)?;
543 let layer = Self::read_unsigned(cursor)? as u32;
544 let datatype = Self::read_unsigned(cursor)? as u32;
545 let width = Self::read_unsigned(cursor)?;
546 let height = Self::read_unsigned(cursor)?;
547 let x = Self::read_signed(cursor)?;
548 let y = Self::read_signed(cursor)?;
549
550 Ok(Rectangle {
551 layer,
552 datatype,
553 x,
554 y,
555 width,
556 height,
557 repetition: None,
558 properties: Vec::new(),
559 })
560 }
561
562 fn read_polygon(cursor: &mut Cursor<Vec<u8>>) -> Result<Polygon, Box<dyn std::error::Error>> {
563 let _info_byte = Self::read_u8(cursor)?;
564 let layer = Self::read_unsigned(cursor)? as u32;
565 let datatype = Self::read_unsigned(cursor)? as u32;
566 let point_count = Self::read_unsigned(cursor)? as usize;
567
568 let mut points = Vec::new();
569 for _ in 0..point_count {
570 let x = Self::read_signed(cursor)?;
571 let y = Self::read_signed(cursor)?;
572 points.push((x, y));
573 }
574
575 let x = Self::read_signed(cursor)?;
576 let y = Self::read_signed(cursor)?;
577
578 Ok(Polygon {
579 layer,
580 datatype,
581 x,
582 y,
583 points,
584 repetition: None,
585 properties: Vec::new(),
586 })
587 }
588
589 fn read_path(cursor: &mut Cursor<Vec<u8>>) -> Result<OPath, Box<dyn std::error::Error>> {
590 let _info_byte = Self::read_u8(cursor)?;
591 let layer = Self::read_unsigned(cursor)? as u32;
592 let datatype = Self::read_unsigned(cursor)? as u32;
593 let half_width = Self::read_unsigned(cursor)?;
594
595 let ext_scheme_type = Self::read_u8(cursor)?;
596 let extension_scheme = match ext_scheme_type {
597 0 => ExtensionScheme::Flush,
598 1 => ExtensionScheme::HalfWidth,
599 2 => {
600 let start = Self::read_signed(cursor)?;
601 let end = Self::read_signed(cursor)?;
602 ExtensionScheme::Custom { start, end }
603 }
604 _ => ExtensionScheme::Flush,
605 };
606
607 let point_count = Self::read_unsigned(cursor)? as usize;
608 let mut points = Vec::new();
609 for _ in 0..point_count {
610 let x = Self::read_signed(cursor)?;
611 let y = Self::read_signed(cursor)?;
612 points.push((x, y));
613 }
614
615 let x = Self::read_signed(cursor)?;
616 let y = Self::read_signed(cursor)?;
617
618 Ok(OPath {
619 layer,
620 datatype,
621 x,
622 y,
623 half_width,
624 extension_scheme,
625 points,
626 repetition: None,
627 properties: Vec::new(),
628 })
629 }
630
631 fn read_trapezoid(
632 cursor: &mut Cursor<Vec<u8>>,
633 ) -> Result<Trapezoid, Box<dyn std::error::Error>> {
634 let layer = Self::read_unsigned(cursor)? as u32;
635 let datatype = Self::read_unsigned(cursor)? as u32;
636 let orientation = Self::read_u8(cursor)? != 0;
637 let width = Self::read_unsigned(cursor)?;
638 let height = Self::read_unsigned(cursor)?;
639 let delta_a = Self::read_signed(cursor)?;
640 let delta_b = Self::read_signed(cursor)?;
641 let x = Self::read_signed(cursor)?;
642 let y = Self::read_signed(cursor)?;
643
644 Ok(Trapezoid {
645 layer,
646 datatype,
647 orientation,
648 width,
649 height,
650 delta_a,
651 delta_b,
652 x,
653 y,
654 repetition: None,
655 properties: Vec::new(),
656 })
657 }
658
659 fn read_ctrapezoid(
660 cursor: &mut Cursor<Vec<u8>>,
661 ) -> Result<CTrapezoid, Box<dyn std::error::Error>> {
662 let layer = Self::read_unsigned(cursor)? as u32;
663 let datatype = Self::read_unsigned(cursor)? as u32;
664 let trap_type = Self::read_u8(cursor)?;
665 let width = Self::read_unsigned(cursor)?;
666 let height = Self::read_unsigned(cursor)?;
667 let x = Self::read_signed(cursor)?;
668 let y = Self::read_signed(cursor)?;
669
670 Ok(CTrapezoid {
671 layer,
672 datatype,
673 trap_type,
674 width,
675 height,
676 x,
677 y,
678 repetition: None,
679 properties: Vec::new(),
680 })
681 }
682
683 fn read_circle(cursor: &mut Cursor<Vec<u8>>) -> Result<Circle, Box<dyn std::error::Error>> {
684 let layer = Self::read_unsigned(cursor)? as u32;
685 let datatype = Self::read_unsigned(cursor)? as u32;
686 let radius = Self::read_unsigned(cursor)?;
687 let x = Self::read_signed(cursor)?;
688 let y = Self::read_signed(cursor)?;
689
690 Ok(Circle {
691 layer,
692 datatype,
693 radius,
694 x,
695 y,
696 repetition: None,
697 properties: Vec::new(),
698 })
699 }
700
701 fn read_text(
702 cursor: &mut Cursor<Vec<u8>>,
703 _names: &NameTable,
704 ) -> Result<OText, Box<dyn std::error::Error>> {
705 let layer = Self::read_unsigned(cursor)? as u32;
706 let texttype = Self::read_unsigned(cursor)? as u32;
707 let string = Self::read_string(cursor)?;
708 let x = Self::read_signed(cursor)?;
709 let y = Self::read_signed(cursor)?;
710
711 Ok(OText {
712 layer,
713 texttype,
714 string,
715 x,
716 y,
717 repetition: None,
718 properties: Vec::new(),
719 })
720 }
721
722 fn read_placement(
723 cursor: &mut Cursor<Vec<u8>>,
724 _names: &NameTable,
725 ) -> Result<Placement, Box<dyn std::error::Error>> {
726 let cell_name = Self::read_string(cursor)?;
727 let x = Self::read_signed(cursor)?;
728 let y = Self::read_signed(cursor)?;
729
730 Ok(Placement {
731 cell_name,
732 x,
733 y,
734 magnification: None,
735 angle: None,
736 mirror: false,
737 repetition: None,
738 properties: Vec::new(),
739 })
740 }
741
742 fn read_u8<R: Read>(cursor: &mut R) -> Result<u8, Box<dyn std::error::Error>> {
744 let mut buf = [0u8; 1];
745 cursor.read_exact(&mut buf)?;
746 Ok(buf[0])
747 }
748
749 fn write_u8<W: Write>(writer: &mut W, value: u8) -> Result<(), Box<dyn std::error::Error>> {
750 writer.write_all(&[value])?;
751 Ok(())
752 }
753
754 fn read_bytes<R: Read>(
755 cursor: &mut R,
756 len: usize,
757 ) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
758 let mut buf = vec![0u8; len];
759 cursor.read_exact(&mut buf)?;
760 Ok(buf)
761 }
762
763 fn read_unsigned<R: Read>(cursor: &mut R) -> Result<u64, Box<dyn std::error::Error>> {
764 let mut result = 0u64;
766 let mut shift = 0;
767
768 loop {
769 let byte = Self::read_u8(cursor)?;
770 result |= ((byte & 0x7F) as u64) << shift;
771
772 if byte & 0x80 == 0 {
773 break;
774 }
775 shift += 7;
776 }
777
778 Ok(result)
779 }
780
781 fn write_unsigned<W: Write>(
782 writer: &mut W,
783 mut value: u64,
784 ) -> Result<(), Box<dyn std::error::Error>> {
785 loop {
786 let mut byte = (value & 0x7F) as u8;
787 value >>= 7;
788
789 if value != 0 {
790 byte |= 0x80;
791 }
792
793 Self::write_u8(writer, byte)?;
794
795 if value == 0 {
796 break;
797 }
798 }
799 Ok(())
800 }
801
802 fn read_signed<R: Read>(cursor: &mut R) -> Result<i64, Box<dyn std::error::Error>> {
803 let unsigned = Self::read_unsigned(cursor)?;
804
805 let signed = if unsigned & 1 == 0 {
807 (unsigned >> 1) as i64
808 } else {
809 -((unsigned >> 1) as i64) - 1
810 };
811
812 Ok(signed)
813 }
814
815 fn write_signed<W: Write>(
816 writer: &mut W,
817 value: i64,
818 ) -> Result<(), Box<dyn std::error::Error>> {
819 let unsigned = if value >= 0 {
821 (value as u64) << 1
822 } else {
823 (((-value - 1) as u64) << 1) | 1
824 };
825
826 Self::write_unsigned(writer, unsigned)
827 }
828
829 fn read_string<R: Read>(cursor: &mut R) -> Result<String, Box<dyn std::error::Error>> {
830 let len = Self::read_unsigned(cursor)? as usize;
831 let bytes = Self::read_bytes(cursor, len)?;
832 Ok(String::from_utf8_lossy(&bytes).into_owned())
835 }
836
837 fn write_string<W: Write>(writer: &mut W, s: &str) -> Result<(), Box<dyn std::error::Error>> {
838 Self::write_unsigned(writer, s.len() as u64)?;
839 writer.write_all(s.as_bytes())?;
840 Ok(())
841 }
842
843 fn read_real<R: Read>(cursor: &mut R) -> Result<f64, Box<dyn std::error::Error>> {
844 let type_byte = Self::read_u8(cursor)?;
845
846 match type_byte {
847 0 => Ok(0.0),
848 1 => Ok(1.0),
849 2 => {
850 let mantissa = Self::read_unsigned(cursor)? as f64;
851 let exponent = Self::read_signed(cursor)? as i32;
852 Ok(mantissa * 10f64.powi(exponent))
853 }
854 3 => {
855 let mantissa = Self::read_signed(cursor)? as f64;
856 let exponent = Self::read_signed(cursor)? as i32;
857 Ok(mantissa * 10f64.powi(exponent))
858 }
859 4 | 5 => {
860 let mantissa = if type_byte == 4 {
861 Self::read_unsigned(cursor)? as f64
862 } else {
863 Self::read_signed(cursor)? as f64
864 };
865 let denominator = Self::read_unsigned(cursor)? as f64;
866 let exponent = Self::read_signed(cursor)? as i32;
867 Ok((mantissa / denominator) * 10f64.powi(exponent))
868 }
869 6 => {
870 let mut bytes = [0u8; 4];
871 cursor.read_exact(&mut bytes)?;
872 Ok(f32::from_le_bytes(bytes) as f64)
873 }
874 7 => {
875 let mut bytes = [0u8; 8];
876 cursor.read_exact(&mut bytes)?;
877 Ok(f64::from_le_bytes(bytes))
878 }
879 _ => Err(format!(
880 "Invalid real type: {} (may indicate corrupted file or misaligned read)",
881 type_byte
882 )
883 .into()),
884 }
885 }
886
887 fn write_real<W: Write>(writer: &mut W, value: f64) -> Result<(), Box<dyn std::error::Error>> {
888 Self::write_u8(writer, 7)?;
890 writer.write_all(&value.to_le_bytes())?;
891 Ok(())
892 }
893
894 fn read_layer_interval<R: Read>(
895 cursor: &mut R,
896 ) -> Result<Vec<u32>, Box<dyn std::error::Error>> {
897 let type_byte = Self::read_u8(cursor)?;
898
899 match type_byte {
900 0 => {
901 let value = Self::read_unsigned(cursor)? as u32;
902 Ok(vec![value])
903 }
904 1 => {
905 let start = Self::read_unsigned(cursor)? as u32;
906 let end = Self::read_unsigned(cursor)? as u32;
907 Ok((start..=end).collect())
908 }
909 2 => {
910 let count = Self::read_unsigned(cursor)? as usize;
911 let mut values = Vec::new();
912 for _ in 0..count {
913 values.push(Self::read_unsigned(cursor)? as u32);
914 }
915 Ok(values)
916 }
917 _ => Err("Invalid layer interval type".into()),
918 }
919 }
920}
921
922impl OASISCell {
923 fn write<W: Write>(
924 &self,
925 writer: &mut W,
926 names: &NameTable,
927 ) -> Result<(), Box<dyn std::error::Error>> {
928 OASISFile::write_u8(writer, 14)?; OASISFile::write_u8(writer, 13)?;
934
935 let name_ref = names
937 .cell_names
938 .iter()
939 .find(|(_, n)| n.as_str() == self.name)
940 .map(|(r, _)| *r);
941
942 if let Some(ref_num) = name_ref {
943 OASISFile::write_unsigned(writer, (ref_num as u64) << 1)?;
944 } else {
945 OASISFile::write_unsigned(writer, 1)?;
946 OASISFile::write_string(writer, &self.name)?;
947 }
948
949 for element in &self.elements {
951 element.write(writer, names)?;
952 }
953
954 Ok(())
955 }
956}
957
958impl OASISElement {
959 fn write<W: Write>(
960 &self,
961 writer: &mut W,
962 names: &NameTable,
963 ) -> Result<(), Box<dyn std::error::Error>> {
964 match self {
965 OASISElement::Rectangle(r) => r.write(writer),
966 OASISElement::Polygon(p) => p.write(writer),
967 OASISElement::Path(p) => p.write(writer),
968 OASISElement::Trapezoid(t) => t.write(writer),
969 OASISElement::CTrapezoid(ct) => ct.write(writer),
970 OASISElement::Circle(c) => c.write(writer),
971 OASISElement::Text(t) => t.write(writer, names),
972 OASISElement::Placement(p) => p.write(writer, names),
973 }
974 }
975}
976
977impl Rectangle {
978 fn write<W: Write>(&self, writer: &mut W) -> Result<(), Box<dyn std::error::Error>> {
979 OASISFile::write_u8(writer, 19)?; OASISFile::write_u8(writer, 0)?; OASISFile::write_unsigned(writer, self.layer as u64)?;
982 OASISFile::write_unsigned(writer, self.datatype as u64)?;
983 OASISFile::write_unsigned(writer, self.width)?;
984 OASISFile::write_unsigned(writer, self.height)?;
985 OASISFile::write_signed(writer, self.x)?;
986 OASISFile::write_signed(writer, self.y)?;
987 Ok(())
988 }
989}
990
991impl Polygon {
992 fn write<W: Write>(&self, writer: &mut W) -> Result<(), Box<dyn std::error::Error>> {
993 OASISFile::write_u8(writer, 20)?; OASISFile::write_u8(writer, 0)?; OASISFile::write_unsigned(writer, self.layer as u64)?;
996 OASISFile::write_unsigned(writer, self.datatype as u64)?;
997 OASISFile::write_unsigned(writer, self.points.len() as u64)?;
998
999 for (x, y) in &self.points {
1000 OASISFile::write_signed(writer, *x)?;
1001 OASISFile::write_signed(writer, *y)?;
1002 }
1003
1004 OASISFile::write_signed(writer, self.x)?;
1005 OASISFile::write_signed(writer, self.y)?;
1006 Ok(())
1007 }
1008}
1009
1010impl OPath {
1011 fn write<W: Write>(&self, writer: &mut W) -> Result<(), Box<dyn std::error::Error>> {
1012 OASISFile::write_u8(writer, 21)?; OASISFile::write_u8(writer, 0)?; OASISFile::write_unsigned(writer, self.layer as u64)?;
1015 OASISFile::write_unsigned(writer, self.datatype as u64)?;
1016 OASISFile::write_unsigned(writer, self.half_width)?;
1017
1018 match &self.extension_scheme {
1020 ExtensionScheme::Flush => OASISFile::write_u8(writer, 0)?,
1021 ExtensionScheme::HalfWidth => OASISFile::write_u8(writer, 1)?,
1022 ExtensionScheme::Custom { start, end } => {
1023 OASISFile::write_u8(writer, 2)?;
1024 OASISFile::write_signed(writer, *start)?;
1025 OASISFile::write_signed(writer, *end)?;
1026 }
1027 }
1028
1029 OASISFile::write_unsigned(writer, self.points.len() as u64)?;
1030 for (x, y) in &self.points {
1031 OASISFile::write_signed(writer, *x)?;
1032 OASISFile::write_signed(writer, *y)?;
1033 }
1034
1035 OASISFile::write_signed(writer, self.x)?;
1036 OASISFile::write_signed(writer, self.y)?;
1037 Ok(())
1038 }
1039}
1040
1041impl Trapezoid {
1042 fn write<W: Write>(&self, writer: &mut W) -> Result<(), Box<dyn std::error::Error>> {
1043 OASISFile::write_u8(writer, 22)?; OASISFile::write_unsigned(writer, self.layer as u64)?;
1045 OASISFile::write_unsigned(writer, self.datatype as u64)?;
1046 OASISFile::write_u8(writer, if self.orientation { 1 } else { 0 })?;
1047 OASISFile::write_unsigned(writer, self.width)?;
1048 OASISFile::write_unsigned(writer, self.height)?;
1049 OASISFile::write_signed(writer, self.delta_a)?;
1050 OASISFile::write_signed(writer, self.delta_b)?;
1051 OASISFile::write_signed(writer, self.x)?;
1052 OASISFile::write_signed(writer, self.y)?;
1053 Ok(())
1054 }
1055}
1056
1057impl CTrapezoid {
1058 fn write<W: Write>(&self, writer: &mut W) -> Result<(), Box<dyn std::error::Error>> {
1059 OASISFile::write_u8(writer, 23)?; OASISFile::write_unsigned(writer, self.layer as u64)?;
1061 OASISFile::write_unsigned(writer, self.datatype as u64)?;
1062 OASISFile::write_u8(writer, self.trap_type)?;
1063 OASISFile::write_unsigned(writer, self.width)?;
1064 OASISFile::write_unsigned(writer, self.height)?;
1065 OASISFile::write_signed(writer, self.x)?;
1066 OASISFile::write_signed(writer, self.y)?;
1067 Ok(())
1068 }
1069}
1070
1071impl Circle {
1072 fn write<W: Write>(&self, writer: &mut W) -> Result<(), Box<dyn std::error::Error>> {
1073 OASISFile::write_u8(writer, 24)?; OASISFile::write_unsigned(writer, self.layer as u64)?;
1075 OASISFile::write_unsigned(writer, self.datatype as u64)?;
1076 OASISFile::write_unsigned(writer, self.radius)?;
1077 OASISFile::write_signed(writer, self.x)?;
1078 OASISFile::write_signed(writer, self.y)?;
1079 Ok(())
1080 }
1081}
1082
1083impl OText {
1084 fn write<W: Write>(
1085 &self,
1086 writer: &mut W,
1087 _names: &NameTable,
1088 ) -> Result<(), Box<dyn std::error::Error>> {
1089 OASISFile::write_u8(writer, 18)?; OASISFile::write_unsigned(writer, self.layer as u64)?;
1091 OASISFile::write_unsigned(writer, self.texttype as u64)?;
1092 OASISFile::write_string(writer, &self.string)?;
1093 OASISFile::write_signed(writer, self.x)?;
1094 OASISFile::write_signed(writer, self.y)?;
1095 Ok(())
1096 }
1097}
1098
1099impl Placement {
1100 fn write<W: Write>(
1101 &self,
1102 writer: &mut W,
1103 _names: &NameTable,
1104 ) -> Result<(), Box<dyn std::error::Error>> {
1105 OASISFile::write_u8(writer, 16)?; OASISFile::write_string(writer, &self.cell_name)?;
1107 OASISFile::write_signed(writer, self.x)?;
1108 OASISFile::write_signed(writer, self.y)?;
1109 Ok(())
1110 }
1111}