Skip to main content

wim_parser/
lib.rs

1use anyhow::{Context, Result};
2use std::fs::File;
3use std::io::{BufReader, Read, Seek, SeekFrom};
4use std::path::Path;
5use tracing::{debug, info};
6
7// 性能优化导入
8use encoding_rs::UTF_16LE;
9use quick_xml::events::Event;
10use quick_xml::Reader;
11
12/// 字符串池用于减少内存分配
13#[derive(Debug)]
14struct StringPool {
15    pool: Vec<String>,
16    index: usize,
17}
18
19#[allow(dead_code)]
20impl StringPool {
21    fn new() -> Self {
22        Self {
23            pool: Vec::with_capacity(32), // 预分配32个字符串
24            index: 0,
25        }
26    }
27
28    fn get_string(&mut self) -> &mut String {
29        if self.index >= self.pool.len() {
30            self.pool.push(String::with_capacity(256)); // 预分配容量
31        }
32        let string = &mut self.pool[self.index];
33        string.clear();
34        self.index += 1;
35        string
36    }
37
38    fn reset(&mut self) {
39        self.index = 0;
40        // 保留字符串对象,只重置索引
41    }
42}
43
44/// WIM 文件头结构体 (WIMHEADER_V1_PACKED)
45/// 总大小:204 字节
46#[derive(Debug, Clone)]
47#[allow(dead_code)]
48pub struct WimHeader {
49    /// 文件签名 "MSWIM\x00\x00\x00"
50    pub signature: [u8; 8],
51    /// 文件头大小
52    pub header_size: u32,
53    /// 格式版本
54    pub format_version: u32,
55    /// 文件标志
56    pub file_flags: u32,
57    /// 压缩文件大小
58    pub compressed_size: u32,
59    /// 唯一标识符 (GUID)
60    pub guid: [u8; 16],
61    /// 段号
62    pub segment_number: u16,
63    /// 段总数
64    pub total_segments: u16,
65    /// 镜像数量
66    pub image_count: u32,
67    /// 偏移表文件资源
68    pub offset_table_resource: FileResourceEntry,
69    /// XML 数据文件资源
70    pub xml_data_resource: FileResourceEntry,
71    /// 引导元数据文件资源
72    pub boot_metadata_resource: FileResourceEntry,
73    /// 可引导镜像索引
74    pub bootable_image_index: u32,
75    /// 完整性数据文件资源
76    pub integrity_resource: FileResourceEntry,
77}
78
79/// 文件资源条目结构体 (_RESHDR_DISK_SHORT)
80/// 总大小:24 字节
81#[derive(Debug, Clone)]
82#[allow(dead_code)]
83pub struct FileResourceEntry {
84    /// 资源大小 (7 字节)
85    pub size: u64,
86    /// 资源标志 (1 字节)
87    pub flags: u8,
88    /// 资源偏移 (8 字节)
89    pub offset: u64,
90    /// 原始大小 (8 字节)
91    pub original_size: u64,
92}
93
94/// 文件资源条目标志
95#[derive(Debug, Clone)]
96#[allow(dead_code)]
97pub struct ResourceFlags;
98
99#[allow(dead_code)]
100impl ResourceFlags {
101    pub const FREE: u8 = 0x01; // 条目空闲
102    pub const METADATA: u8 = 0x02; // 包含元数据
103    pub const COMPRESSED: u8 = 0x04; // 已压缩
104    pub const SPANNED: u8 = 0x08; // 跨段
105}
106
107/// 文件标志
108#[derive(Debug, Clone)]
109#[allow(dead_code)]
110pub struct FileFlags;
111
112#[allow(dead_code)]
113impl FileFlags {
114    pub const COMPRESSION: u32 = 0x00000002; // 资源已压缩
115    pub const READONLY: u32 = 0x00000004; // 只读
116    pub const SPANNED: u32 = 0x00000008; // 跨段
117    pub const RESOURCE_ONLY: u32 = 0x00000010; // 仅包含文件资源
118    pub const METADATA_ONLY: u32 = 0x00000020; // 仅包含元数据
119    pub const COMPRESS_XPRESS: u32 = 0x00020000; // XPRESS 压缩
120    pub const COMPRESS_LZX: u32 = 0x00040000; // LZX 压缩
121}
122
123/// 镜像信息结构体
124#[derive(Debug, Clone)]
125#[allow(dead_code)]
126pub struct ImageInfo {
127    /// 镜像索引
128    pub index: u32,
129    /// 镜像名称
130    pub name: String,
131    /// 镜像描述
132    pub description: String,
133    /// 目录数量
134    pub dir_count: u32,
135    /// 文件数量
136    pub file_count: u32,
137    /// 总字节数
138    pub total_bytes: u64,
139    /// 创建时间
140    pub creation_time: Option<u64>,
141    /// 最后修改时间
142    pub last_modification_time: Option<u64>,
143    /// 版本信息
144    pub version: Option<String>,
145    /// 架构信息
146    pub architecture: Option<String>,
147}
148
149#[allow(dead_code)]
150impl ImageInfo {
151    /// 创建新的ImageInfo实例(用于优化的XML解析)
152    pub fn new_with_index(index: u32) -> Self {
153        Self {
154            index,
155            name: String::new(),
156            description: String::new(),
157            dir_count: 0,
158            file_count: 0,
159            total_bytes: 0,
160            creation_time: None,
161            last_modification_time: None,
162            version: None,
163            architecture: None,
164        }
165    }
166
167    /// 高效设置字段值(避免多次字符串分配)
168    pub fn set_field(&mut self, tag: &str, value: &str) {
169        match tag {
170            "DISPLAYNAME" => self.name = value.to_string(),
171            "DISPLAYDESCRIPTION" => self.description = value.to_string(),
172            "DIRCOUNT" => self.dir_count = value.parse().unwrap_or(0),
173            "FILECOUNT" => self.file_count = value.parse().unwrap_or(0),
174            "TOTALBYTES" => self.total_bytes = value.parse().unwrap_or(0),
175            "ARCH" => {
176                self.architecture = match value {
177                    "0" => Some("x86".to_string()),
178                    "9" => Some("x64".to_string()),
179                    "5" => Some("ARM".to_string()),
180                    "12" => Some("ARM64".to_string()),
181                    _ => None,
182                };
183            }
184            _ => {} // 忽略其他标签
185        }
186    }
187
188    /// 根据名称和描述推断版本和架构信息
189    pub fn infer_version_and_arch(&mut self) {
190        let combined_text = format!("{} {}", self.name, self.description).to_lowercase();
191
192        // 推断版本信息
193        if self.version.is_none() {
194            self.version = if combined_text.contains("windows 11") {
195                Some("Windows 11".to_string())
196            } else if combined_text.contains("windows 10") {
197                Some("Windows 10".to_string())
198            } else if combined_text.contains("windows server 2022") {
199                Some("Windows Server 2022".to_string())
200            } else if combined_text.contains("windows server 2019") {
201                Some("Windows Server 2019".to_string())
202            } else if combined_text.contains("windows server") {
203                Some("Windows Server".to_string())
204            } else if combined_text.contains("windows") {
205                Some("Windows".to_string())
206            } else {
207                None
208            };
209        }
210
211        // 推断架构信息(仅在未从XML ARCH标签获取时)
212        if self.architecture.is_none() {
213            self.architecture = if combined_text.contains("x64") || combined_text.contains("amd64")
214            {
215                Some("x64".to_string())
216            } else if combined_text.contains("x86") {
217                Some("x86".to_string())
218            } else if combined_text.contains("arm64") {
219                Some("ARM64".to_string())
220            } else {
221                None
222            };
223        }
224    }
225}
226
227/// WIM 文件解析器
228#[allow(dead_code)]
229pub struct WimParser {
230    file: BufReader<File>,
231    header: Option<WimHeader>,
232    images: Vec<ImageInfo>,
233    string_pool: StringPool,
234}
235
236#[allow(dead_code)]
237impl WimParser {
238    /// 创建新的 WIM 解析器
239    pub fn new<P: AsRef<Path>>(wim_path: P) -> Result<Self> {
240        let file = File::open(wim_path.as_ref())
241            .with_context(|| format!("无法打开 WIM 文件: {}", wim_path.as_ref().display()))?;
242
243        let buffered_file = BufReader::with_capacity(64 * 1024, file); // 64KB缓冲区
244
245        debug!("创建 WIM 解析器: {}", wim_path.as_ref().display());
246
247        Ok(Self {
248            file: buffered_file,
249            header: None,
250            images: Vec::with_capacity(8), // 预分配镜像容量
251            string_pool: StringPool::new(),
252        })
253    }
254
255    /// 创建用于测试的 WIM 解析器(不需要实际文件)
256    #[doc(hidden)]
257    #[allow(dead_code)]
258    pub fn new_for_test(file: File) -> Self {
259        Self {
260            file: BufReader::new(file),
261            header: None,
262            images: Vec::with_capacity(8),
263            string_pool: StringPool::new(),
264        }
265    }
266
267    /// 读取并解析 WIM 文件头
268    pub fn read_header(&mut self) -> Result<&WimHeader> {
269        if self.header.is_none() {
270            debug!("开始读取 WIM 文件头");
271
272            // 跳转到文件开始
273            self.file.seek(SeekFrom::Start(0))?;
274
275            // 读取 204 字节的文件头
276            let mut header_buffer = vec![0u8; 204];
277            self.file
278                .read_exact(&mut header_buffer)
279                .context("读取 WIM 文件头失败")?;
280
281            let header = self.parse_header_buffer(&header_buffer)?;
282
283            // 验证签名
284            if &header.signature != b"MSWIM\x00\x00\x00" {
285                return Err(anyhow::anyhow!("无效的 WIM 文件签名"));
286            }
287
288            info!(
289                "成功读取 WIM 文件头 - 版本: {}, 镜像数: {}",
290                header.format_version, header.image_count
291            );
292
293            self.header = Some(header);
294        }
295        Ok(self.header.as_ref().unwrap())
296    }
297
298    /// 解析文件头缓冲区
299    fn parse_header_buffer(&self, buffer: &[u8]) -> Result<WimHeader> {
300        use std::convert::TryInto;
301
302        // 辅助函数:从缓冲区读取 little-endian 数值
303        let read_u32_le = |offset: usize| -> u32 {
304            u32::from_le_bytes(buffer[offset..offset + 4].try_into().unwrap())
305        };
306
307        let read_u16_le = |offset: usize| -> u16 {
308            u16::from_le_bytes(buffer[offset..offset + 2].try_into().unwrap())
309        };
310
311        let read_u64_le = |offset: usize| -> u64 {
312            u64::from_le_bytes(buffer[offset..offset + 8].try_into().unwrap())
313        };
314
315        // 解析文件资源条目
316        let parse_resource_entry = |offset: usize| -> FileResourceEntry {
317            // 读取 7 字节的大小 + 1 字节标志
318            let size_bytes = &buffer[offset..offset + 7];
319            let mut size_array = [0u8; 8];
320            size_array[..7].copy_from_slice(size_bytes);
321            let size = u64::from_le_bytes(size_array);
322
323            let flags = buffer[offset + 7];
324            let offset_val = read_u64_le(offset + 8);
325            let original_size = read_u64_le(offset + 16);
326
327            FileResourceEntry {
328                size,
329                flags,
330                offset: offset_val,
331                original_size,
332            }
333        };
334
335        // 解析文件头各个字段
336        let mut signature = [0u8; 8];
337        signature.copy_from_slice(&buffer[0..8]);
338
339        let header = WimHeader {
340            signature,
341            header_size: read_u32_le(8),
342            format_version: read_u32_le(12),
343            file_flags: read_u32_le(16),
344            compressed_size: read_u32_le(20),
345            guid: buffer[24..40].try_into().unwrap(),
346            segment_number: read_u16_le(40),
347            total_segments: read_u16_le(42),
348            image_count: read_u32_le(44),
349            offset_table_resource: parse_resource_entry(48),
350            xml_data_resource: parse_resource_entry(72),
351            boot_metadata_resource: parse_resource_entry(96),
352            bootable_image_index: read_u32_le(120),
353            integrity_resource: parse_resource_entry(124),
354        };
355
356        debug!(
357            "解析 WIM 头部完成 - 镜像数: {}, 文件标志: 0x{:08X}",
358            header.image_count, header.file_flags
359        );
360
361        Ok(header)
362    }
363
364    /// 读取并解析 XML 数据
365    pub fn read_xml_data(&mut self) -> Result<()> {
366        // 确保文件头已读取
367        if self.header.is_none() {
368            self.read_header()?;
369        }
370
371        let header = self.header.as_ref().unwrap();
372
373        // 检查 XML 数据资源是否存在
374        if header.xml_data_resource.size == 0 {
375            return Err(anyhow::anyhow!("WIM 文件中没有 XML 数据资源"));
376        }
377
378        debug!(
379            "开始读取 XML 数据,偏移: {}, 大小: {}",
380            header.xml_data_resource.offset, header.xml_data_resource.size
381        );
382
383        // 跳转到 XML 数据位置
384        self.file
385            .seek(SeekFrom::Start(header.xml_data_resource.offset))?;
386
387        // 读取 XML 数据
388        let mut xml_buffer = vec![0u8; header.xml_data_resource.size as usize];
389        self.file
390            .read_exact(&mut xml_buffer)
391            .context("读取 XML 数据失败")?;
392
393        // 解析 XML 数据
394        self.parse_xml_data(&xml_buffer)?;
395
396        info!("成功解析 {} 个镜像的信息", self.images.len());
397        Ok(())
398    }
399
400    /// 解析 XML 数据
401    fn parse_xml_data(&mut self, xml_buffer: &[u8]) -> Result<()> {
402        // XML 数据以 UTF-16 LE BOM 开始
403        if xml_buffer.len() < 2 {
404            return Err(anyhow::anyhow!("XML 数据太短"));
405        }
406
407        // 检查 BOM (0xFEFF)
408        if xml_buffer[0] != 0xFF || xml_buffer[1] != 0xFE {
409            return Err(anyhow::anyhow!("无效的 XML 数据 BOM"));
410        }
411
412        // 将 UTF-16 LE 转换为 UTF-8
413        let xml_utf16_data = &xml_buffer[2..]; // 跳过 BOM
414
415        // 确保数据长度为偶数(UTF-16 每个字符 2 字节)
416        if !xml_utf16_data.len().is_multiple_of(2) {
417            return Err(anyhow::anyhow!("XML UTF-16 数据长度不是偶数"));
418        }
419
420        // 转换为 u16 数组
421        let mut utf16_chars = Vec::new();
422        for chunk in xml_utf16_data.chunks_exact(2) {
423            let char_val = u16::from_le_bytes([chunk[0], chunk[1]]);
424            utf16_chars.push(char_val);
425        }
426
427        // 转换为 UTF-8 字符串
428        let xml_string = String::from_utf16(&utf16_chars).context("无法将 XML 数据转换为 UTF-8")?;
429
430        debug!("XML 数据长度: {} 字符", xml_string.len());
431
432        // 解析 XML 镜像信息
433        self.parse_xml_images(&xml_string)?;
434
435        Ok(())
436    }
437
438    /// 优化的XML解析函数 - 使用proper XML parser和高效UTF-16解码
439    fn parse_xml_data_optimized(&mut self, xml_buffer: &[u8]) -> Result<()> {
440        // 检查基本格式
441        if xml_buffer.len() < 2 {
442            return Err(anyhow::anyhow!("XML 数据太短"));
443        }
444
445        // 检查 BOM (0xFEFF)
446        if xml_buffer[0] != 0xFF || xml_buffer[1] != 0xFE {
447            return Err(anyhow::anyhow!("无效的 XML 数据 BOM"));
448        }
449
450        // 使用encoding_rs进行高效UTF-16解码
451        let (xml_string, _, had_errors) = UTF_16LE.decode(&xml_buffer[2..]);
452        if had_errors {
453            return Err(anyhow::anyhow!("UTF-16解码过程中发现错误"));
454        }
455
456        debug!("XML 数据长度: {} 字符", xml_string.len());
457
458        // 使用quick-xml进行解析
459        self.parse_xml_images_optimized(&xml_string)?;
460
461        Ok(())
462    }
463
464    /// 优化的XML镜像解析函数 - 使用quick-xml
465    fn parse_xml_images_optimized(&mut self, xml_content: &str) -> Result<()> {
466        self.images.clear();
467
468        let mut reader = Reader::from_str(xml_content);
469        reader.config_mut().trim_text(true);
470
471        let mut current_image: Option<ImageInfo> = None;
472        let mut current_tag = String::new();
473        let mut in_windows_section = false;
474
475        loop {
476            match reader.read_event() {
477                Ok(Event::Start(ref e)) => {
478                    match e.name().as_ref() {
479                        b"IMAGE" => {
480                            // 提取INDEX属性
481                            for attr in e.attributes().flatten() {
482                                if attr.key.as_ref() == b"INDEX" {
483                                    if let Ok(index_str) = std::str::from_utf8(&attr.value) {
484                                        if let Ok(index) = index_str.parse::<u32>() {
485                                            current_image = Some(ImageInfo::new_with_index(index));
486                                        }
487                                    }
488                                }
489                            }
490                        }
491                        b"WINDOWS" => {
492                            in_windows_section = true;
493                        }
494                        tag => {
495                            current_tag = String::from_utf8_lossy(tag).into_owned();
496                        }
497                    }
498                }
499                Ok(Event::Text(e)) => {
500                    if let Some(ref mut image) = current_image {
501                        // 获取文本内容
502                        let text = std::str::from_utf8(&e)?;
503
504                        // 特殊处理WINDOWS节中的ARCH标签
505                        if in_windows_section && current_tag == "ARCH" {
506                            image.set_field("ARCH", text);
507                        } else if !in_windows_section {
508                            // 其他标签在非WINDOWS节中处理
509                            image.set_field(&current_tag, text);
510                        }
511                    }
512                }
513                Ok(Event::End(ref e)) => {
514                    match e.name().as_ref() {
515                        b"IMAGE" => {
516                            if let Some(mut image) = current_image.take() {
517                                // 推断版本和架构信息(如果尚未设置)
518                                image.infer_version_and_arch();
519                                self.images.push(image);
520                            }
521                        }
522                        b"WINDOWS" => {
523                            in_windows_section = false;
524                        }
525                        _ => {}
526                    }
527                }
528                Ok(Event::Eof) => break,
529                Err(e) => return Err(anyhow::anyhow!("XML解析错误: {}", e)),
530                _ => {}
531            }
532        }
533
534        info!("优化解析完成:成功解析 {} 个镜像的信息", self.images.len());
535        Ok(())
536    }
537
538    /// 解析 XML 中的镜像信息
539    fn parse_xml_images(&mut self, xml_content: &str) -> Result<()> {
540        // 简单的 XML 解析(基于字符串匹配)
541        // 在实际生产环境中,建议使用专门的 XML 解析库
542
543        self.images.clear();
544
545        // 查找所有 <IMAGE> 标签
546        let mut start_pos = 0;
547        while let Some(image_start) = xml_content[start_pos..].find("<IMAGE") {
548            let absolute_start = start_pos + image_start;
549
550            // 查找对应的 </IMAGE> 标签
551            if let Some(image_end) = xml_content[absolute_start..].find("</IMAGE>") {
552                let absolute_end = absolute_start + image_end + 8; // 包含 </IMAGE>
553                let image_xml = &xml_content[absolute_start..absolute_end];
554
555                // 解析单个镜像信息
556                if let Ok(image_info) = self.parse_single_image_xml(image_xml) {
557                    self.images.push(image_info);
558                }
559
560                start_pos = absolute_end;
561            } else {
562                break;
563            }
564        }
565
566        Ok(())
567    }
568
569    /// 解析单个镜像的 XML 信息
570    pub fn parse_single_image_xml(&self, image_xml: &str) -> Result<ImageInfo> {
571        // 辅助函数:从 XML 中提取标签值
572        let extract_tag_value = |xml: &str, tag: &str| -> Option<String> {
573            let start_tag = format!("<{tag}>");
574            let end_tag = format!("</{tag}>");
575
576            if let Some(start) = xml.find(&start_tag) {
577                if let Some(end) = xml.find(&end_tag) {
578                    let value_start = start + start_tag.len();
579                    if value_start < end {
580                        return Some(xml[value_start..end].trim().to_string());
581                    }
582                }
583            }
584            None
585        };
586
587        // 提取 INDEX 属性
588        let index = if let Some(index_start) = image_xml.find("INDEX=\"") {
589            let index_value_start = index_start + 7; // "INDEX=\"".len()
590            if let Some(index_end) = image_xml[index_value_start..].find("\"") {
591                let index_str = &image_xml[index_value_start..index_value_start + index_end];
592                index_str.parse().unwrap_or(0)
593            } else {
594                0
595            }
596        } else {
597            0
598        };
599
600        // 提取各种信息
601        let name =
602            extract_tag_value(image_xml, "DISPLAYNAME").unwrap_or_else(|| format!("Image {index}"));
603        let description = extract_tag_value(image_xml, "DISPLAYDESCRIPTION")
604            .unwrap_or_else(|| "Unknown".to_string());
605        let dir_count = extract_tag_value(image_xml, "DIRCOUNT")
606            .and_then(|s| s.parse().ok())
607            .unwrap_or(0);
608        let file_count = extract_tag_value(image_xml, "FILECOUNT")
609            .and_then(|s| s.parse().ok())
610            .unwrap_or(0);
611        let total_bytes = extract_tag_value(image_xml, "TOTALBYTES")
612            .and_then(|s| s.parse().ok())
613            .unwrap_or(0);
614
615        // 尝试从XML中的ARCH标签解析架构信息
616        let arch_from_xml = self.parse_arch_from_xml(image_xml);
617
618        // 从名称中提取版本信息,架构信息优先使用XML中的ARCH标签
619        let (version, arch_from_name) = self.extract_version_and_arch(&name, &description);
620        let architecture = arch_from_xml.or(arch_from_name);
621
622        let image_info = ImageInfo {
623            index,
624            name,
625            description,
626            dir_count,
627            file_count,
628            total_bytes,
629            creation_time: None,          // 可以进一步解析 CREATIONTIME
630            last_modification_time: None, // 可以进一步解析 LASTMODIFICATIONTIME
631            version,
632            architecture,
633        };
634
635        debug!(
636            "解析镜像信息: {} - {} - {} - {:#?}",
637            image_info.index, image_info.name, image_info.description, image_info.architecture
638        );
639
640        Ok(image_info)
641    }
642
643    /// 从镜像名称和描述中提取版本和架构信息
644    fn extract_version_and_arch(
645        &self,
646        name: &str,
647        description: &str,
648    ) -> (Option<String>, Option<String>) {
649        let combined_text = format!("{name} {description}").to_lowercase();
650
651        // 提取版本信息
652        let version = if combined_text.contains("windows 11") {
653            Some("Windows 11".to_string())
654        } else if combined_text.contains("windows 10") {
655            Some("Windows 10".to_string())
656        } else if combined_text.contains("windows server 2022") {
657            Some("Windows Server 2022".to_string())
658        } else if combined_text.contains("windows server 2019") {
659            Some("Windows Server 2019".to_string())
660        } else if combined_text.contains("windows server") {
661            Some("Windows Server".to_string())
662        } else if combined_text.contains("windows") {
663            Some("Windows".to_string())
664        } else {
665            None
666        };
667
668        // 提取架构信息
669        let architecture = if combined_text.contains("x64") || combined_text.contains("amd64") {
670            Some("x64".to_string())
671        } else if combined_text.contains("x86") {
672            Some("x86".to_string())
673        } else if combined_text.contains("arm64") {
674            Some("ARM64".to_string())
675        } else {
676            None
677        };
678
679        (version, architecture)
680    }
681
682    /// 从XML中的ARCH标签解析架构信息
683    pub fn parse_arch_from_xml(&self, image_xml: &str) -> Option<String> {
684        // 辅助函数:从 XML 中提取标签值
685        let extract_tag_value = |xml: &str, tag: &str| -> Option<String> {
686            let start_tag = format!("<{tag}>");
687            let end_tag = format!("</{tag}>");
688
689            if let Some(start) = xml.find(&start_tag) {
690                if let Some(end) = xml.find(&end_tag) {
691                    let value_start = start + start_tag.len();
692                    if value_start < end {
693                        return Some(xml[value_start..end].trim().to_string());
694                    }
695                }
696            }
697            None
698        };
699
700        // 提取ARCH标签值
701        if let Some(arch_value) = extract_tag_value(image_xml, "ARCH") {
702            match arch_value.as_str() {
703                "0" => Some("x86".to_string()),
704                "9" => Some("x64".to_string()),
705                "5" => Some("ARM".to_string()),
706                "12" => Some("ARM64".to_string()),
707                _ => {
708                    debug!("未知的架构值: {}", arch_value);
709                    None
710                }
711            }
712        } else {
713            None
714        }
715    }
716
717    /// 获取所有镜像信息
718    pub fn get_images(&self) -> &[ImageInfo] {
719        &self.images
720    }
721
722    /// 获取指定索引的镜像信息
723    #[allow(dead_code)]
724    pub fn get_image(&self, index: u32) -> Option<&ImageInfo> {
725        self.images.iter().find(|img| img.index == index)
726    }
727
728    /// 获取文件头信息
729    #[allow(dead_code)]
730    pub fn get_header(&self) -> Option<&WimHeader> {
731        self.header.as_ref()
732    }
733
734    /// 检查是否包含多个镜像
735    #[allow(dead_code)]
736    pub fn has_multiple_images(&self) -> bool {
737        self.header
738            .as_ref()
739            .map(|h| h.image_count > 1)
740            .unwrap_or(false)
741    }
742
743    /// 获取镜像数量
744    #[allow(dead_code)]
745    pub fn get_image_count(&self) -> u32 {
746        self.header.as_ref().map(|h| h.image_count).unwrap_or(0)
747    }
748
749    /// 检查是否为压缩文件
750    #[allow(dead_code)]
751    pub fn is_compressed(&self) -> bool {
752        self.header
753            .as_ref()
754            .map(|h| h.file_flags & FileFlags::COMPRESSION != 0)
755            .unwrap_or(false)
756    }
757
758    /// 获取压缩类型
759    #[allow(dead_code)]
760    pub fn get_compression_type(&self) -> Option<&'static str> {
761        if let Some(header) = &self.header {
762            if header.file_flags & FileFlags::COMPRESS_XPRESS != 0 {
763                Some("XPRESS")
764            } else if header.file_flags & FileFlags::COMPRESS_LZX != 0 {
765                Some("LZX")
766            } else if header.file_flags & FileFlags::COMPRESSION != 0 {
767                Some("Unknown")
768            } else {
769                None
770            }
771        } else {
772            None
773        }
774    }
775
776    /// 完整解析 WIM 文件(头部 + XML 数据)
777    pub fn parse_full(&mut self) -> Result<()> {
778        self.read_header()?;
779        self.read_xml_data()?;
780        Ok(())
781    }
782}
783
784impl std::fmt::Display for ImageInfo {
785    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
786        write!(f, "镜像 {} - {}", self.index, self.name)?;
787        if let Some(ref version) = self.version {
788            write!(f, " [{version}]")?;
789        }
790        if let Some(ref arch) = self.architecture {
791            write!(f, " [{arch}]")?;
792        }
793        write!(f, " | 描述: {}", self.description)?;
794        write!(
795            f,
796            " | 文件数: {}, 目录数: {}",
797            self.file_count, self.dir_count
798        )?;
799        write!(f, " | 总大小: {} MB", self.total_bytes / (1024 * 1024))?;
800        Ok(())
801    }
802}
803
804impl std::fmt::Display for WimHeader {
805    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
806        writeln!(f, "WIM Header:")?;
807        writeln!(f, "  Format Version: {}", self.format_version)?;
808        writeln!(f, "  File Flags: 0x{:08X}", self.file_flags)?;
809        writeln!(f, "  Image Count: {}", self.image_count)?;
810        writeln!(
811            f,
812            "  Segment: {}/{}",
813            self.segment_number, self.total_segments
814        )?;
815        writeln!(f, "  Bootable Image Index: {}", self.bootable_image_index)?;
816        Ok(())
817    }
818}
819
820#[allow(dead_code)]
821impl WimParser {
822    /// 获取所有镜像的版本摘要
823    #[allow(dead_code)]
824    pub fn get_version_summary(&self) -> Vec<String> {
825        let mut summaries = Vec::new();
826
827        for image in &self.images {
828            let mut summary = format!("镜像 {}: {}", image.index, image.name);
829
830            if let Some(ref version) = image.version {
831                summary.push_str(&format!(" ({version})"));
832            }
833
834            if let Some(ref arch) = image.architecture {
835                summary.push_str(&format!(" [{arch}]"));
836            }
837
838            summaries.push(summary);
839        }
840
841        summaries
842    }
843
844    /// 获取主要版本信息(如果有多个镜像,返回最常见的版本)
845    pub fn get_primary_version(&self) -> Option<String> {
846        if self.images.is_empty() {
847            return None;
848        }
849
850        // 统计版本出现频率
851        let mut version_counts = std::collections::HashMap::new();
852        for image in &self.images {
853            if let Some(ref version) = image.version {
854                *version_counts.entry(version.clone()).or_insert(0) += 1;
855            }
856        }
857
858        // 找到最常见的版本
859        version_counts
860            .into_iter()
861            .max_by_key(|(_, count)| *count)
862            .map(|(version, _)| version)
863    }
864
865    /// 获取主要架构信息(如果有多个镜像,返回最常见的架构)
866    pub fn get_primary_architecture(&self) -> Option<String> {
867        if self.images.is_empty() {
868            return None;
869        }
870
871        // 统计架构出现频率
872        let mut arch_counts = std::collections::HashMap::new();
873        for image in &self.images {
874            if let Some(ref arch) = image.architecture {
875                *arch_counts.entry(arch.clone()).or_insert(0) += 1;
876            }
877        }
878
879        // 找到最常见的架构
880        arch_counts
881            .into_iter()
882            .max_by_key(|(_, count)| *count)
883            .map(|(arch, _)| arch)
884    }
885
886    /// 检查是否包含指定版本的镜像
887    #[allow(dead_code)]
888    pub fn has_version(&self, version: &str) -> bool {
889        self.images.iter().any(|img| {
890            img.version
891                .as_ref()
892                .is_some_and(|v| v.to_lowercase().contains(&version.to_lowercase()))
893        })
894    }
895
896    /// 检查是否包含指定架构的镜像
897    #[allow(dead_code)]
898    pub fn has_architecture(&self, arch: &str) -> bool {
899        self.images.iter().any(|img| {
900            img.architecture
901                .as_ref()
902                .is_some_and(|a| a.to_lowercase().contains(&arch.to_lowercase()))
903        })
904    }
905
906    /// 获取Windows版本的详细信息
907    pub fn get_windows_info(&self) -> Option<WindowsInfo> {
908        let primary_version = self.get_primary_version()?;
909        let primary_arch = self.get_primary_architecture()?;
910
911        // 检查是否是Windows镜像
912        if !primary_version.to_lowercase().contains("windows") {
913            return None;
914        }
915
916        // 计算总的镜像版本(如Pro, Home, Enterprise等)
917        let mut editions = Vec::new();
918        for image in &self.images {
919            let name_lower = image.name.to_lowercase();
920            if name_lower.contains("pro") && !editions.contains(&"Pro".to_string()) {
921                editions.push("Pro".to_string());
922            } else if name_lower.contains("home") && !editions.contains(&"Home".to_string()) {
923                editions.push("Home".to_string());
924            } else if name_lower.contains("enterprise")
925                && !editions.contains(&"Enterprise".to_string())
926            {
927                editions.push("Enterprise".to_string());
928            } else if name_lower.contains("education")
929                && !editions.contains(&"Education".to_string())
930            {
931                editions.push("Education".to_string());
932            }
933        }
934
935        Some(WindowsInfo {
936            version: primary_version,
937            architecture: primary_arch,
938            editions,
939            image_count: self.images.len() as u32,
940            total_size: self.images.iter().map(|img| img.total_bytes).sum(),
941        })
942    }
943}
944
945/// Windows 版本信息摘要
946#[derive(Debug, Clone)]
947pub struct WindowsInfo {
948    pub version: String,
949    pub architecture: String,
950    pub editions: Vec<String>,
951    pub image_count: u32,
952    pub total_size: u64,
953}
954
955impl std::fmt::Display for WindowsInfo {
956    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
957        write!(f, "{} ({})", self.version, self.architecture)?;
958        if !self.editions.is_empty() {
959            write!(f, " - 版本: {}", self.editions.join(", "))?;
960        }
961        write!(f, " | 镜像数量: {}", self.image_count)?;
962        write!(f, " | 总大小: {} MB", self.total_size / (1024 * 1024))?;
963        Ok(())
964    }
965}
966
967// 基准测试和测试辅助函数
968#[cfg(any(test, feature = "benchmarking"))]
969impl WimParser {
970    /// 测试用:直接解析XML数据(当前实现)
971    pub fn parse_xml_data_for_bench(&mut self, xml_buffer: &[u8]) -> Result<()> {
972        self.parse_xml_data(xml_buffer)
973    }
974
975    /// 测试用:直接解析XML数据(优化实现)
976    pub fn parse_xml_data_optimized_for_bench(&mut self, xml_buffer: &[u8]) -> Result<()> {
977        self.parse_xml_data_optimized(xml_buffer)
978    }
979
980    /// 测试用:切换到优化解析模式
981    pub fn use_optimized_parsing(&mut self, xml_buffer: &[u8]) -> Result<()> {
982        self.parse_xml_data_optimized(xml_buffer)
983    }
984}