gemini-browser

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

transform.go (2422B)


      1 // Copyright 2013 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 (
      8 	"unicode/utf8"
      9 
     10 	"golang.org/x/text/transform"
     11 )
     12 
     13 // Reset implements the Reset method of the transform.Transformer interface.
     14 func (Form) Reset() {}
     15 
     16 // Transform implements the Transform method of the transform.Transformer
     17 // interface. It may need to write segments of up to MaxSegmentSize at once.
     18 // Users should either catch ErrShortDst and allow dst to grow or have dst be at
     19 // least of size MaxTransformChunkSize to be guaranteed of progress.
     20 func (f Form) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
     21 	// Cap the maximum number of src bytes to check.
     22 	b := src
     23 	eof := atEOF
     24 	if ns := len(dst); ns < len(b) {
     25 		err = transform.ErrShortDst
     26 		eof = false
     27 		b = b[:ns]
     28 	}
     29 	i, ok := formTable[f].quickSpan(inputBytes(b), 0, len(b), eof)
     30 	n := copy(dst, b[:i])
     31 	if !ok {
     32 		nDst, nSrc, err = f.transform(dst[n:], src[n:], atEOF)
     33 		return nDst + n, nSrc + n, err
     34 	}
     35 
     36 	if err == nil && n < len(src) && !atEOF {
     37 		err = transform.ErrShortSrc
     38 	}
     39 	return n, n, err
     40 }
     41 
     42 func flushTransform(rb *reorderBuffer) bool {
     43 	// Write out (must fully fit in dst, or else it is an ErrShortDst).
     44 	if len(rb.out) < rb.nrune*utf8.UTFMax {
     45 		return false
     46 	}
     47 	rb.out = rb.out[rb.flushCopy(rb.out):]
     48 	return true
     49 }
     50 
     51 var errs = []error{nil, transform.ErrShortDst, transform.ErrShortSrc}
     52 
     53 // transform implements the transform.Transformer interface. It is only called
     54 // when quickSpan does not pass for a given string.
     55 func (f Form) transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
     56 	// TODO: get rid of reorderBuffer. See CL 23460044.
     57 	rb := reorderBuffer{}
     58 	rb.init(f, src)
     59 	for {
     60 		// Load segment into reorder buffer.
     61 		rb.setFlusher(dst[nDst:], flushTransform)
     62 		end := decomposeSegment(&rb, nSrc, atEOF)
     63 		if end < 0 {
     64 			return nDst, nSrc, errs[-end]
     65 		}
     66 		nDst = len(dst) - len(rb.out)
     67 		nSrc = end
     68 
     69 		// Next quickSpan.
     70 		end = rb.nsrc
     71 		eof := atEOF
     72 		if n := nSrc + len(dst) - nDst; n < end {
     73 			err = transform.ErrShortDst
     74 			end = n
     75 			eof = false
     76 		}
     77 		end, ok := rb.f.quickSpan(rb.src, nSrc, end, eof)
     78 		n := copy(dst[nDst:], rb.src.bytes[nSrc:end])
     79 		nSrc += n
     80 		nDst += n
     81 		if ok {
     82 			if err == nil && n < rb.nsrc && !atEOF {
     83 				err = transform.ErrShortSrc
     84 			}
     85 			return nDst, nSrc, err
     86 		}
     87 	}
     88 }