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.

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