lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Hi,

	I couldn't hold it ;)

Please note that the 'decodeJSON' is not very optimal. I had to use some 'string.gsub' to translate from JSON(JS) to Lua, but it actually works :)

The only drawback I found so far, was with holes (nil's) inside arrays/lists.

PS: No, I don't use and have never used JSON nor CGILua (but I do use a patched Xavante).

--- BEGIN OF CODE ---

-- This code uses the same license as Lua 5

local gsub,sub,find,format = string.gsub,string.sub,string.find,string.format
local replacechars = {["["] = '{'; ["]"] = '}'; [":"] = '='}

function decodeJSON(buffer)
    assert(type(buffer)=='string')
    local strings,stringi = {},1

    -- remove quoted text
    buffer = gsub(buffer, '(".-[^\\]?")',
                function(str)
                    if strings[str] then return strings[str] end
                    local i      = stringi
                    stringi      = stringi+1
                    strings[str] = '%'..i
                    strings[i]   = str
                    return '%'..i
                end)

    -- remove long comments
    buffer = gsub(buffer, '%/%*(.-)%*%/' , '')

    -- remove line comments
    buffer = gsub(buffer, '//(.-)\n'     , '')

    -- replace the characters that are different between JS and Lua
buffer = gsub(buffer, '[%[%]%:]' , function(c) return replacechars[c] end)

    -- remove spaces (Have no use, but I like tight things ;))
    -- buffer = gsub(buffer, '%s+'          , '')

    -- reinsert quotes
    buffer = gsub(buffer, '%%(%d+)()'    ,
                function(i,stop)
                    local s = strings[tonumber(i)]
                    -- check if the string is used as a key or as value
                    if find(buffer, '^%s*%=', stop) then return '['..s..']'
                    else                                 return s
                    end
                end)

    -- "local null" just avoids global lookup.
    local f, err = loadstring('local null; return ' .. buffer)

    if not f then
        return nil,err
    else
        -- Avoid a bit some attacks
        setfenv(f,{})
        return f()
    end
end

local function encodevalue(value)
    local tv = type(value)
        if tv=='string'  then return format('%q',value)
    elseif tv=='number'  then return tostring(value)
    elseif tv=='table'   then return encodeJSON(value)
    elseif tv=='boolean' then return value and 'true' or 'false'
    elseif tv=='nil'     then return 'null'
    else error('Invalid value to encode: '..value)
    end
end

function encodeJSON(value)
    assert(type(value)=='table')
    local s = ''
    local obj = false

    for key in pairs(value) do
        local tk = type(key)
-- Uncomment this line if you only want string keys for Object (I don't
        -- really know if JSON allow anything else than string...)
-- assert(tk=='number' or tk=='string', 'Invalid table key for encoding')
        if tk~='number' then
            obj=true
            break
        end
    end

    if obj then
        local first=true
        for key,val in pairs(value) do
s=(first and '{' or s..',')..format('%q:%s',key,encodevalue(val))
            first=false
        end
        s=s..'}'
    else
        local first=true
        for i,val in ipairs(value) do
            s=(first and '[' or s..',')..encodevalue(val)
            first=false
        end
        s=s..']'
    end
    return s
end

--- END OF CODE ---

Hope it helps,
	Me.