shared_mime/runtime/
mimeinfo.rs1use std::{
4 fs::read_dir,
5 path::{Path, PathBuf},
6};
7
8use log::*;
9use serde::Serialize;
10
11use crate::record::MimeTypeRecord;
12
13use super::{parse_mime_package, xdg_mime_search_dirs, XDGError};
14
15#[derive(Serialize, Debug, Clone)]
17pub struct SharedMimeInfo {
18 pub directories: Vec<SMIDir>,
20}
21
22#[derive(Serialize, Debug, Clone)]
24pub struct SMIDir {
25 pub path: PathBuf,
26 pub packages: Vec<SMIPackage>,
27}
28
29#[derive(Serialize, Debug, Clone)]
31pub struct SMIPackage {
32 pub filename: String,
33 pub types: Vec<MimeTypeRecord>,
34}
35
36pub fn load_xdg_mime_info() -> Result<SharedMimeInfo, XDGError> {
38 let dirs = xdg_mime_search_dirs();
39 Ok(SharedMimeInfo {
40 directories: dirs
41 .into_iter()
42 .filter_map(|d| load_xdg_mime_dir(d).transpose())
43 .collect::<Result<Vec<_>, _>>()?,
44 })
45}
46
47fn load_xdg_mime_dir<P: AsRef<Path>>(path: P) -> Result<Option<SMIDir>, XDGError> {
48 let path = path.as_ref();
49 let mut buf = path.to_path_buf();
50 buf.push("packages");
51 debug!("looking for packages in {}", path.display());
52 if !buf.try_exists()? {
53 debug!("{} does not exist", buf.display());
54 return Ok(None);
55 }
56
57 let mut packages = Vec::new();
58 for entry in read_dir(&buf)? {
59 let entry = entry?;
60 let ep = entry.path();
61 let ext = ep.extension().map_or("".into(), |e| e.to_string_lossy());
62 debug!("extension {}", ext);
63 if entry.file_name().as_encoded_bytes()[0] != b'.' && ext == "xml" {
64 debug!("reading package file {}", ep.display());
65 packages.push(SMIPackage {
66 filename: ep
67 .file_name()
68 .ok_or(XDGError::Layout("package missing filename".into()))?
69 .to_string_lossy()
70 .to_string(),
71 types: parse_mime_package(&ep)?
72 .types
73 .into_iter()
74 .map(MimeTypeRecord::from)
75 .collect(),
76 })
77 } else {
78 debug!("ignoring file {}", ep.display());
79 }
80 }
81
82 Ok(Some(SMIDir {
83 path: path.to_path_buf(),
84 packages,
85 }))
86}