provenant/parsers/
microsoft_update_manifest.rs1use crate::models::{DatasourceId, PackageType};
13use std::fs;
14use std::path::Path;
15
16use log::warn;
17use quick_xml::events::Event;
18use quick_xml::reader::Reader;
19
20use crate::models::PackageData;
21
22use super::PackageParser;
23
24const PACKAGE_TYPE: PackageType = PackageType::WindowsUpdate;
25
26pub struct MicrosoftUpdateManifestParser;
27
28impl PackageParser for MicrosoftUpdateManifestParser {
29 const PACKAGE_TYPE: PackageType = PACKAGE_TYPE;
30
31 fn is_match(path: &Path) -> bool {
32 path.extension().is_some_and(|ext| ext == "mum")
33 }
34
35 fn extract_packages(path: &Path) -> Vec<PackageData> {
36 let content = match fs::read_to_string(path) {
37 Ok(c) => c,
38 Err(e) => {
39 warn!("Failed to read .mum file {:?}: {}", path, e);
40 return vec![PackageData {
41 package_type: Some(PACKAGE_TYPE),
42 datasource_id: Some(DatasourceId::MicrosoftUpdateManifestMum),
43 ..Default::default()
44 }];
45 }
46 };
47
48 vec![parse_mum_xml(&content)]
49 }
50}
51
52pub(crate) fn parse_mum_xml(content: &str) -> PackageData {
53 let mut reader = Reader::from_str(content);
54 reader.config_mut().trim_text(true);
55
56 let mut name = None;
57 let mut version = None;
58 let mut description = None;
59 let mut copyright = None;
60 let mut homepage_url = None;
61
62 let mut buf = Vec::new();
63
64 loop {
65 match reader.read_event_into(&mut buf) {
66 Ok(Event::Empty(e)) => {
67 if e.name().as_ref() == b"assemblyIdentity" {
68 for attr in e.attributes().filter_map(|a| a.ok()) {
69 match attr.key.as_ref() {
70 b"name" => name = String::from_utf8(attr.value.to_vec()).ok(),
71 b"version" => version = String::from_utf8(attr.value.to_vec()).ok(),
72 _ => {}
73 }
74 }
75 }
76 }
77 Ok(Event::Start(e)) => {
78 if e.name().as_ref() == b"assembly" {
79 for attr in e.attributes().filter_map(|a| a.ok()) {
80 match attr.key.as_ref() {
81 b"description" => {
82 description = String::from_utf8(attr.value.to_vec()).ok()
83 }
84 b"copyright" => copyright = String::from_utf8(attr.value.to_vec()).ok(),
85 b"supportInformation" => {
86 homepage_url = String::from_utf8(attr.value.to_vec()).ok()
87 }
88 _ => {}
89 }
90 }
91 }
92 }
93 Ok(Event::Eof) => break,
94 Err(e) => {
95 warn!(
96 "Error parsing XML at position {}: {}",
97 reader.buffer_position(),
98 e
99 );
100 break;
101 }
102 _ => {}
103 }
104 buf.clear();
105 }
106
107 PackageData {
108 package_type: Some(PACKAGE_TYPE),
109 name,
110 version,
111 description,
112 homepage_url,
113 copyright,
114 datasource_id: Some(DatasourceId::MicrosoftUpdateManifestMum),
115 ..Default::default()
116 }
117}
118
119crate::register_parser!(
120 "Microsoft Update Manifest .mum file",
121 &["*.mum"],
122 "windows-update",
123 "",
124 None,
125);