Files
lualibs-bundle/bundle.lua
T
Cosmin Apreutesei 985b0b2f5a unimportant
2018-09-24 18:53:31 +03:00

163 lines
3.5 KiB
Lua
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- Bundle Lua API, currently containing the blob loader.
-- Written by Cosmin Apreutesei. Public Domain.
local ffi = require'ffi'
local BBIN_PREFIX = 'Bbin_'
local bundle = {}
--portable way to get exe's directory, based on arg[0].
--the resulted directory is relative to the current directory.
local dir = arg[0]:gsub('[/\\]?[^/\\]+$', '') or '' --remove file name
dir = dir == '' and '.' or dir
--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 fs = require'fs'
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)
local fs = require'fs'
return bundle.open_dir_listing(dir, load_blob(dir))
end
--reading the filesystem
local function load_file(file)
file = 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 s = load_file(file)
if not s then return end
--TODO: use fs.mmap() here
return {data = ffi.cast('const void*', s), size = #s,
close = function() local _ = s; end}
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)
local fs = require'fs'
return (fs.open(file))
end
function fs_dir_file(dir)
local fs = require'fs'
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
function bundle.load(file)
return load_file(file) or load_blob(file)
end
function bundle.mmap(file)
return mmap_file(file) or mmap_blob(file)
end
function bundle.fs_open(file)
return fs_open_file(file) or fs_open_blob(file)
end
function bundle.fs_dir(dir)
return fs_dir_file(dir) or fs_dir_blob(dir)
end
local ok, ver = pcall(require, 'bundle_appversion')
bundle.appversion = ok and ver or nil
return bundle