Skip to content

Commit 215c5fe

Browse files
committed
Encode
1 parent 13e3fa3 commit 215c5fe

7 files changed

Lines changed: 369 additions & 137 deletions

File tree

secretary/utils/encode/sec32.go

Lines changed: 118 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,31 @@
11
package encode
22

3-
import "github.com/codeharik/secretary/utils"
3+
import (
4+
"strings"
5+
6+
"github.com/codeharik/secretary/utils"
7+
)
48

59
var SEC32KeyMap = [][]byte{
610
/*00*/ {'~'},
711
/*01*/ {'a', 'A'},
812
/*02*/ {'p', 'P', 'b', 'B', '+'},
9-
/*03*/ {'c', 'C', 's', 'S', ':'},
13+
/*03*/ {'c', 'C', 's', 'S'},
1014
/*04*/ {'d', 'D', '/'},
1115
/*05*/ {'e', 'E', '='},
1216
/*06*/ {'i', 'I'},
13-
/*07*/ {'f', 'F', '"', '\''},
14-
/*08*/ {'g', 'G', 'j', 'J', 'x', 'X', 'z', 'Z'},
17+
/*07*/ {'f', 'F'},
18+
/*08*/ {'g', 'G', 'j', 'J', 'z', 'Z'},
1519
/*09*/ {'h', 'H', '%'},
1620
/*10*/ {'o', 'O'},
17-
/*11*/ {'k', 'K', 'q', 'Q', '?', '!', '\\', '|'},
18-
/*12*/ {'l', 'L', '&', '@'},
19-
/*13*/ {'m', 'M', '-'},
20-
/*14*/ {'n', 'N', '*'},
21+
/*11*/ {'k', 'K', 'q', 'Q'}, // '?', '!', '\\', '|','&', '@','#','$','^'},
22+
/*12*/ {'l', 'L'},
23+
/*13*/ {'m', 'M', '*'},
24+
/*14*/ {'n', 'N', '-'},
2125
/*15*/ {'t', 'T'},
22-
/*16*/ {'r', 'R', '^'},
23-
/*17*/ {'u', 'U', 'v', 'V', '#'},
24-
/*18*/ {'w', 'W', 'y', 'Y', '$'},
26+
/*16*/ {'r', 'R'},
27+
/*17*/ {'u', 'U', 'v', 'V'},
28+
/*18*/ {'x', 'X', 'y', 'Y', 'w', 'W'},
2529
/*19*/ {'0'},
2630
/*20*/ {'1'},
2731
/*21*/ {'2'},
@@ -34,10 +38,13 @@ var SEC32KeyMap = [][]byte{
3438
/*28*/ {'9'},
3539
/*29*/ {'(', '[', '<', '{'},
3640
/*30*/ {')', ']', '>', '}'},
37-
/*31*/ {'_', '.', ',', ';', ' ', '\n'},
41+
/*31*/ {'_', '.', ',', ';', ' ', '\n', '"', '\'', '`', ':'},
3842
}
3943

40-
const SEC32 = `-apcdeifghoklmntruw0123456789QR_`
44+
var (
45+
ASCII32 = [32]byte{}
46+
SEC32 = []byte(`-apcdeifghoklmntrux0123456789QR_`)
47+
)
4148

4249
var (
4350
ASCII32Index = [256]byte{}
@@ -50,57 +57,145 @@ func init() {
5057
SEC32Index[i] = 0
5158
}
5259
for index, chars := range SEC32KeyMap {
60+
ASCII32[index] = chars[0]
5361
SEC32Index[SEC32[index]] = byte(index)
5462
for _, c := range chars {
5563
ASCII32Index[c] = byte(index)
5664
}
5765
}
5866
}
5967

60-
func AsciiToSec32(str string) string {
68+
func StringToSec32(str string) string {
6169
return string(utils.Map(
6270
[]byte(str),
6371
func(c byte) byte {
6472
return SEC32[ASCII32Index[c]]
6573
}))
6674
}
6775

68-
func Ascii32ToIndex(str string) []byte {
76+
func StringToIndex32(str string) []byte {
6977
return utils.Map(
7078
[]byte(str),
7179
func(c byte) byte {
7280
return ASCII32Index[c]
7381
})
7482
}
7583

76-
func IndexToAscii32(arr []byte) string {
84+
func StringToIndex32Packed(str string) []byte {
85+
return Pack8to5(StringToIndex32(str))
86+
}
87+
88+
func Index32ToAscii32(indexes []byte) string {
7789
return string(utils.Map(
78-
arr,
90+
indexes,
7991
func(i byte) byte {
80-
return SEC32KeyMap[i][0]
92+
return ASCII32[i]
8193
}))
8294
}
8395

84-
func Sec32ToAscii(str string) string {
96+
func Index32PackedToAscii32(indexes []byte) string {
97+
return Index32ToAscii32(Unpack5to8(indexes))
98+
}
99+
100+
func Sec32ToAscii32(str string) string {
85101
return string(utils.Map(
86102
[]byte(str),
87103
func(c byte) byte {
88-
return SEC32KeyMap[SEC32Index[c]][0]
104+
return ASCII32[SEC32Index[c]]
89105
}))
90106
}
91107

92-
func Sec32ToIndex(str string) []byte {
108+
func Sec32ToIndex32(str string) []byte {
93109
return utils.Map(
94110
[]byte(str),
95111
func(c byte) byte {
96112
return SEC32Index[c]
97113
})
98114
}
99115

100-
func IndexToSec32(arr []byte) string {
116+
func Sec32ToIndex32Packed(str string) []byte {
117+
return Pack8to5(Sec32ToIndex32(str))
118+
}
119+
120+
func Index32ToSec32(indexes []byte) string {
101121
return string(utils.Map(
102-
arr,
122+
indexes,
103123
func(i byte) byte {
104124
return SEC32[i]
105125
}))
106126
}
127+
128+
func Index32PackedToSec32(indexes []byte) string {
129+
return Index32ToSec32(Unpack5to8(indexes))
130+
}
131+
132+
func ExpandStringToSec32(str string) string {
133+
unpacked := Unpack5to8([]byte(str))
134+
enc := make([]byte, len(unpacked))
135+
for i := 0; i < len(unpacked); i++ {
136+
enc[i] = SEC32[unpacked[i]]
137+
}
138+
return string(enc)
139+
}
140+
141+
func Sec32ToExpandString(str string) string {
142+
packed := Pack8to5(Sec32ToIndex32(str))
143+
return strings.Trim(string(packed), "\x00")
144+
}
145+
146+
// 87654321 | 87654321 | 87654321 | 87654321 | 87654321 | 87654321 | 87654321 | 87654321
147+
// Encode
148+
// 0,5 1,3 1,2 2,5 3,1 3,4 4,4 4,1 5,5 6,2 6,3 7,5
149+
// 54321 543 | 21 54321 5 | 4321 5432 | 1 54321 54 | 321 54321
150+
// Pack8to5 converts 8-bit bytes into 5-bit packed format
151+
func Pack8to5(input []byte) []byte {
152+
// Calculate the number of bytes needed for the packed output
153+
// Each 8 bits (1 byte) will produce 5 bits, so we need to round up
154+
// the number of input bytes to the nearest multiple of 8.
155+
e := len(input) % 8
156+
if e != 0 {
157+
input = append(input, make([]byte, 8-e)...)
158+
}
159+
160+
// The length of the packed output will be (5/8) * len(input)
161+
packed := make([]byte, (5*len(input))/8)
162+
163+
for u, p := 0, 0; u < len(input); u += 8 {
164+
packed[p] = (input[u]&0b00011111)<<3 | (input[u+1]&0b00011100)>>2
165+
packed[p+1] = (input[u+1]&0b00000011)<<6 | (input[u+2]&0b00011111)<<1 | (input[u+3]&0b00010000)>>4
166+
packed[p+2] = input[u+3]<<4 | (input[u+4]&0b00011110)>>1
167+
packed[p+3] = (input[u+4]&0b00000001)<<7 | (input[u+5]&0b00011111)<<2 | (input[u+6]&0b00011000)>>3
168+
packed[p+4] = input[u+6]<<5 | (input[u+7] & 0b00011111)
169+
p += 5
170+
}
171+
172+
return packed
173+
}
174+
175+
// Encode
176+
// 54321 543 | 21 54321 5 | 4321 5432 | 1 54321 54 | 321 54321
177+
// Decode
178+
// 0,5 0,3 1,2 1,5 1,1 2,4 2,4 3,1 3,5 3,2 4,3 4,5
179+
// 00054321 | 00054321 | 00054321 | 00054321 | 00054321 | 00054321 | 00054321 | 00054321
180+
func Unpack5to8(packed []byte) []byte {
181+
e := len(packed) % 5
182+
if e != 0 {
183+
packed = append(packed, make([]byte, 5-e)...)
184+
}
185+
186+
unpacked := make([]byte, (8*len(packed))/5)
187+
188+
for u, p := 0, 0; p < len(packed); p += 5 {
189+
unpacked[u] = packed[p] >> 3
190+
unpacked[u+1] = (packed[p]<<2 | packed[p+1]>>6) & 0b00011111
191+
unpacked[u+2] = (packed[p+1] >> 1) & 0b00011111
192+
unpacked[u+3] = (packed[p+1]<<4 | packed[p+2]>>4) & 0b00011111
193+
unpacked[u+4] = (packed[p+2]<<1 | packed[p+3]>>7) & 0b00011111
194+
unpacked[u+5] = (packed[p+3] >> 2) & 0b00011111
195+
unpacked[u+6] = (packed[p+3]<<3 | packed[p+4]>>5) & 0b00011111
196+
unpacked[u+7] = packed[p+4] & 0b00011111
197+
u += 8
198+
}
199+
200+
return unpacked
201+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,110 @@
11
package encode
2+
3+
import (
4+
"bytes"
5+
"strings"
6+
"testing"
7+
8+
"github.com/codeharik/secretary/utils"
9+
)
10+
11+
// Test basic character mappings
12+
func TestEncodingDecoding32(t *testing.T) {
13+
tests := []struct {
14+
input string
15+
sec32 string
16+
asc32 string
17+
}{
18+
{"", "", ""},
19+
{"| +\n_", "-_p__", "~_p__"},
20+
{
21+
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
22+
"apcdefghigklmnopkrctuuxxxg",
23+
"apcdefghigklmnopkrctuuxxxg",
24+
},
25+
{
26+
"0123456789",
27+
"0123456789",
28+
"0123456789",
29+
},
30+
{
31+
`=+-*/\%^<>!?@#$&(),;:'"_. `,
32+
`epnmd-h-QR------QR________`,
33+
`epnmd~h~()~~~~~~()________`,
34+
},
35+
{
36+
"abcdefghijklmnopqrstuvwxyz",
37+
"apcdefghigklmnopkrctuuxxxg",
38+
"apcdefghigklmnopkrctuuxxxg",
39+
},
40+
{
41+
"~`|",
42+
"-_-",
43+
"~_~",
44+
},
45+
}
46+
47+
for _, tt := range tests {
48+
49+
stringToSec32 := StringToSec32(tt.input)
50+
if stringToSec32 != tt.sec32 {
51+
utils.Log(t, "inp %q", tt.input, "sec %q", stringToSec32, "exp %q", tt.sec32)
52+
}
53+
54+
stringToIndex32 := StringToIndex32(tt.input)
55+
sec32ToIndex32 := Sec32ToIndex32(stringToSec32)
56+
if bytes.Compare(stringToIndex32, sec32ToIndex32) != 0 {
57+
utils.Log(t, "inp %q", tt.input, "sec %q", sec32ToIndex32, "exp %q", stringToIndex32)
58+
}
59+
60+
index32ToSec32 := Index32ToSec32(sec32ToIndex32)
61+
if index32ToSec32 != stringToSec32 {
62+
utils.Log(t, "sec %q", index32ToSec32, "sec %q", stringToSec32)
63+
}
64+
65+
sec32ToAscii32 := Sec32ToAscii32(stringToSec32)
66+
index32ToAscii32 := Index32ToAscii32(stringToIndex32)
67+
if sec32ToAscii32 != tt.asc32 || index32ToAscii32 != tt.asc32 {
68+
utils.Log(t, "inp %q", tt.input, "exp %q", tt.asc32, "asc %q", sec32ToAscii32, "asc %q", index32ToAscii32)
69+
}
70+
71+
stringToIndex32Packed := StringToIndex32Packed(tt.input)
72+
sec32ToIndex32Packed := Sec32ToIndex32Packed(stringToSec32)
73+
if bytes.Compare(stringToIndex32Packed, sec32ToIndex32Packed) != 0 {
74+
t.Fatal("Should be equal", stringToIndex32Packed, sec32ToIndex32Packed)
75+
}
76+
77+
index32PackedToAscii32 := Index32PackedToAscii32(stringToIndex32Packed)
78+
index32PackedToSec32 := Index32PackedToSec32(stringToIndex32Packed)
79+
if !strings.HasPrefix(index32PackedToAscii32, sec32ToAscii32) ||
80+
!strings.HasPrefix(index32PackedToSec32, stringToSec32) {
81+
t.Fatal()
82+
}
83+
84+
expandStringToSec32 := ExpandStringToSec32(tt.input)
85+
sec32ToExpandString := Sec32ToExpandString(expandStringToSec32)
86+
if tt.input != sec32ToExpandString {
87+
t.Fatal("Should be equal", tt.input, sec32ToExpandString)
88+
}
89+
}
90+
}
91+
92+
func TestPackUnpack8to5(t *testing.T) {
93+
for i := 1; i < 9; i++ {
94+
arr := utils.GenerateRandomSliceMinMax[byte](i, 0, 127)
95+
96+
packed := Pack8to5(arr)
97+
unpacked := Unpack5to8(packed)
98+
99+
if binStr(unpacked, false, 5) != binStr(packed, false, 8) {
100+
utils.Log(
101+
"arr", arr,
102+
"arr", binStr(arr, true, 8), "",
103+
"arr", binStr(arr, true, 5), "",
104+
"pac", binStr(packed, false, 8), "",
105+
"unp", binStr(unpacked, false, 5),
106+
)
107+
t.Fatal()
108+
}
109+
}
110+
}

0 commit comments

Comments
 (0)