| // Copyright 2011 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package norm | |
| import "io" | |
| type normWriter struct { | |
| rb reorderBuffer | |
| w io.Writer | |
| buf []byte | |
| } | |
| // Write implements the standard write interface. If the last characters are | |
| // not at a normalization boundary, the bytes will be buffered for the next | |
| // write. The remaining bytes will be written on close. | |
| func (w *normWriter) Write(data []byte) (n int, err error) { | |
| // Process data in pieces to keep w.buf size bounded. | |
| const chunk = 4000 | |
| for len(data) > 0 { | |
| // Normalize into w.buf. | |
| m := len(data) | |
| if m > chunk { | |
| m = chunk | |
| } | |
| w.rb.src = inputBytes(data[:m]) | |
| w.rb.nsrc = m | |
| w.buf = doAppend(&w.rb, w.buf, 0) | |
| data = data[m:] | |
| n += m | |
| // Write out complete prefix, save remainder. | |
| // Note that lastBoundary looks back at most 31 runes. | |
| i := lastBoundary(&w.rb.f, w.buf) | |
| if i == -1 { | |
| i = 0 | |
| } | |
| if i > 0 { | |
| if _, err = w.w.Write(w.buf[:i]); err != nil { | |
| break | |
| } | |
| bn := copy(w.buf, w.buf[i:]) | |
| w.buf = w.buf[:bn] | |
| } | |
| } | |
| return n, err | |
| } | |
| // Close forces data that remains in the buffer to be written. | |
| func (w *normWriter) Close() error { | |
| if len(w.buf) > 0 { | |
| _, err := w.w.Write(w.buf) | |
| if err != nil { | |
| return err | |
| } | |
| } | |
| return nil | |
| } | |
| // Writer returns a new writer that implements Write(b) | |
| // by writing f(b) to w. The returned writer may use an | |
| // internal buffer to maintain state across Write calls. | |
| // Calling its Close method writes any buffered data to w. | |
| func (f Form) Writer(w io.Writer) io.WriteCloser { | |
| wr := &normWriter{rb: reorderBuffer{}, w: w} | |
| wr.rb.init(f, nil) | |
| return wr | |
| } | |
| type normReader struct { | |
| rb reorderBuffer | |
| r io.Reader | |
| inbuf []byte | |
| outbuf []byte | |
| bufStart int | |
| lastBoundary int | |
| err error | |
| } | |
| // Read implements the standard read interface. | |
| func (r *normReader) Read(p []byte) (int, error) { | |
| for { | |
| if r.lastBoundary-r.bufStart > 0 { | |
| n := copy(p, r.outbuf[r.bufStart:r.lastBoundary]) | |
| r.bufStart += n | |
| if r.lastBoundary-r.bufStart > 0 { | |
| return n, nil | |
| } | |
| return n, r.err | |
| } | |
| if r.err != nil { | |
| return 0, r.err | |
| } | |
| outn := copy(r.outbuf, r.outbuf[r.lastBoundary:]) | |
| r.outbuf = r.outbuf[0:outn] | |
| r.bufStart = 0 | |
| n, err := r.r.Read(r.inbuf) | |
| r.rb.src = inputBytes(r.inbuf[0:n]) | |
| r.rb.nsrc, r.err = n, err | |
| if n > 0 { | |
| r.outbuf = doAppend(&r.rb, r.outbuf, 0) | |
| } | |
| if err == io.EOF { | |
| r.lastBoundary = len(r.outbuf) | |
| } else { | |
| r.lastBoundary = lastBoundary(&r.rb.f, r.outbuf) | |
| if r.lastBoundary == -1 { | |
| r.lastBoundary = 0 | |
| } | |
| } | |
| } | |
| } | |
| // Reader returns a new reader that implements Read | |
| // by reading data from r and returning f(data). | |
| func (f Form) Reader(r io.Reader) io.Reader { | |
| const chunk = 4000 | |
| buf := make([]byte, chunk) | |
| rr := &normReader{rb: reorderBuffer{}, r: r, inbuf: buf} | |
| rr.rb.init(f, buf) | |
| return rr | |
| } |