use crate::error::{Result, ZiporaError};
use base64::engine::general_purpose;
use base64::Engine;
pub fn encode_base64(data: &[u8]) -> Result<String> {
Ok(general_purpose::STANDARD.encode(data))
}
pub fn decode_base64(data: &str) -> Result<Vec<u8>> {
general_purpose::STANDARD
.decode(data)
.map_err(|e| ZiporaError::invalid_data(format!("base64 decode error: {}", e)))
}
pub fn encode_base64_to_buffer(data: &[u8], output: &mut [u8]) -> Result<usize> {
let encoded = general_purpose::STANDARD.encode(data);
let bytes = encoded.as_bytes();
if bytes.len() > output.len() {
return Err(ZiporaError::invalid_data("output buffer too small for base64 encoding"));
}
output[..bytes.len()].copy_from_slice(bytes);
Ok(bytes.len())
}
pub fn decode_base64_from_buffer(data: &[u8], output: &mut [u8]) -> Result<usize> {
let input_str = std::str::from_utf8(data)
.map_err(|e| ZiporaError::invalid_data(format!("invalid UTF-8 in base64 input: {}", e)))?;
let decoded = general_purpose::STANDARD
.decode(input_str)
.map_err(|e| ZiporaError::invalid_data(format!("base64 decode error: {}", e)))?;
if decoded.len() > output.len() {
return Err(ZiporaError::invalid_data("output buffer too small for base64 decoding"));
}
output[..decoded.len()].copy_from_slice(&decoded);
Ok(decoded.len())
}
pub fn calculate_encoded_len(input_len: usize) -> usize {
((input_len + 2) / 3) * 4
}
pub fn calculate_decoded_len(encoded_len: usize) -> usize {
(encoded_len / 4) * 3
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_encode_decode_roundtrip() {
let data = b"Hello, World!";
let encoded = encode_base64(data).unwrap();
assert_eq!(encoded, "SGVsbG8sIFdvcmxkIQ==");
let decoded = decode_base64(&encoded).unwrap();
assert_eq!(decoded, data);
}
#[test]
fn test_buffer_operations() {
let data = b"test";
let mut enc_buf = vec![0u8; calculate_encoded_len(data.len())];
let written = encode_base64_to_buffer(data, &mut enc_buf).unwrap();
enc_buf.truncate(written);
let mut dec_buf = vec![0u8; calculate_decoded_len(written)];
let dec_written = decode_base64_from_buffer(&enc_buf, &mut dec_buf).unwrap();
assert_eq!(&dec_buf[..dec_written], data);
}
#[test]
fn test_empty() {
assert_eq!(encode_base64(b"").unwrap(), "");
assert_eq!(decode_base64("").unwrap(), Vec::<u8>::new());
}
#[test]
fn test_length_calculations() {
assert_eq!(calculate_encoded_len(0), 0);
assert_eq!(calculate_encoded_len(1), 4);
assert_eq!(calculate_encoded_len(3), 4);
assert_eq!(calculate_encoded_len(4), 8);
}
}