forked from NYANDEV/forgejo
108 lines
1.7 KiB
Go
108 lines
1.7 KiB
Go
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])
|
|
}
|