1package moxio
2
3import (
4 "encoding/base64"
5 "io"
6)
7
8// implement io.Closer
9type closerFunc func() error
10
11func (f closerFunc) Close() error {
12 return f()
13}
14
15// Base64Writer turns a writer for data into one that writes base64 content on
16// \r\n separated lines of max 78+2 characters length.
17func Base64Writer(w io.Writer) io.WriteCloser {
18 lw := &lineWrapper{w: w}
19 bw := base64.NewEncoder(base64.StdEncoding, lw)
20 return struct {
21 io.Writer
22 io.Closer
23 }{
24 Writer: bw,
25 Closer: closerFunc(func() error {
26 if err := bw.Close(); err != nil {
27 return err
28 }
29 return lw.Close()
30 }),
31 }
32}
33
34type lineWrapper struct {
35 w io.Writer
36 n int // Written on current line.
37}
38
39func (lw *lineWrapper) Write(buf []byte) (int, error) {
40 wrote := 0
41 for len(buf) > 0 {
42 n := min(78-lw.n, len(buf))
43 nn, err := lw.w.Write(buf[:n])
44 if nn > 0 {
45 wrote += nn
46 buf = buf[nn:]
47 }
48 if err != nil {
49 return wrote, err
50 }
51 lw.n += nn
52 if lw.n == 78 {
53 _, err := lw.w.Write([]byte("\r\n"))
54 if err != nil {
55 return wrote, err
56 }
57 lw.n = 0
58 }
59 }
60 return wrote, nil
61}
62
63func (lw *lineWrapper) Close() error {
64 if lw.n > 0 {
65 lw.n = 0
66 _, err := lw.w.Write([]byte("\r\n"))
67 return err
68 }
69 return nil
70}
71