* reload1.c (eliminate_regs_1): Call gen_rtx_raw_SUBREG for SUBREGs
[official-gcc.git] / libgo / go / mime / quotedprintable / writer.go
blob16ea0bf7d622806f7829259251778c5a48834677
1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 package quotedprintable
7 import "io"
9 const lineMaxLen = 76
11 // A Writer is a quoted-printable writer that implements io.WriteCloser.
12 type Writer struct {
13 // Binary mode treats the writer's input as pure binary and processes end of
14 // line bytes as binary data.
15 Binary bool
17 w io.Writer
18 i int
19 line [78]byte
20 cr bool
23 // NewWriter returns a new Writer that writes to w.
24 func NewWriter(w io.Writer) *Writer {
25 return &Writer{w: w}
28 // Write encodes p using quoted-printable encoding and writes it to the
29 // underlying io.Writer. It limits line length to 76 characters. The encoded
30 // bytes are not necessarily flushed until the Writer is closed.
31 func (w *Writer) Write(p []byte) (n int, err error) {
32 for i, b := range p {
33 switch {
34 // Simple writes are done in batch.
35 case b >= '!' && b <= '~' && b != '=':
36 continue
37 case isWhitespace(b) || !w.Binary && (b == '\n' || b == '\r'):
38 continue
41 if i > n {
42 if err := w.write(p[n:i]); err != nil {
43 return n, err
45 n = i
48 if err := w.encode(b); err != nil {
49 return n, err
51 n++
54 if n == len(p) {
55 return n, nil
58 if err := w.write(p[n:]); err != nil {
59 return n, err
62 return len(p), nil
65 // Close closes the Writer, flushing any unwritten data to the underlying
66 // io.Writer, but does not close the underlying io.Writer.
67 func (w *Writer) Close() error {
68 if err := w.checkLastByte(); err != nil {
69 return err
72 return w.flush()
75 // write limits text encoded in quoted-printable to 76 characters per line.
76 func (w *Writer) write(p []byte) error {
77 for _, b := range p {
78 if b == '\n' || b == '\r' {
79 // If the previous byte was \r, the CRLF has already been inserted.
80 if w.cr && b == '\n' {
81 w.cr = false
82 continue
85 if b == '\r' {
86 w.cr = true
89 if err := w.checkLastByte(); err != nil {
90 return err
92 if err := w.insertCRLF(); err != nil {
93 return err
95 continue
98 if w.i == lineMaxLen-1 {
99 if err := w.insertSoftLineBreak(); err != nil {
100 return err
104 w.line[w.i] = b
105 w.i++
106 w.cr = false
109 return nil
112 func (w *Writer) encode(b byte) error {
113 if lineMaxLen-1-w.i < 3 {
114 if err := w.insertSoftLineBreak(); err != nil {
115 return err
119 w.line[w.i] = '='
120 w.line[w.i+1] = upperhex[b>>4]
121 w.line[w.i+2] = upperhex[b&0x0f]
122 w.i += 3
124 return nil
127 const upperhex = "0123456789ABCDEF"
129 // checkLastByte encodes the last buffered byte if it is a space or a tab.
130 func (w *Writer) checkLastByte() error {
131 if w.i == 0 {
132 return nil
135 b := w.line[w.i-1]
136 if isWhitespace(b) {
137 w.i--
138 if err := w.encode(b); err != nil {
139 return err
143 return nil
146 func (w *Writer) insertSoftLineBreak() error {
147 w.line[w.i] = '='
148 w.i++
150 return w.insertCRLF()
153 func (w *Writer) insertCRLF() error {
154 w.line[w.i] = '\r'
155 w.line[w.i+1] = '\n'
156 w.i += 2
158 return w.flush()
161 func (w *Writer) flush() error {
162 if _, err := w.w.Write(w.line[:w.i]); err != nil {
163 return err
166 w.i = 0
167 return nil
170 func isWhitespace(b byte) bool {
171 return b == ' ' || b == '\t'