-- file.lua —— 符合 HMI 内存安全规范的文件操作模块
-- ?? 严禁返回完整文件内容！所有操作必须流式处理！

_ENCRYPT_ = 0

file = {}
local CHUNK_SIZE = 2048  -- 与平台限制一致

-- 文件模式（与 HMI API 一致）
file.mode = {
    read   = 0,  -- 只读
    create = 1,  -- 覆盖写
    append = 2   -- 追加写
}

-- 安全字符串分割（plain=true）
function my_split(str, sep)
    if not str or #str == 0 then return {} end
    local t, last = {}, 0
    local s, e = string.find(str, sep, 1, true)
    while s do
        table.insert(t, string.sub(str, last + 1, s - 1))
        last = e
        s, e = string.find(str, sep, last + 1, true)
    end
    if last < #str then table.insert(t, string.sub(str, last + 1)) end
    return t
end

-- 检查文件是否存在
function file.exists(filepath)
    if type(filepath) ~= "string" or #filepath == 0 then return false end
    local ok = file_open(filepath, file.mode.read)
    if ok then file_close() end
    return ok
end

-- 【安全】流式读取文件（核心接口）
-- @filepath: 文件路径
-- @on_chunk: 回调函数(chunk_table, offset, is_last)
--   - chunk_table: 当前块字节数组 (1~2048 字节)
--   - offset: 当前块起始偏移
--   - is_last: 是否最后一块
-- @return: true 成功, false 失败
function file.read_stream(filepath, on_chunk)
    if not file.exists(filepath) then return false end
    
    local ok = file_open(filepath, file.mode.read)
    if not ok then return false end
    
    local size = file_size()
    if size == 0 then
        file_close()
        return true
    end
    
    local blocks = math.ceil(size / CHUNK_SIZE)
    for i = 1, blocks do
        local offset = (i - 1) * CHUNK_SIZE
        if not file_seek(offset) then break end
        
        local count = (i == blocks) and (size % CHUNK_SIZE ~= 0 and size % CHUNK_SIZE or CHUNK_SIZE) or CHUNK_SIZE
        local chunk = file_read(count)
        
        if not chunk or #chunk == 0 then break end
        
        local is_last = (i == blocks)
        if not on_chunk(chunk, offset, is_last) then
            -- 回调返回 false 可提前终止
            break
        end
        feed_dog()
    end
    
    file_close()
    return true
end

-- 【安全】写入文件（仅接受小块数据）
-- @filepath: 目标路径
-- @data: string 或 byte table (≤2048 字节)
-- @mode: file.mode.create / append
-- @return: true 成功, false 失败
function file.write_chunk(filepath, data, mode)

    if mode ~= file.mode.create and mode ~= file.mode.append then return false end

    local is_str = (type(data) == "string")
    local len = is_str and string.len(data) or #data

    if len == 0 then return true end
    if len > CHUNK_SIZE 
    then
        print("ERROR: write_chunk data too large (>2048)")
        return false
    end

    local ok = file_open(filepath, mode)
    if not ok then return false end

    -- 追加模式需定位到末尾
    if mode == file.mode.append 
    then
        local size = file_size()
        if not file_seek(size) 
        then
            file_close()
            return false
        end
    end
    
    -- 构建字节数组
    local buf = {}
    if is_str 
    then
        for i = 1, len do buf[i] = string.byte(data, i) end
    else
        for i = 1, len do buf[i] = data[i] end
    end
    
    local ret = file_write(buf)
    file_close()
    return ret
end

-- 【辅助】安全读取小文件（仅用于 ≤4KB 配置文件）
-- @as_string: true→字符串, false→字节数组
-- @max_size: 最大允许大小（默认 4096）
function file.read_small(as_string, filepath, max_size)
    max_size = max_size or 4096
    if not file.exists(filepath) then return nil end
    
    local ok = file_open(filepath, file.mode.read)
    if not ok then return nil end
    
    local size = file_size()
    if size > max_size then
        file_close()
        return nil  -- 拒绝大文件
    end
    
    local chunk = file_read(size)
    file_close()
    
    if not chunk then return nil end
    
    if as_string then
        local str = ""
        for _, b in ipairs(chunk) do
            str = str .. string.char(b)
        end
        return str
    else
        return chunk
    end
end