-
Notifications
You must be signed in to change notification settings - Fork 0
/
scrapelib.lua
executable file
·143 lines (133 loc) · 3.42 KB
/
scrapelib.lua
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
local sub = string.sub
local function ref(data, start, ...)
local x = start
for i = 1, select('#', ...) do
local ty = sub(x, 1, 1)
assert(ty == 't' or ty == 'f' or ty == 'u')
x = data[tonumber(sub(x, 2))][select(i, ...)]
end
return x
end
local function tpairs(data, x)
assert(type(x) == 'string')
local tx = sub(x, 1, 1)
assert(tx == 't' or tx == 'f' or tx == 'u')
return pairs(data[tonumber(sub(x, 2))])
end
local function resolve(data, top, depth)
depth = depth or math.huge
if top == nil then
return nil
end
local refs = {}
local function fun(x, lvl)
if lvl >= depth then
return x
end
assert(type(x) == 'string', tostring(x) .. ' is not a string')
local rx = refs[x]
if rx then
assert(type(rx) == 'table', 'unsupported loop in structure: ' .. x)
return rx
end
local tx = sub(x, 1, 1)
if tx == 'n' then
return tonumber(sub(x, 2))
elseif tx == 's' then
return sub(x, 2)
elseif tx == 'b' then
return x == 'btrue'
elseif tx == 'e' then
return '<function environment>'
elseif tx == 'm' then
return '<metatable>'
elseif tx == 'f' or tx == 'u' then
refs[x] = true
local ret = fun('t' .. sub(x, 2), lvl + 1)
refs[x] = ret
return ret
elseif tx == 't' then
refs[x] = true
local t = {}
for k, v in tpairs(data, x) do
t[fun(k, lvl + 1)] = fun(v, lvl + 1)
end
refs[x] = t
return t
else
error('invalid type on ' .. x)
end
end
return fun(top, 0)
end
local function names(data, rend)
local result = {}
local refs = {}
local stack = { { '_G', rend } }
while #stack > 0 do
local str, r = unpack(table.remove(stack))
refs[r] = true
for k, v in data:tpairs(r) do
local tk = sub(k, 1, 1)
local s = str
if tk == 'm' then
s = 'getmetatable(' .. s .. ')'
elseif tk == 'e' then
s = 'getfenv(' .. s .. ')'
elseif tk == 'n' or tk == 'b' then
s = s .. '[' .. sub(k, 2) .. ']'
elseif tk == 's' then
s = s .. '.' .. sub(k, 2)
elseif tk == 't' or tk == 'f' or tk == 'u' then
print('ignoring table key ' .. k)
else
error('invalid key ' .. k)
end
if v == rend then
table.insert(result, s)
elseif not refs[v] then
local tv = sub(v, 1, 1)
if tv == 't' or tv == 'u' or tv == 'f' then
table.insert(stack, { s, v })
end
end
end
end
return result
end
local function global(data, ...)
return ref(data, 't1', ...)
end
local function capsule(data, ...)
return global(data, 'sSimpleCheckout', 'sOnLoad', 'e', ...)
end
local dataMT = {
__index = {
capsule = capsule,
global = global,
names = names,
ref = ref,
resolve = resolve,
tpairs = tpairs,
},
__metatable = 'WowlessSaverData',
__newindex = function()
error('cannot modify a scrape table')
end,
}
local function parseDataDump(filename)
local data = loadstring('return ' .. require('pl.file').read(filename))
return setmetatable(data(), dataMT)
end
local function parseSavedVariables(filename)
local fenv = {}
setfenv(loadfile(filename), fenv)()
local str = require('libdeflate'):DecompressDeflate(fenv.TheFlatDumper)
local ret = loadstring('return ' .. str)()
setmetatable(ret.Data, dataMT)
return ret
end
return {
parseDataDump = parseDataDump,
parseSavedVariables = parseSavedVariables,
}