forked from FAForever/fa
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathUTF.lua
176 lines (163 loc) · 5.17 KB
/
UTF.lua
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
local StringChar = string.char
local MathMod = math.mod
local MathFloor = math.floor
local StringLen = string.len
local TableDeepcopy = table.deepcopy
local unpack = unpack
local STR_xtoi = STR_xtoi
local STR_itox = STR_itox
local STR_Utf8SubString = STR_Utf8SubString
local TableInsert = table.insert
local StringSub = string.sub
local StringByte = string.byte
function UTF(unicode)
if unicode <= 0x7F then
return StringChar(unicode)
end
if (unicode <= 0x7FF) then
local Byte0 = 0xC0 + MathFloor(unicode / 0x40);
local Byte1 = 0x80 + MathMod(unicode, 0x40);
return StringChar(Byte0, Byte1);
end
if (unicode <= 0xFFFF) then
local Byte0 = 0xE0 + MathFloor(unicode / 0x1000);
local Byte1 = 0x80 + MathMod(MathFloor(unicode / 0x40), 0x40);
local Byte2 = 0x80 + MathMod(unicode, 0x40);
return StringChar(Byte0, Byte1, Byte2);
end
if (unicode <= 0x10FFFF) then
local code = unicode
local Byte3 = 0x80 + MathMod(code, 0x40);
code = MathFloor(code / 0x40)
local Byte2 = 0x80 + MathMod(code, 0x40);
code = MathFloor(code / 0x40)
local Byte1 = 0x80 + MathMod(code, 0x40);
code = MathFloor(code / 0x40)
local Byte0 = 0xF0 + code;
return StringChar(Byte0, Byte1, Byte2, Byte3);
end
WARN('Unicode cannot be greater than U+10FFFF! (UTF(' .. unicode .. '))')
return ""
end
function InsertChar(str, chr, pos)
-- if we insert char to start or end of text just glue chr and str
if pos == 0 then
return chr .. str
end
local strLen = STR_Utf8Len(str)
if pos == strLen then
return str .. chr
end
-- otherwise insert
return STR_Utf8SubString(str, 1, pos) .. chr .. STR_Utf8SubString(str, pos + 1, strLen - pos) -- split str and add chr between parts
end
function AddUnicodeCharToEditText(edit, unicode)
if unicode <= 0x7F then
return false
end
local unicodeChar = UTF(unicode)
if unicodeChar ~= "" then
local text = edit:GetText()
local charLim = edit:GetMaxChars()
if STR_Utf8Len(text) >= charLim then
PlaySound(Sound({
Cue = 'UI_Menu_Error_01',
Bank = 'Interface'
}))
return true
end
local pos = edit:GetCaretPosition()
text = InsertChar(text, unicodeChar, pos)
edit:SetText(text)
edit:SetCaretPosition(pos + 1)
return true
end
return false
end
-- creates escape version of a given unicode string for storing it in Prefs file
-- not the best solution because unicodes have different length and string is much larger
--- @param str string
--- @return string
function EscapeString(str)
local function norm(s)
if StringLen(s) == 1 then
return '0' .. s
end
return s
end
local function sym_to_unicode(sym)
local symlen = StringLen(sym)
local s = '\\u'
for i = 1, symlen do
s = s .. norm(STR_itox(StringByte(sym, i)))
end
return s
end
local len = STR_Utf8Len(str)
local result = ''
for i = 1, len do
local sym = STR_Utf8SubString(str, i, 1)
result = result .. sym_to_unicode(sym)
end
return result
end
-- creates unescape version of a given string for retrieving from Prefs file
-- MUST BE \u*code*\u*code*...
-- unless string would be empty
--- @param str string
--- @return string
function UnescapeString(str)
local function unicode_to_sym(unicode)
local bytes = {}
local unilen = StringLen(unicode)
for i = 3, unilen, 2 do
TableInsert(bytes, STR_xtoi(StringSub(unicode, i, i + 1)))
end
return StringChar(unpack(bytes))
end
local result = ''
for s in string.gfind(str, "\\u%x+") do
result = result .. unicode_to_sym(s)
end
return result
end
--- unescapes given table : goes through all fields and if value is string -- unescapes it
---@param t table @given table
---@param doNotCopy boolean @determines whether given table is deepcopied or not
---@return table @unescaped table
function UnescapeTable(t, doNotCopy)
if not t then
return
end
if not doNotCopy then
t = TableDeepcopy(t)
end
for k, v in t do
if type(v) == 'string' then
t[k] = UnescapeString(v)
elseif type(v) == 'table' then
t[k] = UnescapeTable(v, true)
end
end
return t
end
--- escapes given table : goes through all fields and if value is string -- escapes it
---@param t table @given table
---@param doNotCopy boolean @determines whether given table is deepcopied or not
---@return table @escaped table
function EscapeTable(t, doNotCopy)
if not t then
return
end
if not doNotCopy then
t = TableDeepcopy(t)
end
for k, v in t do
if type(v) == 'string' then
t[k] = EscapeString(v)
elseif type(v) == 'table' then
t[k] = EscapeTable(v, true)
end
end
return t
end