Переглянути джерело

!63 add: 并入未完成的luf, 暂存吧
Merge pull request !63 from Wendal/feature_luf

Wendal 4 роки тому
батько
коміт
f33321d3f7

+ 4 - 0
bsp/win32/CMakeLists.txt

@@ -63,6 +63,10 @@ add_library(luat ${TOPROOT}/luat/modules/luat_main.c
                  ${TOPROOT}/components/sfd/luat_lib_sfd.c
                  ${TOPROOT}/components/sfd/luat_sfd_mem.c
                  ${TOPROOT}/components/sfd/luat_sfd_w25q.c
+                 ${TOPROOT}/components/luf/luat_lib_luf.c
+                 ${TOPROOT}/components/luf/luat_luf_dump.c
+                 ${TOPROOT}/components/luf/luat_luf_undump.c
+                 ${TOPROOT}/components/luf/luat_luf_cmp.c
                  ${TOPROOT}/luat/modules/crc.c
                  ${TOPROOT}/luat/vfs/luat_vfs.c
                  ${TOPROOT}/luat/vfs/luat_fs_luadb.c

+ 30 - 0
bsp/win32/luf_test/abc.lua

@@ -0,0 +1,30 @@
+
+local abc = {}
+abc.version = 1
+-- abc[1] = 123
+-- abc["hi"] = function (name)
+--     log.info("*abc*", name)
+-- --     return "Hi, ".. name, function ()
+-- --         os.exit(123)
+-- --     end
+--     return "hi, ".. name
+-- end
+-- _G.print(1)
+-- log.info("abc", "Great")
+-- -- return abc
+-- wendal = 1
+
+function abc.h2(name) 
+    local function hi12345678901234567890123456789012345678902()
+        
+    end
+    hi12345678901234567890123456789012345678902()
+
+    if sys == nil then
+        print()
+    end
+
+    return "hi, " .. name, function() end
+end
+
+return abc

BIN
bsp/win32/luf_test/abc.luf


+ 18 - 0
bsp/win32/luf_test/disk/main.lua

@@ -0,0 +1,18 @@
+
+PROJECT = "luf2"
+VERSION = "1.0.0"
+
+log.info("main", "hi")
+
+-- local sys = require ("sys")
+
+-- log.info("main", "sys", sys)
+
+-- sys.taskInit(function()
+--     while true do
+--         log.info("sys", "task loop")
+--         sys.wait(1000)
+--     end
+-- end)
+
+-- sys.run()

+ 116 - 0
bsp/win32/luf_test/luadb.lua

@@ -0,0 +1,116 @@
+
+-- 读取命令行参数
+local srcpath = "disk"
+if arg[1] then
+    srcpath = arg[1]
+end
+
+
+local function lsdir(path, files, shortname)
+    local exe = io.popen("dir /b " .. (shortname and " " or " /s ") .. path)
+    if exe then
+        for line in exe:lines() do
+            table.insert(files, line)
+        end
+        exe:close()
+    end
+end
+
+
+local function oscall(cmd, quite, cwd)
+    if cwd and Base_CWD then
+        lfs.chdir(cwd)
+    end
+    if tool_debug then
+        log.info("cmd", cmd)
+    end
+    local exe = io.popen(cmd)
+    if exe then
+        for line in exe:lines() do
+            if not quite then
+                log.info("cmd", line)
+            end
+        end
+        exe:close()
+    end
+    if cwd and Base_CWD then
+        lfs.chdir(Base_CWD)
+    end
+end
+
+function TLD(buff, T, D)
+    buff:pack("bb", T, D:len())
+    buff:write(D)
+end
+
+local files = {}
+lsdir(srcpath, files, true)
+-- oscall("mkdir tmp")
+
+local buff = zbuff.create(256*1024)
+local magic = string.char(0x5A, 0xA5, 0X5A, 0xA5)
+
+-- -- 先写入magic
+--buff:pack("bbbbbb", 0x01, 0x04, 0XA5, 0x5A, 0xA5, 0x5A)
+TLD(buff, 0x01, magic)
+
+-- 然后是版本号
+--buff:write(string.char(0x02, 0x02, 0x00, 0x02))
+TLD(buff, 0x02, string.char(0x00, 0x02))
+
+-- head长度
+buff:write(string.char(0x03, 0x04))
+buff:pack("I", 0x18)
+
+-- 文件数量
+buff:write(string.char(0x04, 0x02))
+buff:pack("H", #files)
+
+-- CRC值
+buff:write(string.char(0xFE, 0x02))
+buff:pack("H", 0xFFFF)
+
+for _, value in ipairs(files) do
+    TLD(buff, 0x01, magic)
+    local tname = value
+    local data = nil
+    if value:sub(-4) == ".lua" then
+        tname = value .. "c"
+        local func, err = loadfile(srcpath .. "\\" .. value)
+        if err then
+            log.error("luac", "bad lua format", err)
+            os.exit(1)
+        end
+        -- if value == "main.lua" then
+            -- data = string.dump(func)
+            -- io.writeFile(tname, string.dump(func))
+        -- else
+            -- io.writeFile("tmp\\" .. tname, luf.dump(func, false, 0x80E0000 + buff:seek(0, zbuff.SEEK_CUR) + 3*2 + tname:len() + 4 + 2))
+            -- log.info("what pos", buff:seek(0, zbuff.SEEK_CUR))
+            -- log.info(">> pos", string.format("%08X", 0x080E0000 + buff:seek(0, zbuff.SEEK_CUR) + 3*2 + tname:len() + 4 + 2 + 64))
+            -- data = luf.dump(func, false, 0x80E0000 + buff:seek(0, zbuff.SEEK_CUR) + 3*2 + tname:len() + 4 + 2)
+            data = luf.dump(func, false, 0x080E0033)
+            log.info("iowrite", tname, #data)
+            io.writeFile(tname, data)
+        -- end
+    else
+        data = io.readFile(srcpath .. "\\" .. value)
+    end
+    -- log.info("luadb1", tname, #data, buff:seek(0, zbuff.SEEK_CUR))
+    TLD(buff, 0x02, tname)
+    TLD(buff, 0x03, pack.pack("I", #data))
+    TLD(buff, 0xFE, string.char(0xFF, 0xFF))
+    log.info("luadb2", tname, #data, buff:seek(0, zbuff.SEEK_CUR), string.format("%02X", buff:seek(0, zbuff.SEEK_CUR)))
+    -- log.info(">> pos", string.format("%08X", 0x80E0000 + buff:seek(0, zbuff.SEEK_CUR)))
+    buff:write(data)
+    log.info("luadb3", tname, #data, buff:seek(0, zbuff.SEEK_CUR))
+end
+
+local data = buff:toStr(0, buff:seek(0, zbuff.SEEK_CUR))
+log.info("target", #data)
+
+io.writeFile("disk.bin", data)
+
+--print(json.encode(arg))
+
+os.exit(0)

+ 22 - 0
bsp/win32/luf_test/main.lua

@@ -0,0 +1,22 @@
+
+log.info("main", "hi")
+
+local func = loadfile("sys.lua")
+log.info("func", func)
+buff = zbuff.create(32*1024)
+data = luf.dump(func, false, buff)
+
+buff:write(data)
+
+func2 = luf.undump(data)
+
+local sys = func2()
+
+sys.taskInit(function()
+    while true do
+        log.info("sys", "task loop")
+        sys.wait(1000)
+    end
+end)
+
+sys.run()

+ 32 - 0
bsp/win32/luf_test/main_luf.lua

@@ -0,0 +1,32 @@
+
+log.info("main", "hi")
+
+local func = loadfile("sys.lua")
+log.info("func", func)
+buff = zbuff.create(32*1024)
+data = luf.dump(func, false, buff)
+buff:write(data)
+
+--buff:write(data)
+
+io.writeFile("sys.luf", data)
+io.writeFile("sys.luac", string.dump(func))
+io.writeFile("sys.luacs", string.dump(func, true))
+
+f = load(data)
+log.info("load", f)
+if f then
+    log.info("load", "f?")
+    sys = f()
+    sys.publish("ABC", 123)
+    log.info("load sys", sys)
+    sys.taskInit(function()
+        log.info("sys", "wait 1s")
+        sys.wait(1000)
+        log.info("os", "exit now")
+        os.exit()
+    end)
+    sys.run()
+end
+
+os.exit(0)

+ 44 - 0
bsp/win32/luf_test/main_test.lua

@@ -0,0 +1,44 @@
+
+log.info("main", "hi")
+
+local func = loadfile("abc.lua")
+log.info("func", func)
+buff = zbuff.create(32*1024)
+data = luf.dump(func, false, buff)
+
+buff:write(data)
+buff:seek(0, zbuff.SEEK_SET)
+
+log.info("data", #data)
+-- print(data:toHex())
+
+io.writeFile("abc.luf", data)
+io.writeFile("abc.luac", string.dump(func))
+io.writeFile("abc.luacs", string.dump(func, true))
+
+func2 = luf.undump(data)
+
+if func2 then
+    log.info("func??", func2)
+    -- luf.cmp(func, func2)
+    local abc = func2()
+    log.info("table?", type(abc))
+    log.info("table?", json.encode(abc))
+    if abc.version then
+        log.info("abc", abc["version"])
+    else
+        log.info("abc", "no version")
+    end
+    if abc.h2 then
+        log.info("abc", abc.h2("wendal"))
+    else
+        log.info("abc", "no hi function")
+    end
+    log.info("func??", "end", abc[1])
+else
+    log.info("func", "nil!!!")
+end
+
+log.info("change?", buff:toStr(0, #data) == data)
+
+os.exit(0)

+ 404 - 0
bsp/win32/luf_test/sys.lua

@@ -0,0 +1,404 @@
+--- 模块功能:Luat协程调度框架
+--module(..., package.seeall)
+
+local sys = {}
+
+local table = _G.table
+local unpack = table.unpack
+local rtos = _G.rtos
+local coroutine = _G.coroutine
+local log = _G.log
+
+-- lib脚本版本号,只要lib中的任何一个脚本做了修改,都需要更新此版本号
+SCRIPT_LIB_VER = "1.0.0"
+
+-- TaskID最大值
+local TASK_TIMER_ID_MAX = 0x1FFFFF
+-- msgId 最大值(请勿修改否则会发生msgId碰撞的危险)
+local MSG_TIMER_ID_MAX = 0x7FFFFF
+
+-- 任务定时器id
+local taskTimerId = 0
+-- 消息定时器id
+local msgId = TASK_TIMER_ID_MAX
+-- 定时器id表
+local timerPool = {}
+local taskTimerPool = {}
+--消息定时器参数表
+local para = {}
+--定时器是否循环表
+--local loop = {}
+--lua脚本运行出错时,是否回退为本地烧写的版本
+--local sRollBack = true
+
+_G.COROUTINE_ERROR_ROLL_BACK = true
+_G.COROUTINE_ERROR_RESTART = true
+
+-- 对coroutine.resume加一个修饰器用于捕获协程错误
+--local rawcoresume = coroutine.resume
+local function wrapper(co,...)
+    local arg = {...}
+    if not arg[1] then
+        local traceBack = debug.traceback(co)
+        traceBack = (traceBack and traceBack~="") and (arg[2].."\r\n"..traceBack) or arg[2]
+        log.error("coroutine.resume",traceBack)
+        --if errDump and type(errDump.appendErr)=="function" then
+        --    errDump.appendErr(traceBack)
+        --end
+        if _G.COROUTINE_ERROR_ROLL_BACK then
+            sys.timerStart(assert,500,false,traceBack)
+        elseif _G.COROUTINE_ERROR_RESTART then
+            rtos.reboot()
+        end
+    end
+    return ...
+end
+sys.coresume = function(...)
+    local arg = {...}
+    return wrapper(arg[1], coroutine.resume(...))
+end
+
+--- Task任务延时函数,只能用于任务函数中
+-- @number ms  整数,最大等待126322567毫秒
+-- @return 定时结束返回nil,被其他线程唤起返回调用线程传入的参数
+-- @usage sys.wait(30)
+function sys.wait(ms)
+    -- 参数检测,参数不能为负值
+    --assert(ms > 0, "The wait time cannot be negative!")
+    -- 选一个未使用的定时器ID给该任务线程
+    while true do
+        if taskTimerId >= TASK_TIMER_ID_MAX - 1 then
+            taskTimerId = 0
+        else
+            taskTimerId = taskTimerId + 1
+        end
+        if taskTimerPool[taskTimerId] == nil then
+            break
+        end
+    end
+    local timerid = taskTimerId
+    taskTimerPool[coroutine.running()] = timerid
+    timerPool[timerid] = coroutine.running()
+    -- 调用core的rtos定时器
+    if 1 ~= rtos.timer_start(timerid, ms) then log.debug("rtos.timer_start error") return end
+    -- 挂起调用的任务线程
+    local message = {coroutine.yield()}
+    if #message ~= 0 then
+        rtos.timer_stop(timerid)
+        taskTimerPool[coroutine.running()] = nil
+        timerPool[timerid] = nil
+        return unpack(message)
+    end
+end
+
+--- Task任务的条件等待函数(包括事件消息和定时器消息等条件),只能用于任务函数中。
+-- @param id 消息ID
+-- @number ms 等待超时时间,单位ms,最大等待126322567毫秒
+-- @return result 接收到消息返回true,超时返回false
+-- @return data 接收到消息返回消息参数
+-- @usage result, data = sys.waitUntil("SIM_IND", 120000)
+function sys.waitUntil(id, ms)
+    sys.subscribe(id, coroutine.running())
+    local message = ms and {sys.wait(ms)} or {coroutine.yield()}
+    sys.unsubscribe(id, coroutine.running())
+    return message[1] ~= nil, unpack(message, 2, #message)
+end
+
+--- Task任务的条件等待函数扩展(包括事件消息和定时器消息等条件),只能用于任务函数中。
+-- @param id 消息ID
+-- @number ms 等待超时时间,单位ms,最大等待126322567毫秒
+-- @return message 接收到消息返回message,超时返回false
+-- @return data 接收到消息返回消息参数
+-- @usage result, data = sys.waitUntilExt("SIM_IND", 120000)
+function sys.waitUntilExt(id, ms)
+    sys.subscribe(id, coroutine.running())
+    local message = ms and {sys.wait(ms)} or {coroutine.yield()}
+    sys.unsubscribe(id, coroutine.running())
+    if message[1] ~= nil then return unpack(message) end
+    return false
+end
+
+--- 创建一个任务线程,在模块最末行调用该函数并注册模块中的任务函数,main.lua导入该模块即可
+-- @param fun 任务函数名,用于resume唤醒时调用
+-- @param ... 任务函数fun的可变参数
+-- @return co  返回该任务的线程号
+-- @usage sys.taskInit(task1,'a','b')
+function sys.taskInit(fun, ...)
+    local co = coroutine.create(fun)
+    sys.coresume(co, ...)
+    return co
+end
+
+------------------------------------------ rtos消息回调处理部分 ------------------------------------------
+--[[
+函数名:cmpTable
+功能  :比较两个table的内容是否相同,注意:table中不能再包含table
+参数  :
+t1:第一个table
+t2:第二个table
+返回值:相同返回true,否则false
+]]
+local function cmpTable(t1, t2)
+    if not t2 then return #t1 == 0 end
+    if #t1 == #t2 then
+        for i = 1, #t1 do
+            if unpack(t1, i, i) ~= unpack(t2, i, i) then
+                return false
+            end
+        end
+        return true
+    end
+    return false
+end
+
+--- 关闭定时器
+-- @param val 值为number时,识别为定时器ID,值为回调函数时,需要传参数
+-- @param ... val值为函数时,函数的可变参数
+-- @return 无
+-- @usage timerStop(1)
+function sys.timerStop(val, ...)
+    -- val 为定时器ID
+    if type(val) == 'number' then
+        timerPool[val], para[val] = nil
+        rtos.timer_stop(val)
+    else
+        for k, v in pairs(timerPool) do
+            -- 回调函数相同
+            if type(v) == 'table' and v.cb == val or v == val then
+                -- 可变参数相同
+                if cmpTable({...}, para[k]) then
+                    rtos.timer_stop(k)
+                    timerPool[k], para[k] = nil
+                    break
+                end
+            end
+        end
+    end
+end
+
+--- 关闭同一回调函数的所有定时器
+-- @param fnc 定时器回调函数
+-- @return 无
+-- @usage timerStopAll(cbFnc)
+function sys.timerStopAll(fnc)
+    for k, v in pairs(timerPool) do
+        if type(v) == "table" and v.cb == fnc or v == fnc then
+            rtos.timer_stop(k)
+            timerPool[k], para[k] = nil
+        end
+    end
+end
+
+function sys.timerAdvStart(fnc, ms, _repeat, ...)
+    --回调函数和时长检测
+    --assert(fnc ~= nil, "sys.timerStart(first param) is nil !")
+    --assert(ms > 0, "sys.timerStart(Second parameter) is <= zero !")
+    -- 关闭完全相同的定时器
+    local arg = {...}
+    if #arg == 0 then
+        sys.timerStop(fnc)
+    else
+        sys.timerStop(fnc, ...)
+    end
+    -- 为定时器申请ID,ID值 1-20 留给任务,20-30留给消息专用定时器
+    while true do
+        if msgId >= MSG_TIMER_ID_MAX then msgId = TASK_TIMER_ID_MAX end
+        msgId = msgId + 1
+        if timerPool[msgId] == nil then
+            timerPool[msgId] = fnc
+            break
+        end
+    end
+    --调用底层接口启动定时器
+    if rtos.timer_start(msgId, ms, _repeat) ~= 1 then return end
+    --如果存在可变参数,在定时器参数表中保存参数
+    if #arg ~= 0 then
+        para[msgId] = arg
+    end
+    --返回定时器id
+    return msgId
+end
+
+--- 开启一个定时器
+-- @param fnc 定时器回调函数
+-- @number ms 整数,最大定时126322567毫秒
+-- @param ... 可变参数 fnc的参数
+-- @return number 定时器ID,如果失败,返回nil
+function sys.timerStart(fnc, ms, ...)
+    return sys.timerAdvStart(fnc, ms, 0, ...)
+end
+
+--- 开启一个循环定时器
+-- @param fnc 定时器回调函数
+-- @number ms 整数,最大定时126322567毫秒
+-- @param ... 可变参数 fnc的参数
+-- @return number 定时器ID,如果失败,返回nil
+function sys.timerLoopStart(fnc, ms, ...)
+    return sys.timerAdvStart(fnc, ms, -1, ...)
+end
+
+--- 判断某个定时器是否处于开启状态
+-- @param val 有两种形式
+--一种是开启定时器时返回的定时器id,此形式时不需要再传入可变参数...就能唯一标记一个定时器
+--另一种是开启定时器时的回调函数,此形式时必须再传入可变参数...才能唯一标记一个定时器
+-- @param ... 可变参数
+-- @return number 开启状态返回true,否则nil
+function sys.timerIsActive(val, ...)
+    if type(val) == "number" then
+        return timerPool[val]
+    else
+        for k, v in pairs(timerPool) do
+            if v == val then
+                if cmpTable({...}, para[k]) then return true end
+            end
+        end
+    end
+end
+
+
+------------------------------------------ LUA应用消息订阅/发布接口 ------------------------------------------
+-- 订阅者列表
+local subscribers = {}
+--内部消息队列
+local messageQueue = {}
+
+--- 订阅消息
+-- @param id 消息id
+-- @param callback 消息回调处理
+-- @usage subscribe("NET_STATUS_IND", callback)
+function sys.subscribe(id, callback)
+    --if not id or type(id) == "boolean" or (type(callback) ~= "function" and type(callback) ~= "thread") then
+    --    log.warn("warning: sys.subscribe invalid parameter", id, callback)
+    --    return
+    --end
+    --log.debug("sys", "subscribe", id, callback)
+    if type(id) == "table" then
+        -- 支持多topic订阅
+        for _, v in pairs(id) do sys.subscribe(v, callback) end
+        return
+    end
+    if not subscribers[id] then subscribers[id] = {} end
+    subscribers[id][callback] = true
+end
+--- 取消订阅消息
+-- @param id 消息id
+-- @param callback 消息回调处理
+-- @usage unsubscribe("NET_STATUS_IND", callback)
+function sys.unsubscribe(id, callback)
+    --if not id or type(id) == "boolean" or (type(callback) ~= "function" and type(callback) ~= "thread") then
+    --    log.warn("warning: sys.unsubscribe invalid parameter", id, callback)
+    --    return
+    --end
+    --log.debug("sys", "unsubscribe", id, callback)
+    if type(id) == "table" then
+        -- 支持多topic订阅
+        for _, v in pairs(id) do sys.unsubscribe(v, callback) end
+        return
+    end
+    if subscribers[id] then subscribers[id][callback] = nil end
+    -- 判断消息是否无其他订阅
+    for k, _ in pairs(subscribers[id]) do
+        return
+    end
+    subscribers[id] = nil
+end
+
+--- 发布内部消息,存储在内部消息队列中
+-- @param ... 可变参数,用户自定义
+-- @return 无
+-- @usage publish("NET_STATUS_IND")
+function sys.publish(...)
+    table.insert(messageQueue, {...})
+end
+
+-- 分发消息
+local function dispatch()
+    while true do
+        if #messageQueue == 0 then
+            break
+        end
+        local message = table.remove(messageQueue, 1)
+        if subscribers[message[1]] then
+            for callback, _ in pairs(subscribers[message[1]]) do
+                if type(callback) == "function" then
+                    callback(unpack(message, 2, #message))
+                elseif type(callback) == "thread" then
+                    sys.coresume(callback, unpack(message))
+                end
+            end
+        end
+    end
+end
+
+-- rtos消息回调
+--local handlers = {}
+--setmetatable(handlers, {__index = function() return function() end end, })
+
+--- 注册rtos消息回调处理函数
+-- @number id 消息类型id
+-- @param handler 消息处理函数
+-- @return 无
+-- @usage rtos.on(rtos.MSG_KEYPAD, function(param) handle keypad message end)
+--function sys.on(id, handler)
+--    handlers[id] = handler
+--end
+
+------------------------------------------ Luat 主调度框架  ------------------------------------------
+local function safeRun()
+    -- 分发内部消息
+    dispatch()
+    -- 阻塞读取外部消息
+    local msg, param, exparam = rtos.receive(rtos.INF_TIMEOUT)
+    --log.info("sys", msg, param, exparam, tableNSize(timerPool), tableNSize(para), tableNSize(taskTimerPool), tableNSize(subscribers))
+    -- 空消息?
+    if not msg or msg == 0 then
+        -- 无任何操作
+    -- 判断是否为定时器消息,并且消息是否注册
+    elseif msg == rtos.MSG_TIMER and timerPool[param] then
+        if param < TASK_TIMER_ID_MAX then
+            local taskId = timerPool[param]
+            timerPool[param] = nil
+            if taskTimerPool[taskId] == param then
+                taskTimerPool[taskId] = nil
+                sys.coresume(taskId)
+            end
+        else
+            local cb = timerPool[param]
+            --如果不是循环定时器,从定时器id表中删除此定时器
+            if exparam == 0 then timerPool[param] = nil end
+            if para[param] ~= nil then
+                cb(unpack(para[param]))
+                if exparam == 0 then para[param] = nil end
+            else
+                cb()
+            end
+            --如果是循环定时器,继续启动此定时器
+            --if loop[param] then rtos.timer_start(param, loop[param]) end
+        end
+    --其他消息(音频消息、充电管理消息、按键消息等)
+    --elseif type(msg) == "number" then
+    --    handlers[msg](param, exparam)
+    --else
+    --    handlers[msg.id](msg)
+    end
+end
+
+--- run()从底层获取core消息并及时处理相关消息,查询定时器并调度各注册成功的任务线程运行和挂起
+-- @return 无
+-- @usage sys.run()
+function sys.run()
+    --local result, err
+    while true do
+        --if sRollBack then
+            safeRun()
+        --else
+        --    result, err = pcall(safeRun)
+        --    if not result then rtos.restart(err) end
+        --end
+    end
+end
+
+_G.sys_pub = sys.publish
+
+return sys
+----------------------------

+ 1 - 0
bsp/win32/luf_test/toburn.bat

@@ -0,0 +1 @@
+wm_tool.exe -dl script.img -ds 115200 -ws 115200 -c COM83 -rs rts

+ 1 - 0
bsp/win32/luf_test/toimg.bat

@@ -0,0 +1 @@
+wm_tool.exe -b disk.bin -it 1 -fc 0 -ih 20008000 -ra 80E0000 -ua 0 -nh 0  -un 0 -o script

+ 4 - 9
bsp/win32/port/luat_base_win32.c

@@ -25,7 +25,7 @@ static const luaL_Reg loadedlibs[] = {
   {LUA_OSLIBNAME, luaopen_os},        // os库,已精简
   {LUA_STRLIBNAME, luaopen_string},   // string库,字符串操作
   {LUA_MATHLIBNAME, luaopen_math},    // math 数值计算
-//  {LUA_UTF8LIBNAME, luaopen_utf8},
+  {LUA_UTF8LIBNAME, luaopen_utf8},
   {LUA_DBLIBNAME, luaopen_debug},     // debug库,已精简
 #if defined(LUA_COMPAT_BITLIB)
   {LUA_BITLIBNAME, luaopen_bit32},    // 不太可能启用
@@ -39,22 +39,17 @@ static const luaL_Reg loadedlibs[] = {
   {"zbuff", luaopen_zbuff},            // 
 //   {"mqttcore", luaopen_mqttcore},      // 
 //   {"libcoap", luaopen_libcoap},        // 
-// #ifdef LUA_USE_WINDOWS
-//   {"lfs", luaopen_lfs},                //
-// //   {"rs232.core", luaopen_rs232_core},
-// #endif
   {"crypto", luaopen_crypto},
   {"fatfs", luaopen_fatfs},
   {"sfd",   luaopen_sfd},
   {"lfs2",   luaopen_lfs2},
   {"gpio",   luaopen_gpio},
+#ifdef LUAT_USE_LUF
+  {"luf",    luaopen_luf},
+#endif
 #ifdef LUAT_USE_LVGL
   {"lvgl",   luaopen_lvgl},
-//   {"lcd",    luaopen_lcd},
 #endif
-// #ifdef LUAT_USE_LWIP
-//   {"lwip",   luaopen_lwip},
-// #endif
   {NULL, NULL}
 };
 

+ 3 - 0
components/luf/README.md

@@ -0,0 +1,3 @@
+# Luf 格式加载器
+
+TODO 这个库还没完成, 仅做临时保存

+ 98 - 0
components/luf/luat_lib_luf.c

@@ -0,0 +1,98 @@
+#include "luat_base.h"
+#include "luat_malloc.h"
+
+#include "lprefix.h"
+
+
+#include <stddef.h>
+
+#include "lua.h"
+#include "lapi.h"
+
+#include "lobject.h"
+#include "lstate.h"
+#include "lundump.h"
+#include "luat_zbuff.h"
+
+int luf_dump(lua_State *L, const Proto *f, lua_Writer w, void *data, int strip, int ptroffset);
+
+LClosure *luat_luf_undump(lua_State *L, const char* ptr, size_t len, const char *name);
+
+void luat_luf_cmp(lua_State *L, const Proto* p1, const Proto *p2);
+
+static int writer (lua_State *L, const void *b, size_t size, void *B) {
+  (void)L;
+  luaL_addlstring((luaL_Buffer *) B, (const char *)b, size);
+  return 0;
+}
+
+static int l_luf_dump(lua_State* L) {
+  luaL_Buffer b;
+  TValue *o;
+  int strip = lua_toboolean(L, 2);
+  uint32_t ptroffset = 0;
+  luaL_checktype(L, 1, LUA_TFUNCTION);
+
+  luat_zbuff_t *zbuff = NULL;
+
+  if (lua_isuserdata(L, 3)) {
+    zbuff = luaL_checkudata(L, 3, LUAT_ZBUFF_TYPE);
+    ptroffset = (uint32_t)zbuff->addr;
+  }
+  else if (lua_isinteger(L, 3)) {
+    ptroffset = luaL_checkinteger(L, 3);
+  }
+
+  lua_settop(L, 1);
+  luaL_buffinit(L,&b);
+
+  lua_lock(L);
+  api_checknelems(L, 1);
+  o = L->top - 1;
+  if (luf_dump(L, getproto(o), writer, &b, strip, ptroffset) != 0)
+    return luaL_error(L, "unable to dump given function");
+  luaL_pushresult(&b);
+  lua_unlock(L);
+  return 1;
+}
+
+static int l_luf_undump(lua_State* L) {
+  size_t len;
+  const char* data = luaL_checklstring(L, 1, &len);
+  luat_luf_undump(L, data, len, NULL);
+  return 1;
+}
+
+static int l_luf_cmp(lua_State* L) {
+  luaL_checktype(L, 1, LUA_TFUNCTION);
+  luaL_checktype(L, 2, LUA_TFUNCTION);
+
+  lua_settop(L, 2);
+
+  TValue *o;
+  Proto* p1;
+  Proto* p2;
+
+  o = L->top - 2;
+  p1 = getproto(o);
+  o = L->top - 1;
+  p2 = getproto(o);
+
+  luat_luf_cmp(L, p1, p2);
+
+  return 0;
+}
+
+#include "rotable.h"
+static const rotable_Reg reg_luf[] =
+{
+    { "dump" ,        l_luf_dump , 0},
+    { "undump" ,      l_luf_undump , 0},
+    { "cmp",          l_luf_cmp,   0},
+	{ NULL,          NULL ,       0}
+};
+
+LUAMOD_API int luaopen_luf( lua_State *L ) {
+    luat_newlib(L, reg_luf);
+    return 1;
+}

+ 129 - 0
components/luf/luat_luf_cmp.c

@@ -0,0 +1,129 @@
+#include "luat_base.h"
+#include "luat_malloc.h"
+
+#define ldump_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <stddef.h>
+
+#include "lua.h"
+
+#include "lobject.h"
+#include "lstate.h"
+#include "lundump.h"
+#include "lstring.h"
+
+#define LUAT_LOG_TAG "cmp"
+#include "luat_log.h"
+
+static void cmpProto(const Proto* p1, const Proto *p2);
+
+static void cmpCode(const Proto* p1, const Proto *p2) {
+    LLOGD("code %d", memcmp(p1->code, p2->code, sizeof(Instruction)*p1->sizecode));
+}
+
+
+static void cmpConstants(const Proto* p1, const Proto *p2) {
+    for (size_t i = 0; i < p1->sizek; i++)
+    {
+        TValue* o1 = &p1->k[i];
+        TValue* o2 = &p2->k[i];
+        if (ttype(o1) != ttype(o2)) {
+            LLOGD("Constants Not Match %d %d %d", i, ttype(o1), ttype(o2));
+            continue;
+        }
+        switch (p1->k[i].tt_)
+        {
+        case LUA_TSHRSTR:
+        case LUA_TLNGSTR:
+            if (tsslen(tsvalue(o1)) != tsslen(tsvalue(o2))) {
+                LLOGE("strlen NOT match %d %d", tsslen(tsvalue(o1)), tsslen(tsvalue(o2)));
+            }
+            if (!strcmp(getstr(tsvalue(o1)), getstr(tsvalue(o2)))) {
+                LLOGE("str value NOT match %s %s", getstr(tsvalue(o1)), getstr(tsvalue(o2)));
+            }
+            break;
+        
+        default:
+            break;
+        }
+    }
+    
+}
+static void cmpUpvalues(const Proto* p1, const Proto *p2) {
+    for (size_t i = 0; i < p1->sizeupvalues; i++)
+    {
+        Upvaldesc* u1 = &p1->upvalues[i];
+        Upvaldesc* u2 = &p2->upvalues[i];
+
+        if (u1->idx != u2->idx) {
+            LLOGE("upvalues idx NOT match %d %d", u1->idx, u2->idx);
+        }
+        if (u1->instack != u2->instack) {
+            LLOGE("upvalues instack NOT match %d %d", u1->instack, u2->instack);
+        }
+        if (u1->name == NULL || u2->name == NULL) {
+            LLOGE("upvalues NULL name %d", i);
+        }
+        if (strcmp(getstr(u1->name), getstr(u2->name))) {
+            LLOGE("upvalues name NOT match %s %s", getstr(u1->name), getstr(u2->name));
+        }
+    }
+    
+}
+static void cmpProtos(const Proto* p1, const Proto *p2) {
+    LLOGD("protos %d", p1->sizep == p2->sizep);
+    if (p1->sizep == p2->sizep) {
+        for (size_t i = 0; i < p1->sizep; i++)
+        {
+            cmpProto(p1->p[i], p2->p[i]);
+        }
+    }
+}
+static void cmpDebug(const Proto* p1, const Proto *p2) {
+    LLOGD("linenumbers %d", memcmp(p1->lineinfo, p2->lineinfo, sizeof(int) * p1->sizelineinfo));
+    for (size_t i = 0; i < p1->sizelineinfo; i++)
+    {
+        /* code */
+    }
+    
+}
+
+static void cmpProto(const Proto* p1, const Proto *p2) {
+    if (p1 == NULL || p2 == NULL) {
+        LLOGD("p1/p2 is null");
+        return;
+    }
+    if (p1 == p2) {
+        LLOGD("p1 == p2, in pointer form");
+        return;
+    }
+
+    LLOGD("source %s %s %d", getstr(p1->source), getstr(p2->source), strcmp(getstr(p1->source), getstr(p2->source)));
+
+    // 对比几个属性
+    LLOGD("linedefined %d %d %d", p1->linedefined, p2->linedefined, p1->linedefined == p2->linedefined);
+    LLOGD("lastlinedefined %d %d %d", p1->lastlinedefined, p2->lastlinedefined, p1->lastlinedefined == p2->lastlinedefined);
+    LLOGD("is_vararg %d %d %d", p1->is_vararg, p2->is_vararg, p1->is_vararg == p2->is_vararg);
+    LLOGD("numparams %d %d %d", p1->numparams, p2->numparams, p1->numparams == p2->numparams);
+    LLOGD("sizecode %d %d %d", p1->sizecode, p2->sizecode, p1->sizecode == p2->sizecode);
+    LLOGD("sizek %d %d %d", p1->sizek, p2->sizek, p1->sizek == p2->sizek);
+    LLOGD("sizelineinfo %d %d %d", p1->sizelineinfo, p2->sizelineinfo, p1->sizelineinfo == p2->sizelineinfo);
+    LLOGD("sizelocvars %d %d %d", p1->sizelocvars, p2->sizelocvars, p1->sizelocvars == p2->sizelocvars);
+    LLOGD("sizeupvalues %d %d %d", p1->sizeupvalues, p2->sizeupvalues, p1->sizeupvalues == p2->sizeupvalues);
+
+    cmpCode(p1, p2);
+    cmpConstants(p1, p2);
+    cmpUpvalues(p1, p2);
+    cmpProtos(p1, p2);
+    cmpDebug(p1, p2);
+}
+
+void luat_luf_cmp(lua_State *L, const Proto* p1, const Proto *p2) {
+    if (p1 == NULL || p2 == NULL)
+        return;
+    cmpProto(p1, p2);
+}

+ 479 - 0
components/luf/luat_luf_dump.c

@@ -0,0 +1,479 @@
+/*
+** $Id: ldump.c,v 2.37.1.1 2017/04/19 17:20:42 roberto Exp $
+** save precompiled Lua chunks
+** See Copyright Notice in lua.h
+*/
+
+#include "luat_base.h"
+#include "luat_malloc.h"
+
+#define ldump_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <stddef.h>
+
+#include "lua.h"
+
+#include "lobject.h"
+#include "lstate.h"
+#include "lundump.h"
+#include "lstring.h"
+#include "lgc.h"
+
+#define LUAT_LOG_TAG "dump"
+#include "luat_log.h"
+
+#define white2gray(x)	resetbits(x->marked, WHITEBITS)
+#define black2gray(x)	resetbit(x->marked, BLACKBIT)
+
+// #define fslen(s) (sizeof(TString) + tsslen(s) + 1)
+static size_t fslen(TString *ts) {
+  size_t t = sizeof(TString) + tsslen(ts) + 1;
+  if (t % 0x04 != 0) {
+    t += (4 - (t % 0x04));
+  }
+  return t;
+}
+
+#define LUF_SIGNATURE "\x1cLUF"
+
+typedef struct {
+  lua_State *L;
+  lua_Writer writer;
+  void *data;
+  int strip;
+  int status;
+} DumpState;
+
+
+static void DumpString (const TString *s, DumpState *D);
+
+static size_t fd_offset = 0;
+static size_t str_offset = 0;
+
+typedef struct strpool
+{
+  TString* ts[256];
+  void* ptr[256];
+  void* next;
+}strpool_t;
+
+static strpool_t *spool = NULL;
+
+static void  spool_init(void) {
+  spool = luat_heap_malloc(sizeof(strpool_t));
+  memset(spool, 0, sizeof(strpool_t));
+}
+static void  spool_deinit(void) {
+  strpool_t *tmp = spool;
+  while (tmp != NULL) {
+    luat_heap_free(tmp);
+    tmp = (strpool_t *)tmp->next;
+  }
+}
+static void spool_dump(DumpState *D) {
+  strpool_t *tmp = spool;
+  while (tmp != NULL) {
+    for (size_t i = 0; i < 256; i++)
+    {
+      if (tmp->ts[i] == NULL)
+        return;
+      DumpString(tmp->ts[i], D);
+    }
+    tmp = (strpool_t *)tmp->next;
+  }
+}
+
+static TString* spool_add(TString* ts) {
+  if (ts == NULL)
+    return ts;
+  strpool_t *tmp = spool;
+  // strpool_t *next = NULL;
+  while (tmp != NULL) {
+    for (size_t i = 0; i < 256; i++)
+    {
+      if (tmp->ts[i] == NULL) {
+        //LLOGD("add string [%s]", getstr(ts));
+        tmp->ts[i] = ts;
+        tmp->ptr[i] = (void*)(str_offset);
+        str_offset += fslen(ts);
+
+        LLOGD("spool_add new %s %p", getstr(ts), tmp->ptr[i]);
+        return tmp->ptr[i];
+      }
+      if (!strcmp(getstr(ts), getstr(tmp->ts[i]))) {
+        LLOGD("spool_add match %s %p", getstr(ts), tmp->ptr[i]);
+        return tmp->ptr[i];
+      }
+    }
+    if (tmp->next == NULL)
+      break;
+    tmp = tmp->next;
+  }
+  tmp->next = luat_heap_malloc(sizeof(strpool_t));
+  memset(tmp->next, 0, sizeof(strpool_t));
+
+  tmp->ts[0] = ts;
+  tmp->ptr[0] = (void*)(str_offset);
+  str_offset += fslen(ts);
+  LLOGD("spool_add new %s %p", getstr(ts), tmp->ptr[0]);
+  return tmp->ptr[0];
+}
+
+size_t countProtoDumpSize(Proto *f) {
+  if (f == NULL)
+    return 0;
+  size_t count = 0;
+
+
+  /*
+  DumpInt(f->linedefined, D);
+  DumpInt(f->lastlinedefined, D);
+  DumpByte(f->numparams, D);
+  DumpByte(f->is_vararg, D);
+  DumpByte(f->maxstacksize, D);
+  DumpByte(f->source == NULL ? 0 : 1, D);
+  */
+  count += sizeof(int) * 2 + sizeof(lu_byte) * 4;
+
+  count += f->sizecode * sizeof(Instruction);
+  count += f->sizek * sizeof(TValue);
+  count += f->sizeupvalues * sizeof(Upvaldesc);
+  count += f->sizelineinfo * sizeof(int);
+  count += f->sizelocvars * sizeof(LocVar);
+
+  for (size_t i = 0; i < f->sizep; i++)
+  {
+    count += countProtoDumpSize(f->p[i]);
+  }
+
+  count += sizeof(int) * 6; // sizeX * 6
+
+  return count;
+}
+
+
+/*
+** All high-level dumps go through DumpVector; you can change it to
+** change the endianness of the result
+*/
+#define DumpVector(v,n,D)	DumpBlock(v,(n)*sizeof((v)[0]),D)
+
+#define DumpLiteral(s,D)	DumpBlock(s, sizeof(s) - sizeof(char), D)
+
+// static TString* AddMockString(TString* ts) {
+//   if (ts == NULL)
+//     return ts;
+//   TString* t = (TString*) (fd_offset + str_offset);
+//   str_offset += (sizeof(TString) + tsslen(ts) + 1);
+//   return t;
+// }
+
+static void DumpBlock (const void *b, size_t size, DumpState *D) {
+  if (D->status == 0 && size > 0) {
+    lua_unlock(D->L);
+    D->status = (*D->writer)(D->L, b, size, D->data);
+    lua_lock(D->L);
+  }
+
+  fd_offset +=  size;
+}
+
+
+#define DumpVar(x,D)		DumpVector(&x,1,D);
+
+
+static void DumpByte (int y, DumpState *D) {
+  lu_byte x = (lu_byte)y;
+  DumpVar(x, D);
+}
+
+
+static void DumpInt (int x, DumpState *D) {
+  DumpVar(x, D);
+}
+
+
+static void DumpNumber (lua_Number x, DumpState *D) {
+  DumpVar(x, D);
+}
+
+
+static void DumpInteger (lua_Integer x, DumpState *D) {
+  DumpVar(x, D);
+}
+
+
+static void DumpString (const TString *s, DumpState *D) {
+  // size_t size = 0;
+  // if (s == NULL) {
+  //   DumpByte(0, D);
+  //   return;
+  // }
+  // DumpByte(1, D);
+  TString ts;
+  memcpy(&ts, s, sizeof(TString));
+  ts.next = NULL;
+  if (ts.tt == LUA_TSHRSTR) {
+    ts.u.hnext = NULL;
+    // ts.u.lnglen = ts.shrlen;
+    // ts.hash = (getstr(s), ts.shrlen, 0);
+    ts.extra = 1;
+    // ts.tt = LUA_TLNGSTR;
+  }
+  white2gray((&ts));
+  //LLOGD("B>DumpString %d %d", fslen(s), fd_offset);
+  DumpBlock(&ts, sizeof(TString), D);
+  DumpBlock(getstr(s), tsslen(s)+1, D);
+  if ((tsslen(s) + 1) % 0x04 != 0) {
+    for (size_t i = 0; i < (4-((tsslen(s) + 1) % 0x04)); i++)
+    {
+      DumpByte(0, D);
+    }
+  }
+  //LLOGD("A>DumpString %d %d", fslen(s), fd_offset);
+}
+
+static void DumpCode (const Proto *f, DumpState *D) {
+  //DumpInt(f->sizecode, D);
+  DumpVector(f->code, f->sizecode, D);
+  for (size_t i = 0; i < f->sizecode; i++)
+  {
+    LLOGD("Code %02X -> %08X", i, f->code[i]);
+  }
+}
+
+
+static void DumpFunction(const Proto *f, TString *psource, DumpState *D);
+
+static void DumpConstants (const Proto *f, DumpState *D) {
+  int i;
+  int n = f->sizek;
+
+  //LLOGD("DumpConstants %d %d", n, n * sizeof(TValue));
+  //DumpInt(n, D);
+
+  //size_t init_offset = fd_offset + sizeof(TValue) * n + sizeof(int);
+  //size_t i_offset = init_offset;
+  TValue tmp;
+  TString* ts;
+  for (i = 0; i < n; i++) {
+    const TValue *o = &f->k[i];
+    switch (ttype(o)) {
+      case LUA_TSHRSTR:
+      case LUA_TLNGSTR:
+      // {
+        //memcpy(&tmp, o, sizeof(TValue));
+        ts = spool_add(tsvalue(o));
+        tmp.value_.gc = ts;
+        tmp.tt_ = ttype(o);
+        // tmp.tt_ = LUA_TLNGSTR;
+        DumpBlock(&tmp, sizeof(TValue), D);
+        break;
+      //   o = &tmp;
+      //  init_offset += fslen(tsvalue(o)) + 1;
+      //   //break;
+      // }
+      default:
+        DumpBlock(o, sizeof(TValue), D);
+        break;
+    }
+  }
+  //LLOGD("DumpConstants1 Strings len %d %d %d %d", init_offset, i_offset, fd_offset, init_offset - i_offset);
+  // DumpInt(init_offset - i_offset, D);
+  // for (i = 0; i < n; i++) {
+  //   const TValue *o = &f->k[i];
+  //   switch (ttype(o)) {
+  //     case LUA_TSHRSTR:
+  //     case LUA_TLNGSTR:
+  //     {
+  //       DumpString(tsvalue(o), D);
+  //       break;
+  //     }
+  //   }
+  // }
+  //LLOGD("DumpConstants2 Strings len %d %d %d %d", init_offset, i_offset, fd_offset, init_offset - i_offset);
+}
+
+
+static void DumpProtos (const Proto *f, DumpState *D) {
+  int i;
+  int n = f->sizep;
+  // DumpInt(n, D);
+  for (i = 0; i < n; i++)
+    DumpFunction(f->p[i], f->source, D);
+}
+
+
+static void DumpUpvalues (const Proto *f, DumpState *D) {
+  int i, n;
+  i = 0;
+  n = f->sizeupvalues;
+  // DumpInt(n, D);
+  //LLOGD("LoadUpvalues %d %d", n, sizeof(Upvaldesc) * n);
+  // size_t init_offset = fd_offset + sizeof(Upvaldesc) * f->sizeupvalues + sizeof(int);
+  // size_t i_offset = init_offset;
+  Upvaldesc desc;
+  for (i = 0; i < n; i++) {
+    desc.name = spool_add(f->upvalues[i].name);
+    desc.idx = f->upvalues[i].idx;
+    desc.instack = f->upvalues[i].instack;
+
+    DumpBlock(&desc, sizeof(Upvaldesc), D);
+
+    // if (f->upvalues[i].name) {
+    //   init_offset += fslen(f->upvalues[i].name) + 1;
+    //   //LLOGD("DumpUpvalues name %s %d %d", getstr(f->upvalues[i].name), i_offset, init_offset);
+    // }
+    // else {
+    //   init_offset += 1;
+    // }
+  }
+  
+  //LLOGD("DumpUpvalues Strings len %d %d %d %d", init_offset, i_offset, fd_offset, init_offset - i_offset);
+  // DumpInt(init_offset - i_offset, D);
+  // for (i = 0; i < n; i++) {
+  //   DumpString(f->upvalues[i].name, D);
+  // }
+}
+
+
+static void DumpDebug (const Proto *f, DumpState *D) {
+  int i, n;
+  n = f->sizelineinfo;
+  // DumpInt(n, D);
+  DumpVector(f->lineinfo, n, D);
+  n = f->sizelocvars;
+  // DumpInt(n, D);
+  // size_t init_offset = fd_offset + sizeof(LocVar) * f->sizelocvars + sizeof(int);
+  // size_t i_offset = init_offset;
+  LocVar lv;
+  for (i = 0; i < n; i++) {
+    lv.varname = spool_add(f->locvars[i].varname);
+    lv.startpc = f->locvars[i].startpc;
+    lv.endpc   = f->locvars[i].endpc;
+    DumpBlock(&lv, sizeof(LocVar), D);
+  }
+  //LLOGD("DumpDebug Strings len %d %d %d %d", init_offset, i_offset, fd_offset, init_offset - i_offset);
+  // DumpInt(init_offset - i_offset, D);
+  // for (i = 0; i < n; i++) {
+  //   DumpString(f->locvars[i].varname, D);
+  // }
+}
+
+
+static void DumpFunction (const Proto *f, TString *psource, DumpState *D) {
+  //DumpString(f->source, D);
+  // LLOGD("<<<<<<<<< DumpFunction");
+
+  DumpInt(f->linedefined, D);
+  DumpInt(f->lastlinedefined, D);
+  DumpByte(f->numparams, D);
+  DumpByte(f->is_vararg, D);
+  DumpByte(f->maxstacksize, D);
+  DumpByte(f->source == NULL ? 0 : 1, D);
+
+  LLOGD("linedefined %d", f->linedefined);
+  LLOGD("lastlinedefined %d", f->lastlinedefined);
+  LLOGD("numparams %d", f->numparams);
+  LLOGD("is_vararg %d", f->is_vararg);
+  LLOGD("maxstacksize %d", f->maxstacksize);
+
+  DumpInt(f->sizecode, D);
+  DumpInt(f->sizek, D);
+  DumpInt(f->sizeupvalues, D);
+  DumpInt(f->sizep, D);
+  DumpInt(f->sizelineinfo, D);
+  DumpInt(f->sizelocvars, D);
+
+  LLOGD("sizecode %d", f->sizecode);
+  LLOGD("sizek %d", f->sizek);
+  LLOGD("sizeupvalues %d", f->sizeupvalues);
+  LLOGD("sizep %d", f->sizep);
+  LLOGD("sizelineinfo %d", f->sizelineinfo);
+  LLOGD("sizelocvars %d", f->sizelocvars);
+
+  DumpCode(f, D);
+  DumpConstants(f, D);
+  DumpUpvalues(f, D);
+  DumpProtos(f, D);
+  DumpDebug(f, D);
+
+  // LLOGD(">>>>>>>>>>>>> DumpFunction");
+
+  //if (f->source)
+  //  DumpString((const TString*)f->source, D);
+}
+
+
+static void DumpHeader (DumpState *D) { // 15+12
+  DumpLiteral(LUF_SIGNATURE, D); // 4
+  DumpByte(LUAC_VERSION, D); // 1, 5
+  DumpByte(LUAC_FORMAT + 1, D); // 1, 6
+  DumpLiteral(LUAC_DATA, D); // 6, 12
+  DumpByte(sizeof(int), D); // 1, 13
+  DumpByte(sizeof(size_t), D); // 1, 14
+  DumpByte(sizeof(Instruction), D); // 1, 15
+  DumpByte(sizeof(lua_Integer), D); // 1, 16
+  DumpByte(sizeof(lua_Number), D); // 1, 17
+  DumpInteger(LUAC_INT, D); // 4, 21
+  DumpNumber(LUAC_NUM, D);  // 4, 25
+}
+
+
+/*
+** dump Lua function as precompiled chunk
+*/
+int luf_dump(lua_State *L, const Proto *f, lua_Writer w, void *data,
+              int strip, int ptroffset) {
+  DumpState D;
+  D.L = L;
+  D.writer = w;
+  D.data = data;
+  D.strip = strip;
+  D.status = 0;
+
+  fd_offset = ptroffset;
+  LLOGD("fd_offset %08X  ptroffset %08X", fd_offset, ptroffset);
+
+  // LLOGD("sizeof(Upvaldesc) %d", sizeof(Upvaldesc));
+  // LLOGD("sizeof(LocVar) %d", sizeof(LocVar));
+
+  DumpHeader(&D); // 25
+  DumpByte(f->sizeupvalues, &D); // 1, 26
+
+  size_t fill_offset = fd_offset % 0x04;
+  LLOGD("fix %d 0x00", fill_offset);
+  if (fill_offset != 0) {
+    for (size_t i = 0; i < (4 - fill_offset); i++)
+    {
+      DumpByte(0, &D);
+    }
+  }
+  
+
+  LLOGD("after header + sizeupvalues, fd_offset %08X", fd_offset);
+
+  size_t tcount = countProtoDumpSize(f);
+  spool_init();
+  str_offset = fd_offset + tcount + 4;
+  // LLOGD("sizeupvalues %d", f->sizeupvalues);
+  LLOGD("str_offset %08X", str_offset);
+  LLOGD("tcount %08X  ptroffset %08X", tcount, ptroffset);
+  DumpInt(f->source == NULL ? 0 : str_offset, &D);
+  TString* tmp = spool_add(f->source);
+  LLOGD("source tmp %p", tmp);
+  DumpFunction(f, NULL, &D);
+  // LLOGD("after DumpFunction <");
+  spool_dump(&D);
+  // LLOGD("spool_dump <");
+  spool_deinit();
+  // LLOGD("spool_deinit <");
+  LLOGD("LClosure %d Proto %d Upvaldesc %d LocVal %d", 
+      sizeof(LClosure), sizeof(Proto), sizeof(Upvaldesc), sizeof(LocVar));
+  return D.status;
+}
+

+ 471 - 0
components/luf/luat_luf_undump.c

@@ -0,0 +1,471 @@
+/*
+** $Id: lundump.c,v 2.44.1.1 2017/04/19 17:20:42 roberto Exp $
+** load precompiled Lua chunks
+** See Copyright Notice in lua.h
+*/
+
+#define lundump_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <string.h>
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstring.h"
+#include "lundump.h"
+#include "lzio.h"
+#include "ltable.h"
+
+#include "luat_base.h"
+#include "luat_fs.h"
+
+#define LUAT_LOG_TAG "undump"
+#include "luat_log.h"
+
+#define LUF_SIGNATURE "\x1cLUF"
+
+
+#if !defined(luai_verifycode)
+#define luai_verifycode(L,b,f)  /* empty */
+#endif
+
+typedef struct {
+  lua_State *L;
+  ZIO *Z;
+  const char *name;
+} LoadState;
+
+static void dumpHex(const char* tag, void* ptr, size_t len) {
+  uint8_t* c = (uint8_t*)ptr;
+  for (size_t i = 0; i < len / 8; i++)
+  {
+    LLOGD("%s %p %02X %02X %02X %02X %02X %02X %02X %02X", tag, &c[i*8], c[i*8], c[i*8+1], c[i*8+2], c[i*8+3],
+                                                                         c[i*8+4], c[i*8+5], c[i*8+6], c[i*8+7]);
+  }
+}
+
+
+static l_noret error(LoadState *S, const char *why) {
+  luaO_pushfstring(S->L, "luf %s: %s precompiled chunk", S->name, why);
+  luaD_throw(S->L, LUA_ERRSYNTAX);
+}
+
+
+/*
+** All high-level loads go through LoadVector; you can change it to
+** adapt to the endianness of the input
+*/
+#define LoadVector(S,b,n)	LoadBlock(S,b,(n)*sizeof((b)[0]))
+
+static void LoadBlock (LoadState *S, void *b, size_t size) {
+  if (luaZ_read(S->Z, b, size) != 0)
+    error(S, "truncated");
+}
+
+static void* DistBlock (LoadState *S, size_t size) {
+  uint8_t b = 0;
+  const char* p = S->Z->p;
+  for (size_t i = 0; i < size; i++)
+  {
+    if (luaZ_read(S->Z, &b, 1) != 0)
+      error(S, "truncated");
+  }
+  return (void*)p;
+}
+
+
+#define LoadVar(S,x)		LoadVector(S,&x,1)
+
+
+static lu_byte LoadByte (LoadState *S) {
+  lu_byte x;
+  LoadVar(S, x);
+  return x;
+}
+
+
+static int LoadInt (LoadState *S) {
+  int x;
+  LoadVar(S, x);
+  return x;
+}
+
+
+static lua_Number LoadNumber (LoadState *S) {
+  lua_Number x;
+  LoadVar(S, x);
+  return x;
+}
+
+
+static lua_Integer LoadInteger (LoadState *S) {
+  lua_Integer x;
+  LoadVar(S, x);
+  return x;
+}
+
+
+// static TString *LoadString (LoadState *S, Proto *p) {
+//   lu_byte t = LoadByte(S);
+//   if (t == 0)
+//     return NULL;
+//   TString * ts = (TString*)S->Z->p;
+//   // LLOGD("LoadString >> %d %p", tsslen(ts), ts);
+//   DistBlock(S, sizeof(TString) + tsslen(ts) + 1);
+//   // LLOGD("LoadString >> %s", getstr(ts));
+//   return ts;
+// }
+
+static void LoadCode (LoadState *S, Proto *f) {
+  // int n = LoadInt(S);
+  // LLOGD("LoadCode %d %d", n, sizeof(Instruction) * n);
+  // f->sizecode = n;
+  // f->code = luat_heap_malloc(sizeof(Instruction) * f->sizecode);
+  // memcpy(f->code, S->Z->p, sizeof(Instruction) * f->sizecode);
+  f->code = DistBlock(S, sizeof(Instruction) * f->sizecode);
+  //f->code = ((uint8_t*)f->code) + 2;
+  LLOGD("f->code %p", f->code);
+  for (size_t i = 0; i < f->sizecode; i++)
+  {
+    LLOGD("Code %02X -> %08X", i, f->code[i]);
+  }
+  
+}
+
+
+static void LoadFunction(LoadState *S, Proto *f, TString *psource);
+
+
+static void LoadConstants (LoadState *S, Proto *f) {
+  // int i;
+  // int n = LoadInt(S);
+  // LLOGD("LoadConstants %d %d", n, sizeof(TValue) * n);
+  // f->sizek = n;
+  // 指向常数数组
+  f->k = DistBlock(S, sizeof(TValue) * f->sizek);
+  // 跳过字符串段
+  for (size_t i = 0; i < f->sizek; i++)
+  {
+    TValue *t = &f->k[i];
+    switch (ttype(t))
+    {
+    case LUA_TSHRSTR:
+    case LUA_TLNGSTR:
+      LLOGD("const string %p %s", tsvalue(t), getstr(tsvalue(t)));
+      break;
+    default:
+      break;
+    }
+  }
+  
+
+  
+  
+  // LLOGD("1>>LoadConstants %02X %02X %02X %02X", *(S->Z->p), *(S->Z->p + 1), *(S->Z->p + 2), *(S->Z->p + 3));
+  // n = LoadInt(S);
+  // LLOGD("LoadConstants skip Strings %d", n);
+  // DistBlock(S, sizeof(char) * n);
+
+  // LLOGD("2>>LoadConstants %02X %02X %02X %02X", *(S->Z->p), *(S->Z->p + 1), *(S->Z->p + 2), *(S->Z->p + 3));
+}
+
+
+static void LoadProtos (LoadState *S, Proto *f) {
+  int i;
+  // int n = LoadInt(S);
+  f->p = luaM_newvector(S->L, f->sizep, Proto *);
+  // f->sizep = n;
+  for (i = 0; i < f->sizep; i++)
+    f->p[i] = NULL;
+  for (i = 0; i < f->sizep; i++) {
+    f->p[i] = luaF_newproto(S->L);
+    luaC_objbarrier(S->L, f, f->p[i]);
+    LoadFunction(S, f->p[i], f->source);
+  }
+  // LLOGD("LoadProtos %d %d", n, sizeof(Proto *) * n);
+}
+
+
+static void LoadUpvalues (LoadState *S, Proto *f) {
+  int i, n;
+  // n = LoadInt(S);
+  // f->sizeupvalues = n;
+  // LLOGD("LoadUpvalues %d %d", n, sizeof(Upvaldesc) * n);
+  f->upvalues = DistBlock(S, sizeof(Upvaldesc) * f->sizeupvalues);
+  // char* tmp = luaM_newvector(S->L, n, Upvaldesc);
+  // memcpy(tmp, f->upvalues, sizeof(Upvaldesc) * n);
+  // f->upvalues = tmp;
+  // 跳过字符串段
+  // n = LoadInt(S);
+  // LLOGD("LoadUpvalues skip Strings %d", n);
+  // DistBlock(S, sizeof(char) * n);
+}
+
+
+static void LoadDebug (LoadState *S, Proto *f) {
+  int i, n;
+  
+  // n = LoadInt(S);
+  // f->sizelineinfo = n;
+  // LLOGD("LoadDebug sizelineinfo %d %d", n, sizeof(int) * n);
+  f->lineinfo = DistBlock(S, sizeof(int) * f->sizelineinfo);
+  
+  // n = LoadInt(S);
+  // f->sizelocvars = n;
+  // LLOGD("LoadDebug sizelocvars %d %d", n, sizeof(LocVar) * n);
+  f->locvars = DistBlock(S, sizeof(LocVar) * f->sizelocvars);
+
+  // n = LoadInt(S);
+  // DistBlock(S, sizeof(char) * n);
+}
+
+
+static void LoadFunction (LoadState *S, Proto *f, TString *psource) {
+  //LLOGD(">> %02X %02X %02X %02X", *(S->Z->p), *(S->Z->p + 1), *(S->Z->p + 2), *(S->Z->p + 3));
+  f->source = psource;  /* reuse parent's source */
+
+  if (f->source)
+    LLOGI("%s %d source %s", __FILE__, __LINE__, getstr(f->source));
+  else
+    LLOGD("no source ?");
+
+  f->linedefined = LoadInt(S);
+  f->lastlinedefined = LoadInt(S);
+  f->numparams = LoadByte(S);
+  f->is_vararg = LoadByte(S);
+  f->maxstacksize = LoadByte(S);
+  LoadByte(S); // f->source != NULL ?
+
+  // LLOGD("linedefined %d", f->linedefined);
+  // LLOGD("lastlinedefined %d", f->lastlinedefined);
+  // LLOGD("numparams %d", f->numparams);
+  // LLOGD("is_vararg %d", f->is_vararg);
+  // LLOGD("maxstacksize %d", f->maxstacksize);
+
+  f->sizecode = LoadInt(S);
+  f->sizek = LoadInt(S);
+  f->sizeupvalues = LoadInt(S);
+  f->sizep = LoadInt(S);
+  f->sizelineinfo = LoadInt(S);
+  f->sizelocvars = LoadInt(S);
+
+  // LLOGD("sizecode %d", f->sizecode);
+  // LLOGD("sizek %d", f->sizek);
+  // LLOGD("sizeupvalues %d", f->sizeupvalues);
+  // LLOGD("sizep %d", f->sizep);
+  // LLOGD("sizelineinfo %d", f->sizelineinfo);
+  // LLOGD("sizelocvars %d", f->sizelocvars);
+
+  LoadCode(S, f);
+  LoadConstants(S, f);
+  LoadUpvalues(S, f);
+  LoadProtos(S, f);
+  LoadDebug(S, f);
+
+  // for (size_t i = 0; i < f->sizelineinfo; i++)
+  // {
+  //   LLOGD("lineinfo %d %p", f->lineinfo[i], &f->lineinfo[i]);
+  // }
+  // for (size_t i = 0; i < f->sizek; i++)
+  // {
+  //   switch (f->k[i].tt_)
+  //   {
+  //   case LUA_TSHRSTR:
+  //   case LUA_TLNGSTR:
+  //     // LLOGD("const string %s", getstr(tsvalue(&f->k[i])));
+  //     LLOGD("const string %s", getstr(tsvalue(&f->k[i])));
+  //     break;
+  //   }
+  // }
+  // for (size_t i = 0; i < f->sizelocvars; i++)
+  // {
+  //   LLOGD("locval string %s", getstr(f->locvars[i].varname));
+  // }
+  LLOGD("f->upvalues %p %08X", f->upvalues, (uint32_t)f->upvalues);
+  for (size_t i = 0; i < f->sizeupvalues; i++)
+  {
+    // LLOGD("upval string %s", getstr(f->upvalues[i].name));
+    LLOGD("upval string %p", f->upvalues[i].name);
+  }
+}
+
+
+static void checkliteral (LoadState *S, const char *s, const char *msg) {
+  char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */
+  size_t len = strlen(s);
+  // buff[len] = 0;
+  LoadVector(S, buff, len);
+  // LLOGD("buff>> %02X %02X %02X %02X", buff[0], buff[1], buff[2], buff[3]);
+  // LLOGD("s>>    %02X %02X %02X %02X", s[0], s[1], s[2], s[3]);
+  if (memcmp(s, buff, len) != 0)
+    error(S, msg);
+}
+
+
+static void fchecksize (LoadState *S, size_t size, const char *tname) {
+  if (LoadByte(S) != size)
+    error(S, luaO_pushfstring(S->L, "%s size mismatch in", tname));
+}
+
+
+#define checksize(S,t)	fchecksize(S,sizeof(t),#t)
+
+static void checkHeader (LoadState *S) {
+  checkliteral(S, LUF_SIGNATURE + 1, "not a");  /* 1st char already checked */
+  if (LoadByte(S) != LUAC_VERSION)
+    error(S, "version mismatch in");
+  if (LoadByte(S) != 1)
+    error(S, "format mismatch in");
+  checkliteral(S, LUAC_DATA, "corrupted");
+  checksize(S, int);
+  checksize(S, size_t);
+  checksize(S, Instruction);
+  checksize(S, lua_Integer);
+  checksize(S, lua_Number);
+  if (LoadInteger(S) != LUAC_INT)
+    error(S, "endianness mismatch in");
+  if (LoadNumber(S) != LUAC_NUM)
+    error(S, "float format mismatch in");
+}
+
+extern void luat_os_print_heapinfo(const char* tag);
+
+typedef struct LoadS {
+  const char *s;
+  size_t size;
+} LoadS;
+
+
+static const char *getS (lua_State *L, void *ud, size_t *size) {
+  LoadS *ls = (LoadS *)ud;
+  (void)L;  /* not used */
+  if (ls->size == 0) return NULL;
+  *size = ls->size;
+  ls->size = 0;
+  return ls->s;
+}
+
+/*
+** load precompiled chunk
+*/
+LClosure *luat_luf_undump(lua_State *L, const char* ptr, size_t len, const char *name) {
+  LoadState S;
+  LClosure *cl;
+
+  ZIO z;
+  LoadS ls;
+  ls.s = ptr;
+  ls.size = len;
+  luaZ_init(L, &z, getS, &ls);
+
+  zgetc(&z);
+
+  S.name = name;
+  S.L = L;
+  S.Z = &z;
+  checkHeader(&S);
+  cl = luaF_newLclosure(L, LoadByte(&S));
+  setclLvalue(L, L->top, cl);
+  luaD_inctop(L);
+  cl->p = luaF_newproto(L);
+  // LLOGD("sizeupvalues %d", cl->nupvalues);
+  luaC_objbarrier(L, cl, cl->p); // add by wendal, refer: https://github.com/lua/lua/commit/f5eb809d3f1da13683cd02184042e67228206205
+  size_t s = LoadInt(&S);
+  LoadFunction(&S, cl->p, (TString*)s);
+  lua_assert(cl->nupvalues == cl->p->sizeupvalues);
+  luai_verifycode(L, buff, cl->p);
+  luaF_initupvals(L, cl);
+
+  //-----------------
+  // from lua_load
+  LClosure *f = cl;
+    if (f->nupvalues >= 1) {  /* does it have an upvalue? */
+      /* get global table from registry */
+      Table *reg = hvalue(&G(L)->l_registry);
+      const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
+      /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
+      setobj(L, f->upvals[0]->v, gt);
+      luaC_upvalbarrier(L, f->upvals[0]);
+    }
+  //-----------------
+  //sizeof(LClosure) + sizeof(Proto) + sizeof(UpVal);
+  return cl;
+}
+
+#ifndef LoadF
+typedef struct LoadF {
+  int n;  /* number of pre-read characters */
+  FILE *f;  /* file being read */
+  char buff[BUFSIZ];  /* area for reading file */
+} LoadF;
+#endif
+
+LClosure *luat_luf_undump2(lua_State *L, ZIO *Z, const char *name) {
+  LoadState S;
+  LClosure *cl;
+
+  S.name = name;
+  S.L = L;
+  S.Z = Z;
+
+#ifdef LUAT_USE_FS_VFS
+  LLOGD("try mmap");
+  char* ptr = (char*)luat_vfs_mmap(((LoadF*)Z->data)->f);
+  if (ptr != NULL) {
+    LLOGD("found mmap %p", ptr);
+    ZIO z;
+    LoadS ls;
+    ls.s = ptr;
+    ls.size = 64*1024;
+    luaZ_init(L, &z, getS, &ls);
+    zgetc(&z);
+    S.Z = &z;
+    // LLOGD(">> %02X %02X %02X %02X", S.Z->p[0], S.Z->p[1], S.Z->p[2], S.Z->p[3]);
+    // LLOGD(">> %02X %02X %02X %02X", S.Z->p[4], S.Z->p[5], S.Z->p[6], S.Z->p[7]);
+    // LLOGD(">> %02X %02X %02X %02X", S.Z->p[8], S.Z->p[9], S.Z->p[10], S.Z->p[11]);
+  }
+#endif
+
+  // LLOGD("LClosure %d Proto %d Upvaldesc %d LocVal %d", 
+  //     sizeof(LClosure), sizeof(Proto), sizeof(Upvaldesc), sizeof(LocVar));
+
+  checkHeader(&S);
+  cl = luaF_newLclosure(L, LoadByte(&S));
+  // 有几个对齐用的字节
+  size_t fd_offset = (size_t)S.Z->p;
+  if (fd_offset % 0x04 != 0) {
+    LLOGD("skip %d 0x00", fd_offset % 0x04);
+    for (size_t i = 0; i < (4 - (fd_offset % 0x04)); i++)
+    {
+      LoadByte(&S);
+    }
+  }
+  //
+  setclLvalue(L, L->top, cl);
+  luaD_inctop(L);
+  cl->p = luaF_newproto(L);
+  luaC_objbarrier(L, cl, cl->p); // add by wendal, refer: https://github.com/lua/lua/commit/f5eb809d3f1da13683cd02184042e67228206205
+  size_t s = LoadInt(&S);
+  LoadFunction(&S, cl->p, (TString*)s);
+  lua_assert(cl->nupvalues == cl->p->sizeupvalues);
+  luai_verifycode(L, buff, cl->p);
+
+  // dumpHex("& upvalues", &cl->p->upvalues[0], 8);
+  // dumpHex("& upvalues[0].name", &cl->p->upvalues[0].name, 8);
+  // dumpHex("> upvalues[0].name", cl->p->upvalues[0].name, 8);
+  // LLOGD("> getstr(upvalues[0].name) %p", getstr(cl->p->upvalues[0].name));
+  // LLOGD("> getstr(upvalues[0].name) %s", getstr(cl->p->upvalues[0].name));
+  // dumpHex("head",     (char*)0x080E0000, 8);
+  //dumpHex("lineinfo", cl->p->lineinfo, 8);
+  //LLOGD("lineinfo %d %d", cl->p->lineinfo[0], cl->p->lineinfo[1]);
+
+  return cl;
+}

+ 6 - 0
lua/src/ldo.c

@@ -762,6 +762,7 @@ static void checkmode (lua_State *L, const char *mode, const char *x) {
   }
 }
 
+LClosure *luat_luf_undump2(lua_State *L, ZIO *Z, const char *name);
 
 static void f_parser (lua_State *L, void *ud) {
   LClosure *cl;
@@ -771,6 +772,11 @@ static void f_parser (lua_State *L, void *ud) {
     checkmode(L, p->mode, "binary");
     cl = luaU_undump(L, p->z, p->name);
   }
+#ifdef LUAT_USE_LUF
+  else if (c == 0x1C) {
+    cl = luat_luf_undump2(L, p->z, p->name);
+  }
+#endif
   else {
     checkmode(L, p->mode, "text");
     cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);

+ 21 - 19
lua/src/lstrlib.c

@@ -178,26 +178,26 @@ static int str_char (lua_State *L) {
   return 1;
 }
 
+#if defined(LUA_USE_LINUX) || defined(LUA_USE_WINDOWS) || defined(LUA_USE_MACOSX)
+static int writer (lua_State *L, const void *b, size_t size, void *B) {
+  (void)L;
+  luaL_addlstring((luaL_Buffer *) B, (const char *)b, size);
+  return 0;
+}
 
-// static int writer (lua_State *L, const void *b, size_t size, void *B) {
-//   (void)L;
-//   luaL_addlstring((luaL_Buffer *) B, (const char *)b, size);
-//   return 0;
-// }
-
-
-// static int str_dump (lua_State *L) {
-//   luaL_Buffer b;
-//   int strip = lua_toboolean(L, 2);
-//   luaL_checktype(L, 1, LUA_TFUNCTION);
-//   lua_settop(L, 1);
-//   luaL_buffinit(L,&b);
-//   if (lua_dump(L, writer, &b, strip) != 0)
-//     return luaL_error(L, "unable to dump given function");
-//   luaL_pushresult(&b);
-//   return 1;
-// }
 
+static int str_dump (lua_State *L) {
+  luaL_Buffer b;
+  int strip = lua_toboolean(L, 2);
+  luaL_checktype(L, 1, LUA_TFUNCTION);
+  lua_settop(L, 1);
+  luaL_buffinit(L,&b);
+  if (lua_dump(L, writer, &b, strip) != 0)
+    return luaL_error(L, "unable to dump given function");
+  luaL_pushresult(&b);
+  return 1;
+}
+#endif
 
 
 /*
@@ -1549,7 +1549,9 @@ int l_str_fromBase64(lua_State *L);
 static const rotable_Reg strlib[] = {
   {"byte", str_byte, 0},
   {"char", str_char, 0},
-  //{"dump", str_dump, 0},
+#if defined(LUA_USE_LINUX) || defined(LUA_USE_WINDOWS) || defined(LUA_USE_MACOSX)
+  {"dump", str_dump, 0},
+#endif
   {"find", str_find, 0},
   {"format", str_format, 0},
   {"gmatch", gmatch, 0},

+ 2 - 0
luat/include/luat_libs.h

@@ -105,4 +105,6 @@ LUAMOD_API int luaopen_otp( lua_State *L );
 LUAMOD_API int luaopen_mlx90640( lua_State *L );
 LUAMOD_API int luaopen_zlib( lua_State *L );
 
+LUAMOD_API int luaopen_luf( lua_State *L );
+
 #endif