Skip to content

Commit 9a0992b

Browse files
committed
更新
1 parent 87566fe commit 9a0992b

4 files changed

Lines changed: 282 additions & 1 deletion

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
### 项目介绍
55

66
* 常用的编码解码算法
7-
* 算法包括: (Hex/Base32/Base45/Base58/Base62/Base64/Base85/Base91/Base100/MorseITU/JSON)
7+
* 算法包括: (Hex/Base32/Base45/Base58/Base62/Base64/Base85/Base91/Base92/Base100/MorseITU/JSON)
88

99

1010
### 下载安装

base91/base91.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ func NewEncoding(encoder string) *Encoding {
3636
if len(encoder) != 91 {
3737
panic("go-encoding/base91: encoding alphabet is not 91 bytes long")
3838
}
39+
3940
for i := 0; i < len(encoder); i++ {
4041
if encoder[i] == '\n' || encoder[i] == '\r' {
4142
panic("go-encoding/base91: encoding alphabet contains newline character")
@@ -49,9 +50,11 @@ func NewEncoding(encoder string) *Encoding {
4950
// 0xff indicates that this entry in the decode map is not in the encoding alphabet.
5051
e.decodeMap[i] = 0xff
5152
}
53+
5254
for i := 0; i < len(encoder); i++ {
5355
e.decodeMap[encoder[i]] = byte(i)
5456
}
57+
5558
return e
5659
}
5760

base92/base92.go

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
package base92
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
const (
8+
// approximation of ceil(log(256)/log(base)).
9+
// power of two -> speed up DecodeString()
10+
numerator = 16
11+
denominator = 13
12+
)
13+
14+
// encodeStd is the standard base92 encoding alphabet
15+
const encodeStd = " !#$%&'()*+,-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~"
16+
17+
// StdEncoding is the default encoding enc.
18+
var StdEncoding = NewEncoding(encodeStd)
19+
20+
type Encoding struct {
21+
encode [92]byte
22+
decodeMap [128]byte
23+
}
24+
25+
// NewEncoding returns a new Encoding defined by the given alphabet, which must
26+
// be a 92-byte string that does not contain CR or LF ('\r', '\n').
27+
func NewEncoding(encoder string) *Encoding {
28+
if len(encoder) != 92 {
29+
panic("go-encoding/base91: encoding alphabet is not 92 bytes long")
30+
}
31+
32+
for i := 0; i < len(encoder); i++ {
33+
if encoder[i] == '\n' || encoder[i] == '\r' {
34+
panic("go-encoding/base92: encoding alphabet contains newline character")
35+
}
36+
}
37+
38+
e := new(Encoding)
39+
copy(e.encode[:], encoder)
40+
41+
for i := 0; i < len(e.decodeMap); i++ {
42+
// 0xff indicates that this entry in the decode map is not in the encoding alphabet.
43+
e.decodeMap[i] = 0xff
44+
}
45+
46+
for i := 0; i < len(encoder); i++ {
47+
e.decodeMap[encoder[i]] = byte(i)
48+
}
49+
50+
return e
51+
}
52+
53+
/*
54+
* Encoder
55+
*/
56+
57+
// EncodeToString encodes binary bytes into a Base92 string.
58+
func (enc *Encoding) Encode(bin []byte) []byte {
59+
size := len(bin)
60+
61+
zcount := 0
62+
for zcount < size && bin[zcount] == 0 {
63+
zcount++
64+
}
65+
66+
// It is crucial to make this as short as possible, especially for
67+
// the usual case of bitcoin addrs
68+
// This is an integer simplification of
69+
// ceil(log(256)/log(base))
70+
size = zcount + (size-zcount)*numerator/denominator + 1
71+
72+
out := make([]byte, size)
73+
74+
var i, high int
75+
var carry uint32
76+
77+
high = size - 1
78+
for _, b := range bin {
79+
i = size - 1
80+
for carry = uint32(b); i > high || carry != 0; i-- {
81+
carry += 256 * uint32(out[i])
82+
out[i] = byte(carry % 92)
83+
carry /= 92
84+
}
85+
86+
high = i
87+
}
88+
89+
// Determine the additional "zero-gap" in the buffer (aside from zcount)
90+
for i = zcount; i < size && out[i] == 0; i++ {
91+
}
92+
93+
// Now encode the values with actual alphabet in-place
94+
val := out[i-zcount:]
95+
size = len(val)
96+
for i = 0; i < size; i++ {
97+
out[i] = enc.encode[val[i]]
98+
}
99+
100+
return out[:size]
101+
}
102+
103+
// EncodeToString encodes binary bytes into Base92 bytes.
104+
func (enc *Encoding) EncodeToString(bin []byte) string {
105+
return string(enc.Encode(bin))
106+
}
107+
108+
/*
109+
* Decoder
110+
*/
111+
112+
// Decode decodes src using the encoding enc.
113+
func (enc *Encoding) Decode(src []byte) ([]byte, error) {
114+
return enc.DecodeString(string(src))
115+
}
116+
117+
// DecodeString decodes a Base92 string into binary bytes.
118+
func (enc *Encoding) DecodeString(str string) ([]byte, error) {
119+
if len(str) == 0 {
120+
return nil, nil
121+
}
122+
123+
zero := enc.encode[0]
124+
strLen := len(str)
125+
126+
var zcount int
127+
for i := 0; i < strLen && str[i] == zero; i++ {
128+
zcount++
129+
}
130+
131+
var t, c uint64
132+
133+
// the 32bit algo stretches the result up to 2 times
134+
binu := make([]byte, 2*((strLen*denominator/numerator)+1))
135+
outi := make([]uint32, (strLen+3)/4)
136+
137+
for _, r := range str {
138+
if r > 127 {
139+
return nil, fmt.Errorf("go-encoding/base92: high-bit set on invalid digit")
140+
}
141+
142+
if enc.decodeMap[r] == 0xff {
143+
return nil, fmt.Errorf("go-encoding/base92: invalid digit %q", r)
144+
}
145+
146+
c = uint64(enc.decodeMap[r])
147+
148+
for j := len(outi) - 1; j >= 0; j-- {
149+
t = uint64(outi[j])*92 + c
150+
c = t >> 32
151+
outi[j] = uint32(t & 0xffffffff)
152+
}
153+
}
154+
155+
// initial mask depends on b92sz,
156+
// on further loops it always starts at 24 bits
157+
mask := (uint(strLen%4) * 8)
158+
if mask == 0 {
159+
mask = 32
160+
}
161+
mask -= 8
162+
163+
outLen := 0
164+
for j := 0; j < len(outi); j++ {
165+
// loop relies on uint overflow
166+
for mask < 32 {
167+
binu[outLen] = byte(outi[j] >> mask)
168+
mask -= 8
169+
outLen++
170+
}
171+
172+
mask = 24
173+
}
174+
175+
// find the most significant byte post-decode, if any
176+
for msb := zcount; msb < len(binu); msb++ {
177+
if binu[msb] > 0 {
178+
return binu[msb-zcount : outLen], nil
179+
}
180+
}
181+
182+
return binu[:outLen], nil
183+
}

base92/base92_test.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package base92
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
)
7+
8+
var cases = []struct {
9+
name string
10+
bin []byte
11+
}{
12+
{"nil", nil},
13+
{"empty", []byte{}},
14+
{"zero", []byte{0}},
15+
{"one", []byte{1}},
16+
{"two", []byte{2}},
17+
{"ten", []byte{10}},
18+
{"2zeros", []byte{0, 0}},
19+
{"2ones", []byte{1, 1}},
20+
{"64zeros", []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
21+
{"65zeros", []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
22+
{"ascii", []byte("c'est une longue chanson")},
23+
{"utf8", []byte("Garçon, un café très fort !")},
24+
}
25+
26+
func Test_Encode(t *testing.T) {
27+
for _, c := range cases {
28+
t.Run(c.name, func(t *testing.T) {
29+
str := StdEncoding.EncodeToString(c.bin)
30+
31+
ni := len(c.bin)
32+
if ni > 70 {
33+
ni = 70 // print max the first 70 bytes
34+
}
35+
na := len(str)
36+
if na > 70 {
37+
na = 70 // print max the first 70 characters
38+
}
39+
t.Logf("bin len=%d [:%d]=%v", len(c.bin), ni, c.bin[:ni])
40+
t.Logf("str len=%d [:%d]=%q", len(str), na, str[:na])
41+
42+
got, err := StdEncoding.DecodeString(str)
43+
if err != nil {
44+
t.Errorf("Decode() error = %v", err)
45+
return
46+
}
47+
48+
ng := len(got)
49+
if ng > 70 {
50+
ng = 70 // print max the first 70 bytes
51+
}
52+
t.Logf("got len=%d [:%d]=%v", len(got), ng, got[:ng])
53+
54+
if (len(got) == 0) && (len(c.bin) == 0) {
55+
return
56+
}
57+
58+
if !reflect.DeepEqual(got, c.bin) {
59+
t.Errorf("Decode() = %v, want %v", got, c.bin)
60+
}
61+
})
62+
}
63+
}
64+
65+
func Test_Encode_Check(t *testing.T) {
66+
var cases = []struct {
67+
name string
68+
src []byte
69+
enc string
70+
}{
71+
{
72+
"index-1",
73+
[]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255},
74+
" !2V2aO7r^-Kf",
75+
},
76+
}
77+
78+
for _, c := range cases {
79+
t.Run(c.name, func(t *testing.T) {
80+
str := StdEncoding.EncodeToString(c.src)
81+
if !reflect.DeepEqual(str, c.enc) {
82+
t.Errorf("EncodeToString() = %v, want %v", str, c.enc)
83+
}
84+
85+
got, err := StdEncoding.DecodeString(c.enc)
86+
if err != nil {
87+
t.Fatal(err)
88+
}
89+
90+
if !reflect.DeepEqual(got, c.src) {
91+
t.Errorf("DecodeString() = %v, want %v", got, c.src)
92+
}
93+
})
94+
}
95+
}

0 commit comments

Comments
 (0)