This repository has been archived by the owner on Aug 2, 2023. It is now read-only.
/
decode.go
200 lines (178 loc) · 4.38 KB
/
decode.go
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
package binary
import (
"bytes"
"encoding/binary"
"fmt"
)
func decode(r *bytes.Buffer, c *Chunk) {
var h Header
must(binary.Read(r, order, &h))
assert(h.Signature == head, "not a precompiled chunk")
assert(h.Version == LUAC_VERSION, "version mismatch")
assert(h.Format == LUAC_FORMAT, "format mismatch")
assert(h.LuacData == tail, "corrupted")
assert(h.GoIntSize == CINT_SIZE, "int size mismatch")
assert(h.SizetSize == CSIZET_SIZE, "size_t size mismatch")
assert(h.InstrSize == INSTRUCTION_SIZE, "instruction size mismatch")
assert(h.LuaIntSize == LUA_INTEGER_SIZE, "lua integer size mismatch")
assert(h.LuaNumSize == LUA_NUMBER_SIZE, "lua number size mismatch")
assert(h.LuacIntEnc == LUAC_INT, "endianess mismatch")
assert(h.LuacNumEnc == LUAC_NUM, "float format mismatch")
c.Header = h
// decode size_upvalues (?)
_, err := r.ReadByte()
must(err)
// decode container closure prototype
decodePrototype(r, &c.Entry)
}
func decodePrototype(r *bytes.Buffer, proto *Prototype) {
// decode source name string (b[0] == length)
// b[0] == 0xFF ? uint64 : size
proto.Source = decodeString(r)
// decode line start
must(binary.Read(r, order, &proto.SrcPos))
// decode line end
must(binary.Read(r, order, &proto.EndPos))
// decode number of parameters
must(binary.Read(r, order, &proto.Params))
// decode is varadic
must(binary.Read(r, order, &proto.Vararg))
// decode maximum stack size
must(binary.Read(r, order, &proto.Stack))
// decode instruction bytecode
//
// leading 4-bytes is number of instructions
{
var num uint32
must(binary.Read(r, order, &num))
proto.Code = make([]uint32, num)
for i := range proto.Code {
must(binary.Read(r, order, &proto.Code[i]))
}
}
// decode constants
//
// leading 4-bytes is number of constants
{
var num uint32
must(binary.Read(r, order, &num))
proto.Consts = make([]interface{}, num)
for i := range proto.Consts {
proto.Consts[i] = decodeConst(r)
}
}
// decode upvalues
//
// leading 4-bytes is number of upvalues
{
var num uint32
must(binary.Read(r, order, &num))
proto.UpValues = make([]UpValue, num)
for i := range proto.UpValues {
var (
upv UpValue
err error
)
upv.InStack, err = r.ReadByte()
must(err)
upv.Index, err = r.ReadByte()
must(err)
proto.UpValues[i] = upv
}
}
// decode nested closure prototypes
//
// leading 4-bytes is number of prototypes
{
var num uint32
must(binary.Read(r, order, &num))
proto.Protos = make([]Prototype, num)
for i := range proto.Protos {
var fn Prototype
decodePrototype(r, &fn)
proto.Protos[i] = fn
}
}
// decode line info (pc -> line)
//
// leading 4-bytes is number of pcln entries
{
var num uint32
must(binary.Read(r, order, &num))
proto.PcLnTab = make([]uint32, num)
for i := range proto.PcLnTab {
must(binary.Read(r, order, &proto.PcLnTab[i]))
}
}
// decode local variables
//
// leading 4-bytes is number of pcln entries
{
var num uint32
must(binary.Read(r, order, &num))
proto.Locals = make([]LocalVar, num)
for i := range proto.Locals {
local := LocalVar{Name: decodeString(r)}
must(binary.Read(r, order, &local.Live))
must(binary.Read(r, order, &local.Dead))
proto.Locals[i] = local
}
}
// decode upvalue names
//
// leading 4-bytes is number of pcln entries
{
var num uint32
must(binary.Read(r, order, &num))
proto.UpNames = make([]string, num)
for i := range proto.UpNames {
proto.UpNames[i] = decodeString(r)
}
}
}
func decodeString(r *bytes.Buffer) string {
b, err := r.ReadByte()
must(err)
switch {
case b == 0x00:
return ""
case b == 0xFF:
var u64 uint64
must(binary.Read(r, order, &u64))
return string(r.Next(int(u64) - 1))
default:
return string(r.Next(int(b) - 1))
}
}
func decodeConst(r *bytes.Buffer) interface{} {
t, err := r.ReadByte()
must(err)
switch t {
case LUA_TYPE_NIL: // NIL
return nil
case LUA_TYPE_BOOL: // BOOL
b, err := r.ReadByte()
must(err)
var v bool
if b == 0 {
v = false
} else if b == 1 {
v = true
} else {
panic(fmt.Errorf("invalid bool constant: %d", b))
}
return v
case LUA_NUM_INT: // INT
var i64 int64
must(binary.Read(r, order, &i64))
return i64
case LUA_NUM_FLOAT: // FLOAT
var f64 float64
must(binary.Read(r, order, &f64))
return f64
case LUA_STR_SHORT, LUA_STR_LONG: // STRING
return decodeString(r)
default:
panic(fmt.Errorf("unexpected constant type: %d", t))
}
}