-
Notifications
You must be signed in to change notification settings - Fork 3
/
LibCompress.lua
126 lines (118 loc) · 3.13 KB
/
LibCompress.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
-- LibCompress.lua
--
-- Authors: jjsheets and Galmok of European Stormrage (Horde)
-- Email: [email protected] and [email protected]
-- Licence: GPL version 2 (General Public License)
--
-- Hacked severely by Taehl ([email protected])
----------------------------------------------------------------------------------
assert(not TLibCompress, "LibCompress already loaded. Possibly loading different versions of LibCompress")
TLibCompress = {}
local assert = assert
local type = type
local unpack = unpack or table.unpack
local tconcat = table.concat
local schar = string.char
local ssub = string.sub
local sbyte = string.byte
local mmodf = math.modf
local function encode(x)
local bytes = {}
local xmod
repeat
x, xmod = mmodf(x/255)
xmod = xmod * 255
bytes[#bytes + 1] = xmod
until x <= 0
if #bytes == 1 and bytes[1] > 0 and bytes[1] < 250 then
return schar(bytes[1])
else
for i = 1, #bytes do bytes[i] = bytes[i] + 1 end
return schar(256 - #bytes, unpack(bytes))
end
end
local function decode(ss,i)
i = i or 1
local a = sbyte(ss,i,i)
if a > 249 then
local r = 0
a = 256 - a
for n = i+a, i+1, -1 do
r = r * 255 + sbyte(ss,n,n) - 1
end
return r, a + 1
else
return a, 1
end
end
function TLibCompress.CompressLZW(uncompressed)
assert(type(uncompressed) == 'string')
local result = {'\222'}
local ressize = 1
local w = ''
local dict = {}
local dict_size = 256
for i = 0, 255 do
dict[schar(i)] = i
end
for i = 1, #uncompressed do
local c = ssub(uncompressed,i,i)
local wc = w..c
if dict[wc] then
w = wc
else
dict[wc] = dict_size
dict_size = dict_size +1
local r = encode(dict[w])
ressize = ressize + #r
result[#result + 1] = r
w = c
end
end
if w then
local r = encode(dict[w])
ressize = ressize + #r
result[#result + 1] = r
end
if (#uncompressed+1) > ressize then
return tconcat(result)
else
return '\1'..uncompressed
end
end
function TLibCompress.DecompressLZW(compressed)
assert(type(compressed) == 'string')
local UC
UC, compressed = ssub(compressed,1,1), ssub(compressed, 2)
if UC == '\1' then
return compressed
end
if UC ~= "\222" then
return nil, "Can only decompress LZW compressed data ("..tostring(UC)..")"
end
local dict_size = 256
local dict = {}
for i = 0, 255 do
dict[i] = schar(i)
end
local result = {}
local t = 1
local delta, k
k, delta = decode(compressed,t)
t = t + delta
result[#result+1] = dict[k]
local w = dict[k]
local entry
local csize = #compressed
while t <= csize do
k, delta = decode(compressed,t)
t = t + delta
entry = dict[k] or (w..ssub(w,1,1))
result[#result+1] = entry
dict[dict_size] = w..ssub(entry,1,1)
dict_size = dict_size + 1
w = entry
end
return tconcat(result)
end
return TLibCompress