aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/golang.org/x/text/unicode/norm/transform.go
blob: 9f47efbaf65fef06f903bdf8f6301bdd536db48f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// Copyright 2013 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 (
    "unicode/utf8"

    "golang.org/x/text/transform"
)

// Reset implements the Reset method of the transform.Transformer interface.
func (Form) Reset() {}

// Transform implements the Transform method of the transform.Transformer
// interface. It may need to write segments of up to MaxSegmentSize at once.
// Users should either catch ErrShortDst and allow dst to grow or have dst be at
// least of size MaxTransformChunkSize to be guaranteed of progress.
func (f Form) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
    n := 0
    // Cap the maximum number of src bytes to check.
    b := src
    eof := atEOF
    if ns := len(dst); ns < len(b) {
        err = transform.ErrShortDst
        eof = false
        b = b[:ns]
    }
    i, ok := formTable[f].quickSpan(inputBytes(b), n, len(b), eof)
    n += copy(dst[n:], b[n:i])
    if !ok {
        nDst, nSrc, err = f.transform(dst[n:], src[n:], atEOF)
        return nDst + n, nSrc + n, err
    }
    if n < len(src) && !atEOF {
        err = transform.ErrShortSrc
    }
    return n, n, err
}

func flushTransform(rb *reorderBuffer) bool {
    // Write out (must fully fit in dst, or else it is an ErrShortDst).
    if len(rb.out) < rb.nrune*utf8.UTFMax {
        return false
    }
    rb.out = rb.out[rb.flushCopy(rb.out):]
    return true
}

var errs = []error{nil, transform.ErrShortDst, transform.ErrShortSrc}

// transform implements the transform.Transformer interface. It is only called
// when quickSpan does not pass for a given string.
func (f Form) transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
    // TODO: get rid of reorderBuffer. See CL 23460044.
    rb := reorderBuffer{}
    rb.init(f, src)
    for {
        // Load segment into reorder buffer.
        rb.setFlusher(dst[nDst:], flushTransform)
        end := decomposeSegment(&rb, nSrc, atEOF)
        if end < 0 {
            return nDst, nSrc, errs[-end]
        }
        nDst = len(dst) - len(rb.out)
        nSrc = end

        // Next quickSpan.
        end = rb.nsrc
        eof := atEOF
        if n := nSrc + len(dst) - nDst; n < end {
            err = transform.ErrShortDst
            end = n
            eof = false
        }
        end, ok := rb.f.quickSpan(rb.src, nSrc, end, eof)
        n := copy(dst[nDst:], rb.src.bytes[nSrc:end])
        nSrc += n
        nDst += n
        if ok {
            if n < rb.nsrc && !atEOF {
                err = transform.ErrShortSrc
            }
            return nDst, nSrc, err
        }
    }
}