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.

136 lines
3.3 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. // Package modhex implements modhex encoding and decoding.
  2. package modhex
  3. import (
  4. "errors"
  5. "fmt"
  6. "strings"
  7. )
  8. const modhexTable = "cbdefghijklnrtuv"
  9. var modhexMap map[byte]byte
  10. func init() {
  11. modhexMap = make(map[byte]byte)
  12. for i, v := range []byte(modhexTable) {
  13. modhexMap[v] = byte(i)
  14. }
  15. }
  16. // EncodedLen returns the length of an encoding of n source bytes.
  17. // Specifically, it returns n * 2.
  18. func EncodedLen(n int) int {
  19. return n * 2
  20. }
  21. // Encode encodes src into EncodedLen(len(src)) bytes of dst.
  22. //
  23. // Encode returns the number of bytes written to dst, but this is always
  24. // EncodedLen(len(src)).
  25. func Encode(dst, src []byte) int {
  26. // keep track of the number of bytes written to dst
  27. len := 0
  28. // convert each byte of src and store in dst
  29. for _, v := range src {
  30. // convert the upper nibble to modhex
  31. // and store it into dst
  32. dst[len] = modhexTable[v>>4]
  33. len++
  34. // convert the lower nibble to modhex
  35. // and store it into dst
  36. dst[len] = modhexTable[v&0x0f]
  37. len++
  38. }
  39. // return the number of bytes written
  40. return len
  41. }
  42. // EncodeToString returns the modhex encoding of src as a string.
  43. func EncodeToString(src []byte) string {
  44. // make a new slice to hold the encoded bytes
  45. dst := make([]byte, EncodedLen(len(src)))
  46. // encode it!
  47. Encode(dst, src)
  48. // return the encoded bytes as a string
  49. return string(dst)
  50. }
  51. // DecodedLen returns the length of a decoding of n source bytes.
  52. // Specifically, it returns n / 2.
  53. func DecodedLen(n int) int {
  54. return n / 2
  55. }
  56. // ErrLength reports an attempt to decode an odd-length input using Decode
  57. // or DecodeString.
  58. var ErrLength = errors.New("modhex: odd length modhex string")
  59. // InvalidByteError values describe errors resulting from an invalid byte in a
  60. // hex string.
  61. type InvalidByteError byte
  62. func (e InvalidByteError) Error() string {
  63. return fmt.Sprintf("modhex: invalid byte: %#U", rune(e))
  64. }
  65. // Decode decodes src into DecodedLen(len(src)) bytes, returning
  66. // the actual number of bytes written to dst.
  67. //
  68. // Decode expects that src contains only modhex characters and that src has an
  69. // even length. If the input is malformed, Decode returns the number of bytes
  70. // decoded before the error.
  71. func Decode(dst, src []byte) (int, error) {
  72. i, j := 0, 1
  73. for ; j < len(src); j += 2 {
  74. a, ok := modhexMap[src[j-1]]
  75. if !ok {
  76. return i, InvalidByteError(src[j-1])
  77. }
  78. b, ok := modhexMap[src[j]]
  79. if !ok {
  80. return i, InvalidByteError(src[j])
  81. }
  82. dst[i] = (a << 4) | b
  83. i++
  84. }
  85. if len(src)%2 == 1 {
  86. if _, ok := modhexMap[src[j-1]]; !ok {
  87. return i, InvalidByteError(src[j-1])
  88. }
  89. return i, ErrLength
  90. }
  91. return i, nil
  92. }
  93. // DecodeString returns the bytes represented by the modhex string s.
  94. //
  95. // DecodeString expects that s contains only modhex characters and that s
  96. // has an even length. If the input is malformed, DecodeString returns the
  97. // number of bytes decoded before the error.
  98. func DecodeString(s string) ([]byte, error) {
  99. // convert the string to lower case since the map uses lower case
  100. s = strings.ToLower(s)
  101. // convert the input string to an array of bytes
  102. src := []byte(s)
  103. // make a new slice to hold the decoded bytes
  104. dst := make([]byte, DecodedLen(len(src)))
  105. // decode it!
  106. n, err := Decode(dst, src)
  107. // return the decoded bytes along with any errors that may have occured
  108. return dst[:n], err
  109. }