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.

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