Advertisement
Mr_Thomson

JSON API

Sep 15th, 2020
382
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 27.81 KB | None | 0 0
  1. Skip to content
  2. Why GitHub?
  3. Team
  4. Enterprise
  5. Explore
  6. Marketplace
  7. Pricing
  8. Search
  9.  
  10. Sign in
  11. Sign up
  12. coolacid
  13. /
  14. ComputerCraft
  15. 6916
  16. Code
  17. Issues
  18. 3
  19. Pull requests
  20. 1
  21. Actions
  22. Projects
  23. Security
  24. Insights
  25. Join GitHub today
  26. GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
  27.  
  28. ComputerCraft/json.lua
  29. @coolacid
  30. coolacid Twitchdisplay - Split screen and make running more obvious
  31. Latest commit 96b15f7 on Apr 6, 2016
  32. History
  33. 1 contributor
  34. 872 lines (747 sloc) 26.3 KB
  35.  
  36. -- -*- coding: utf-8 -*-
  37. --
  38. -- Simple JSON encoding and decoding in pure Lua.
  39. --
  40. -- Copyright 2010-2013 Jeffrey Friedl
  41. -- http://regex.info/blog/
  42. --
  43. -- Latest version: http://regex.info/blog/lua/json
  44. --
  45. -- This code is released under a Creative Commons CC-BY "Attribution" License:
  46. -- http://creativecommons.org/licenses/by/3.0/deed.en_US
  47. --
  48. -- It can be used for any purpose so long as the copyright notice and
  49. -- web-page links above are maintained. Enjoy.
  50. --
  51. local VERSION = 20131004.7 -- version history at end of file
  52. local OBJDEF = { VERSION = VERSION }
  53.  
  54.  
  55. --
  56. -- Simple JSON encoding and decoding in pure Lua.
  57. -- http://www.json.org/
  58. --
  59. --
  60. -- JSON = (loadfile "JSON.lua")() -- one-time load of the routines
  61. --
  62. -- local lua_value = JSON:decode(raw_json_text)
  63. --
  64. -- local raw_json_text = JSON:encode(lua_table_or_value)
  65. -- local pretty_json_text = JSON:encode_pretty(lua_table_or_value) -- "pretty printed" version for human readability
  66. --
  67. --
  68. -- DECODING
  69. --
  70. -- JSON = (loadfile "JSON.lua")() -- one-time load of the routines
  71. --
  72. -- local lua_value = JSON:decode(raw_json_text)
  73. --
  74. -- If the JSON text is for an object or an array, e.g.
  75. -- { "what": "books", "count": 3 }
  76. -- or
  77. -- [ "Larry", "Curly", "Moe" ]
  78. --
  79. -- the result is a Lua table, e.g.
  80. -- { what = "books", count = 3 }
  81. -- or
  82. -- { "Larry", "Curly", "Moe" }
  83. --
  84. --
  85. -- The encode and decode routines accept an optional second argument, "etc", which is not used
  86. -- during encoding or decoding, but upon error is passed along to error handlers. It can be of any
  87. -- type (including nil).
  88. --
  89. -- With most errors during decoding, this code calls
  90. --
  91. -- JSON:onDecodeError(message, text, location, etc)
  92. --
  93. -- with a message about the error, and if known, the JSON text being parsed and the byte count
  94. -- where the problem was discovered. You can replace the default JSON:onDecodeError() with your
  95. -- own function.
  96. --
  97. -- The default onDecodeError() merely augments the message with data about the text and the
  98. -- location if known (and if a second 'etc' argument had been provided to decode(), its value is
  99. -- tacked onto the message as well), and then calls JSON.assert(), which itself defaults to Lua's
  100. -- built-in assert(), and can also be overridden.
  101. --
  102. -- For example, in an Adobe Lightroom plugin, you might use something like
  103. --
  104. -- function JSON:onDecodeError(message, text, location, etc)
  105. -- LrErrors.throwUserError("Internal Error: invalid JSON data")
  106. -- end
  107. --
  108. -- or even just
  109. --
  110. -- function JSON.assert(message)
  111. -- LrErrors.throwUserError("Internal Error: " .. message)
  112. -- end
  113. --
  114. -- If JSON:decode() is passed a nil, this is called instead:
  115. --
  116. -- JSON:onDecodeOfNilError(message, nil, nil, etc)
  117. --
  118. -- and if JSON:decode() is passed HTML instead of JSON, this is called:
  119. --
  120. -- JSON:onDecodeOfHTMLError(message, text, nil, etc)
  121. --
  122. -- The use of the fourth 'etc' argument allows stronger coordination between decoding and error
  123. -- reporting, especially when you provide your own error-handling routines. Continuing with the
  124. -- the Adobe Lightroom plugin example:
  125. --
  126. -- function JSON:onDecodeError(message, text, location, etc)
  127. -- local note = "Internal Error: invalid JSON data"
  128. -- if type(etc) = 'table' and etc.photo then
  129. -- note = note .. " while processing for " .. etc.photo:getFormattedMetadata('fileName')
  130. -- end
  131. -- LrErrors.throwUserError(note)
  132. -- end
  133. --
  134. -- :
  135. -- :
  136. --
  137. -- for i, photo in ipairs(photosToProcess) do
  138. -- :
  139. -- :
  140. -- local data = JSON:decode(someJsonText, { photo = photo })
  141. -- :
  142. -- :
  143. -- end
  144. --
  145. --
  146. --
  147. --
  148.  
  149. -- DECODING AND STRICT TYPES
  150. --
  151. -- Because both JSON objects and JSON arrays are converted to Lua tables, it's not normally
  152. -- possible to tell which a Lua table came from, or guarantee decode-encode round-trip
  153. -- equivalency.
  154. --
  155. -- However, if you enable strictTypes, e.g.
  156. --
  157. -- JSON = (loadfile "JSON.lua")() --load the routines
  158. -- JSON.strictTypes = true
  159. --
  160. -- then the Lua table resulting from the decoding of a JSON object or JSON array is marked via Lua
  161. -- metatable, so that when re-encoded with JSON:encode() it ends up as the appropriate JSON type.
  162. --
  163. -- (This is not the default because other routines may not work well with tables that have a
  164. -- metatable set, for example, Lightroom API calls.)
  165. --
  166. --
  167. -- ENCODING
  168. --
  169. -- JSON = (loadfile "JSON.lua")() -- one-time load of the routines
  170. --
  171. -- local raw_json_text = JSON:encode(lua_table_or_value)
  172. -- local pretty_json_text = JSON:encode_pretty(lua_table_or_value) -- "pretty printed" version for human readability
  173.  
  174. -- On error during encoding, this code calls:
  175. --
  176. -- JSON:onEncodeError(message, etc)
  177. --
  178. -- which you can override in your local JSON object.
  179. --
  180. --
  181. -- SUMMARY OF METHODS YOU CAN OVERRIDE IN YOUR LOCAL LUA JSON OBJECT
  182. --
  183. -- assert
  184. -- onDecodeError
  185. -- onDecodeOfNilError
  186. -- onDecodeOfHTMLError
  187. -- onEncodeError
  188. --
  189. -- If you want to create a separate Lua JSON object with its own error handlers,
  190. -- you can reload JSON.lua or use the :new() method.
  191. --
  192. ---------------------------------------------------------------------------
  193.  
  194.  
  195. local author = "-[ JSON.lua package by Jeffrey Friedl (http://regex.info/blog/lua/json), version " .. tostring(VERSION) .. " ]-"
  196. local isArray = { __tostring = function() return "JSON array" end } isArray.__index = isArray
  197. local isObject = { __tostring = function() return "JSON object" end } isObject.__index = isObject
  198.  
  199.  
  200. function OBJDEF:newArray(tbl)
  201. return setmetatable(tbl or {}, isArray)
  202. end
  203.  
  204. function OBJDEF:newObject(tbl)
  205. return setmetatable(tbl or {}, isObject)
  206. end
  207.  
  208. local function unicode_codepoint_as_utf8(codepoint)
  209. --
  210. -- codepoint is a number
  211. --
  212. if codepoint <= 127 then
  213. return string.char(codepoint)
  214.  
  215. elseif codepoint <= 2047 then
  216. --
  217. -- 110yyyxx 10xxxxxx <-- useful notation from http://en.wikipedia.org/wiki/Utf8
  218. --
  219. local highpart = math.floor(codepoint / 0x40)
  220. local lowpart = codepoint - (0x40 * highpart)
  221. return string.char(0xC0 + highpart,
  222. 0x80 + lowpart)
  223.  
  224. elseif codepoint <= 65535 then
  225. --
  226. -- 1110yyyy 10yyyyxx 10xxxxxx
  227. --
  228. local highpart = math.floor(codepoint / 0x1000)
  229. local remainder = codepoint - 0x1000 * highpart
  230. local midpart = math.floor(remainder / 0x40)
  231. local lowpart = remainder - 0x40 * midpart
  232.  
  233. highpart = 0xE0 + highpart
  234. midpart = 0x80 + midpart
  235. lowpart = 0x80 + lowpart
  236.  
  237. --
  238. -- Check for an invalid character (thanks Andy R. at Adobe).
  239. -- See table 3.7, page 93, in http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf#G28070
  240. --
  241. if ( highpart == 0xE0 and midpart < 0xA0 ) or
  242. ( highpart == 0xED and midpart > 0x9F ) or
  243. ( highpart == 0xF0 and midpart < 0x90 ) or
  244. ( highpart == 0xF4 and midpart > 0x8F )
  245. then
  246. return "?"
  247. else
  248. return string.char(highpart,
  249. midpart,
  250. lowpart)
  251. end
  252.  
  253. else
  254. --
  255. -- 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx
  256. --
  257. local highpart = math.floor(codepoint / 0x40000)
  258. local remainder = codepoint - 0x40000 * highpart
  259. local midA = math.floor(remainder / 0x1000)
  260. remainder = remainder - 0x1000 * midA
  261. local midB = math.floor(remainder / 0x40)
  262. local lowpart = remainder - 0x40 * midB
  263.  
  264. return string.char(0xF0 + highpart,
  265. 0x80 + midA,
  266. 0x80 + midB,
  267. 0x80 + lowpart)
  268. end
  269. end
  270.  
  271. function OBJDEF:onDecodeError(message, text, location, etc)
  272. if text then
  273. if location then
  274. message = string.format("%s at char %d of: %s", message, location, text)
  275. else
  276. message = string.format("%s: %s", message, text)
  277. end
  278. end
  279. if etc ~= nil then
  280. message = message .. " (" .. OBJDEF:encode(etc) .. ")"
  281. end
  282.  
  283. if self.assert then
  284. self.assert(false, message)
  285. else
  286. assert(false, message)
  287. end
  288. end
  289.  
  290. OBJDEF.onDecodeOfNilError = OBJDEF.onDecodeError
  291. OBJDEF.onDecodeOfHTMLError = OBJDEF.onDecodeError
  292.  
  293. function OBJDEF:onEncodeError(message, etc)
  294. if etc ~= nil then
  295. message = message .. " (" .. OBJDEF:encode(etc) .. ")"
  296. end
  297.  
  298. if self.assert then
  299. self.assert(false, message)
  300. else
  301. assert(false, message)
  302. end
  303. end
  304.  
  305. local function grok_number(self, text, start, etc)
  306. --
  307. -- Grab the integer part
  308. --
  309. local integer_part = text:match('^-?[1-9]%d*', start)
  310. or text:match("^-?0", start)
  311.  
  312. if not integer_part then
  313. self:onDecodeError("expected number", text, start, etc)
  314. end
  315.  
  316. local i = start + integer_part:len()
  317.  
  318. --
  319. -- Grab an optional decimal part
  320. --
  321. local decimal_part = text:match('^%.%d+', i) or ""
  322.  
  323. i = i + decimal_part:len()
  324.  
  325. --
  326. -- Grab an optional exponential part
  327. --
  328. local exponent_part = text:match('^[eE][-+]?%d+', i) or ""
  329.  
  330. i = i + exponent_part:len()
  331.  
  332. local full_number_text = integer_part .. decimal_part .. exponent_part
  333. local as_number = tonumber(full_number_text)
  334.  
  335. if not as_number then
  336. self:onDecodeError("bad number", text, start, etc)
  337. end
  338.  
  339. return as_number, i
  340. end
  341.  
  342.  
  343. local function grok_string(self, text, start, etc)
  344.  
  345. if text:sub(start,start) ~= '"' then
  346. self:onDecodeError("expected string's opening quote", text, start, etc)
  347. end
  348.  
  349. local i = start + 1 -- +1 to bypass the initial quote
  350. local text_len = text:len()
  351. local VALUE = ""
  352. while i <= text_len do
  353. local c = text:sub(i,i)
  354. if c == '"' then
  355. return VALUE, i + 1
  356. end
  357. if c ~= '\\' then
  358. VALUE = VALUE .. c
  359. i = i + 1
  360. elseif text:match('^\\b', i) then
  361. VALUE = VALUE .. "\b"
  362. i = i + 2
  363. elseif text:match('^\\f', i) then
  364. VALUE = VALUE .. "\f"
  365. i = i + 2
  366. elseif text:match('^\\n', i) then
  367. VALUE = VALUE .. "\n"
  368. i = i + 2
  369. elseif text:match('^\\r', i) then
  370. VALUE = VALUE .. "\r"
  371. i = i + 2
  372. elseif text:match('^\\t', i) then
  373. VALUE = VALUE .. "\t"
  374. i = i + 2
  375. else
  376. local hex = text:match('^\\u([0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF])', i)
  377. if hex then
  378. i = i + 6 -- bypass what we just read
  379.  
  380. -- We have a Unicode codepoint. It could be standalone, or if in the proper range and
  381. -- followed by another in a specific range, it'll be a two-code surrogate pair.
  382. local codepoint = tonumber(hex, 16)
  383. if codepoint >= 0xD800 and codepoint <= 0xDBFF then
  384. -- it's a hi surrogate... see whether we have a following low
  385. local lo_surrogate = text:match('^\\u([dD][cdefCDEF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF])', i)
  386. if lo_surrogate then
  387. i = i + 6 -- bypass the low surrogate we just read
  388. codepoint = 0x2400 + (codepoint - 0xD800) * 0x400 + tonumber(lo_surrogate, 16)
  389. else
  390. -- not a proper low, so we'll just leave the first codepoint as is and spit it out.
  391. end
  392. end
  393. VALUE = VALUE .. unicode_codepoint_as_utf8(codepoint)
  394.  
  395. else
  396.  
  397. -- just pass through what's escaped
  398. VALUE = VALUE .. text:match('^\\(.)', i)
  399. i = i + 2
  400. end
  401. end
  402. end
  403.  
  404. self:onDecodeError("unclosed string", text, start, etc)
  405. end
  406.  
  407. local function skip_whitespace(text, start)
  408.  
  409. local match_start, match_end = text:find("^[ \n\r\t]+", start) -- [http://www.ietf.org/rfc/rfc4627.txt] Section 2
  410. if match_end then
  411. return match_end + 1
  412. else
  413. return start
  414. end
  415. end
  416.  
  417. local grok_one -- assigned later
  418.  
  419. local function grok_object(self, text, start, etc)
  420. if not text:sub(start,start) == '{' then
  421. self:onDecodeError("expected '{'", text, start, etc)
  422. end
  423.  
  424. local i = skip_whitespace(text, start + 1) -- +1 to skip the '{'
  425.  
  426. local VALUE = self.strictTypes and self:newObject { } or { }
  427.  
  428. if text:sub(i,i) == '}' then
  429. return VALUE, i + 1
  430. end
  431. local text_len = text:len()
  432. while i <= text_len do
  433. local key, new_i = grok_string(self, text, i, etc)
  434.  
  435. i = skip_whitespace(text, new_i)
  436.  
  437. if text:sub(i, i) ~= ':' then
  438. self:onDecodeError("expected colon", text, i, etc)
  439. end
  440.  
  441. i = skip_whitespace(text, i + 1)
  442.  
  443. local val, new_i = grok_one(self, text, i)
  444.  
  445. VALUE[key] = val
  446.  
  447. --
  448. -- Expect now either '}' to end things, or a ',' to allow us to continue.
  449. --
  450. i = skip_whitespace(text, new_i)
  451.  
  452. local c = text:sub(i,i)
  453.  
  454. if c == '}' then
  455. return VALUE, i + 1
  456. end
  457.  
  458. if text:sub(i, i) ~= ',' then
  459. self:onDecodeError("expected comma or '}'", text, i, etc)
  460. end
  461.  
  462. i = skip_whitespace(text, i + 1)
  463. end
  464.  
  465. self:onDecodeError("unclosed '{'", text, start, etc)
  466. end
  467.  
  468. local function grok_array(self, text, start, etc)
  469. if not text:sub(start,start) == '[' then
  470. self:onDecodeError("expected '['", text, start, etc)
  471. end
  472.  
  473. local i = skip_whitespace(text, start + 1) -- +1 to skip the '['
  474. local VALUE = self.strictTypes and self:newArray { } or { }
  475. if text:sub(i,i) == ']' then
  476. return VALUE, i + 1
  477. end
  478.  
  479. local text_len = text:len()
  480. while i <= text_len do
  481. local val, new_i = grok_one(self, text, i)
  482.  
  483. table.insert(VALUE, val)
  484.  
  485. i = skip_whitespace(text, new_i)
  486.  
  487. --
  488. -- Expect now either ']' to end things, or a ',' to allow us to continue.
  489. --
  490. local c = text:sub(i,i)
  491. if c == ']' then
  492. return VALUE, i + 1
  493. end
  494. if text:sub(i, i) ~= ',' then
  495. self:onDecodeError("expected comma or '['", text, i, etc)
  496. end
  497. i = skip_whitespace(text, i + 1)
  498. end
  499. self:onDecodeError("unclosed '['", text, start, etc)
  500. end
  501.  
  502.  
  503. grok_one = function(self, text, start, etc)
  504. -- Skip any whitespace
  505. start = skip_whitespace(text, start)
  506.  
  507. if start > text:len() then
  508. self:onDecodeError("unexpected end of string", text, nil, etc)
  509. end
  510.  
  511. if text:find('^"', start) then
  512. return grok_string(self, text, start, etc)
  513.  
  514. elseif text:find('^[-0123456789 ]', start) then
  515. return grok_number(self, text, start, etc)
  516.  
  517. elseif text:find('^%{', start) then
  518. return grok_object(self, text, start, etc)
  519.  
  520. elseif text:find('^%[', start) then
  521. return grok_array(self, text, start, etc)
  522.  
  523. elseif text:find('^true', start) then
  524. return true, start + 4
  525.  
  526. elseif text:find('^false', start) then
  527. return false, start + 5
  528.  
  529. elseif text:find('^null', start) then
  530. return nil, start + 4
  531.  
  532. else
  533. self:onDecodeError("can't parse JSON", text, start, etc)
  534. end
  535. end
  536.  
  537. function OBJDEF:decode(text, etc)
  538. if type(self) ~= 'table' or self.__index ~= OBJDEF then
  539. OBJDEF:onDecodeError("JSON:decode must be called in method format", nil, nil, etc)
  540. end
  541.  
  542. if text == nil then
  543. self:onDecodeOfNilError(string.format("nil passed to JSON:decode()"), nil, nil, etc)
  544. elseif type(text) ~= 'string' then
  545. self:onDecodeError(string.format("expected string argument to JSON:decode(), got %s", type(text)), nil, nil, etc)
  546. end
  547.  
  548. if text:match('^%s*$') then
  549. return nil
  550. end
  551.  
  552. if text:match('^%s*<') then
  553. -- Can't be JSON... we'll assume it's HTML
  554. self:onDecodeOfHTMLError(string.format("html passed to JSON:decode()"), text, nil, etc)
  555. end
  556.  
  557. --
  558. -- Ensure that it's not UTF-32 or UTF-16.
  559. -- Those are perfectly valid encodings for JSON (as per RFC 4627 section 3),
  560. -- but this package can't handle them.
  561. --
  562. if text:sub(1,1):byte() == 0 or (text:len() >= 2 and text:sub(2,2):byte() == 0) then
  563. self:onDecodeError("JSON package groks only UTF-8, sorry", text, nil, etc)
  564. end
  565.  
  566. local success, value = pcall(grok_one, self, text, 1, etc)
  567. if success then
  568. return value
  569. else
  570. -- should never get here... JSON parse errors should have been caught earlier
  571. assert(false, value)
  572. return nil
  573. end
  574. end
  575.  
  576. local function backslash_replacement_function(c)
  577. if c == "\n" then
  578. return "\\n"
  579. elseif c == "\r" then
  580. return "\\r"
  581. elseif c == "\t" then
  582. return "\\t"
  583. elseif c == "\b" then
  584. return "\\b"
  585. elseif c == "\f" then
  586. return "\\f"
  587. elseif c == '"' then
  588. return '\\"'
  589. elseif c == '\\' then
  590. return '\\\\'
  591. else
  592. return string.format("\\u%04x", c:byte())
  593. end
  594. end
  595.  
  596. local chars_to_be_escaped_in_JSON_string
  597. = '['
  598. .. '"' -- class sub-pattern to match a double quote
  599. .. '%\\' -- class sub-pattern to match a backslash
  600. .. '%z' -- class sub-pattern to match a null
  601. .. '\001' .. '-' .. '\031' -- class sub-pattern to match control characters
  602. .. ']'
  603.  
  604. local function json_string_literal(value)
  605. local newval = value:gsub(chars_to_be_escaped_in_JSON_string, backslash_replacement_function)
  606. return '"' .. newval .. '"'
  607. end
  608.  
  609. local function object_or_array(self, T, etc)
  610. --
  611. -- We need to inspect all the keys... if there are any strings, we'll convert to a JSON
  612. -- object. If there are only numbers, it's a JSON array.
  613. --
  614. -- If we'll be converting to a JSON object, we'll want to sort the keys so that the
  615. -- end result is deterministic.
  616. --
  617. local string_keys = { }
  618. local seen_number_key = false
  619. local maximum_number_key
  620.  
  621. for key in pairs(T) do
  622. if type(key) == 'number' then
  623. seen_number_key = true
  624. if not maximum_number_key or maximum_number_key < key then
  625. maximum_number_key = key
  626. end
  627. elseif type(key) == 'string' then
  628. table.insert(string_keys, key)
  629. else
  630. self:onEncodeError("can't encode table with a key of type " .. type(key), etc)
  631. end
  632. end
  633.  
  634. if seen_number_key and #string_keys > 0 then
  635. --
  636. -- Mixed key types... don't know what to do, so bail
  637. --
  638. self:onEncodeError("a table with both numeric and string keys could be an object or array; aborting", etc)
  639.  
  640. elseif #string_keys == 0 then
  641. --
  642. -- An array
  643. --
  644. if seen_number_key then
  645. return nil, maximum_number_key -- an array
  646. else
  647. --
  648. -- An empty table...
  649. --
  650. if tostring(T) == "JSON array" then
  651. return nil
  652. elseif tostring(T) == "JSON object" then
  653. return { }
  654. else
  655. -- have to guess, so we'll pick array, since empty arrays are likely more common than empty objects
  656. return nil
  657. end
  658. end
  659. else
  660. --
  661. -- An object, so return a list of keys
  662. --
  663. table.sort(string_keys)
  664. return string_keys
  665. end
  666. end
  667.  
  668. --
  669. -- Encode
  670. --
  671. local encode_value -- must predeclare because it calls itself
  672. function encode_value(self, value, parents, etc)
  673.  
  674.  
  675. if value == nil then
  676. return 'null'
  677. end
  678.  
  679. if type(value) == 'string' then
  680. return json_string_literal(value)
  681. elseif type(value) == 'number' then
  682. if value ~= value then
  683. --
  684. -- NaN (Not a Number).
  685. -- JSON has no NaN, so we have to fudge the best we can. This should really be a package option.
  686. --
  687. return "null"
  688. elseif value >= math.huge then
  689. --
  690. -- Positive infinity. JSON has no INF, so we have to fudge the best we can. This should
  691. -- really be a package option. Note: at least with some implementations, positive infinity
  692. -- is both ">= math.huge" and "<= -math.huge", which makes no sense but that's how it is.
  693. -- Negative infinity is properly "<= -math.huge". So, we must be sure to check the ">="
  694. -- case first.
  695. --
  696. return "1e+9999"
  697. elseif value <= -math.huge then
  698. --
  699. -- Negative infinity.
  700. -- JSON has no INF, so we have to fudge the best we can. This should really be a package option.
  701. --
  702. return "-1e+9999"
  703. else
  704. return tostring(value)
  705. end
  706. elseif type(value) == 'boolean' then
  707. return tostring(value)
  708.  
  709. elseif type(value) ~= 'table' then
  710. self:onEncodeError("can't convert " .. type(value) .. " to JSON", etc)
  711.  
  712. else
  713. --
  714. -- A table to be converted to either a JSON object or array.
  715. --
  716. local T = value
  717.  
  718. if parents[T] then
  719. self:onEncodeError("table " .. tostring(T) .. " is a child of itself", etc)
  720. else
  721. parents[T] = true
  722. end
  723.  
  724. local result_value
  725.  
  726. local object_keys, maximum_number_key = object_or_array(self, T, etc)
  727. if maximum_number_key then
  728. --
  729. -- An array...
  730. --
  731. local ITEMS = { }
  732. for i = 1, maximum_number_key do
  733. table.insert(ITEMS, encode_value(self, T[i], parents, etc))
  734. end
  735.  
  736. result_value = "[" .. table.concat(ITEMS, ",") .. "]"
  737. elseif object_keys then
  738. --
  739. -- An object
  740. --
  741.  
  742. --
  743. -- We'll always sort the keys, so that comparisons can be made on
  744. -- the results, etc. The actual order is not particularly
  745. -- important (e.g. it doesn't matter what character set we sort
  746. -- as); it's only important that it be deterministic... the same
  747. -- every time.
  748. --
  749. local PARTS = { }
  750. for _, key in ipairs(object_keys) do
  751. local encoded_key = encode_value(self, tostring(key), parents, etc)
  752. local encoded_val = encode_value(self, T[key], parents, etc)
  753. table.insert(PARTS, string.format("%s:%s", encoded_key, encoded_val))
  754. end
  755. result_value = "{" .. table.concat(PARTS, ",") .. "}"
  756. else
  757. --
  758. -- An empty array/object... we'll treat it as an array, though it should really be an option
  759. --
  760. result_value = "[]"
  761. end
  762.  
  763. parents[T] = false
  764. return result_value
  765. end
  766. end
  767.  
  768. local encode_pretty_value -- must predeclare because it calls itself
  769. function encode_pretty_value(self, value, parents, indent, etc)
  770.  
  771. if type(value) == 'string' then
  772. return json_string_literal(value)
  773.  
  774. elseif type(value) == 'number' then
  775. return tostring(value)
  776.  
  777. elseif type(value) == 'boolean' then
  778. return tostring(value)
  779.  
  780. elseif type(value) == 'nil' then
  781. return 'null'
  782.  
  783. elseif type(value) ~= 'table' then
  784. self:onEncodeError("can't convert " .. type(value) .. " to JSON", etc)
  785.  
  786. else
  787. --
  788. -- A table to be converted to either a JSON object or array.
  789. --
  790. local T = value
  791.  
  792. if parents[T] then
  793. self:onEncodeError("table " .. tostring(T) .. " is a child of itself", etc)
  794. end
  795. parents[T] = true
  796.  
  797. local result_value
  798.  
  799. local object_keys = object_or_array(self, T, etc)
  800. if not object_keys then
  801. --
  802. -- An array...
  803. --
  804. local ITEMS = { }
  805. for i = 1, #T do
  806. table.insert(ITEMS, encode_pretty_value(self, T[i], parents, indent, etc))
  807. end
  808.  
  809. result_value = "[ " .. table.concat(ITEMS, ", ") .. " ]"
  810.  
  811. else
  812.  
  813. --
  814. -- An object -- can keys be numbers?
  815. --
  816.  
  817. local KEYS = { }
  818. local max_key_length = 0
  819. for _, key in ipairs(object_keys) do
  820. local encoded = encode_pretty_value(self, tostring(key), parents, "", etc)
  821. max_key_length = math.max(max_key_length, #encoded)
  822. table.insert(KEYS, encoded)
  823. end
  824. local key_indent = indent .. " "
  825. local subtable_indent = indent .. string.rep(" ", max_key_length + 2 + 4)
  826. local FORMAT = "%s%" .. tostring(max_key_length) .. "s: %s"
  827.  
  828. local COMBINED_PARTS = { }
  829. for i, key in ipairs(object_keys) do
  830. local encoded_val = encode_pretty_value(self, T[key], parents, subtable_indent, etc)
  831. table.insert(COMBINED_PARTS, string.format(FORMAT, key_indent, KEYS[i], encoded_val))
  832. end
  833. result_value = "{\n" .. table.concat(COMBINED_PARTS, ",\n") .. "\n" .. indent .. "}"
  834. end
  835.  
  836. parents[T] = false
  837. return result_value
  838. end
  839. end
  840.  
  841. function OBJDEF:encode(value, etc)
  842. if type(self) ~= 'table' or self.__index ~= OBJDEF then
  843. OBJDEF:onEncodeError("JSON:encode must be called in method format", etc)
  844. end
  845.  
  846. local parents = {}
  847. return encode_value(self, value, parents, etc)
  848. end
  849.  
  850. function OBJDEF:encode_pretty(value, etc)
  851. local parents = {}
  852. local subtable_indent = ""
  853. return encode_pretty_value(self, value, parents, subtable_indent, etc)
  854. end
  855.  
  856. function OBJDEF.__tostring()
  857. return "JSON encode/decode package"
  858. end
  859.  
  860. OBJDEF.__index = OBJDEF
  861.  
  862. function OBJDEF:new(args)
  863. local new = { }
  864.  
  865. if args then
  866. for key, val in pairs(args) do
  867. new[key] = val
  868. end
  869. end
  870.  
  871. return setmetatable(new, OBJDEF)
  872. end
  873.  
  874. return OBJDEF:new()
  875.  
  876. --
  877. -- Version history:
  878. --
  879. -- 20131004.7 Release under a Creative Commons CC-BY license, which I should have done from day one, sorry.
  880. --
  881. -- 20130120.6 Comment update: added a link to the specific page on my blog where this code can
  882. -- be found, so that folks who come across the code outside of my blog can find updates
  883. -- more easily.
  884. --
  885. -- 20111207.5 Added support for the 'etc' arguments, for better error reporting.
  886. --
  887. -- 20110731.4 More feedback from David Kolf on how to make the tests for Nan/Infinity system independent.
  888. --
  889. -- 20110730.3 Incorporated feedback from David Kolf at http://lua-users.org/wiki/JsonModules:
  890. --
  891. -- * When encoding lua for JSON, Sparse numeric arrays are now handled by
  892. -- spitting out full arrays, such that
  893. -- JSON:encode({"one", "two", [10] = "ten"})
  894. -- returns
  895. -- ["one","two",null,null,null,null,null,null,null,"ten"]
  896. --
  897. -- In 20100810.2 and earlier, only up to the first non-null value would have been retained.
  898. --
  899. -- * When encoding lua for JSON, numeric value NaN gets spit out as null, and infinity as "1+e9999".
  900. -- Version 20100810.2 and earlier created invalid JSON in both cases.
  901. --
  902. -- * Unicode surrogate pairs are now detected when decoding JSON.
  903. --
  904. -- 20100810.2 added some checking to ensure that an invalid Unicode character couldn't leak in to the UTF-8 encoding
  905. --
  906. -- 20100731.1 initial public release
  907. --
  908. © 2020 GitHub, Inc.
  909. Terms
  910. Privacy
  911. Security
  912. Status
  913. Help
  914. Contact GitHub
  915. Pricing
  916. API
  917. Training
  918. Blog
  919. About
  920.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement