bytes.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. // Package escape contains utilities for escaping parts of InfluxQL
  2. // and InfluxDB line protocol.
  3. package escape // import "github.com/influxdata/influxdb/pkg/escape"
  4. import (
  5. "bytes"
  6. "strings"
  7. )
  8. // Codes is a map of bytes to be escaped.
  9. var Codes = map[byte][]byte{
  10. ',': []byte(`\,`),
  11. '"': []byte(`\"`),
  12. ' ': []byte(`\ `),
  13. '=': []byte(`\=`),
  14. }
  15. // Bytes escapes characters on the input slice, as defined by Codes.
  16. func Bytes(in []byte) []byte {
  17. for b, esc := range Codes {
  18. in = bytes.Replace(in, []byte{b}, esc, -1)
  19. }
  20. return in
  21. }
  22. const escapeChars = `," =`
  23. // IsEscaped returns whether b has any escaped characters,
  24. // i.e. whether b seems to have been processed by Bytes.
  25. func IsEscaped(b []byte) bool {
  26. for len(b) > 0 {
  27. i := bytes.IndexByte(b, '\\')
  28. if i < 0 {
  29. return false
  30. }
  31. if i+1 < len(b) && strings.IndexByte(escapeChars, b[i+1]) >= 0 {
  32. return true
  33. }
  34. b = b[i+1:]
  35. }
  36. return false
  37. }
  38. // AppendUnescaped appends the unescaped version of src to dst
  39. // and returns the resulting slice.
  40. func AppendUnescaped(dst, src []byte) []byte {
  41. var pos int
  42. for len(src) > 0 {
  43. next := bytes.IndexByte(src[pos:], '\\')
  44. if next < 0 || pos+next+1 >= len(src) {
  45. return append(dst, src...)
  46. }
  47. if pos+next+1 < len(src) && strings.IndexByte(escapeChars, src[pos+next+1]) >= 0 {
  48. if pos+next > 0 {
  49. dst = append(dst, src[:pos+next]...)
  50. }
  51. src = src[pos+next+1:]
  52. pos = 0
  53. } else {
  54. pos += next + 1
  55. }
  56. }
  57. return dst
  58. }
  59. // Unescape returns a new slice containing the unescaped version of in.
  60. func Unescape(in []byte) []byte {
  61. if len(in) == 0 {
  62. return nil
  63. }
  64. if bytes.IndexByte(in, '\\') == -1 {
  65. return in
  66. }
  67. i := 0
  68. inLen := len(in)
  69. // The output size will be no more than inLen. Preallocating the
  70. // capacity of the output is faster and uses less memory than
  71. // letting append() do its own (over)allocation.
  72. out := make([]byte, 0, inLen)
  73. for {
  74. if i >= inLen {
  75. break
  76. }
  77. if in[i] == '\\' && i+1 < inLen {
  78. switch in[i+1] {
  79. case ',':
  80. out = append(out, ',')
  81. i += 2
  82. continue
  83. case '"':
  84. out = append(out, '"')
  85. i += 2
  86. continue
  87. case ' ':
  88. out = append(out, ' ')
  89. i += 2
  90. continue
  91. case '=':
  92. out = append(out, '=')
  93. i += 2
  94. continue
  95. }
  96. }
  97. out = append(out, in[i])
  98. i += 1
  99. }
  100. return out
  101. }