-
-
Notifications
You must be signed in to change notification settings - Fork 104
Expand file tree
/
Copy pathb64linebreaker.go
More file actions
108 lines (98 loc) · 2.87 KB
/
Copy pathb64linebreaker.go
File metadata and controls
108 lines (98 loc) · 2.87 KB
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
// SPDX-FileCopyrightText: The go-mail Authors
//
// SPDX-License-Identifier: MIT
package mail
import (
"errors"
"io"
)
// newlineBytes is a byte slice representation of the SingleNewLine constant used for line breaking
// in encoding processes.
var newlineBytes = []byte(SingleNewLine)
// base64LineBreaker handles base64 encoding with the insertion of new lines after a certain number
// of characters.
//
// This struct is used to manage base64 encoding while ensuring that new lines are inserted after
// reaching a specific line length. It satisfies the io.WriteCloser interface.
//
// References:
// - https://datatracker.ietf.org/doc/html/rfc2045 (Base64 and line length limitations)
type base64LineBreaker struct {
line [MaxBodyLength]byte
used int
out io.Writer
}
// Write writes data to the base64LineBreaker, ensuring lines do not exceed MaxBodyLength.
//
// This method writes the provided data to the base64LineBreaker. It ensures that the written
// lines do not exceed the MaxBodyLength. If the data exceeds the limit, it handles the
// continuation by splitting the data and writing new lines as necessary.
//
// Parameters:
// - data: A byte slice containing the data to be written.
//
// Returns:
// - numBytes: The number of bytes written.
// - err: An error if one occurred during the write operation.
func (l *base64LineBreaker) Write(data []byte) (numBytes int, err error) {
if l.out == nil {
err = errors.New("no io.Writer set for base64LineBreaker")
return numBytes, err
}
written := 0
for len(data) > 0 {
space := MaxBodyLength - l.used
if space == 0 {
// buffer full, flush it
_, err = l.out.Write(l.line[0:l.used])
if err != nil {
return written, err
}
_, err = l.out.Write(newlineBytes)
if err != nil {
return written, err
}
l.used = 0
space = MaxBodyLength
}
if len(data) <= space {
copy(l.line[l.used:], data)
l.used += len(data)
written += len(data)
break
}
// Fill the buffer and flush
copy(l.line[l.used:], data[:space])
l.used = MaxBodyLength
_, err = l.out.Write(l.line[0:l.used])
if err != nil {
return written, err
}
_, err = l.out.Write(newlineBytes)
if err != nil {
return written, err
}
l.used = 0
written += space
data = data[space:]
}
return written, nil
}
// Close finalizes the base64LineBreaker, writing any remaining buffered data and appending a newline.
//
// This method ensures that any remaining data in the buffer is written to the output and appends
// a newline. It is used to finalize the base64LineBreaker and should be called when no more data
// is expected to be written.
//
// Returns:
// - err: An error if one occurred during the final write operation.
func (l *base64LineBreaker) Close() (err error) {
if l.used > 0 {
_, err = l.out.Write(l.line[0:l.used])
if err != nil {
return err
}
_, err = l.out.Write(newlineBytes)
}
return err
}