| // Package modhex implements modhex encoding and decoding. | |
| package modhex | |
| 
 | |
| import ( | |
| 	"errors" | |
| 	"fmt" | |
| ) | |
| 
 | |
| 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. | |
| // It returns the number of bytes written to dst, but this is | |
| // always EncodedLen(len(src)). | |
| // Encode implements modhex encoding. | |
| func Encode(dst, src []byte) int { | |
| 	i := 0 | |
| 	for _, v := range src { | |
| 		dst[i] = modhexTable[v>>4] | |
| 		dst[i+1] = modhexTable[v&0x0f] | |
| 		i += 2 | |
| 	} | |
| 	return len(src) * 2 | |
| } | |
| 
 | |
| // EncodeToString returns the modhex encoding of src. | |
| 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 | |
| } | |
| 
 | |
| // 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, fmt.Errorf("modhex: invalid byte: %#U", rune(src[j-1])) | |
| 		} | |
| 
 | |
| 		b, ok := modhexMap[src[j]] | |
| 		if !ok { | |
| 			return i, fmt.Errorf("modhex: invalid byte: %#U", rune(src[j])) | |
| 		} | |
| 
 | |
| 		dst[i] = (a << 4) | b | |
| 		i++ | |
| 	} | |
| 
 | |
| 	if len(src)%2 == 1 { | |
| 		if _, ok := modhexMap[src[j-1]]; !ok { | |
| 			return i, fmt.Errorf("modhex: invalid byte: %#U", rune(src[j-1])) | |
| 		} | |
| 
 | |
| 		return i, errors.New("modhex: odd length modhex string") | |
| 	} | |
| 
 | |
| 	return i, nil | |
| } | |
| 
 | |
| // DecodeString returns the bytes represesented by the modhex string s. | |
| // | |
| // Decode expects that s contains only modhex characters and that s | |
| // has an even length. | |
| // If the input is malformed, Decode returns the number | |
| // of bytes decoded before the error. | |
| func DecodeString(s string) ([]byte, error) { | |
| 	// 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 | |
| }
 |