1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use std::io::{self, Write};

/// Write any data and encode them to base64 data.
pub struct ToBase64Writer<W: Write> {
    inner: W,
    buf: Vec<u8>,
    remaining: Vec<u8>,
}

impl<W: Write> ToBase64Writer<W> {
    pub fn new(inner: W) -> ToBase64Writer<W> {
        ToBase64Writer {
            inner,
            buf: Vec::new(),
            remaining: Vec::new(),
        }
    }
}

impl<W: Write> Write for ToBase64Writer<W> {
    fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
        let remaining_len = self.remaining.len();
        let buf_len = buf.len();

        if remaining_len > 0 {
            let new_buf_len = remaining_len + buf_len;

            if new_buf_len < 3 {
                self.remaining.extend_from_slice(&buf);
                Ok(buf_len)
            } else {
                let actual_max_write_size = new_buf_len / 3 * 3;

                let buf_end = actual_max_write_size - remaining_len;

                self.remaining.extend_from_slice(&buf[..buf_end]);

                let c = actual_max_write_size / 3 * 4;

                self.buf.clear();

                self.buf.reserve(c);

                unsafe { self.buf.set_len(c); }

                base64::encode_config_slice(&self.remaining, base64::STANDARD, &mut self.buf);

                self.remaining.clear();

                self.inner.write(&self.buf)?;

                if buf_len != buf_end {
                    self.remaining.extend_from_slice(&buf[buf_end..]);
                }

                Ok(buf_len)
            }
        } else {
            if buf_len < 3 {
                self.remaining.extend_from_slice(&buf);
                Ok(buf_len)
            } else {
                let actual_max_write_size = buf_len / 3 * 3;

                let buf = if actual_max_write_size == buf_len {
                    buf
                } else {
                    self.remaining.extend_from_slice(&buf[actual_max_write_size..]);
                    &buf[..actual_max_write_size]
                };

                let c = actual_max_write_size / 3 * 4;

                self.buf.clear();

                self.buf.reserve(c);

                unsafe { self.buf.set_len(c); }

                base64::encode_config_slice(buf, base64::STANDARD, &mut self.buf);

                self.inner.write(&self.buf)?;

                Ok(buf_len)
            }
        }
    }

    fn flush(&mut self) -> Result<(), io::Error> {
        let remaining_len = self.remaining.len();

        if remaining_len > 0 {
            let c = (remaining_len + 2) / 3 * 4;

            self.buf.clear();

            self.buf.reserve(c);

            unsafe { self.buf.set_len(c); }

            base64::encode_config_slice(&self.remaining, base64::STANDARD, &mut self.buf);

            self.remaining.clear();

            self.inner.write(&self.buf)?;

            self.inner.flush()
        } else {
            self.inner.flush()
        }
    }
}

impl<W: Write> Drop for ToBase64Writer<W> {
    fn drop(&mut self) {
        self.flush().unwrap()
    }
}