]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - builtin/common/serialize.lua
Lint is bitch
[dragonfireclient.git] / builtin / common / serialize.lua
index 90b8b2ad6a6e40ab4a695e36e97f484b4579fd15..300b394c63166fa2086d2263be989c0b502d031b 100644 (file)
@@ -104,7 +104,7 @@ function core.serialize(x)
                local i = local_index
                local_index = local_index + 1
                var = "_["..i.."]"
-               table.insert(local_defs, var.." = "..val)
+               local_defs[#local_defs + 1] = var.." = "..val
                dumped[x] = var
                return var
        end
@@ -120,31 +120,23 @@ function core.serialize(x)
                elseif tp == "function" then
                        return string.format("loadstring(%q)", string.dump(x))
                elseif tp == "number"   then
-                       -- Serialize integers with string.format to prevent
-                       -- scientific notation, which doesn't preserve
-                       -- precision and breaks things like node position
-                       -- hashes.  Serialize floats normally.
-                       if math.floor(x) == x then
-                               return string.format("%d", x)
-                       else
-                               return tostring(x)
-                       end
+                       -- Serialize numbers reversibly with string.format
+                       return string.format("%.17g", x)
                elseif tp == "table" then
                        local vals = {}
                        local idx_dumped = {}
                        local np = nest_points[x]
                        for i, v in ipairs(x) do
                                if not np or not np[i] then
-                                       table.insert(vals, dump_or_ref_val(v))
+                                       vals[#vals + 1] = dump_or_ref_val(v)
                                end
                                idx_dumped[i] = true
                        end
                        for k, v in pairs(x) do
                                if (not np or not np[k]) and
                                                not idx_dumped[k] then
-                                       table.insert(vals,
-                                               "["..dump_or_ref_val(k).."] = "
-                                               ..dump_or_ref_val(v))
+                                       vals[#vals + 1] = "["..dump_or_ref_val(k).."] = "
+                                               ..dump_or_ref_val(v)
                                end
                        end
                        return "{"..table.concat(vals, ", ").."}"
@@ -156,9 +148,9 @@ function core.serialize(x)
        local function dump_nest_points()
                for parent, vals in pairs(nest_points) do
                        for k, v in pairs(vals) do
-                               table.insert(local_defs, dump_or_ref_val(parent)
+                               local_defs[#local_defs + 1] = dump_or_ref_val(parent)
                                        .."["..dump_or_ref_val(k).."] = "
-                                       ..dump_or_ref_val(v))
+                                       ..dump_or_ref_val(v)
                        end
                end
        end
@@ -178,21 +170,31 @@ end
 
 -- Deserialization
 
-local env = {
-       loadstring = loadstring,
-}
+local function safe_loadstring(...)
+       local func, err = loadstring(...)
+       if func then
+               setfenv(func, {})
+               return func
+       end
+       return nil, err
+end
 
-local safe_env = {
-       loadstring = function() end,
-}
+local function dummy_func() end
 
 function core.deserialize(str, safe)
+       if type(str) ~= "string" then
+               return nil, "Cannot deserialize type '"..type(str)
+                       .."'. Argument must be a string."
+       end
        if str:byte(1) == 0x1B then
                return nil, "Bytecode prohibited"
        end
        local f, err = loadstring(str)
        if not f then return nil, err end
-       setfenv(f, safe and safe_env or env)
+
+       -- The environment is recreated every time so deseralized code cannot
+       -- pollute it with permanent references.
+       setfenv(f, {loadstring = safe and dummy_func or safe_loadstring})
 
        local good, data = pcall(f)
        if good then
@@ -201,18 +203,3 @@ function core.deserialize(str, safe)
                return nil, data
        end
 end
-
-
--- Unit tests
-local test_in = {cat={sound="nyan", speed=400}, dog={sound="woof"}}
-local test_out = core.deserialize(core.serialize(test_in))
-
-assert(test_in.cat.sound == test_out.cat.sound)
-assert(test_in.cat.speed == test_out.cat.speed)
-assert(test_in.dog.sound == test_out.dog.sound)
-
-test_in = {escape_chars="\n\r\t\v\\\"\'", non_european="θשׁ٩∂"}
-test_out = core.deserialize(core.serialize(test_in))
-assert(test_in.escape_chars == test_out.escape_chars)
-assert(test_in.non_european == test_out.non_european)
-