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 := 78 - lw.n
43 if n > len(buf) {
44 n = len(buf)
45 }
46 nn, err := lw.w.Write(buf[:n])
47 if nn > 0 {
48 wrote += nn
49 buf = buf[nn:]
50 }
51 if err != nil {
52 return wrote, err
53 }
54 lw.n += nn
55 if lw.n == 78 {
56 _, err := lw.w.Write([]byte("\r\n"))
57 if err != nil {
58 return wrote, err
59 }
60 lw.n = 0
61 }
62 }
63 return wrote, nil
64}
65
66func (lw *lineWrapper) Close() error {
67 if lw.n > 0 {
68 lw.n = 0
69 _, err := lw.w.Write([]byte("\r\n"))
70 return err
71 }
72 return nil
73}
74