wow_wmo/
api.rs

1use crate::chunk_discovery::{ChunkDiscovery, discover_chunks};
2use crate::error::WmoError;
3use crate::file_type::{WmoFileType, detect_file_type};
4use crate::group_parser::{WmoGroup, parse_group_file};
5use crate::root_parser::{WmoRoot, parse_root_file};
6use std::io::{Read, Seek, SeekFrom};
7
8/// Result of parsing a WMO file
9#[derive(Debug, Clone)]
10pub enum ParsedWmo {
11    /// Root WMO file containing header and references
12    Root(WmoRoot),
13    /// Group file containing geometry data
14    Group(WmoGroup),
15}
16
17impl ParsedWmo {
18    /// Get the file type
19    pub fn file_type(&self) -> WmoFileType {
20        match self {
21            ParsedWmo::Root(_) => WmoFileType::Root,
22            ParsedWmo::Group(_) => WmoFileType::Group,
23        }
24    }
25
26    /// Get the version (always 17 for supported files)
27    pub fn version(&self) -> u32 {
28        match self {
29            ParsedWmo::Root(r) => r.version,
30            ParsedWmo::Group(g) => g.version,
31        }
32    }
33}
34
35/// Result of parsing with additional metadata
36#[derive(Debug, Clone)]
37pub struct ParseResult {
38    /// The parsed WMO data
39    pub wmo: ParsedWmo,
40    /// Chunk discovery information
41    pub discovery: ChunkDiscovery,
42}
43
44impl ParseResult {
45    /// Get metadata about the file parsing
46    pub fn metadata(&self) -> Option<&ChunkDiscovery> {
47        Some(&self.discovery)
48    }
49}
50
51/// Parse a WMO file (root or group) with automatic type detection
52///
53/// This is the main entry point for parsing WMO files. It will:
54/// 1. Discover all chunks in the file (Stage 1)
55/// 2. Determine if it's a root or group file
56/// 3. Parse with the appropriate parser (Stage 2)
57///
58/// # Example
59/// ```no_run
60/// use std::fs::File;
61/// use std::io::BufReader;
62/// use wow_wmo::{parse_wmo, ParsedWmo};
63///
64/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
65/// let file = File::open("example.wmo")?;
66/// let mut reader = BufReader::new(file);
67/// let wmo = parse_wmo(&mut reader)?;
68///
69/// match wmo {
70///     ParsedWmo::Root(root) => {
71///         println!("Root file with {} groups", root.n_groups);
72///     }
73///     ParsedWmo::Group(group) => {
74///         println!("Group {} with {} vertices", group.group_index, group.n_vertices);
75///     }
76/// }
77/// # Ok(())
78/// # }
79/// ```
80pub fn parse_wmo<R: Read + Seek>(reader: &mut R) -> Result<ParsedWmo, WmoError> {
81    // Stage 1: Discover chunks
82    let discovery = discover_chunks(reader).map_err(|e| {
83        WmoError::Io(std::io::Error::new(
84            std::io::ErrorKind::InvalidData,
85            format!("Failed to discover chunks: {}", e),
86        ))
87    })?;
88
89    // Detect file type
90    let file_type = detect_file_type(&discovery);
91
92    // Reset reader to beginning
93    reader.seek(SeekFrom::Start(0))?;
94
95    // Stage 2: Parse based on file type
96    match file_type {
97        WmoFileType::Root => {
98            let root = parse_root_file(reader, discovery)
99                .map_err(|e| WmoError::InvalidFormat(format!("Failed to parse root: {}", e)))?;
100            Ok(ParsedWmo::Root(root))
101        }
102        WmoFileType::Group => {
103            let group = parse_group_file(reader, discovery)
104                .map_err(|e| WmoError::InvalidFormat(format!("Failed to parse group: {}", e)))?;
105            Ok(ParsedWmo::Group(group))
106        }
107    }
108}
109
110/// Parse a WMO file with full metadata
111///
112/// Returns both the parsed data and chunk discovery information
113pub fn parse_wmo_with_metadata<R: Read + Seek>(reader: &mut R) -> Result<ParseResult, WmoError> {
114    // Stage 1: Discover chunks
115    let discovery = discover_chunks(reader).map_err(|e| {
116        WmoError::Io(std::io::Error::new(
117            std::io::ErrorKind::InvalidData,
118            format!("Failed to discover chunks: {}", e),
119        ))
120    })?;
121
122    // Clone discovery for return
123    let discovery_clone = discovery.clone();
124
125    // Detect file type
126    let file_type = detect_file_type(&discovery);
127
128    // Reset reader to beginning
129    reader.seek(SeekFrom::Start(0))?;
130
131    // Stage 2: Parse based on file type
132    let wmo = match file_type {
133        WmoFileType::Root => {
134            let root = parse_root_file(reader, discovery)
135                .map_err(|e| WmoError::InvalidFormat(format!("Failed to parse root: {}", e)))?;
136            ParsedWmo::Root(root)
137        }
138        WmoFileType::Group => {
139            let group = parse_group_file(reader, discovery)
140                .map_err(|e| WmoError::InvalidFormat(format!("Failed to parse group: {}", e)))?;
141            ParsedWmo::Group(group)
142        }
143    };
144
145    Ok(ParseResult {
146        wmo,
147        discovery: discovery_clone,
148    })
149}
150
151/// Discover chunks in a WMO file without parsing content
152///
153/// This performs Stage 1 parsing only, useful for inspecting file structure.
154pub fn discover_wmo_chunks<R: Read + Seek>(reader: &mut R) -> Result<ChunkDiscovery, WmoError> {
155    discover_chunks(reader).map_err(|e| {
156        WmoError::Io(std::io::Error::new(
157            std::io::ErrorKind::InvalidData,
158            format!("Failed to discover chunks: {}", e),
159        ))
160    })
161}