use alloc::string::String;
use alloc::vec::Vec;
#[derive(Clone, Copy)]
pub struct Zisofs {
pub uncompressed_size: u32,
pub block_size_log2: u8,
}
#[derive(Default)]
pub struct RrInfo {
pub name: Option<String>,
pub mode: Option<u32>,
pub symlink_target: Option<Vec<u8>>,
pub zisofs: Option<Zisofs>,
}
pub fn detect_sp(su: &[u8]) -> Option<usize> {
let mut p = 0;
while p + 4 <= su.len() {
let len = su[p + 2] as usize;
if len < 4 || p + len > su.len() {
break;
}
if &su[p..p + 2] == b"SP" && len >= 7 && su[p + 4] == 0xBE && su[p + 5] == 0xEF {
return Some(su[p + 6] as usize);
}
p += len;
}
None
}
pub fn parse_su(su: &[u8]) -> RrInfo {
let mut info = RrInfo::default();
let mut name = Vec::new();
let mut have_nm = false;
let mut sl = Vec::new();
let mut have_sl = false;
let mut p = 0;
while p + 4 <= su.len() {
let len = su[p + 2] as usize;
if len < 4 || p + len > su.len() {
break;
}
let sig = &su[p..p + 2];
let data = &su[p + 4..p + len];
match sig {
b"NM" => {
if !data.is_empty() && data[0] & 0x06 == 0 {
name.extend_from_slice(&data[1..]);
have_nm = true;
}
}
b"PX" => {
if data.len() >= 4 {
info.mode = Some(u32::from_le_bytes([data[0], data[1], data[2], data[3]]));
}
}
b"SL" => {
have_sl = true;
if !data.is_empty() {
parse_sl_components(&data[1..], &mut sl);
}
}
b"ZF" => {
if data.len() >= 8 && &data[0..2] == b"pz" {
info.zisofs = Some(Zisofs {
block_size_log2: data[3],
uncompressed_size: u32::from_le_bytes([data[4], data[5], data[6], data[7]]),
});
}
}
b"ST" => break,
_ => {}
}
p += len;
}
if have_nm {
if let Ok(s) = String::from_utf8(name) {
if !s.is_empty() {
info.name = Some(s);
}
}
}
if have_sl {
info.symlink_target = Some(sl);
}
info
}
fn parse_sl_components(mut comp: &[u8], out: &mut Vec<u8>) {
while comp.len() >= 2 {
let flags = comp[0];
let clen = comp[1] as usize;
if 2 + clen > comp.len() {
break;
}
let content = &comp[2..2 + clen];
let is_root = flags & 0x08 != 0;
if !out.is_empty() && !is_root {
out.push(b'/');
}
if is_root {
if out.is_empty() {
out.push(b'/');
}
} else if flags & 0x02 != 0 {
out.extend_from_slice(b".");
} else if flags & 0x04 != 0 {
out.extend_from_slice(b"..");
} else {
out.extend_from_slice(content);
}
comp = &comp[2 + clen..];
}
}