Skip to content

Commit

Permalink
fixfeat: add base32n
Browse files Browse the repository at this point in the history
  • Loading branch information
thinkgos committed Dec 3, 2024
1 parent 52f92b1 commit 27c1653
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 0 deletions.
73 changes: 73 additions & 0 deletions base32n/base32n.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package base32n

import (
"errors"
"strconv"
"unsafe"
)

var StdEncoding = NewEncoding("abcdefghijklmnopqrstuvwxyz234567")

const (
decodeMapInitialize = "" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
invalidIndex = '\xff'
)

type Encoding struct {
encode [32]byte // mapping of symbol index to symbol byte value
decodeMap [256]uint8 // mapping of symbol byte value to symbol index
}

func NewEncoding(encoder string) *Encoding {
e := new(Encoding)
copy(e.encode[:], encoder)
copy(e.decodeMap[:], decodeMapInitialize)
for i := 0; i < len(encoder); i++ {
char := encoder[i]
e.decodeMap[char] = uint8(i)
}
return e
}

func (enc *Encoding) Encode(num int64) string {
result := make([]byte, 0, 13)
for num > 0 {
remainder := num & 0x1f
result = append(result, enc.encode[remainder])
num >>= 5
}
for i, j := 0, len(result)-1; i < j; i, j = i+1, j-1 {
result[i], result[j] = result[j], result[i]
}
return unsafe.String(unsafe.SliceData(result), len(result))
}

func (enc *Encoding) Decode(s string) (int64, error) {
var num int64 = 0

for i := 0; i < len(s); i++ {
char := s[i]
val := enc.decodeMap[char]
if val == invalidIndex {
return 0, errors.New("illegal base32n data at input byte " + strconv.FormatInt(int64(char), 10))
}
num += int64(val) * int64(1<<uint(5*(len(s)-1-i)))
}
return num, nil
}
22 changes: 22 additions & 0 deletions base32n/base32n_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package base32n

import (
"testing"
"time"

"github.com/stretchr/testify/require"
)

func Test_ValidString(t *testing.T) {
want := time.Now().UnixMicro()
s := StdEncoding.Encode(want)

got, err := StdEncoding.Decode(s)
require.NoError(t, err)
require.Equal(t, want, got)
}

func Test_IllegalString(t *testing.T) {
_, err := StdEncoding.Decode("bril03vgrwtu")
require.Error(t, err)
}

0 comments on commit 27c1653

Please sign in to comment.