aboutsummaryrefslogtreecommitdiff
path: root/modules/mahonia/writer.go
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mahonia/writer.go')
-rw-r--r--modules/mahonia/writer.go108
1 files changed, 108 insertions, 0 deletions
diff --git a/modules/mahonia/writer.go b/modules/mahonia/writer.go
new file mode 100644
index 00000000..bdeb519c
--- /dev/null
+++ b/modules/mahonia/writer.go
@@ -0,0 +1,108 @@
+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])
+}