1 QuestHelper_File
["collect_lzw.lua"] = "Development Version"
5 local function QH_LZW_Bitstreamer_Output(outbits
)
11 append
= function (self
, value
, bits
)
12 self
.cbits
= self
.cbits
+ bits
13 self
.cval
= bit
.lshift(self
.cval
, bits
)
14 self
.cval
= self
.cval
+ value
15 while self
.cbits
>= outbits
do
16 Merger
.Add(self
.r
, strchar(bit
.rshift(self
.cval
, self
.cbits
- outbits
)))
17 self
.cbits
= self
.cbits
- outbits
;
18 self
.cval
= bit
.band(self
.cval
, bit
.lshift(1, self
.cbits
) - 1)
21 finish
= function (self
)
22 if self
.cbits
> 0 then self
:append(0, outbits
- self
.cbits
) end
23 return Merger
.Finish(self
.r
)
28 local function QH_LZW_Bitstreamer_Input(indata
, outbits
)
34 depend
= function (self
, bits
)
35 while self
.cbits
< bits
do
36 self
.cbits
= self
.cbits
+ outbits
37 self
.cval
= bit
.lshift(self
.cval
, outbits
) + strbyte(indata
, self
.coffset
)
38 self
.coffset
= self
.coffset
+ 1
40 local rv
= bit
.rshift(self
.cval
, self
.cbits
- bits
)
41 self
.cbits
= self
.cbits
- bits
;
42 self
.cval
= bit
.band(self
.cval
, bit
.lshift(1, self
.cbits
) - 1)
48 local function QH_LZW_Decompress(input
, tokens
, outbits
)
51 for i
= 0, tokens
-1 do
55 local dsize
= tokens
+ 1 -- we use the "tokens" value as an EOF marker
60 while nextbits
< dsize
do bits
= bits
+ 1; nextbits
= nextbits
* 2 end
62 local i
= QH_LZW_Bitstreamer_Input(input
, outbits
)
67 local tok
= i
:depend(bits
)
68 if tok
== tokens
then return "" end -- Okay. There's nothing. We get it.
70 Merger
.Add(rv
, d
[tok
])
80 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.
81 if dsize
> nextbits
then
83 nextbits
= nextbits
* 2
87 if tok
== tokens
then break end -- we're done!
92 elseif tok
== dsize
- 1 then
93 entry
= w
.. w
:sub(1, 1)
95 QuestHelper
: Assert(false, "faaaail")
99 d
[dsize
- 1] = w
.. entry
:sub(1, 1) -- Naturally, we're writing to one *less* than dsize, since we already incremented.
104 return Merger
.Finish(rv
)
107 local function QH_LZW_Compress(input
, tokens
, outbits
)
111 for i
= 0, tokens
-1 do
112 d
[string.char(i
)] = i
115 local dsize
= tokens
+ 1 -- we use the "tokens" value as an EOF marker
120 while nextbits
< dsize
do bits
= bits
+ 1; nextbits
= nextbits
* 2 end
122 local r
= QH_LZW_Bitstreamer_Output(outbits
)
127 for ci
= 1, #input
do
128 if idlect
== 100 then
135 local c
= input
:sub(ci
, ci
)
143 if dsize
> nextbits
then
145 nextbits
= nextbits
* 2
150 if w
~= "" then r
:append(d
[w
], bits
) end
152 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.
153 if dsize
> nextbits
then
155 nextbits
= nextbits
* 2
157 r
:append(tokens
, bits
)
159 local rst
= r
:finish()
160 QuestHelper
: Assert(QH_LZW_Decompress(rst
, tokens
, outbits
) == input
) -- yay
165 local function QH_LZW_Compress_Dicts(input
, inputdict
, outputdict
)
169 for i
= 1, #inputdict
do idc
[inputdict
:sub(i
, i
)] = strchar(i
- 1) end
171 for i
= 1, #input
do Merger
.Add(im
, idc
[input
:sub(i
, i
)]) end
172 inproc
= Merger
.Finish(im
)
175 local bits
, dsize
= 1, 2
176 if not outputdict
then bits
= 8 else while dsize
< #outputdict
do bits
= bits
+ 1 ; dsize
= dsize
* 2 end end
177 QuestHelper
: Assert(not outputdict
or #outputdict
== dsize
)
179 local comp
= QH_LZW_Compress(inproc
, inputdict
and #inputdict
or 256, bits
)
182 local origcomp
= comp
184 for i
= 1, #origcomp
do Merger
.Add(im
, outputdict
:sub(strbyte(origcomp
:sub(i
, i
)) + 1)) end
185 comp
= Merger
.Finish(im
)
191 function QH_Collect_LZW_Init(_
, API
)
192 Merger
= API
.Utility_Merger
193 QuestHelper
: Assert(Merger
)
195 API
.Utility_LZW
= {Compress
= QH_LZW_Compress
, Decompress
= QH_LZW_Decompress
, Compress_Dicts
= QH_LZW_Compress_Dicts
}
203 QH_LZW_Compress("TOBEORNOTTOBEORTOBEORNOT", 256, 8)
207 QuestHelper:TextOut("lulz")
209 local inq = "ABABABABA"
213 str = QH_LZW_Compress(inq, alpha, bits)
216 tvr = tvr .. string.format("%d ", strbyte(str, i))
218 QuestHelper:TextOut(tvr)
220 ret = QH_LZW_Decompress(str, alpha, bits)
221 QuestHelper:TextOut(ret)
223 QuestHelper: Assert(inq == ret)