-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathBase64.ttslua
executable file
·139 lines (106 loc) · 4.44 KB
/
Base64.ttslua
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
require('ge_tts.License')
-- Base64 implementation originally based on https://github.com/iskolbin/lbase64 (public domain),
-- but modified for simplicity, TTS and to work with number[] buffers, rather than strings.
local TableUtils = require('ge_tts.TableUtils')
---@class ge_tts__Base64
local Base64 = {}
local extract = bit32.extract
local PAD_KEY = 64
---@param char62? nil | string
---@param char63? nil | string
---@param charPad? nil | string
---@return table<number, number>
function Base64.encodingMap(char62, char63, charPad)
---@type table<number, number>
local encodingTable = {}
for b64code, char in pairs({
[0] = 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2',
'3', '4', '5', '6', '7', '8', '9', char62 or '+', char63 or '/', charPad or '='
}) do
encodingTable[b64code] = char:byte()
end
return encodingTable
end
---@overload fun(char62: string, char63: string): table<number, number>
---@overload fun(char62: string): table<number, number>
---@overload fun(): table<number, number>
---@param char62 string
---@param char63 string
---@param charPad? string
---@return table<number, number>
function Base64.decodingMap(char62, char63, charPad)
return TableUtils.invert(Base64.encodingMap(char62, char63, charPad))
end
local DEFAULT_ENCODING_MAP = Base64.encodingMap()
local DEFAULT_DECODING_MAP = Base64.decodingMap()
---@overload fun(buffer: number[], pad: boolean): string
---@overload fun(buffer: number[]): string
---@param buffer number[]
---@param pad boolean
---@param map table<number, number>
---@return string
function Base64.encode(buffer, pad, map)
pad = pad == nil or pad
map = map or DEFAULT_ENCODING_MAP
---@type string[]
local components = {}
local index = 1
local length = #buffer
local lastComponentSize = length % 3
for offset = 1, length - lastComponentSize, 3 do
local a, b, c = --[[---@not nil, nil, nil]] table.unpack(buffer, offset, offset + 2)
local v = a * 0x10000 + b * 0x100 + c
components[index] = string.char(map[extract(v, 18, 6)], map[extract(v, 12, 6)], map[extract(v, 6, 6)], map[extract(v, 0, 6)])
index = index + 1
end
if lastComponentSize == 2 then
local a, b = --[[---@not nil, nil]] table.unpack(buffer, length - 1, length)
local v = a * 0x10000 + b * 0x100
components[index] = string.char(map[extract(v, 18, 6)], map[extract(v, 12, 6)], map[extract(v, 6, 6)]) .. (pad and string.char(map[PAD_KEY]) or '')
elseif lastComponentSize == 1 then
local v = buffer[length] * 0x10000
components[index] = string.char(map[extract(v, 18, 6)], map[extract(v, 12, 6)]) .. (pad and string.char(map[PAD_KEY], map[PAD_KEY]) or '')
end
return table.concat(components)
end
---@overload fun(b64: string): number[]
---@param b64 string
---@param map table<number, number>
---@return number[]
function Base64.decode(b64, map)
map = map or DEFAULT_DECODING_MAP
---@type number[]
local buffer = {}
local offset = 1
local length = #b64
if map[--[[---@not nil]] b64:sub(-2, -2):byte()] == PAD_KEY then
length = length - 2
elseif map[--[[---@not nil]] b64:sub(-1, -1):byte()] == PAD_KEY then
length = length - 1
end
local lastBlockSize = length % 4
local fullBlockEnd = length - lastBlockSize
for i = 1, fullBlockEnd, 4 do
local a, b, c, d = --[[---@not nil, nil, nil, nil]] b64:byte(i, i + 3)
local v = map[a] * 0x40000 + map[b] * 0x1000 + map[c] * 0x40 + map[d]
buffer[offset] = extract(v, 16, 8)
buffer[offset + 1] = extract(v, 8, 8)
buffer[offset + 2] = extract(v, 0, 8)
offset = offset + 3
end
if lastBlockSize == 3 then
local a, b, c = --[[---@not nil, nil, nil]] b64:byte(fullBlockEnd + 1, fullBlockEnd + 3)
local v = map[a] * 0x40000 + map[b] * 0x1000 + map[c] * 0x40
buffer[offset] = extract(v, 16, 8)
buffer[offset + 1] = extract(v, 8, 8)
elseif lastBlockSize == 2 then
local a, b = --[[---@not nil, nil]] b64:byte(fullBlockEnd + 1, fullBlockEnd + 2)
local v = map[a] * 0x40000 + map[b] * 0x1000
buffer[offset] = extract(v, 16, 8)
end
return buffer
end
return Base64