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

// Package modhex implements modhex encoding and decoding.
package modhex
import (
"errors"
"fmt"
"strings"
)
const modhexTable = "cbdefghijklnrtuv"
var modhexMap map[byte]byte
func init() {
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
len := 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[len] = modhexTable[v>>4]
len++
// convert the lower nibble to modhex
// and store it into dst
dst[len] = modhexTable[v&0x0f]
len++
}
// return the number of bytes written
return len
}
// 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) {
i, j := 0, 1
for ; j < len(src); j += 2 {
a, ok := modhexMap[src[j-1]]
if !ok {
return i, InvalidByteError(src[j-1])
}
b, ok := modhexMap[src[j]]
if !ok {
return i, InvalidByteError(src[j])
}
dst[i] = (a << 4) | b
i++
}
if len(src)%2 == 1 {
if _, ok := modhexMap[src[j-1]]; !ok {
return i, InvalidByteError(src[j-1])
}
return i, ErrLength
}
return i, 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
}