1use std::path::Path;
21
22use super::PackageParser;
23use crate::models::{DatasourceId, PackageData, PackageType};
24use crate::utils::magic;
25
26macro_rules! file_recognizer {
38 ($name:ident, $pkg_type:expr, $datasource:expr, $match_fn:expr) => {
39 pub struct $name;
40
41 impl PackageParser for $name {
42 const PACKAGE_TYPE: PackageType = $pkg_type;
43
44 fn is_match(path: &Path) -> bool {
45 ($match_fn)(path)
46 }
47
48 fn extract_packages(path: &Path) -> Vec<PackageData> {
49 let _ = path;
50 vec![PackageData {
51 package_type: Some($pkg_type),
52 datasource_id: Some($datasource),
53 ..Default::default()
54 }]
55 }
56 }
57 };
58}
59
60file_recognizer!(
63 JavaJarRecognizer,
64 PackageType::Jar,
65 DatasourceId::JavaJar,
66 |path: &Path| path.extension().and_then(|e| e.to_str()) == Some("jar")
67);
68
69file_recognizer!(
70 IvyXmlRecognizer,
71 PackageType::Ivy,
72 DatasourceId::AntIvyXml,
73 |path: &Path| path.to_str().is_some_and(|p| p.ends_with("/ivy.xml"))
74);
75
76file_recognizer!(
77 JavaWarRecognizer,
78 PackageType::War,
79 DatasourceId::JavaWarArchive,
80 |path: &Path| path.extension().and_then(|e| e.to_str()) == Some("war")
81);
82
83file_recognizer!(
84 JavaWarWebXmlRecognizer,
85 PackageType::War,
86 DatasourceId::JavaWarWebXml,
87 |path: &Path| path
88 .to_str()
89 .is_some_and(|p| p.ends_with("/WEB-INF/web.xml") || p.ends_with("WEB-INF/web.xml"))
90);
91
92file_recognizer!(
93 JavaEarRecognizer,
94 PackageType::Ear,
95 DatasourceId::JavaEarArchive,
96 |path: &Path| path.extension().and_then(|e| e.to_str()) == Some("ear")
97);
98
99file_recognizer!(
100 JavaEarAppXmlRecognizer,
101 PackageType::Ear,
102 DatasourceId::JavaEarApplicationXml,
103 |path: &Path| path.to_str().is_some_and(
104 |p| p.ends_with("/META-INF/application.xml") || p.ends_with("META-INF/application.xml")
105 )
106);
107
108file_recognizer!(
111 Axis2ModuleXmlRecognizer,
112 PackageType::Axis2,
113 DatasourceId::Axis2ModuleXml,
114 |path: &Path| {
115 path.to_str().is_some_and(|p| {
116 let lower = p.to_lowercase();
117 lower.ends_with("/meta-inf/module.xml") || lower.ends_with("meta-inf/module.xml")
118 })
119 }
120);
121
122file_recognizer!(
123 Axis2MarRecognizer,
124 PackageType::Axis2,
125 DatasourceId::Axis2Mar,
126 |path: &Path| path.extension().and_then(|e| e.to_str()) == Some("mar")
127);
128
129file_recognizer!(
132 JBossSarRecognizer,
133 PackageType::JbossService,
134 DatasourceId::JbossSar,
135 |path: &Path| path.extension().and_then(|e| e.to_str()) == Some("sar")
136);
137
138file_recognizer!(
139 JBossServiceXmlRecognizer,
140 PackageType::JbossService,
141 DatasourceId::JbossServiceXml,
142 |path: &Path| {
143 path.to_str().is_some_and(|p| {
144 let lower = p.to_lowercase();
145 lower.ends_with("/meta-inf/jboss-service.xml")
146 || lower.ends_with("meta-inf/jboss-service.xml")
147 })
148 }
149);
150
151file_recognizer!(
154 MeteorPackageRecognizer,
155 PackageType::Meteor,
156 DatasourceId::MeteorPackage,
157 |path: &Path| path.to_str().is_some_and(|p| p.ends_with("/package.js"))
158);
159
160file_recognizer!(
163 AndroidLibraryRecognizer,
164 PackageType::AndroidLib,
165 DatasourceId::AndroidAarLibrary,
166 |path: &Path| path.extension().and_then(|e| e.to_str()) == Some("aar")
167);
168
169file_recognizer!(
170 MozillaXpiRecognizer,
171 PackageType::Mozilla,
172 DatasourceId::MozillaXpi,
173 |path: &Path| path.extension().and_then(|e| e.to_str()) == Some("xpi")
174);
175
176file_recognizer!(
177 ChromeCrxRecognizer,
178 PackageType::Chrome,
179 DatasourceId::ChromeCrx,
180 |path: &Path| path.extension().and_then(|e| e.to_str()) == Some("crx")
181);
182
183file_recognizer!(
184 IosIpaRecognizer,
185 PackageType::Ios,
186 DatasourceId::IosIpa,
187 |path: &Path| path.extension().and_then(|e| e.to_str()) == Some("ipa")
188);
189
190file_recognizer!(
193 CabArchiveRecognizer,
194 PackageType::Cab,
195 DatasourceId::MicrosoftCabinet,
196 |path: &Path| path.extension().and_then(|e| e.to_str()) == Some("cab")
197);
198
199file_recognizer!(
200 SharArchiveRecognizer,
201 PackageType::Shar,
202 DatasourceId::SharShellArchive,
203 |path: &Path| path.extension().and_then(|e| e.to_str()) == Some("shar")
204);
205
206file_recognizer!(
209 AppleDmgRecognizer,
210 PackageType::Dmg,
211 DatasourceId::AppleDmg,
212 |path: &Path| {
213 path.extension()
214 .and_then(|e| e.to_str())
215 .is_some_and(|ext| ext == "dmg" || ext == "sparseimage")
216 }
217);
218
219file_recognizer!(
220 IsoImageRecognizer,
221 PackageType::Iso,
222 DatasourceId::IsoDiskImage,
223 |path: &Path| {
224 path.extension()
225 .and_then(|e| e.to_str())
226 .is_some_and(|ext| ext == "iso" || ext == "udf" || ext == "img")
227 }
228);
229
230file_recognizer!(
233 SquashfsRecognizer,
234 PackageType::Squashfs,
235 DatasourceId::SquashfsDiskImage,
236 |path: &Path| magic::is_squashfs(path)
237);
238
239file_recognizer!(
240 NsisRecognizer,
241 PackageType::Nsis,
242 DatasourceId::NsisInstaller,
243 |path: &Path| {
244 path.extension()
245 .and_then(|e| e.to_str())
246 .is_some_and(|ext| ext == "exe")
247 && magic::is_nsis_installer(path)
248 }
249);
250
251file_recognizer!(
252 InstallShieldRecognizer,
253 PackageType::Installshield,
254 DatasourceId::InstallshieldInstaller,
255 |path: &Path| {
256 path.extension()
257 .and_then(|e| e.to_str())
258 .is_some_and(|ext| ext == "exe")
259 && magic::is_zip(path)
260 }
261);
262
263pub(crate) static RECOGNIZER_METADATA: &[super::metadata::ParserMetadata] = &[
264 super::metadata::ParserMetadata {
265 description: "Misc file type recognizers (JAR, WAR, EAR, AAR, iOS, Chrome, Mozilla, installers, disk images, etc.)",
266 file_patterns: &[
267 "**/*.jar",
268 "**/ivy.xml",
269 "**/*.war",
270 "**/WEB-INF/web.xml",
271 "**/*.ear",
272 "**/META-INF/application.xml",
273 "**/meta-inf/module.xml",
274 "**/*.mar",
275 "**/*.sar",
276 "**/meta-inf/jboss-service.xml",
277 "**/package.js",
278 "**/*.aar",
279 "**/*.xpi",
280 "**/*.crx",
281 "**/*.ipa",
282 "**/*.cab",
283 "**/*.shar",
284 "**/*.dmg",
285 "**/*.sparseimage",
286 "**/*.iso",
287 "**/*.udf",
288 "**/*.img",
289 "**/*.exe",
290 ],
291 package_type: "",
292 primary_language: "",
293 documentation_url: None,
294 },
295];