-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathbundle.lua
167 lines (140 loc) · 3.5 KB
/
bundle.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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
-- Bundle Lua API, currently containing the blob loader.
-- Written by Cosmin Apreutesei. Public Domain.
local ffi = require'ffi'
local fs = require'fs'
local external_dir = require'package.exedir'
local BBIN_PREFIX = 'Bbin_'
if not package.loaded.bundle_loader then
--standalone luajit exe. files are in luapower dir at ../..
external_dir = external_dir..'/../..'
end
local bundle = {}
--reading embedded blobs
local function getsym(sym)
return ffi.C[sym]
end
local function blob_data(file)
local sym = BBIN_PREFIX..file:gsub('[\\%-/%.]', '_')
pcall(ffi.cdef, 'void '..sym..'()')
local ok, p = pcall(getsym, sym)
if not ok then return nil end
local p = ffi.cast('const uint32_t*', p)
return ffi.cast('void*', p+1), p[0]
end
local function load_blob(file)
local data, size = blob_data(file)
return data and ffi.string(data, size)
end
local function mmap_blob(file)
local data, size = blob_data(file)
return data and {data = data, size = size, close = function() end}
end
local function canopen_blob(file)
return blob_data(file) and true or false
end
local function fs_open_blob(file)
local buf, sz = blob_data(file)
if not buf then return nil end
return fs.open_buffer(buf, sz)
end
function bundle.open_dir_listing(dir, s)
local path = require'path'
local entries = s and assert(loadstring(s))()
local d = {}
local closed, name, ftype
local i = 1
function d:next()
if closed then
return nil
end
if not entries then
closed = true
return false, 'not_found'
end
name = entries[i]
if not name then
closed = true
return nil
end
i = i + 1
name, ftype = name:match'^(.-)([/]?)$'
if ftype == '/' then
ftype = 'dir'
else
ftype = 'file'
end
return name, d
end
function d:close() closed = true; return true; end
function d:closed() return closed end
function d:name() return name end
function d:dir() return dir end
function d:path() return path.combine(dir, name) end
function d:attr(attr)
if attr == 'type' then
return ftype
elseif not attr then
return {type = ftype}
else
return nil
end
end
function d:is(ftype1) return ftype == ftype1 end
return d.next, d
end
local function fs_dir_blob(dir)
return bundle.open_dir_listing(dir, load_blob(dir))
end
--reading the filesystem
local function load_file(file)
file = external_dir..'/'..file
local f = io.open(file, 'rb')
if not f then return nil end
local s = f:read'*a'
f:close()
return s
end
local function mmap_file(file)
local m, err = fs.map(file)
if not m then return nil, err end
m.data = ffi.cast('const void*', m.addr)
m.close = m.free
return m
end
local function canopen_file(file)
local f = io.open(file, 'r')
if f then f:close() end
return f and true or false
end
function fs_open_file(file)
return (fs.open(file))
end
function fs_dir_file(dir)
if not fs.is(dir, 'dir') then return nil end
return fs.dir(dir)
end
--user API
function bundle.canopen(file)
return canopen_file(file) or canopen_blob(file)
end
local function check(file, v)
if v then return v end
return nil, ('file not found: %s'):format(file)
end
function bundle.load(file)
return check(file, load_file(file) or load_blob(file))
end
function bundle.mmap(file)
return check(mmap_file(file) or mmap_blob(file))
end
function bundle.fs_open(file)
return check(fs_open_file(file) or fs_open_blob(file))
end
function bundle.fs_dir(dir)
local d, next = fs_dir_file(dir)
if d then return d, next end
return fs_dir_blob(dir)
end
local ok, ver = pcall(require, 'bundle_appversion')
bundle.appversion = ok and ver or nil
return bundle