1 QuestHelper_File
["collect_lzw.lua"] = "Development Version"
2 QuestHelper_Loadtime
["collect_lzw.lua"] = GetTime()
7 local function cleanup(tab
)
8 for _
, v
in pairs(tab
) do
9 QuestHelper
:ReleaseTable(v
)
11 QuestHelper
:ReleaseTable(tab
)
14 local function QH_LZW_Decompress(input
, tokens
, outbits
, inputstatic
)
15 local d
= QuestHelper
:CreateTable("lzw")
17 for i
= 0, tokens
-1 do
18 d
[i
] = QuestHelper
:CreateTable("lzw")
19 d
[i
][0] = string.char(i
)
22 local dsize
= tokens
+ 1 -- we use the "tokens" value as an EOF marker
25 local used
= QuestHelper
:CreateTable("lzw")
26 for _
, v
in ipairs(inputstatic
) do
28 local subi
= v
:sub(1, i
)
29 if not used
[subi
] then
32 d
[bit
.mod(dsize
, tokens
)][math
.floor(dsize
/ tokens
)] = subi
39 QuestHelper
:ReleaseTable(used
)
45 while nextbits
< dsize
do bits
= bits
+ 1; nextbits
= nextbits
* 2 end
47 local i
= Bitstream
.Input(input
, outbits
)
52 local tok
= i
:depend(bits
)
53 if tok
== tokens
then cleanup(d
) return "" end -- Okay. There's nothing. We get it.
55 Merger
.Add(rv
, d
[bit
.mod(tok
, tokens
)][math
.floor(tok
/ tokens
)])
56 local w
= d
[bit
.mod(tok
, tokens
)][math
.floor(tok
/ tokens
)]
65 dsize
= dsize
+ 1 -- We haven't actually added the next element yet. However, we could in theory include it in the stream, so we need to adjust the number of bits properly.
66 if dsize
> nextbits
then
68 nextbits
= nextbits
* 2
72 if tok
== tokens
then break end -- we're done!
75 if d
[bit
.mod(tok
, tokens
)][math
.floor(tok
/ tokens
)] then
76 entry
= d
[bit
.mod(tok
, tokens
)][math
.floor(tok
/ tokens
)]
77 elseif tok
== dsize
- 1 then
78 entry
= w
.. w
:sub(1, 1)
80 QuestHelper
: Assert(false, "faaaail")
84 d
[bit
.mod(dsize
- 1, tokens
)][math
.floor((dsize
- 1) / tokens
)] = w
.. entry
:sub(1, 1) -- Naturally, we're writing to one *less* than dsize, since we already incremented.
91 return Merger
.Finish(rv
)
94 local function QH_LZW_Compress(input
, tokens
, outbits
, inputstatic
)
98 for i
= 0, tokens
-1 do
99 d
[string.char(i
)] = {[""] = i
}
102 local dsize
= tokens
+ 1 -- we use the "tokens" value as an EOF marker
105 for _
, v
in ipairs(inputstatic
) do
106 local da
= d
[v
:sub(1, 1)]
108 local b
= v
:sub(2, i
)
122 while nextbits
< dsize
do bits
= bits
+ 1; nextbits
= nextbits
* 2 end
124 local r
= Bitstream
.Output(outbits
)
129 for ci
= 1, #input
do
130 if idlect
== 100 then
137 local c
= input
:sub(ci
, ci
)
139 if d
[wcp
:sub(1, 1)][wcp
:sub(2)] then
142 r
:append(d
[w
:sub(1, 1)][w
:sub(2)], bits
)
143 d
[wcp
:sub(1, 1)][wcp
:sub(2)] = dsize
145 if dsize
> nextbits
then
147 nextbits
= nextbits
* 2
154 r
:append(d
[w
:sub(1, 1)][w
:sub(2)], bits
)
156 dsize
= dsize
+ 1 -- Our decompressor doesn't realize we're ending here, so it will have added a table entry for that last token. Sigh.
157 if dsize
> nextbits
then
159 nextbits
= nextbits
* 2
163 r
:append(tokens
, bits
)
165 local rst
= r
:finish()
166 QuestHelper
: Assert(QH_LZW_Decompress(rst
, tokens
, outbits
, inputstatic
) == input
) -- yay
171 local function mdict(inputdict
)
172 local idc
= QuestHelper
:CreateTable("lzw mdict")
173 for i
= 1, #inputdict
do if math
.fmod(i
, 100) == 0 then QH_Timeslice_Yield() end idc
[inputdict
:sub(i
, i
)] = strchar(i
- 1) end
177 local function dictize(idcl
, stt
)
178 local im
= QuestHelper
:CreateTable("lzw dictize")
180 local subl
= idcl
[stt
:sub(i
, i
)]
181 QuestHelper
: Assert(subl
)
184 local result
= Merger
.Finish(im
)
185 QuestHelper
:ReleaseTable(im
)
189 local function QH_LZW_Prepare(inputdict
, inputstatic
)
190 QuestHelper
: Assert(inputdict
and inputstatic
)
192 local idc
= mdict(inputdict
)
196 for _
, v
in ipairs(inputstatic
) do
198 if ct
== 10 then QH_Timeslice_Yield() ct
= 0 end
199 table.insert(inpstat
, dictize(idc
, v
))
202 return idc
, #inputdict
, inpstat
205 local function QH_LZW_Compress_Dicts_Prepared(input
, idprepped
, idpreppedsize
, outputdict
, isprepped
)
206 input
= dictize(idprepped
, input
)
208 local bits
, dsize
= 1, 2
209 if not outputdict
then bits
= 8 else while dsize
< #outputdict
do bits
= bits
+ 1 ; dsize
= dsize
* 2 end end
210 QuestHelper
: Assert(not outputdict
or #outputdict
== dsize
)
212 local comp
= QH_LZW_Compress(input
, idpreppedsize
, bits
, isprepped
)
215 local origcomp
= comp
217 for i
= 1, #origcomp
do Merger
.Add(im
, outputdict
:sub(strbyte(origcomp
:sub(i
, i
)) + 1)) end
218 comp
= Merger
.Finish(im
)
224 local function QH_LZW_Compress_Dicts(input
, inputdict
, outputdict
, inputstatic
)
226 local inpstat
= inputstatic
228 local idc
= mdict(inputdict
)
230 inproc
= dictize(idc
, input
)
234 for _
, v
in ipairs(inputstatic
) do
235 table.insert(inpstat
, dictize(idc
, v
))
239 QuestHelper
:ReleaseTable(idc
)
242 local bits
, dsize
= 1, 2
243 if not outputdict
then bits
= 8 else while dsize
< #outputdict
do bits
= bits
+ 1 ; dsize
= dsize
* 2 end end
244 QuestHelper
: Assert(not outputdict
or #outputdict
== dsize
)
246 local comp
= QH_LZW_Compress(inproc
, inputdict
and #inputdict
or 256, bits
, inpstat
)
249 local origcomp
= comp
251 for i
= 1, #origcomp
do Merger
.Add(im
, outputdict
:sub(strbyte(origcomp
:sub(i
, i
)) + 1)) end
252 comp
= Merger
.Finish(im
)
258 local function QH_LZW_Decompress_Dicts_Prepared(compressed
, inputdict
, outputdict
, ispreppred
) -- this is kind of backwards - we assume that "outputdict" is the dictionary that "compressed" is encoded in
259 QuestHelper
: Assert(not outputdict
)
260 QuestHelper
: Assert(inputdict
)
262 local decomp
= QH_LZW_Decompress(compressed
, #inputdict
, 8, ispreppred
)
265 for i
= 1, #decomp
do
266 Merger
.Add(ov
, inputdict
:sub(decomp
:byte(i
) + 1, decomp
:byte(i
) + 1))
268 return Merger
.Finish(ov
)
271 local function QH_LZW_Decompress_Dicts(compressed
, inputdict
, outputdict
, inputstatic
) -- this is kind of backwards - we assume that "outputdict" is the dictionary that "compressed" is encoded in
272 QuestHelper
: Assert(not outputdict
)
273 QuestHelper
: Assert(inputdict
)
275 local inpstat
= inputstatic
276 if inputdict
and inputstatic
then
277 local idc
= mdict(inputdict
)
280 for _
, v
in ipairs(inputstatic
) do
281 table.insert(inpstat
, dictize(idc
, v
))
284 QuestHelper
:ReleaseTable(idc
)
287 local decomp
= QH_LZW_Decompress(compressed
, #inputdict
, 8, inpstat
)
290 for i
= 1, #decomp
do
291 Merger
.Add(ov
, inputdict
:sub(decomp
:byte(i
) + 1, decomp
:byte(i
) + 1))
293 return Merger
.Finish(ov
)
296 QH_LZW_Prepare_Arghhacky
= QH_LZW_Prepare
-- need to rig up a better mechanism for this really
297 QH_LZW_Decompress_Dicts_Arghhacky
= QH_LZW_Decompress_Dicts
-- need to rig up a better mechanism for this really
298 QH_LZW_Decompress_Dicts_Prepared_Arghhacky
= QH_LZW_Decompress_Dicts_Prepared
-- need to rig up a better mechanism for this really
300 function QH_Collect_LZW_Init(_
, API
)
301 Merger
= API
.Utility_Merger
302 QuestHelper
: Assert(Merger
)
304 Bitstream
= API
.Utility_Bitstream
305 QuestHelper
: Assert(Bitstream
)
307 API
.Utility_LZW
= {Compress
= QH_LZW_Compress
, Decompress
= QH_LZW_Decompress
, Compress_Dicts
= QH_LZW_Compress_Dicts
, Decompress_Dicts
= QH_LZW_Decompress_Dicts
, Prepare
= QH_LZW_Prepare
, Compress_Dicts_Prepared
= QH_LZW_Compress_Dicts_Prepared
, Decompress_Dicts_Prepared
= QH_LZW_Decompress_Dicts_Prepared
}
315 QH_LZW_Compress("TOBEORNOTTOBEORTOBEORNOT", 256, 8)
319 QuestHelper:TextOut("lulz")
321 local inq = "ABABABABA"
325 str = QH_LZW_Compress(inq, alpha, bits)
328 tvr = tvr .. string.format("%d ", strbyte(str, i))
330 QuestHelper:TextOut(tvr)
332 ret = QH_LZW_Decompress(str, alpha, bits)
333 QuestHelper:TextOut(ret)
335 QuestHelper: Assert(inq == ret)