Advertisement
Dojnaz

json

Aug 8th, 2023 (edited)
1,058
1
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.  
  4. local function isArray(t)
  5.     local max = 0
  6.     for k,v in pairs(t) do
  7.         if type(k) ~= "number" then
  8.             return false
  9.         elseif k > max then
  10.             max = k
  11.         end
  12.     end
  13.     return max == #t
  14. end
  15.  
  16. local whites = {['\n']=true; ['\r']=true; ['\t']=true; [' ']=true; [',']=true; [':']=true}
  17. function removeWhite(str)
  18.     while whites[str:sub(1, 1)] do
  19.         str = str:sub(2)
  20.     end
  21.     return str
  22. end
  23.  
  24. ------------------------------------------------------------------ encoding
  25.  
  26. local function encodeCommon(val, pretty, tabLevel, tTracking)
  27.     local str = ""
  28.  
  29.     -- Tabbing util
  30.     local function tab(s)
  31.         str = str .. ("\t"):rep(tabLevel) .. s
  32.     end
  33.  
  34.     local function arrEncoding(val, bracket, closeBracket, iterator, loopFunc)
  35.         str = str .. bracket
  36.         if pretty then
  37.             str = str .. "\n"
  38.             tabLevel = tabLevel + 1
  39.         end
  40.         for k,v in iterator(val) do
  41.             tab("")
  42.             loopFunc(k,v)
  43.             str = str .. ","
  44.             if pretty then str = str .. "\n" end
  45.         end
  46.         if pretty then
  47.             tabLevel = tabLevel - 1
  48.         end
  49.         if str:sub(-2) == ",\n" then
  50.             str = str:sub(1, -3) .. "\n"
  51.         elseif str:sub(-1) == "," then
  52.             str = str:sub(1, -2)
  53.         end
  54.         tab(closeBracket)
  55.     end
  56.  
  57.     -- Table encoding
  58.     if type(val) == "table" then
  59.         if not tTracking[val] then
  60.             tTracking[val] = true
  61.             if isArray(val) then
  62.                 arrEncoding(val, "[", "]", ipairs, function(k,v)
  63.                     str = str .. encodeCommon(v, pretty, tabLevel, tTracking)
  64.                 end)
  65.             else
  66.                 arrEncoding(val, "{", "}", pairs, function(k,v)
  67.                     assert(type(k) == "string", "JSON object keys must be strings", 2)
  68.                     str = str .. encodeCommon(k, pretty, tabLevel, tTracking)
  69.                     str = str .. (pretty and ": " or ":") .. encodeCommon(v, pretty, tabLevel, tTracking)
  70.                 end)
  71.             end
  72.         else
  73.             str = 'null'
  74.         end
  75.     -- String encoding
  76.     elseif type(val) == "string" then
  77.         str = '"' .. val:gsub("[%c\"\\]", controls) .. '"'
  78.     -- Number encoding
  79.     elseif type(val) == "number" or type(val) == "boolean" then
  80.         str = tostring(val)
  81.     else
  82.         str = 'null'
  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.             next = assert(decodeControls[next..escape], "Invalid escape character")
  139.         end
  140.  
  141.         s = s .. next
  142.     end
  143.     return s, removeWhite(str:sub(2))
  144. end
  145.  
  146. function parseArray(str)
  147.     str = removeWhite(str:sub(2))
  148.  
  149.     local val = {}
  150.     local i = 1
  151.     while str:sub(1, 1) ~= "]" do
  152.         local v = nil
  153.         v, str = parseValue(str)
  154.         val[i] = v
  155.         i = i + 1
  156.         str = removeWhite(str)
  157.     end
  158.     str = removeWhite(str:sub(2))
  159.     return val, str
  160. end
  161.  
  162. function parseObject(str)
  163.     str = removeWhite(str:sub(2))
  164.  
  165.     local val = {}
  166.     while str:sub(1, 1) ~= "}" do
  167.         local k, v = nil, nil
  168.         k, v, str = parseMember(str)
  169.         val[k] = v
  170.         str = removeWhite(str)
  171.     end
  172.     str = removeWhite(str:sub(2))
  173.     return val, str
  174. end
  175.  
  176. function parseMember(str)
  177.     local k = nil
  178.     k, str = parseValue(str)
  179.     local val = nil
  180.     val, str = parseValue(str)
  181.     return k, val, str
  182. end
  183.  
  184. function parseValue(str)
  185.     local fchar = str:sub(1, 1)
  186.     if fchar == "{" then
  187.         return parseObject(str)
  188.     elseif fchar == "[" then
  189.         return parseArray(str)
  190.     elseif tonumber(fchar) ~= nil or numChars[fchar] then
  191.         return parseNumber(str)
  192.     elseif str:sub(1, 4) == "true" or str:sub(1, 5) == "false" then
  193.         return parseBoolean(str)
  194.     elseif fchar == "\"" then
  195.         return parseString(str)
  196.     elseif str:sub(1, 4) == "null" then
  197.         return parseNull(str)
  198.     end
  199.     return nil
  200. end
  201.  
  202. function decode(str)
  203.     str = removeWhite(str)
  204.     t = parseValue(str)
  205.     return t
  206. end
  207.  
  208. function decodeFromFile(path)
  209.     local file = assert(fs.open(path, "r"))
  210.     local decoded = decode(file.readAll())
  211.     file.close()
  212.     return decoded
  213. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement