transform.go 2.4 KB

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