You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

163 lines
4.0 KiB

  1. // Copyright 2015 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 width
  5. import (
  6. "unicode/utf8"
  7. "golang.org/x/text/transform"
  8. )
  9. type foldTransform struct {
  10. transform.NopResetter
  11. }
  12. func (foldTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
  13. for nSrc < len(src) {
  14. if src[nSrc] < utf8.RuneSelf {
  15. // ASCII fast path.
  16. start, end := nSrc, len(src)
  17. if d := len(dst) - nDst; d < end-start {
  18. end = nSrc + d
  19. }
  20. for nSrc++; nSrc < end && src[nSrc] < utf8.RuneSelf; nSrc++ {
  21. }
  22. n := copy(dst[nDst:], src[start:nSrc])
  23. if nDst += n; nDst == len(dst) {
  24. nSrc = start + n
  25. if nSrc == len(src) {
  26. return nDst, nSrc, nil
  27. }
  28. if src[nSrc] < utf8.RuneSelf {
  29. return nDst, nSrc, transform.ErrShortDst
  30. }
  31. }
  32. continue
  33. }
  34. v, size := trie.lookup(src[nSrc:])
  35. if size == 0 { // incomplete UTF-8 encoding
  36. if !atEOF {
  37. return nDst, nSrc, transform.ErrShortSrc
  38. }
  39. size = 1 // gobble 1 byte
  40. }
  41. if elem(v)&tagNeedsFold == 0 {
  42. if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
  43. return nDst, nSrc, transform.ErrShortDst
  44. }
  45. nDst += size
  46. } else {
  47. data := inverseData[byte(v)]
  48. if len(dst)-nDst < int(data[0]) {
  49. return nDst, nSrc, transform.ErrShortDst
  50. }
  51. i := 1
  52. for end := int(data[0]); i < end; i++ {
  53. dst[nDst] = data[i]
  54. nDst++
  55. }
  56. dst[nDst] = data[i] ^ src[nSrc+size-1]
  57. nDst++
  58. }
  59. nSrc += size
  60. }
  61. return nDst, nSrc, nil
  62. }
  63. type narrowTransform struct {
  64. transform.NopResetter
  65. }
  66. func (narrowTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
  67. for nSrc < len(src) {
  68. if src[nSrc] < utf8.RuneSelf {
  69. // ASCII fast path.
  70. start, end := nSrc, len(src)
  71. if d := len(dst) - nDst; d < end-start {
  72. end = nSrc + d
  73. }
  74. for nSrc++; nSrc < end && src[nSrc] < utf8.RuneSelf; nSrc++ {
  75. }
  76. n := copy(dst[nDst:], src[start:nSrc])
  77. if nDst += n; nDst == len(dst) {
  78. nSrc = start + n
  79. if nSrc == len(src) {
  80. return nDst, nSrc, nil
  81. }
  82. if src[nSrc] < utf8.RuneSelf {
  83. return nDst, nSrc, transform.ErrShortDst
  84. }
  85. }
  86. continue
  87. }
  88. v, size := trie.lookup(src[nSrc:])
  89. if size == 0 { // incomplete UTF-8 encoding
  90. if !atEOF {
  91. return nDst, nSrc, transform.ErrShortSrc
  92. }
  93. size = 1 // gobble 1 byte
  94. }
  95. if k := elem(v).kind(); byte(v) == 0 || k != EastAsianFullwidth && k != EastAsianWide && k != EastAsianAmbiguous {
  96. if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
  97. return nDst, nSrc, transform.ErrShortDst
  98. }
  99. nDst += size
  100. } else {
  101. data := inverseData[byte(v)]
  102. if len(dst)-nDst < int(data[0]) {
  103. return nDst, nSrc, transform.ErrShortDst
  104. }
  105. i := 1
  106. for end := int(data[0]); i < end; i++ {
  107. dst[nDst] = data[i]
  108. nDst++
  109. }
  110. dst[nDst] = data[i] ^ src[nSrc+size-1]
  111. nDst++
  112. }
  113. nSrc += size
  114. }
  115. return nDst, nSrc, nil
  116. }
  117. type wideTransform struct {
  118. transform.NopResetter
  119. }
  120. func (wideTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
  121. for nSrc < len(src) {
  122. // TODO: Consider ASCII fast path. Special-casing ASCII handling can
  123. // reduce the ns/op of BenchmarkWideASCII by about 30%. This is probably
  124. // not enough to warrant the extra code and complexity.
  125. v, size := trie.lookup(src[nSrc:])
  126. if size == 0 { // incomplete UTF-8 encoding
  127. if !atEOF {
  128. return nDst, nSrc, transform.ErrShortSrc
  129. }
  130. size = 1 // gobble 1 byte
  131. }
  132. if k := elem(v).kind(); byte(v) == 0 || k != EastAsianHalfwidth && k != EastAsianNarrow {
  133. if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
  134. return nDst, nSrc, transform.ErrShortDst
  135. }
  136. nDst += size
  137. } else {
  138. data := inverseData[byte(v)]
  139. if len(dst)-nDst < int(data[0]) {
  140. return nDst, nSrc, transform.ErrShortDst
  141. }
  142. i := 1
  143. for end := int(data[0]); i < end; i++ {
  144. dst[nDst] = data[i]
  145. nDst++
  146. }
  147. dst[nDst] = data[i] ^ src[nSrc+size-1]
  148. nDst++
  149. }
  150. nSrc += size
  151. }
  152. return nDst, nSrc, nil
  153. }