-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathlz-string.go
111 lines (98 loc) · 3 KB
/
lz-string.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package encoding
import (
"errors"
"math"
"unicode/utf8"
)
//
// Decompress uri encoded lz-string
// http://pieroxy.net/blog/pages/lz-string/index.html
// https://github.com/pieroxy/lz-string/
//
// map of "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$"
var keyStrUriSafe map[byte]int = map[byte]int{74: 9, 78: 13, 83: 18, 36: 64, 109: 38, 114: 43, 116: 45, 101: 30, 45: 63, 73: 8, 81: 16, 113: 42, 49: 53, 50: 54, 54: 58, 76: 11, 100: 29, 107: 36, 121: 50, 77: 12, 89: 24, 105: 34, 66: 1, 69: 4, 85: 20, 48: 52, 119: 48, 117: 46, 120: 49, 52: 56, 56: 60, 110: 39, 112: 41, 70: 5, 71: 6, 79: 14, 88: 23, 97: 26, 102: 31, 103: 32, 67: 2, 118: 47, 65: 0, 68: 3, 72: 7, 108: 37, 51: 55, 57: 61, 82: 17, 90: 25, 98: 27, 115: 44, 122: 51, 53: 57, 86: 21, 106: 35, 111: 40, 55: 59, 43: 62, 75: 10, 80: 15, 84: 19, 87: 22, 99: 28, 104: 33}
type dataStruct struct {
input string
val int
position int
index int
dictionary []string
enlargeIn float64
numBits int
}
func getBaseValue(char byte) int {
return keyStrUriSafe[char]
}
// Input is composed of ASCII characters, so accessing it by array has no UTF-8 pb.
func readBits(nb int, data *dataStruct) int {
result := 0
power := 1
for i := 0; i < nb; i++ {
respB := data.val & data.position
data.position = data.position / 2
if data.position == 0 {
data.position = 32
data.val = getBaseValue(data.input[data.index])
data.index += 1
}
if respB > 0 {
result |= power
}
power *= 2
}
return result
}
func appendValue(data *dataStruct, str string) {
data.dictionary = append(data.dictionary, str)
data.enlargeIn -= 1
if data.enlargeIn == 0 {
data.enlargeIn = math.Pow(2, float64(data.numBits))
data.numBits += 1
}
}
func getString(last string, data *dataStruct) (string, bool, error) {
c := readBits(data.numBits, data)
switch c {
case 0:
str := string(readBits(8, data))
appendValue(data, str)
return str, false, nil
case 1:
str := string(readBits(16, data))
appendValue(data, str)
return str, false, nil
case 2:
return "", true, nil
}
if c < len(data.dictionary) {
return data.dictionary[c], false, nil
}
if c == len(data.dictionary) {
return concatWithFirstRune(last, last), false, nil
}
return "", false, errors.New("Bad character encoding.")
}
// Need to handle UTF-8, so we need to use rune to concatenate
func concatWithFirstRune(str string, getFirstRune string) string {
r, _ := utf8.DecodeRuneInString(getFirstRune)
return str + string(r)
}
func DecompressFromEncodedUriComponent(input string) (string, error) {
data := dataStruct{input, getBaseValue(input[0]), 32, 1, []string{"0", "1", "2"}, 5, 2}
result, isEnd, err := getString("", &data)
if err != nil || isEnd {
return result, err
}
last := result
data.numBits += 1
for {
str, isEnd, err := getString(last, &data)
if err != nil || isEnd {
return result, err
}
result = result + str
appendValue(&data, concatWithFirstRune(last, str))
last = str
}
return "", errors.New("Unexpected end of buffer reached.")
}