mirror of https://github.com/gogits/gogs.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
108 lines
1.7 KiB
108 lines
1.7 KiB
package mahonia |
|
|
|
import ( |
|
"io" |
|
"unicode/utf8" |
|
) |
|
|
|
// Writer implements character-set encoding for an io.Writer object. |
|
type Writer struct { |
|
wr io.Writer |
|
encode Encoder |
|
inbuf []byte |
|
outbuf []byte |
|
} |
|
|
|
// NewWriter creates a new Writer that uses the receiver to encode text. |
|
func (e Encoder) NewWriter(wr io.Writer) *Writer { |
|
w := new(Writer) |
|
w.wr = wr |
|
w.encode = e |
|
return w |
|
} |
|
|
|
// Write encodes and writes the data from p. |
|
func (w *Writer) Write(p []byte) (n int, err error) { |
|
n = len(p) |
|
|
|
if len(w.inbuf) > 0 { |
|
w.inbuf = append(w.inbuf, p...) |
|
p = w.inbuf |
|
} |
|
|
|
if len(w.outbuf) < len(p) { |
|
w.outbuf = make([]byte, len(p)+10) |
|
} |
|
|
|
outpos := 0 |
|
|
|
for len(p) > 0 { |
|
rune, size := utf8.DecodeRune(p) |
|
if rune == 0xfffd && !utf8.FullRune(p) { |
|
break |
|
} |
|
|
|
p = p[size:] |
|
|
|
retry: |
|
size, status := w.encode(w.outbuf[outpos:], rune) |
|
|
|
if status == NO_ROOM { |
|
newDest := make([]byte, len(w.outbuf)*2) |
|
copy(newDest, w.outbuf) |
|
w.outbuf = newDest |
|
goto retry |
|
} |
|
|
|
if status == STATE_ONLY { |
|
outpos += size |
|
goto retry |
|
} |
|
|
|
outpos += size |
|
} |
|
|
|
w.inbuf = w.inbuf[:0] |
|
if len(p) > 0 { |
|
w.inbuf = append(w.inbuf, p...) |
|
} |
|
|
|
n1, err := w.wr.Write(w.outbuf[0:outpos]) |
|
|
|
if err != nil && n1 < n { |
|
n = n1 |
|
} |
|
|
|
return |
|
} |
|
|
|
func (w *Writer) WriteRune(c rune) (size int, err error) { |
|
if len(w.inbuf) > 0 { |
|
// There are leftover bytes, a partial UTF-8 sequence. |
|
w.inbuf = w.inbuf[:0] |
|
w.WriteRune(0xfffd) |
|
} |
|
|
|
if w.outbuf == nil { |
|
w.outbuf = make([]byte, 16) |
|
} |
|
|
|
outpos := 0 |
|
|
|
retry: |
|
size, status := w.encode(w.outbuf[outpos:], c) |
|
|
|
if status == NO_ROOM { |
|
w.outbuf = make([]byte, len(w.outbuf)*2) |
|
goto retry |
|
} |
|
|
|
if status == STATE_ONLY { |
|
outpos += size |
|
goto retry |
|
} |
|
|
|
outpos += size |
|
|
|
return w.wr.Write(w.outbuf[0:outpos]) |
|
}
|
|
|