lib3mf_core/archive/
model_locator.rs

1use crate::archive::{ArchiveReader, opc::parse_relationships};
2use crate::error::{Lib3mfError, Result};
3
4/// Locates the path of the 3D model file within the archive.
5pub fn find_model_path<R: ArchiveReader>(archive: &mut R) -> Result<String> {
6    // 1. Read _rels/.rels
7    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    // 2. Find the relationship with type 3D Model
17    // 3MF Core Spec: http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel
18    let model_rel_type = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel";
19
20    for rel in rels {
21        if rel.rel_type == model_rel_type {
22            // Target paths in OPC are often relative to the root if they start with /
23            // or relative to the relations file location.
24            // For root relationships, they are usually relative to root.
25            let path = rel.target;
26            if path.starts_with('/') {
27                return Ok(path.trim_start_matches('/').to_string());
28            }
29            return Ok(path);
30        }
31    }
32
33    Err(Lib3mfError::Validation(
34        "No 3D model relationship found".to_string(),
35    ))
36}