readwriter.go

  1// Copyright 2011 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.
  4
  5package norm
  6
  7import "io"
  8
  9type normWriter struct {
 10	rb  reorderBuffer
 11	w   io.Writer
 12	buf []byte
 13}
 14
 15// Write implements the standard write interface.  If the last characters are
 16// not at a normalization boundary, the bytes will be buffered for the next
 17// write. The remaining bytes will be written on close.
 18func (w *normWriter) Write(data []byte) (n int, err error) {
 19	// Process data in pieces to keep w.buf size bounded.
 20	const chunk = 4000
 21
 22	for len(data) > 0 {
 23		// Normalize into w.buf.
 24		m := len(data)
 25		if m > chunk {
 26			m = chunk
 27		}
 28		w.rb.src = inputBytes(data[:m])
 29		w.rb.nsrc = m
 30		w.buf = doAppend(&w.rb, w.buf, 0)
 31		data = data[m:]
 32		n += m
 33
 34		// Write out complete prefix, save remainder.
 35		// Note that lastBoundary looks back at most 31 runes.
 36		i := lastBoundary(&w.rb.f, w.buf)
 37		if i == -1 {
 38			i = 0
 39		}
 40		if i > 0 {
 41			if _, err = w.w.Write(w.buf[:i]); err != nil {
 42				break
 43			}
 44			bn := copy(w.buf, w.buf[i:])
 45			w.buf = w.buf[:bn]
 46		}
 47	}
 48	return n, err
 49}
 50
 51// Close forces data that remains in the buffer to be written.
 52func (w *normWriter) Close() error {
 53	if len(w.buf) > 0 {
 54		_, err := w.w.Write(w.buf)
 55		if err != nil {
 56			return err
 57		}
 58	}
 59	return nil
 60}
 61
 62// Writer returns a new writer that implements Write(b)
 63// by writing f(b) to w. The returned writer may use an
 64// internal buffer to maintain state across Write calls.
 65// Calling its Close method writes any buffered data to w.
 66func (f Form) Writer(w io.Writer) io.WriteCloser {
 67	wr := &normWriter{rb: reorderBuffer{}, w: w}
 68	wr.rb.init(f, nil)
 69	return wr
 70}
 71
 72type normReader struct {
 73	rb           reorderBuffer
 74	r            io.Reader
 75	inbuf        []byte
 76	outbuf       []byte
 77	bufStart     int
 78	lastBoundary int
 79	err          error
 80}
 81
 82// Read implements the standard read interface.
 83func (r *normReader) Read(p []byte) (int, error) {
 84	for {
 85		if r.lastBoundary-r.bufStart > 0 {
 86			n := copy(p, r.outbuf[r.bufStart:r.lastBoundary])
 87			r.bufStart += n
 88			if r.lastBoundary-r.bufStart > 0 {
 89				return n, nil
 90			}
 91			return n, r.err
 92		}
 93		if r.err != nil {
 94			return 0, r.err
 95		}
 96		outn := copy(r.outbuf, r.outbuf[r.lastBoundary:])
 97		r.outbuf = r.outbuf[0:outn]
 98		r.bufStart = 0
 99
100		n, err := r.r.Read(r.inbuf)
101		r.rb.src = inputBytes(r.inbuf[0:n])
102		r.rb.nsrc, r.err = n, err
103		if n > 0 {
104			r.outbuf = doAppend(&r.rb, r.outbuf, 0)
105		}
106		if err == io.EOF {
107			r.lastBoundary = len(r.outbuf)
108		} else {
109			r.lastBoundary = lastBoundary(&r.rb.f, r.outbuf)
110			if r.lastBoundary == -1 {
111				r.lastBoundary = 0
112			}
113		}
114	}
115}
116
117// Reader returns a new reader that implements Read
118// by reading data from r and returning f(data).
119func (f Form) Reader(r io.Reader) io.Reader {
120	const chunk = 4000
121	buf := make([]byte, chunk)
122	rr := &normReader{rb: reorderBuffer{}, r: r, inbuf: buf}
123	rr.rb.init(f, buf)
124	return rr
125}