lib3mf_core/archive/
model_locator.rs1use crate::archive::{ArchiveReader, opc::parse_relationships};
2use crate::error::{Lib3mfError, Result};
3
4pub fn find_model_path<R: ArchiveReader>(archive: &mut R) -> Result<String> {
6 if !archive.entry_exists("_rels/.rels") {
8 return Err(Lib3mfError::InvalidStructure(
9 "Missing _rels/.rels".to_string(),
10 ));
11 }
12
13 let rels_data = archive.read_entry("_rels/.rels")?;
14 let rels = parse_relationships(&rels_data)?;
15
16 let model_rel_type = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel";
19 let thumbnail_rel_type =
20 "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail";
21 let print_ticket_rel_type = "http://schemas.microsoft.com/3dmanufacturing/2013/01/printticket";
22
23 let mut model_path: Option<String> = None;
24 let mut model_count = 0;
25 let mut print_ticket_count = 0;
26
27 for rel in rels {
28 if rel.target_mode.to_lowercase() == "external" {
30 return Err(Lib3mfError::Validation(format!(
31 "External relationships are not allowed in 3MF packages. Found external relationship with target '{}'",
32 rel.target
33 )));
34 }
35
36 if rel.rel_type == model_rel_type {
37 model_count += 1;
38 if model_count > 1 {
39 return Err(Lib3mfError::Validation(
40 "Multiple 3D model part relationships found. Only one 3D model part is allowed per package".to_string(),
41 ));
42 }
43
44 let path = rel.target.clone();
48 model_path = Some(if path.starts_with('/') {
49 path.trim_start_matches('/').to_string()
50 } else {
51 path
52 });
53 } else if rel.rel_type == thumbnail_rel_type {
54 let thumb_path = if rel.target.starts_with('/') {
56 rel.target.trim_start_matches('/').to_string()
57 } else {
58 rel.target.clone()
59 };
60 if !archive.entry_exists(&thumb_path) {
61 return Err(Lib3mfError::Validation(format!(
62 "Thumbnail file '{}' referenced in relationships does not exist in package",
63 thumb_path
64 )));
65 }
66 } else if rel.rel_type == print_ticket_rel_type {
67 print_ticket_count += 1;
68 if print_ticket_count > 1 {
69 return Err(Lib3mfError::Validation(
70 "Multiple print ticket relationships found. Only one print ticket is allowed per package".to_string(),
71 ));
72 }
73 }
74 }
75
76 model_path.ok_or_else(|| Lib3mfError::Validation("No 3D model relationship found".to_string()))
77}