util.go 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. package xml
  2. var (
  3. ltEntityBytes = []byte("<")
  4. ampEntityBytes = []byte("&")
  5. singleQuoteEntityBytes = []byte("'")
  6. doubleQuoteEntityBytes = []byte(""")
  7. )
  8. // EscapeAttrVal returns the escape attribute value bytes without quotes.
  9. func EscapeAttrVal(buf *[]byte, b []byte) []byte {
  10. singles := 0
  11. doubles := 0
  12. for _, c := range b {
  13. if c == '"' {
  14. doubles++
  15. } else if c == '\'' {
  16. singles++
  17. }
  18. }
  19. n := len(b) + 2
  20. var quote byte
  21. var escapedQuote []byte
  22. if doubles > singles {
  23. n += singles * 4
  24. quote = '\''
  25. escapedQuote = singleQuoteEntityBytes
  26. } else {
  27. n += doubles * 4
  28. quote = '"'
  29. escapedQuote = doubleQuoteEntityBytes
  30. }
  31. if n > cap(*buf) {
  32. *buf = make([]byte, 0, n) // maximum size, not actual size
  33. }
  34. t := (*buf)[:n] // maximum size, not actual size
  35. t[0] = quote
  36. j := 1
  37. start := 0
  38. for i, c := range b {
  39. if c == quote {
  40. j += copy(t[j:], b[start:i])
  41. j += copy(t[j:], escapedQuote)
  42. start = i + 1
  43. }
  44. }
  45. j += copy(t[j:], b[start:])
  46. t[j] = quote
  47. return t[:j+1]
  48. }
  49. // EscapeCDATAVal returns the escaped text bytes.
  50. func EscapeCDATAVal(buf *[]byte, b []byte) ([]byte, bool) {
  51. n := 0
  52. for _, c := range b {
  53. if c == '<' || c == '&' {
  54. if c == '<' {
  55. n += 3 // &lt;
  56. } else {
  57. n += 4 // &amp;
  58. }
  59. if n > len("<![CDATA[]]>") {
  60. return b, false
  61. }
  62. }
  63. }
  64. if len(b)+n > cap(*buf) {
  65. *buf = make([]byte, 0, len(b)+n)
  66. }
  67. t := (*buf)[:len(b)+n]
  68. j := 0
  69. start := 0
  70. for i, c := range b {
  71. if c == '<' {
  72. j += copy(t[j:], b[start:i])
  73. j += copy(t[j:], ltEntityBytes)
  74. start = i + 1
  75. } else if c == '&' {
  76. j += copy(t[j:], b[start:i])
  77. j += copy(t[j:], ampEntityBytes)
  78. start = i + 1
  79. }
  80. }
  81. j += copy(t[j:], b[start:])
  82. return t[:j], true
  83. }