1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use std::convert::TryFrom;
use ::regex::Regex;
use super::*;
lazy_static! {
static ref RELIST: Regex = Regex::new(
r"(?x)
^(?P<month>\d{2})(?:\-|/)
(?P<date>\d{2})(?:\-|/)
(?P<year>\d{2,4})\s+
(?P<hour>\d{2}):(?P<minute>\d{2})\s{0,1}(?P<ampm>[AaMmPp]{1,2})\s+
(?:(?P<size>\d+)|(?P<isdir><DIR>))\s+
(?P<name>.+)$
"
)
.unwrap();
}
#[derive(Debug)]
pub struct FtpEntryMsdos {
kind: FtpEntryKind,
name: String,
size: usize,
date_str: String,
}
impl FtpEntryMsdos {
pub fn new(string: &str) -> Option<Self> {
FtpEntryMsdos::try_from(string).ok()
}
}
impl FtpEntryInfo for FtpEntryMsdos {
fn kind(&self) -> super::FtpEntryKind {
self.kind
}
fn name(&self) -> &str {
&self.name
}
fn size(&self) -> usize {
self.size
}
fn date_str(&self) -> &str {
&self.date_str
}
}
impl TryFrom<&str> for FtpEntryMsdos {
type Error = ();
fn try_from(value: &str) -> Result<Self, Self::Error> {
if let Some(caps) = RELIST.captures(&value) {
let as_str = |s| caps.name(s).unwrap().as_str();
let name = as_str("name");
let kind = caps
.name("isdir")
.map_or(FtpEntryKind::File, |_| FtpEntryKind::Directory);
let size = caps
.name("size")
.map(|s| s.as_str().parse::<usize>())
.map_or(0, |r| r.map_or(0, |size| size));
let date_str = {
let month: u8 = as_str("month").parse().unwrap();
let date: u8 = as_str("date").parse().unwrap();
let year: u32 = match (as_str("year").len(), as_str("year").parse::<u32>().unwrap())
{
(len, year) if len < 4 => year + if year < 70 { 2000 } else { 1900 },
(_, year) => year,
};
let mut hour: u8 = as_str("hour").parse().unwrap();
let minute: u8 = as_str("minute").parse().unwrap();
if hour < 12
&& as_str("ampm")
.bytes()
.next()
.unwrap()
.eq_ignore_ascii_case(&b'p')
{
hour += 12;
} else if hour == 12
&& as_str("ampm")
.bytes()
.next()
.unwrap()
.eq_ignore_ascii_case(&b'a')
{
hour = 0;
}
format!(
"{}-{:02}-{:02}T{:02}:{:02}",
year, month, date, hour, minute
)
};
return Ok(Self {
name: name.to_owned(),
kind,
size,
date_str,
});
}
Err(())
}
}