- // Package modhex implements modhex encoding and decoding.
- package modhex
-
- import (
- "errors"
- "fmt"
- "strings"
- )
-
- // modhex character table for encoding
- const modhexTable = "cbdefghijklnrtuv"
-
- var modhexMap map[byte]byte
-
- func init() {
- // create a map from byte to modhex for decoding
- modhexMap = make(map[byte]byte)
- for i, v := range []byte(modhexTable) {
- modhexMap[v] = byte(i)
- }
- }
-
- // EncodedLen returns the length of an encoding of n source bytes.
- // Specifically, it returns n * 2.
- func EncodedLen(n int) int {
- return n * 2
- }
-
- // Encode encodes src into EncodedLen(len(src)) bytes of dst.
- //
- // Encode returns the number of bytes written to dst, but this is always
- // EncodedLen(len(src)).
- func Encode(dst, src []byte) int {
- // keep track of the number of bytes written to dst
- n := 0
-
- // convert each byte of src and store in dst
- for _, v := range src {
- // convert the upper nibble to modhex
- // and store it into dst
- dst[n] = modhexTable[v>>4]
- n++
-
- // convert the lower nibble to modhex
- // and store it into dst
- dst[n] = modhexTable[v&0x0f]
- n++
- }
-
- // return the number of bytes written
- return n
- }
-
- // EncodeToString returns the modhex encoding of src as a string.
- func EncodeToString(src []byte) string {
- // make a new slice to hold the encoded bytes
- dst := make([]byte, EncodedLen(len(src)))
-
- // encode it!
- Encode(dst, src)
-
- // return the encoded bytes as a string
- return string(dst)
- }
-
- // DecodedLen returns the length of a decoding of n source bytes.
- // Specifically, it returns n / 2.
- func DecodedLen(n int) int {
- return n / 2
- }
-
- // ErrLength reports an attempt to decode an odd-length input using Decode
- // or DecodeString.
- var ErrLength = errors.New("modhex: odd length modhex string")
-
- // InvalidByteError values describe errors resulting from an invalid byte in a
- // hex string.
- type InvalidByteError byte
-
- func (e InvalidByteError) Error() string {
- return fmt.Sprintf("modhex: invalid byte: %#U", rune(e))
- }
-
- // Decode decodes src into DecodedLen(len(src)) bytes, returning
- // the actual number of bytes written to dst.
- //
- // Decode expects that src contains only modhex characters and that src has an
- // even length. If the input is malformed, Decode returns the number of bytes
- // decoded before the error.
- func Decode(dst, src []byte) (int, error) {
- // decode the src bytes two at a time
- n, i := 0, 1
- for ; i < len(src); i += 2 {
-
- // try to decode the upper nibble
- a, ok := modhexMap[src[i-1]]
- if !ok {
- return n, InvalidByteError(src[i-1])
- }
-
- // try to decode the lower nibble
- b, ok := modhexMap[src[i]]
- if !ok {
- return n, InvalidByteError(src[i])
- }
-
- // store the decoded value into dst
- dst[n] = (a << 4) | b
- n++
- }
-
- // check for an odd length input
- if len(src)%2 == 1 {
- // first check for an invalid byte
- if _, ok := modhexMap[src[i-1]]; !ok {
- return n, InvalidByteError(src[i-1])
- }
-
- // report the number of bytes written and the length error
- return n, ErrLength
- }
-
- // return the number of bytes written to dst
- return n, nil
- }
-
- // DecodeString returns the bytes represented by the modhex string s.
- //
- // DecodeString expects that s contains only modhex characters and that s
- // has an even length. If the input is malformed, DecodeString returns the
- // number of bytes decoded before the error.
- func DecodeString(s string) ([]byte, error) {
- // convert the string to lower case since the map uses lower case
- s = strings.ToLower(s)
-
- // convert the input string to an array of bytes
- src := []byte(s)
-
- // make a new slice to hold the decoded bytes
- dst := make([]byte, DecodedLen(len(src)))
-
- // decode it!
- n, err := Decode(dst, src)
-
- // return the decoded bytes along with any errors that may have occured
- return dst[:n], err
- }
|