gemini-browser

A text-based gemini browser
git clone git://git.laack.co/gemini-browser.git
Log | Files | Refs | README

readwriter.go (2957B)


      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 
      5 package norm
      6 
      7 import "io"
      8 
      9 type 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.
     18 func (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.
     52 func (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.
     66 func (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 
     72 type 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.
     83 func (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).
    119 func (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 }