Skip to main content

fb2_clean/
lib.rs

1mod config;
2mod i18n;
3mod remove_xml_tags;
4
5#[cfg(feature = "cli")]
6pub mod cli;
7#[cfg(feature = "gui")]
8pub mod gui;
9
10use std::{
11    error::Error,
12    path::{self, Path, PathBuf},
13    result,
14};
15
16pub type Result<T> = result::Result<T, Box<dyn Error>>;
17
18pub use config::{
19    Config,
20    input::{Input, InputFile, InputFileType},
21    output::Output,
22    tags::Tags,
23};
24pub use i18n::{Lang, Msg};
25pub use remove_xml_tags::remove_xml_tags;
26
27#[cfg(windows)]
28const LONG_PATH_PREFIX: &str = r"\\?\";
29
30fn log_prefix_root(level: log::Level) -> &'static str {
31    use log::Level;
32    let msg = match level {
33        Level::Error => Msg::Error,
34        Level::Warn => Msg::Warning,
35        Level::Debug => Msg::Debug,
36        Level::Trace => Msg::Trace,
37        _ => return "",
38    };
39    msg.as_str()
40}
41
42fn ensure_long_path_prefix(path: impl Into<PathBuf>) -> PathBuf {
43    #[cfg(unix)]
44    {
45        path.into()
46    }
47
48    #[cfg(windows)]
49    {
50        let path = path.into();
51
52        if path
53            .as_os_str()
54            .as_encoded_bytes()
55            .starts_with(LONG_PATH_PREFIX.as_bytes())
56        {
57            return path;
58        }
59
60        let mut prf_path = std::ffi::OsString::from(LONG_PATH_PREFIX);
61        prf_path.push(path.as_os_str());
62        prf_path.into()
63    }
64}
65
66/// Displays a path without `\\?\` prefix if exists.
67fn display<P>(path: &P) -> path::Display<'_>
68where
69    P: AsRef<Path> + ?Sized,
70{
71    let path = path.as_ref();
72
73    #[cfg(windows)]
74    {
75        let src_bytes = path.as_os_str().as_encoded_bytes();
76
77        if src_bytes.starts_with(LONG_PATH_PREFIX.as_bytes()) {
78            let display_bytes = if src_bytes.len() == 4 {
79                &[]
80            } else {
81                &src_bytes[4..]
82            };
83
84            // SAFETY: The prefix `\\?\` consists entirely of ASCII characters (1 byte per character).
85            // Slicing at index 4 is guaranteed to fall on a valid UTF-8/WTF-8 code point boundary,
86            // ensuring that the remaining `display_bytes` retain a valid WTF-8 structure.
87            let os_str = unsafe { std::ffi::OsStr::from_encoded_bytes_unchecked(display_bytes) };
88
89            return Path::new(os_str).display();
90        }
91    }
92
93    path.display()
94}