Matteo Scandolo | a6a3aee | 2019-11-26 13:30:14 -0700 | [diff] [blame] | 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 | n := 0 |
| 22 | // Cap the maximum number of src bytes to check. |
| 23 | b := src |
| 24 | eof := atEOF |
| 25 | if ns := len(dst); ns < len(b) { |
| 26 | err = transform.ErrShortDst |
| 27 | eof = false |
| 28 | b = b[:ns] |
| 29 | } |
| 30 | i, ok := formTable[f].quickSpan(inputBytes(b), n, len(b), eof) |
| 31 | n += copy(dst[n:], b[n:i]) |
| 32 | if !ok { |
| 33 | nDst, nSrc, err = f.transform(dst[n:], src[n:], atEOF) |
| 34 | return nDst + n, nSrc + n, err |
| 35 | } |
| 36 | if 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 n < rb.nsrc && !atEOF { |
| 83 | err = transform.ErrShortSrc |
| 84 | } |
| 85 | return nDst, nSrc, err |
| 86 | } |
| 87 | } |
| 88 | } |