1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
//! Archive layer for reading and writing 3MF container files.
//!
//! This module implements the OPC (Open Packaging Conventions) container layer that 3MF is built on.
//! 3MF files are ZIP archives containing XML model files, textures, thumbnails, and metadata, organized
//! according to OPC relationship and content type conventions.
//!
//! ## Architecture
//!
//! The archive layer provides:
//!
//! 1. **Trait-based abstraction**: [`ArchiveReader`] and [`ArchiveWriter`] traits decouple the parser
//! from the underlying ZIP implementation, allowing different backends (file, memory, async, etc.)
//! 2. **OPC relationship discovery**: The [`find_model_path`] function traverses `_rels/.rels` files
//! to locate the main 3D model XML file within the archive.
//! 3. **Default ZIP implementation**: [`ZipArchiver`] provides a standard file-based ZIP backend.
//!
//! ## Typical Usage
//!
//! Opening and reading a 3MF file:
//!
//! ```no_run
//! use lib3mf_core::archive::{ZipArchiver, ArchiveReader, find_model_path};
//! use std::fs::File;
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Open the 3MF ZIP archive
//! let file = File::open("model.3mf")?;
//! let mut archiver = ZipArchiver::new(file)?;
//!
//! // Discover the main model XML path via OPC relationships
//! let model_path = find_model_path(&mut archiver)?;
//! // Typically returns "3D/3dmodel.model" or similar
//!
//! // Read the model XML content
//! let model_xml = archiver.read_entry(&model_path)?;
//!
//! // Read attachments (textures, thumbnails, etc.)
//! if archiver.entry_exists("Metadata/thumbnail.png") {
//! let thumbnail = archiver.read_entry("Metadata/thumbnail.png")?;
//! }
//!
//! // List all entries
//! let entries = archiver.list_entries()?;
//! for entry in entries {
//! println!("Archive contains: {}", entry);
//! }
//! # Ok(())
//! # }
//! ```
//!
//! ## OPC Relationship Discovery
//!
//! The [`find_model_path`] function implements the OPC discovery algorithm:
//!
//! 1. Read `_rels/.rels` (package-level relationships)
//! 2. Find relationship with type `http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel`
//! 3. Extract target path (e.g., `/3D/3dmodel.model`)
//! 4. Normalize path (remove leading `/`)
//!
//! This allows 3MF files to have different internal structures while remaining conformant to the spec.
//!
//! ## ArchiveReader Trait
//!
//! The [`ArchiveReader`] trait provides three core operations:
//!
//! - [`read_entry`](ArchiveReader::read_entry): Read file content by path
//! - [`entry_exists`](ArchiveReader::entry_exists): Check if a path exists
//! - [`list_entries`](ArchiveReader::list_entries): Enumerate all archive contents
//!
//! Implementations must also satisfy `Read + Seek` for compatibility with the ZIP crate.
//!
//! ## ArchiveWriter Trait
//!
//! The [`ArchiveWriter`] trait provides a single operation:
//!
//! - [`write_entry`](ArchiveWriter::write_entry): Write data to a path in the archive
//!
//! Implementations handle compression, content type registration, and relationship generation.
/// OPC relationship discovery — finds the main model XML path within a 3MF archive.
/// OPC relationship and content type parsers.
/// ZIP-based `ArchiveReader` implementation using the `zip` crate.
pub use *;
// pub use opc::*; // Clippy says unused
pub use *;
use crateResult;
use ;
/// Trait for reading entries from an archive (ZIP).
///
/// This trait abstracts over different ZIP backend implementations, allowing the parser to work
/// with files, in-memory buffers, async I/O, or custom storage.
///
/// # Requirements
///
/// Implementations must also implement `Read + Seek` for compatibility with the underlying ZIP library.
///
/// # Examples
///
/// ```no_run
/// use lib3mf_core::archive::{ArchiveReader, ZipArchiver};
/// use std::fs::File;
///
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let file = File::open("model.3mf")?;
/// let mut archive = ZipArchiver::new(file)?;
///
/// // Check if entry exists before reading
/// if archive.entry_exists("3D/3dmodel.model") {
/// let content = archive.read_entry("3D/3dmodel.model")?;
/// println!("Model XML size: {} bytes", content.len());
/// }
///
/// // List all entries
/// for entry in archive.list_entries()? {
/// println!("Found: {}", entry);
/// }
/// # Ok(())
/// # }
/// ```
/// Trait for writing entries to an archive.
///
/// This trait abstracts over different ZIP backend implementations for creating 3MF files.