use crate::ffi::{Buffer, Slice};
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum DecodeError {
Ok = 0,
InvalidLength = 1,
InvalidSymbol = 2,
InvalidPadding = 3,
Invalid = 4,
}
impl DecodeError {
pub fn from_code(code: i32) -> Option<Self> {
Some(match code {
0 => Self::Ok,
1 => Self::InvalidLength,
2 => Self::InvalidSymbol,
3 => Self::InvalidPadding,
4 => Self::Invalid,
_ => return None,
})
}
pub fn of(error: &crate::helpers::base64::DecodeError) -> (Self, u64) {
match error {
crate::helpers::base64::DecodeError::InvalidLength(length) => (Self::InvalidLength, *length as u64),
crate::helpers::base64::DecodeError::InvalidSymbol(symbol) => (Self::InvalidSymbol, *symbol as u64),
crate::helpers::base64::DecodeError::InvalidPadding => (Self::InvalidPadding, 0),
}
}
pub unsafe fn report(out: *mut DecodeError, detail: *mut u64, error: Self, value: u64) {
if !out.is_null() {
unsafe { *out = error };
}
if !detail.is_null() {
unsafe { *detail = value };
}
}
pub fn message(&self) -> &'static str {
match self {
Self::Ok => "ok",
Self::InvalidLength => "length is not a multiple of four",
Self::InvalidSymbol => "symbol is not in the base64 alphabet",
Self::InvalidPadding => "padding is misplaced or carries non-zero bits",
Self::Invalid => "invalid argument",
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn soyokaze_base64_error_message(error: i32) -> Slice {
Slice::maybe(DecodeError::from_code(error).map(|error| error.message()))
}
#[unsafe(no_mangle)]
pub extern "C" fn soyokaze_base64_alphabet() -> Slice {
Slice::new(crate::helpers::base64::ALPHABET)
}
#[unsafe(no_mangle)]
pub extern "C" fn soyokaze_base64_pad() -> u8 {
crate::helpers::base64::PAD
}
#[unsafe(no_mangle)]
pub extern "C" fn soyokaze_base64_invalid() -> u8 {
crate::helpers::base64::INVALID
}
#[unsafe(no_mangle)]
pub extern "C" fn soyokaze_base64_values() -> Slice {
Slice::new(&crate::helpers::base64::VALUES)
}
#[unsafe(no_mangle)]
pub extern "C" fn soyokaze_base64_symbol(value: u8) -> u8 {
crate::helpers::base64::symbol(value)
}
#[unsafe(no_mangle)]
pub extern "C" fn soyokaze_base64_value(symbol: u8) -> i32 {
match crate::helpers::base64::value(symbol) {
Some(value) => value as i32,
None => -1,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_base64_encoded_len(data: *const u8, data_len: usize) -> usize {
crate::helpers::base64::encoded_len(unsafe { Slice::borrow(data, data_len) }.unwrap_or_default())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_base64_sextets(group: *const u8, group_len: usize, out: *mut u32, error: *mut DecodeError, detail: *mut u64) -> bool {
let Some(group) = (unsafe { Slice::borrow(group, group_len) }) else {
unsafe { DecodeError::report(error, detail, DecodeError::Invalid, 0) };
return false;
};
match crate::helpers::base64::sextets(group) {
Ok(bits) => {
if !out.is_null() {
unsafe { *out = bits };
}
unsafe { DecodeError::report(error, detail, DecodeError::Ok, 0) };
true
}
Err(failure) => {
let (failure, value) = DecodeError::of(&failure);
unsafe { DecodeError::report(error, detail, failure, value) };
false
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_base64_encode(data: *const u8, data_len: usize) -> Buffer {
match unsafe { Slice::borrow(data, data_len) } {
Some(data) => Buffer::new(crate::helpers::base64::encode(data).into_bytes()),
None => Buffer::EMPTY,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_base64_decode(text: *const u8, text_len: usize, out: *mut Buffer, error: *mut DecodeError, detail: *mut u64) -> bool {
let Some(text) = (unsafe { Slice::borrow_text(text, text_len) }) else {
unsafe { DecodeError::report(error, detail, DecodeError::Invalid, 0) };
return false;
};
match crate::helpers::base64::decode(text) {
Ok(octets) => {
if !out.is_null() {
unsafe { *out = Buffer::new(octets) };
}
unsafe { DecodeError::report(error, detail, DecodeError::Ok, 0) };
true
}
Err(failure) => {
let (failure, value) = DecodeError::of(&failure);
unsafe { DecodeError::report(error, detail, failure, value) };
false
}
}
}