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.

124 lines
3.0 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. // Decode decodes src into DecodedLen(len(src)) bytes, returning
  57. // the actual number of bytes written to dst.
  58. //
  59. // Decode expects that src contains only modhex characters and that src has an
  60. // even length. If the input is malformed, Decode returns the number of bytes
  61. // decoded before the error.
  62. func Decode(dst, src []byte) (int, error) {
  63. i, j := 0, 1
  64. for ; j < len(src); j += 2 {
  65. a, ok := modhexMap[src[j-1]]
  66. if !ok {
  67. return i, fmt.Errorf("modhex: invalid byte: %#U", rune(src[j-1]))
  68. }
  69. b, ok := modhexMap[src[j]]
  70. if !ok {
  71. return i, fmt.Errorf("modhex: invalid byte: %#U", rune(src[j]))
  72. }
  73. dst[i] = (a << 4) | b
  74. i++
  75. }
  76. if len(src)%2 == 1 {
  77. if _, ok := modhexMap[src[j-1]]; !ok {
  78. return i, fmt.Errorf("modhex: invalid byte: %#U", rune(src[j-1]))
  79. }
  80. return i, errors.New("modhex: odd length modhex string")
  81. }
  82. return i, nil
  83. }
  84. // DecodeString returns the bytes represented by the modhex string s.
  85. //
  86. // DecodeString expects that s contains only modhex characters and that s
  87. // has an even length. If the input is malformed, DecodeString returns the
  88. // number of bytes decoded before the error.
  89. func DecodeString(s string) ([]byte, error) {
  90. // convert the string to lower case since the map uses lower case
  91. s = strings.ToLower(s)
  92. // convert the input string to an array of bytes
  93. src := []byte(s)
  94. // make a new slice to hold the decoded bytes
  95. dst := make([]byte, DecodedLen(len(src)))
  96. // decode it!
  97. n, err := Decode(dst, src)
  98. // return the decoded bytes along with any errors that may have occured
  99. return dst[:n], err
  100. }