|
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 } |