lib3mf_core/archive/
opc.rs

1use crate::error::{Lib3mfError, Result};
2use quick_xml::events::Event;
3use quick_xml::reader::Reader;
4use serde::{Deserialize, Serialize};
5
6/// Represents an OPC Relationship.
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct Relationship {
9    pub id: String,
10    pub rel_type: String,
11    pub target: String,
12    pub target_mode: String,
13}
14
15/// Represents an OPC Content Type override or default.
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub enum ContentType {
18    Default {
19        extension: String,
20        content_type: String,
21    },
22    Override {
23        part_name: String,
24        content_type: String,
25    },
26}
27
28/// Parses relationship file (e.g., _rels/.rels).
29pub fn parse_relationships(xml_content: &[u8]) -> Result<Vec<Relationship>> {
30    let mut reader = Reader::from_reader(xml_content);
31    reader.config_mut().trim_text(true);
32
33    let mut rels = Vec::new();
34    let mut buf = Vec::new();
35
36    loop {
37        match reader.read_event_into(&mut buf) {
38            Ok(Event::Empty(e)) | Ok(Event::Start(e)) => {
39                if e.name().as_ref() == b"Relationship" {
40                    let mut id = String::new();
41                    let mut rel_type = String::new();
42                    let mut target = String::new();
43                    let mut target_mode = "Internal".to_string(); // Default
44
45                    for attr in e.attributes() {
46                        let attr = attr.map_err(|e| Lib3mfError::Validation(e.to_string()))?;
47                        match attr.key.as_ref() {
48                            b"Id" => id = String::from_utf8_lossy(&attr.value).to_string(),
49                            b"Type" => rel_type = String::from_utf8_lossy(&attr.value).to_string(),
50                            b"Target" => target = String::from_utf8_lossy(&attr.value).to_string(),
51                            b"TargetMode" => {
52                                target_mode = String::from_utf8_lossy(&attr.value).to_string()
53                            }
54                            _ => {}
55                        }
56                    }
57                    rels.push(Relationship {
58                        id,
59                        rel_type,
60                        target,
61                        target_mode,
62                    });
63                }
64            }
65            Ok(Event::Eof) => break,
66            Err(e) => return Err(Lib3mfError::Validation(e.to_string())),
67            _ => {}
68        }
69        buf.clear();
70    }
71
72    Ok(rels)
73}
74
75/// Parses `[Content_Types].xml`.
76pub fn parse_content_types(xml_content: &[u8]) -> Result<Vec<ContentType>> {
77    let mut reader = Reader::from_reader(xml_content);
78    reader.config_mut().trim_text(true);
79
80    let mut types = Vec::new();
81    let mut buf = Vec::new();
82
83    loop {
84        match reader.read_event_into(&mut buf) {
85            Ok(Event::Empty(e)) | Ok(Event::Start(e)) => match e.name().as_ref() {
86                b"Default" => {
87                    let mut extension = String::new();
88                    let mut content_type = String::new();
89                    for attr in e.attributes() {
90                        let attr = attr.map_err(|e| Lib3mfError::Validation(e.to_string()))?;
91                        match attr.key.as_ref() {
92                            b"Extension" => {
93                                extension = String::from_utf8_lossy(&attr.value).to_string()
94                            }
95                            b"ContentType" => {
96                                content_type = String::from_utf8_lossy(&attr.value).to_string()
97                            }
98                            _ => {}
99                        }
100                    }
101                    types.push(ContentType::Default {
102                        extension,
103                        content_type,
104                    });
105                }
106                b"Override" => {
107                    let mut part_name = String::new();
108                    let mut content_type = String::new();
109                    for attr in e.attributes() {
110                        let attr = attr.map_err(|e| Lib3mfError::Validation(e.to_string()))?;
111                        match attr.key.as_ref() {
112                            b"PartName" => {
113                                part_name = String::from_utf8_lossy(&attr.value).to_string()
114                            }
115                            b"ContentType" => {
116                                content_type = String::from_utf8_lossy(&attr.value).to_string()
117                            }
118                            _ => {}
119                        }
120                    }
121                    types.push(ContentType::Override {
122                        part_name,
123                        content_type,
124                    });
125                }
126                _ => {}
127            },
128            Ok(Event::Eof) => break,
129            Err(e) => return Err(Lib3mfError::Validation(e.to_string())),
130            _ => {}
131        }
132        buf.clear();
133    }
134
135    Ok(types)
136}