Browse Source

Make modhex more like encoding/hex package

master
Blink The Things 3 years ago
parent
commit
5dad14dde3
2 changed files with 74 additions and 52 deletions
  1. +62
    -40
      modhex.go
  2. +12
    -12
      modhex_test.go

+ 62
- 40
modhex.go View File

@ -1,3 +1,4 @@
// Package modhex implements modhex encoding and decoding.
package modhex
import (
@ -5,62 +6,83 @@ import (
"fmt"
)
const hexChars = "0123456789abcdef"
const modhexChars = "cbdefghijklnrtuv"
const modhexTable = "cbdefghijklnrtuv"
var modhex2HexMap map[byte]byte
var hex2ModhexMap map[byte]byte
var modhexMap map[byte]byte
func init() {
hex2ModhexMap = make(map[byte]byte)
for i, h := range []byte(hexChars) {
hex2ModhexMap[h] = modhexChars[i]
}
modhex2HexMap = make(map[byte]byte)
for i, m := range []byte(modhexChars) {
modhex2HexMap[m] = hexChars[i]
modhexMap = make(map[byte]byte)
for i, v := range []byte(modhexTable) {
modhexMap[v] = byte(i)
}
}
// EncodeHex encodes a hex string into a modhex string
func EncodeHex(hex string) (string, error) {
size := len([]byte(hex))
// EncodedLen returns the length of an encoding of n source bytes.
// Specifically, it returns n * 2.
func EncodedLen(n int) int {
return n * 2
}
if size%2 == 1 {
return "", errors.New("size of input hex input not even")
// 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 {
j := 0
for _, v := range src {
dst[j] = modhexTable[v>>4]
dst[j+1] = modhexTable[v&0x0f]
j += 2
}
return len(src) * 2
}
var modhex = make([]byte, size)
for i, h := range []byte(hex) {
if m, ok := hex2ModhexMap[h]; ok {
modhex[i] = m
} else {
return "", fmt.Errorf("input not hex encoded; position %d", i)
}
}
// EncodeToString returns the modhex encoding of src.
func EncodeToString(src []byte) string {
dst := make([]byte, EncodedLen(len(src)))
Encode(dst, src)
return string(dst)
}
return string(modhex), nil
// DecodedLen returns the length of a decoding of n source bytes.
// Specifically, it returns n / 2.
func DecodedLen(n int) int {
return n / 2
}
// DecodeHex decodes a modhex string into a hex string
func DecodeHex(modhex string) (string, error) {
size := len([]byte(modhex))
// Decode decodes src into DecodedLen(len(src)) bytes,
// returning the actual number of bytes written to dst.
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]))
}
if size%2 == 1 {
return "", errors.New("size of modhex input not even")
}
b, ok := modhexMap[src[j]]
if !ok {
return i, fmt.Errorf("modhex: invalid byte: %#U", rune(src[j]))
}
var hex = make([]byte, size)
dst[i] = (a << 4) | b
i++
}
for i, m := range []byte(modhex) {
if h, ok := modhex2HexMap[m]; ok {
hex[i] = h
} else {
return "", fmt.Errorf("input not modhex encoded; position %d", 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 string(hex), nil
return i, nil
}
// DecodeString returns the bytes represesented by the modhex string s.
func DecodeString(s string) ([]byte, error) {
src := []byte(s)
n, err := Decode(src, src)
return src[:n], err
}

+ 12
- 12
modhex_test.go View File

@ -1,6 +1,9 @@
package modhex
import "testing"
import (
"encoding/hex"
"testing"
)
type test struct {
hex string
@ -26,24 +29,21 @@ func TestEncodeHexDecodeHex(t *testing.T) {
}
for _, tc := range tests {
modhex, err := EncodeHex(tc.hex)
if err != nil {
t.Errorf("EncodeHex Error: %s\n", err)
}
src, _ := hex.DecodeString(tc.hex)
modhex := EncodeToString(src)
if modhex != tc.modhex {
t.Errorf("EncodeHex Incorrect: Actual: %s; Expected: %s\n", modhex, tc.modhex)
t.Errorf("Encode Incorrect: Actual: %s; Expected: %s\n", modhex, tc.modhex)
}
hex, err := DecodeHex(tc.modhex)
hexBytes, err := DecodeString(tc.modhex)
if err != nil {
t.Errorf("DecodeHex Error: %s\n", err)
t.Error(err)
}
if hex != tc.hex {
t.Errorf("DecodeHex Incorrect: Actual: %s; Expected: %s\n", hex, tc.hex)
hexStr := hex.EncodeToString(hexBytes)
if hexStr != tc.hex {
t.Errorf("Decode Incorrect: Actual: %s; Expected: %s\n", hexStr, tc.hex)
}
}
}

Loading…
Cancel
Save