email_encoding/body/
base64.rsuse std::fmt::{self, Write};
use std::str;
use ::base64::Engine;
const LINE_LEN: usize = 76;
const CRLF: &str = "\r\n";
pub fn encode(b: &[u8], w: &mut dyn Write) -> fmt::Result {
let mut buf = [0; LINE_LEN];
let mut chunks = b.chunks(LINE_LEN / 4 * 3).peekable();
while let Some(chunk) = chunks.next() {
let len = ::base64::engine::general_purpose::STANDARD
.encode_slice(chunk, &mut buf)
.unwrap();
w.write_str(str::from_utf8(&buf[..len]).expect("base64 produced an invalid encode"))?;
if chunks.peek().is_some() {
w.write_str(CRLF)?;
}
}
Ok(())
}
pub fn encoded_len(input_len: usize) -> usize {
let mut base64_len = input_len / 3 * 4;
if input_len % 3 != 0 {
base64_len += 4 - base64_len % 4;
}
let mut crlf_len = base64_len / LINE_LEN * CRLF.len();
if crlf_len >= CRLF.len() && base64_len % LINE_LEN == 0 {
crlf_len -= CRLF.len();
}
base64_len + crlf_len
}
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use super::{encode, encoded_len};
#[test]
fn empty() {
let input = b"";
let mut output = String::new();
encode(input, &mut output).unwrap();
assert_eq!(output, "");
assert_eq!(output.len(), encoded_len(input.len()));
}
#[test]
fn oneline() {
let input = b"012";
let mut output = String::new();
encode(input, &mut output).unwrap();
assert_eq!(output, "MDEy");
assert_eq!(output.len(), encoded_len(input.len()));
}
#[test]
fn oneline_padded() {
let input = b"0123";
let mut output = String::new();
encode(input, &mut output).unwrap();
assert_eq!(output, "MDEyMw==");
assert_eq!(output.len(), encoded_len(input.len()));
}
#[test]
fn multiline() {
let input =
b"012345678998765432100123456789987654321001234567899876543210012345678998765432100";
let mut output = String::new();
encode(input, &mut output).unwrap();
assert_eq!(
output,
concat!(
"MDEyMzQ1Njc4OTk4NzY1NDMyMTAwMTIzNDU2Nzg5OTg3NjU0MzIxMDAxMjM0NTY3ODk5ODc2NTQz\r\n",
"MjEwMDEyMzQ1Njc4OTk4NzY1NDMyMTAw"
)
);
assert_eq!(output.len(), encoded_len(input.len()));
}
#[test]
fn multiline_padded() {
let input =
b"01234567899876543210012345678998765432100123456789987654321001234567899876543210";
let mut output = String::new();
encode(input, &mut output).unwrap();
assert_eq!(
output,
concat!(
"MDEyMzQ1Njc4OTk4NzY1NDMyMTAwMTIzNDU2Nzg5OTg3NjU0MzIxMDAxMjM0NTY3ODk5ODc2NTQz\r\n",
"MjEwMDEyMzQ1Njc4OTk4NzY1NDMyMTA="
)
);
assert_eq!(output.len(), encoded_len(input.len()));
}
#[test]
fn multiline_exact() {
let input =
b"012345678998765432100123456789987654321001234567899876543210012345678998765432100123456789987654321001234567899876543210012345678998765432100123456789987654321001234567899";
let mut output = String::new();
encode(input, &mut output).unwrap();
assert_eq!(
output,
concat!(
"MDEyMzQ1Njc4OTk4NzY1NDMyMTAwMTIzNDU2Nzg5OTg3NjU0MzIxMDAxMjM0NTY3ODk5ODc2NTQz\r\n",
"MjEwMDEyMzQ1Njc4OTk4NzY1NDMyMTAwMTIzNDU2Nzg5OTg3NjU0MzIxMDAxMjM0NTY3ODk5ODc2\r\n",
"NTQzMjEwMDEyMzQ1Njc4OTk4NzY1NDMyMTAwMTIzNDU2Nzg5OTg3NjU0MzIxMDAxMjM0NTY3ODk5"
)
);
assert_eq!(output.len(), encoded_len(input.len()));
}
}