2 module("bc", package
.seeall
)
18 LiteralOp
= {name
="LiteralOp"}
19 function LiteralOp
:new(value
)
20 local obj
= newobject(self
)
25 VBROp
= {name
="VBROp"}
26 function VBROp
:new(bits
)
27 local obj
= newobject(self
)
33 FixedOp
= {name
="FixedOp"}
34 function FixedOp
:new(bits
)
35 local obj
= newobject(self
)
41 ArrayOp
= {name
="ArrayOp"}
42 function ArrayOp
:new(elem_type
)
43 local obj
= newobject(self
)
44 obj
.elem_type
= elem_type
50 function File
:new(filename
, app_magic_number
)
51 local obj
= newobject(self
)
53 obj
.file
= io
.open(filename
, "w")
57 obj
.file
:write(app_magic_number
)
58 obj
.current_abbrev_width
= 2
64 -- Witness the joy of trying to do bitwise manipulation in a language that
65 -- has no bitwise operators.
66 function File
:write_fixed(val
, bits
)
67 -- print(string.format("Write fixed: %d, %d", val, bits))
68 -- print(string.format("Existing bytes(%d): %d", self.current_bits, self.current_byte))
70 local bits_this_byte
= math
.min(8-self
.current_bits
, bits
)
71 local low_bits
= val
% (2 ^ bits_this_byte
)
72 self
.current_byte
= self
.current_byte
+ (low_bits
* (2 ^ self
.current_bits
))
73 self
.current_bits
= self
.current_bits
+ bits_this_byte
74 if self
.current_bits
== 8 then
75 -- print(string.format("Flushing byte %d", self.current_byte))
76 self
.file
:write(string.char(self
.current_byte
))
79 self
.offset
= self
.offset
+ 1
81 bits
= bits
- bits_this_byte
82 val
= math
.floor(val
/ (2 ^ bits_this_byte
))
86 function File
:align_32_bits()
87 if self
.current_bits
> 0 then
88 self
:write_fixed(0, 8-self
.current_bits
)
91 if self
.offset
% 4 > 0 then
92 self
:write_fixed(0, (4 - (self
.offset
% 4)) * 8)
96 function File
:write_vbr(val
, bits
)
97 -- print(string.format("Write VBR: %d, %d", val, bits))
98 local high_bit
= 2 ^
(bits
-1)
104 bits_remaining
= 1 + math
.floor(math
.log(val
) / math
.log(2))
108 if bits_remaining
> (bits
-1) then
109 self
:write_fixed(high_bit
+ (val
% high_bit
), bits
)
110 bits_remaining
= bits_remaining
- (bits
-1)
111 val
= math
.floor(val
/ high_bit
)
113 self
:write_fixed(val
, bits
)
119 function File
:enter_subblock(block_id
)
120 -- print(string.format("++ Enter subblock: %d", block_id))
121 local old_abbrev_width
= self
.current_abbrev_width
122 self
:write_fixed(ENTER_SUBBLOCK
, self
.current_abbrev_width
)
123 self
:write_vbr(block_id
, 8)
124 self
:write_vbr(4, 4) -- no need to make this configurable at the moment
125 self
.current_abbrev_width
= 4
128 self
:write_fixed(0, 32) -- we'll fill this in later
129 table.insert(self
.stack
, {old_abbrev_width
, self
.file
:seek()})
132 function File
:end_subblock(block_id
)
133 -- print(string.format("-- End subblock: %d", block_id))
134 self
:write_fixed(END_BLOCK
, self
.current_abbrev_width
)
137 self
.current_abbrev_width
, block_offset
= unpack(table.remove(self
.stack
))
138 local current_offset
= self
.file
:seek()
139 self
.file
:seek("set", block_offset
- 4)
140 self
:write_fixed((current_offset
- block_offset
) / 4, 32)
141 self
.file
:seek("set", current_offset
)
144 function File
:write_unabbreviated_record(id
, ...)
145 -- print(string.format("Write unabbreviated record: %d", id))
147 self
:write_fixed(UNABBREV_RECORD
, self
.current_abbrev_width
)
148 self
:write_vbr(id
, 6)
149 self
:write_vbr(#args
, 6)
150 for arg
in each(args
) do
151 self
:write_vbr(arg
, 6)
155 function File
:write_abbreviated_val(val
, op
)
156 if op
.class
== VBROp
then
157 self
:write_vbr(val
, op
.bits
)
158 elseif op
.class
== FixedOp
then
159 self
:write_fixed(val
, op
.bits
)
161 error("Unknown op type!")
165 function File
:write_abbreviated_record(abbreviation
, ...)
166 -- print("Write abbreviated record:" .. serialize({...}))
168 if #args
~= #abbreviation
.ops
then
169 error("Wrong number of arguments for abbreviated record")
171 self
:write_fixed(abbreviation
.id
, self
.current_abbrev_width
)
172 for i
, arg
in ipairs(args
) do
173 local op
= abbreviation
.ops
[i
]
174 if op
.class
== ArrayOp
then
175 self
:write_vbr(arg
:len(), 6)
176 for int
in each({arg
:byte(1, arg
:len())}) do
177 self
:write_abbreviated_val(int
, op
.elem_type
)
180 self
:write_abbreviated_val(arg
, op
)
185 function File
:write_abbrev_op(arg
)
186 if arg
.class
== LiteralOp
then
187 self
:write_fixed(1, 1)
188 self
:write_vbr(arg
.value
, 8)
189 elseif arg
.class
== VBROp
then
190 self
:write_fixed(0, 1)
191 self
:write_fixed(ENCODING_VBR
, 3)
192 self
:write_vbr(arg
.bits
, 5)
193 elseif arg
.class
== FixedOp
then
194 self
:write_fixed(0, 1)
195 self
:write_fixed(ENCODING_FIXED
, 3)
196 self
:write_vbr(arg
.bits
, 5)
198 error("Unknown/unhandled op type")
202 function File
:define_abbreviation(abbrev_id
, ...)
203 local abbrev
= {id
=abbrev_id
, ops
={}}
205 self
:write_fixed(DEFINE_ABBREV
, self
.current_abbrev_width
)
206 if args
[#args
].class
== ArrayOp
then
207 self
:write_vbr(#args
+1, 5)
209 self
:write_vbr(#args
, 5)
212 for arg
in each(args
) do
213 if arg
.class
~= LiteralOp
then
214 table.insert(abbrev
.ops
, arg
)
217 if arg
.class
== ArrayOp
then
218 self
:write_fixed(0, 1)
219 self
:write_fixed(ENCODING_ARRAY
, 3)
220 self
:write_abbrev_op(arg
.elem_type
)
222 self
:write_abbrev_op(arg
)