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 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
)
195 for _
, v
in ipairs(inputstatic
) do
196 table.insert(inpstat
, dictize(idc
, v
))
199 return idc
, #inputdict
, inpstat
202 local function QH_LZW_Compress_Dicts_Prepared(input
, idprepped
, idpreppedsize
, outputdict
, isprepped
)
203 input
= dictize(idprepped
, input
)
205 local bits
, dsize
= 1, 2
206 if not outputdict
then bits
= 8 else while dsize
< #outputdict
do bits
= bits
+ 1 ; dsize
= dsize
* 2 end end
207 QuestHelper
: Assert(not outputdict
or #outputdict
== dsize
)
209 local comp
= QH_LZW_Compress(input
, idpreppedsize
, bits
, isprepped
)
212 local origcomp
= comp
214 for i
= 1, #origcomp
do Merger
.Add(im
, outputdict
:sub(strbyte(origcomp
:sub(i
, i
)) + 1)) end
215 comp
= Merger
.Finish(im
)
221 local function QH_LZW_Compress_Dicts(input
, inputdict
, outputdict
, inputstatic
)
223 local inpstat
= inputstatic
225 local idc
= mdict(inputdict
)
227 inproc
= dictize(idc
, input
)
231 for _
, v
in ipairs(inputstatic
) do
232 table.insert(inpstat
, dictize(idc
, v
))
236 QuestHelper
:ReleaseTable(idc
)
239 local bits
, dsize
= 1, 2
240 if not outputdict
then bits
= 8 else while dsize
< #outputdict
do bits
= bits
+ 1 ; dsize
= dsize
* 2 end end
241 QuestHelper
: Assert(not outputdict
or #outputdict
== dsize
)
243 local comp
= QH_LZW_Compress(inproc
, inputdict
and #inputdict
or 256, bits
, inpstat
)
246 local origcomp
= comp
248 for i
= 1, #origcomp
do Merger
.Add(im
, outputdict
:sub(strbyte(origcomp
:sub(i
, i
)) + 1)) end
249 comp
= Merger
.Finish(im
)
255 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
256 QuestHelper
: Assert(not outputdict
)
257 QuestHelper
: Assert(inputdict
)
259 local decomp
= QH_LZW_Decompress(compressed
, #inputdict
, 8, ispreppred
)
262 for i
= 1, #decomp
do
263 Merger
.Add(ov
, inputdict
:sub(decomp
:byte(i
) + 1, decomp
:byte(i
) + 1))
265 return Merger
.Finish(ov
)
268 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
269 QuestHelper
: Assert(not outputdict
)
270 QuestHelper
: Assert(inputdict
)
272 local inpstat
= inputstatic
273 if inputdict
and inputstatic
then
274 local idc
= mdict(inputdict
)
277 for _
, v
in ipairs(inputstatic
) do
278 table.insert(inpstat
, dictize(idc
, v
))
281 QuestHelper
:ReleaseTable(idc
)
284 local decomp
= QH_LZW_Decompress(compressed
, #inputdict
, 8, inpstat
)
287 for i
= 1, #decomp
do
288 Merger
.Add(ov
, inputdict
:sub(decomp
:byte(i
) + 1, decomp
:byte(i
) + 1))
290 return Merger
.Finish(ov
)
293 QH_LZW_Prepare_Arghhacky
= QH_LZW_Prepare
-- need to rig up a better mechanism for this really
294 QH_LZW_Decompress_Dicts_Arghhacky
= QH_LZW_Decompress_Dicts
-- need to rig up a better mechanism for this really
295 QH_LZW_Decompress_Dicts_Prepared_Arghhacky
= QH_LZW_Decompress_Dicts_Prepared
-- need to rig up a better mechanism for this really
297 function QH_Collect_LZW_Init(_
, API
)
298 Merger
= API
.Utility_Merger
299 QuestHelper
: Assert(Merger
)
301 Bitstream
= API
.Utility_Bitstream
302 QuestHelper
: Assert(Bitstream
)
304 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
}
312 QH_LZW_Compress("TOBEORNOTTOBEORTOBEORNOT", 256, 8)
316 QuestHelper:TextOut("lulz")
318 local inq = "ABABABABA"
322 str = QH_LZW_Compress(inq, alpha, bits)
325 tvr = tvr .. string.format("%d ", strbyte(str, i))
327 QuestHelper:TextOut(tvr)
329 ret = QH_LZW_Decompress(str, alpha, bits)
330 QuestHelper:TextOut(ret)
332 QuestHelper: Assert(inq == ret)