use super::error::Ps2mcError;
pub const ENTRY_SIZE: usize = 512;
pub const MODE_FILE: u16 = 0x0010;
pub const MODE_DIR: u16 = 0x0020;
pub const MODE_EXISTS: u16 = 0x8000;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Ps2Time {
pub sec: u8,
pub min: u8,
pub hour: u8,
pub day: u8,
pub month: u8,
pub year: u16,
}
impl Ps2Time {
pub fn from_bytes(bytes: &[u8; 8]) -> Self {
Self {
sec: bytes[1],
min: bytes[2],
hour: bytes[3],
day: bytes[4],
month: bytes[5],
year: u16::from_le_bytes([bytes[6], bytes[7]]),
}
}
}
#[derive(Debug, Clone)]
pub struct Entry {
pub mode: u16,
pub length: usize,
pub created: Ps2Time,
pub cluster: u32,
pub modified: Ps2Time,
pub name_bytes: [u8; 32],
}
impl Entry {
pub fn from_raw(bytes: &[u8]) -> Result<Self, Ps2mcError> {
if bytes.len() < ENTRY_SIZE {
return Err(Ps2mcError::InvalidEntryLength {
expected: ENTRY_SIZE,
actual: bytes.len(),
});
}
let mode = u16::from_le_bytes([bytes[0], bytes[1]]);
let length = u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]);
let mut created_bytes = [0u8; 8];
created_bytes.copy_from_slice(&bytes[8..16]);
let created = Ps2Time::from_bytes(&created_bytes);
let cluster = u32::from_le_bytes([bytes[16], bytes[17], bytes[18], bytes[19]]);
let mut modified_bytes = [0u8; 8];
modified_bytes.copy_from_slice(&bytes[24..32]);
let modified = Ps2Time::from_bytes(&modified_bytes);
let mut name_bytes = [0u8; 32];
name_bytes.copy_from_slice(&bytes[64..96]);
Ok(Self {
mode,
length: length as usize,
created,
cluster,
modified,
name_bytes,
})
}
pub fn build(byte_val: &[u8]) -> Vec<Self> {
byte_val
.chunks_exact(ENTRY_SIZE)
.filter_map(|chunk| Self::from_raw(chunk).ok())
.collect()
}
pub fn is_dir(&self) -> bool {
let mask = MODE_DIR | MODE_EXISTS;
(self.mode & mask) == mask
}
pub fn is_file(&self) -> bool {
let mask = MODE_FILE | MODE_EXISTS;
(self.mode & mask) == mask
}
pub fn is_exists(&self) -> bool {
(self.mode & MODE_EXISTS) > 0
}
pub fn decode_name(&self) -> String {
let clean = self.name_bytes.split(|&b| b == 0).next().unwrap();
if clean.is_empty() {
return String::new();
}
let (res, _, has_error) = encoding_rs::SHIFT_JIS.decode(clean);
if has_error {
String::from_utf8_lossy(clean).into_owned()
} else {
res.into_owned()
}
}
}