use crate::cesr::{bex_dex, decode_b64, encode_b64, get_sizes, BaseMatter, Parsable};
use crate::errors::MatterError;
use crate::Matter;
use std::any::Any;
#[derive(Debug, Clone)]
pub struct Bexter {
base: BaseMatter,
}
impl Bexter {
pub fn new(
raw: Option<&[u8]>,
code: Option<&str>,
soft: Option<&str>,
rize: Option<usize>,
) -> Result<Self, MatterError> {
if !bex_dex::TUPLE.contains(&(code.unwrap())) {
return Err(MatterError::UnsupportedCodeError(String::from(
code.unwrap_or("None"),
)));
}
let base = BaseMatter::new(raw, code, soft, rize)?;
Ok(Bexter { base })
}
pub fn from_qb64(qb64: &str) -> Result<Self, MatterError> {
let base = BaseMatter::from_qb64(qb64)?;
if !bex_dex::TUPLE.contains(&(base.code())) {
return Err(MatterError::UnsupportedCodeError(String::from(base.code())));
}
Ok(Bexter { base })
}
pub fn bext(&self) -> Result<String, MatterError> {
Self::derawify(self.raw(), self.code())
}
pub fn rawify(bext: &[u8]) -> Result<Vec<u8>, MatterError> {
let ts = bext.len() % 4; let ws = (4 - ts) % 4; let ls = (3 - ts) % 3;
let mut base = Vec::with_capacity(ws + bext.len());
base.extend(vec![b'A'; ws]);
base.extend_from_slice(bext);
let base_str = std::str::from_utf8(&base)
.map_err(|_| MatterError::DecodingError("Invalid UTF-8 in base64 input".to_string()))?;
let decoded = decode_b64(base_str)?;
if ls < decoded.len() {
Ok(decoded[ls..].to_vec())
} else {
Ok(Vec::new())
}
}
pub fn from_bext(bext: &[u8]) -> Result<Self, MatterError> {
let raw = Self::rawify(bext)?;
Self::new(Some(&raw), Some(bex_dex::TUPLE[0]), None, None)
}
pub fn derawify(raw: &[u8], code: &str) -> Result<String, MatterError> {
let sizes = get_sizes();
let ls = match sizes.get(code) {
Some(size) => size.ls,
None => return Err(MatterError::UnsupportedCodeError(code.to_string())),
};
let lead_bytes = vec![0u8; ls as usize];
let mut full_data = Vec::with_capacity(lead_bytes.len() + raw.len());
full_data.extend_from_slice(&lead_bytes);
full_data.extend_from_slice(raw);
let bext = encode_b64(&full_data);
let ws = if ls == 0 && !bext.is_empty() {
if bext.starts_with('A') {
1
} else {
0
}
} else {
(ls + 1) % 4
};
if ws < bext.len() as u32 {
Ok(bext[ws as usize..].to_string())
} else {
Ok(String::new())
}
}
}
impl Parsable for Bexter {
fn from_qb64b(data: &mut Vec<u8>, strip: Option<bool>) -> Result<Self, MatterError> {
let base = BaseMatter::from_qb64b(data, strip)?;
if !bex_dex::TUPLE.contains(&(base.code())) {
return Err(MatterError::UnsupportedCodeError(String::from(base.code())));
}
Ok(Bexter { base })
}
fn from_qb2(data: &mut Vec<u8>, strip: Option<bool>) -> Result<Self, MatterError> {
let base = BaseMatter::from_qb2(data, strip)?;
if !bex_dex::TUPLE.contains(&(base.code())) {
return Err(MatterError::UnsupportedCodeError(String::from(base.code())));
}
Ok(Bexter { base })
}
}
impl Matter for Bexter {
fn code(&self) -> &str {
self.base.code()
}
fn raw(&self) -> &[u8] {
self.base.raw()
}
fn qb64(&self) -> String {
self.base.qb64()
}
fn qb64b(&self) -> Vec<u8> {
self.base.qb64b()
}
fn qb2(&self) -> Vec<u8> {
self.base.qb2()
}
fn soft(&self) -> &str {
self.base.soft()
}
fn full_size(&self) -> usize {
self.base.full_size()
}
fn size(&self) -> usize {
self.base.size()
}
fn is_transferable(&self) -> bool {
self.base.is_transferable()
}
fn is_digestive(&self) -> bool {
self.base.is_digestive()
}
fn is_prefixive(&self) -> bool {
self.base.is_prefixive()
}
fn is_special(&self) -> bool {
self.base.is_special()
}
fn as_any(&self) -> &dyn Any {
self
}
}