Advertisement
osmarks

JSON-Fixed

Oct 3rd, 2018
212
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ------------------------------------------------------------------ utils
  2. local controls = {["\n"]="\\n", ["\r"]="\\r", ["\t"]="\\t", ["\b"]="\\b", ["\f"]="\\f", ["\""]="\\\"", ["\\"]="\\\\", ["/"] = "\\/"}
  3. -- Encode stuff with fancy Unicode sequences. Kind of wrong. Oh well.
  4. for i = 0, 31 do
  5.     controls[string.char(i)] = string.format("\\u%04x", i)
  6. end
  7.  
  8. local function isArray(t)
  9.     local max = 0
  10.     for k,v in pairs(t) do
  11.         if type(k) ~= "number" then
  12.             return false
  13.         elseif k > max then
  14.             max = k
  15.         end
  16.     end
  17.     return max == #t
  18. end
  19.  
  20. local whites = {['\n']=true; ['\r']=true; ['\t']=true; [' ']=true; [',']=true; [':']=true}
  21. function removeWhite(str)
  22.     while whites[str:sub(1, 1)] do
  23.         str = str:sub(2)
  24.     end
  25.     return str
  26. end
  27.  
  28. ------------------------------------------------------------------ encoding
  29.  
  30. local function encodeCommon(val, pretty, tabLevel, tTracking)
  31.     local str = ""
  32.  
  33.     -- Tabbing util
  34.     local function tab(s)
  35.         str = str .. ("\t"):rep(tabLevel) .. s
  36.     end
  37.  
  38.     local function arrEncoding(val, bracket, closeBracket, iterator, loopFunc)
  39.         str = str .. bracket
  40.         if pretty then
  41.             str = str .. "\n"
  42.             tabLevel = tabLevel + 1
  43.         end
  44.         for k,v in iterator(val) do
  45.             tab("")
  46.             loopFunc(k,v)
  47.             str = str .. ","
  48.             if pretty then str = str .. "\n" end
  49.         end
  50.         if pretty then
  51.             tabLevel = tabLevel - 1
  52.         end
  53.         if str:sub(-2) == ",\n" then
  54.             str = str:sub(1, -3) .. "\n"
  55.         elseif str:sub(-1) == "," then
  56.             str = str:sub(1, -2)
  57.         end
  58.         tab(closeBracket)
  59.     end
  60.  
  61.     -- Table encoding
  62.     if type(val) == "table" then
  63.         assert(not tTracking[val], "Cannot encode a table holding itself recursively")
  64.         tTracking[val] = true
  65.         if isArray(val) then
  66.             arrEncoding(val, "[", "]", ipairs, function(k,v)
  67.                 str = str .. encodeCommon(v, pretty, tabLevel, tTracking)
  68.             end)
  69.         else
  70.             arrEncoding(val, "{", "}", pairs, function(k,v)
  71.                 assert(type(k) == "string", "JSON object keys must be strings", 2)
  72.                 str = str .. encodeCommon(k, pretty, tabLevel, tTracking)
  73.                 str = str .. (pretty and ": " or ":") .. encodeCommon(v, pretty, tabLevel, tTracking)
  74.             end)
  75.         end
  76.     -- String encoding
  77.     elseif type(val) == "string" then
  78.         str = '"' .. val:gsub("[%c\"\\]", controls) .. '"'
  79.     -- Number encoding
  80.     elseif type(val) == "number" or type(val) == "boolean" then
  81.         str = tostring(val)
  82.     else
  83.         error("JSON only supports arrays, objects, numbers, booleans, and strings", 2)
  84.     end
  85.     return str
  86. end
  87.  
  88. function encode(val)
  89.     return encodeCommon(val, false, 0, {})
  90. end
  91.  
  92. function encodePretty(val)
  93.     return encodeCommon(val, true, 0, {})
  94. end
  95.  
  96. ------------------------------------------------------------------ decoding
  97.  
  98. local decodeControls = {}
  99. for k,v in pairs(controls) do
  100.     decodeControls[v] = k
  101. end
  102.  
  103. function parseBoolean(str)
  104.     if str:sub(1, 4) == "true" then
  105.         return true, removeWhite(str:sub(5))
  106.     else
  107.         return false, removeWhite(str:sub(6))
  108.     end
  109. end
  110.  
  111. function parseNull(str)
  112.     return nil, removeWhite(str:sub(5))
  113. end
  114.  
  115. local numChars = {['e']=true; ['E']=true; ['+']=true; ['-']=true; ['.']=true}
  116. function parseNumber(str)
  117.     local i = 1
  118.     while numChars[str:sub(i, i)] or tonumber(str:sub(i, i)) do
  119.         i = i + 1
  120.     end
  121.     local val = tonumber(str:sub(1, i - 1))
  122.     str = removeWhite(str:sub(i))
  123.     return val, str
  124. end
  125.  
  126. function parseString(str)
  127.     str = str:sub(2)
  128.     local s = ""
  129.     while str:sub(1,1) ~= "\"" do
  130.         local next = str:sub(1,1)
  131.         str = str:sub(2)
  132.         assert(next ~= "\n", "Unclosed string")
  133.  
  134.         if next == "\\" then
  135.             local escape = str:sub(1,1)
  136.             str = str:sub(2)
  137.  
  138.             -- Handle \uXXXX escapes. Probably wrongly, too!
  139.             if escape == "u" then
  140.                 local escapeValue = str:sub(1, 4)
  141.                 str = str:sub(5)
  142.                 next = string.char(math.min(255, tonumber(escapeValue, 16)))
  143.             else
  144.                 next = assert(decodeControls[next..escape], "Invalid escape " .. next .. escape)
  145.             end
  146.         end
  147.  
  148.         s = s .. next
  149.     end
  150.     return s, removeWhite(str:sub(2))
  151. end
  152.  
  153. function parseArray(str)
  154.     str = removeWhite(str:sub(2))
  155.  
  156.     local val = {}
  157.     local i = 1
  158.     while str:sub(1, 1) ~= "]" do
  159.         local v = nil
  160.         v, str = parseValue(str)
  161.         val[i] = v
  162.         i = i + 1
  163.         str = removeWhite(str)
  164.     end
  165.     str = removeWhite(str:sub(2))
  166.     return val, str
  167. end
  168.  
  169. function parseObject(str)
  170.     str = removeWhite(str:sub(2))
  171.  
  172.     local val = {}
  173.     while str:sub(1, 1) ~= "}" do
  174.         local k, v = nil, nil
  175.         k, v, str = parseMember(str)
  176.         val[k] = v
  177.         str = removeWhite(str)
  178.     end
  179.     str = removeWhite(str:sub(2))
  180.     return val, str
  181. end
  182.  
  183. function parseMember(str)
  184.     local k = nil
  185.     k, str = parseValue(str)
  186.     local val = nil
  187.     val, str = parseValue(str)
  188.     return k, val, str
  189. end
  190.  
  191. function parseValue(str)
  192.     local fchar = str:sub(1, 1)
  193.     if fchar == "{" then
  194.         return parseObject(str)
  195.     elseif fchar == "[" then
  196.         return parseArray(str)
  197.     elseif tonumber(fchar) ~= nil or numChars[fchar] then
  198.         return parseNumber(str)
  199.     elseif str:sub(1, 4) == "true" or str:sub(1, 5) == "false" then
  200.         return parseBoolean(str)
  201.     elseif fchar == "\"" then
  202.         return parseString(str)
  203.     elseif str:sub(1, 4) == "null" then
  204.         return parseNull(str)
  205.     end
  206.     return nil
  207. end
  208.  
  209. function decode(str)
  210.     str = removeWhite(str)
  211.     t = parseValue(str)
  212.     return t
  213. end
  214.  
  215. function decodeFromFile(path)
  216.     local file = assert(fs.open(path, "r"))
  217.     local decoded = decode(file.readAll())
  218.     file.close()
  219.     return decoded
  220. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement