use super::internal;
use std::fmt::{self, Debug};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Z85p {
payload: Vec<u8>,
}
pub use internal::ParserError;
impl fmt::Display for Z85p {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl Z85p {
pub fn encode(input: &[u8]) -> Z85p {
let length = input.len();
let tail_size = length % 4;
let has_tail = tail_size != 0;
let chunked_size = length - tail_size;
let mut payload = Vec::with_capacity(length / 4 * 5 + 5);
for chunk in input[..chunked_size].chunks(4) {
let z85_chunk = internal::encode_chunk(chunk);
payload.extend_from_slice(&z85_chunk);
}
if has_tail {
let tail = &input[chunked_size..];
let z85_tail = internal::encode_tail(tail);
payload.extend_from_slice(&z85_tail);
}
Z85p { payload }
}
pub fn decode(&self) -> Vec<u8> {
let input = &self.payload;
let length = input.len();
if length == 0 {
return vec![];
}
let has_tail = input[length - 5] == b'#';
let mut chunked_size = length;
if has_tail {
chunked_size -= 5;
}
let mut out = Vec::with_capacity(length / 5 * 4);
for chunk in input[..chunked_size].chunks(5) {
let binchunk = internal::decode_chunk(chunk);
out.extend_from_slice(&binchunk);
}
if has_tail {
let last_chunk = &input[chunked_size..];
let bintail = internal::decode_tail(last_chunk);
out.extend_from_slice(&bintail);
}
out
}
pub unsafe fn wrap_bytes_unchecked(input: Vec<u8>) -> Self {
Z85p { payload: input }
}
pub fn wrap_bytes(input: Vec<u8>) -> Result<Z85p, ParserError> {
use internal::CVResult::*;
use ParserError::*;
let length = input.len();
if length % 5 != 0 {
return Err(InvalidInputSize(length));
}
let has_tail = length != 0 && input[length - 5] == b'#';
let mut chunked_size = length;
if has_tail {
chunked_size -= 5;
}
for (cpos, chunk) in input[..chunked_size].chunks(5).enumerate() {
match internal::validate_chunk(chunk) {
WrongChunk => return Err(InvalidChunk(cpos * 5)),
WrongByte(pos, l) => return Err(InvalidByte(cpos * 5 + pos, l)),
Fine => (),
}
}
if has_tail {
match internal::validate_tail(&input[chunked_size..]) {
WrongChunk => return Err(InvalidChunk(length - 5)),
WrongByte(pos, l) => return Err(InvalidByte(length - 5 + pos, l)),
Fine => (),
}
}
Ok(Z85p { payload: input })
}
pub fn as_str(&self) -> &str {
unsafe { std::str::from_utf8_unchecked(&self.payload) }
}
pub fn as_bytes(&self) -> &[u8] {
self.payload.as_slice()
}
}