· 3 years ago · Nov 26, 2021, 09:02 PM
1-- -*- coding: utf-8 -*-
2--
3-- Simple JSON encoding and decoding in pure Lua.
4--
5-- Copyright 2010-2014 Jeffrey Friedl
6-- http://regex.info/blog/
7--
8-- Latest version: http://regex.info/blog/lua/json
9--
10-- This code is released under a Creative Commons CC-BY "Attribution" License:
11-- http://creativecommons.org/licenses/by/3.0/deed.en_US
12--
13-- It can be used for any purpose so long as the copyright notice above,
14-- the web-page links above, and the 'AUTHOR_NOTE' string below are
15-- maintained. Enjoy.
16--
17local VERSION = 20141223.14 -- version history at end of file
18local AUTHOR_NOTE = "-[ JSON.lua package by Jeffrey Friedl (http://regex.info/blog/lua/json) version 20141223.14 ]-"
19
20--
21-- The 'AUTHOR_NOTE' variable exists so that information about the source
22-- of the package is maintained even in compiled versions. It's also
23-- included in OBJDEF below mostly to quiet warnings about unused variables.
24--
25local OBJDEF = {
26 VERSION = VERSION,
27 AUTHOR_NOTE = AUTHOR_NOTE,
28}
29
30
31--
32-- Simple JSON encoding and decoding in pure Lua.
33-- http://www.json.org/
34--
35--
36-- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines
37--
38-- local lua_value = JSON:decode(raw_json_text)
39--
40-- local raw_json_text = JSON:encode(lua_table_or_value)
41-- local pretty_json_text = JSON:encode_pretty(lua_table_or_value) -- "pretty printed" version for human readability
42--
43--
44--
45-- DECODING (from a JSON string to a Lua table)
46--
47--
48-- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines
49--
50-- local lua_value = JSON:decode(raw_json_text)
51--
52-- If the JSON text is for an object or an array, e.g.
53-- { "what": "books", "count": 3 }
54-- or
55-- [ "Larry", "Curly", "Moe" ]
56--
57-- the result is a Lua table, e.g.
58-- { what = "books", count = 3 }
59-- or
60-- { "Larry", "Curly", "Moe" }
61--
62--
63-- The encode and decode routines accept an optional second argument,
64-- "etc", which is not used during encoding or decoding, but upon error
65-- is passed along to error handlers. It can be of any type (including nil).
66--
67--
68--
69-- ERROR HANDLING
70--
71-- With most errors during decoding, this code calls
72--
73-- JSON:onDecodeError(message, text, location, etc)
74--
75-- with a message about the error, and if known, the JSON text being
76-- parsed and the byte count where the problem was discovered. You can
77-- replace the default JSON:onDecodeError() with your own function.
78--
79-- The default onDecodeError() merely augments the message with data
80-- about the text and the location if known (and if a second 'etc'
81-- argument had been provided to decode(), its value is tacked onto the
82-- message as well), and then calls JSON.assert(), which itself defaults
83-- to Lua's built-in assert(), and can also be overridden.
84--
85-- For example, in an Adobe Lightroom plugin, you might use something like
86--
87-- function JSON:onDecodeError(message, text, location, etc)
88-- LrErrors.throwUserError("Internal Error: invalid JSON data")
89-- end
90--
91-- or even just
92--
93-- function JSON.assert(message)
94-- LrErrors.throwUserError("Internal Error: " .. message)
95-- end
96--
97-- If JSON:decode() is passed a nil, this is called instead:
98--
99-- JSON:onDecodeOfNilError(message, nil, nil, etc)
100--
101-- and if JSON:decode() is passed HTML instead of JSON, this is called:
102--
103-- JSON:onDecodeOfHTMLError(message, text, nil, etc)
104--
105-- The use of the fourth 'etc' argument allows stronger coordination
106-- between decoding and error reporting, especially when you provide your
107-- own error-handling routines. Continuing with the the Adobe Lightroom
108-- plugin example:
109--
110-- function JSON:onDecodeError(message, text, location, etc)
111-- local note = "Internal Error: invalid JSON data"
112-- if type(etc) = 'table' and etc.photo then
113-- note = note .. " while processing for " .. etc.photo:getFormattedMetadata('fileName')
114-- end
115-- LrErrors.throwUserError(note)
116-- end
117--
118-- :
119-- :
120--
121-- for i, photo in ipairs(photosToProcess) do
122-- :
123-- :
124-- local data = JSON:decode(someJsonText, { photo = photo })
125-- :
126-- :
127-- end
128--
129--
130--
131--
132--
133-- DECODING AND STRICT TYPES
134--
135-- Because both JSON objects and JSON arrays are converted to Lua tables,
136-- it's not normally possible to tell which original JSON type a
137-- particular Lua table was derived from, or guarantee decode-encode
138-- round-trip equivalency.
139--
140-- However, if you enable strictTypes, e.g.
141--
142-- JSON = assert(loadfile "JSON.lua")() --load the routines
143-- JSON.strictTypes = true
144--
145-- then the Lua table resulting from the decoding of a JSON object or
146-- JSON array is marked via Lua metatable, so that when re-encoded with
147-- JSON:encode() it ends up as the appropriate JSON type.
148--
149-- (This is not the default because other routines may not work well with
150-- tables that have a metatable set, for example, Lightroom API calls.)
151--
152--
153-- ENCODING (from a lua table to a JSON string)
154--
155-- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines
156--
157-- local raw_json_text = JSON:encode(lua_table_or_value)
158-- local pretty_json_text = JSON:encode_pretty(lua_table_or_value) -- "pretty printed" version for human readability
159-- local custom_pretty = JSON:encode(lua_table_or_value, etc, { pretty = true, indent = "| ", align_keys = false })
160--
161-- On error during encoding, this code calls:
162--
163-- JSON:onEncodeError(message, etc)
164--
165-- which you can override in your local JSON object.
166--
167-- The 'etc' in the error call is the second argument to encode()
168-- and encode_pretty(), or nil if it wasn't provided.
169--
170--
171-- PRETTY-PRINTING
172--
173-- An optional third argument, a table of options, allows a bit of
174-- configuration about how the encoding takes place:
175--
176-- pretty = JSON:encode(val, etc, {
177-- pretty = true, -- if false, no other options matter
178-- indent = " ", -- this provides for a three-space indent per nesting level
179-- align_keys = false, -- see below
180-- })
181--
182-- encode() and encode_pretty() are identical except that encode_pretty()
183-- provides a default options table if none given in the call:
184--
185-- { pretty = true, align_keys = false, indent = " " }
186--
187-- For example, if
188--
189-- JSON:encode(data)
190--
191-- produces:
192--
193-- {"city":"Kyoto","climate":{"avg_temp":16,"humidity":"high","snowfall":"minimal"},"country":"Japan","wards":11}
194--
195-- then
196--
197-- JSON:encode_pretty(data)
198--
199-- produces:
200--
201-- {
202-- "city": "Kyoto",
203-- "climate": {
204-- "avg_temp": 16,
205-- "humidity": "high",
206-- "snowfall": "minimal"
207-- },
208-- "country": "Japan",
209-- "wards": 11
210-- }
211--
212-- The following three lines return identical results:
213-- JSON:encode_pretty(data)
214-- JSON:encode_pretty(data, nil, { pretty = true, align_keys = false, indent = " " })
215-- JSON:encode (data, nil, { pretty = true, align_keys = false, indent = " " })
216--
217-- An example of setting your own indent string:
218--
219-- JSON:encode_pretty(data, nil, { pretty = true, indent = "| " })
220--
221-- produces:
222--
223-- {
224-- | "city": "Kyoto",
225-- | "climate": {
226-- | | "avg_temp": 16,
227-- | | "humidity": "high",
228-- | | "snowfall": "minimal"
229-- | },
230-- | "country": "Japan",
231-- | "wards": 11
232-- }
233--
234-- An example of setting align_keys to true:
235--
236-- JSON:encode_pretty(data, nil, { pretty = true, indent = " ", align_keys = true })
237--
238-- produces:
239--
240-- {
241-- "city": "Kyoto",
242-- "climate": {
243-- "avg_temp": 16,
244-- "humidity": "high",
245-- "snowfall": "minimal"
246-- },
247-- "country": "Japan",
248-- "wards": 11
249-- }
250--
251-- which I must admit is kinda ugly, sorry. This was the default for
252-- encode_pretty() prior to version 20141223.14.
253--
254--
255-- AMBIGUOUS SITUATIONS DURING THE ENCODING
256--
257-- During the encode, if a Lua table being encoded contains both string
258-- and numeric keys, it fits neither JSON's idea of an object, nor its
259-- idea of an array. To get around this, when any string key exists (or
260-- when non-positive numeric keys exist), numeric keys are converted to
261-- strings.
262--
263-- For example,
264-- JSON:encode({ "one", "two", "three", SOMESTRING = "some string" }))
265-- produces the JSON object
266-- {"1":"one","2":"two","3":"three","SOMESTRING":"some string"}
267--
268-- To prohibit this conversion and instead make it an error condition, set
269-- JSON.noKeyConversion = true
270--
271
272
273
274
275--
276-- SUMMARY OF METHODS YOU CAN OVERRIDE IN YOUR LOCAL LUA JSON OBJECT
277--
278-- assert
279-- onDecodeError
280-- onDecodeOfNilError
281-- onDecodeOfHTMLError
282-- onEncodeError
283--
284-- If you want to create a separate Lua JSON object with its own error handlers,
285-- you can reload JSON.lua or use the :new() method.
286--
287---------------------------------------------------------------------------
288
289local default_pretty_indent = " "
290local default_pretty_options = { pretty = true, align_keys = false, indent = default_pretty_indent }
291
292local isArray = { __tostring = function() return "JSON array" end } isArray.__index = isArray
293local isObject = { __tostring = function() return "JSON object" end } isObject.__index = isObject
294
295
296function OBJDEF:newArray(tbl)
297 return setmetatable(tbl or {}, isArray)
298end
299
300function OBJDEF:newObject(tbl)
301 return setmetatable(tbl or {}, isObject)
302end
303
304local function unicode_codepoint_as_utf8(codepoint)
305 --
306 -- codepoint is a number
307 --
308 if codepoint <= 127 then
309 return string.char(codepoint)
310
311 elseif codepoint <= 2047 then
312 --
313 -- 110yyyxx 10xxxxxx <-- useful notation from http://en.wikipedia.org/wiki/Utf8
314 --
315 local highpart = math.floor(codepoint / 0x40)
316 local lowpart = codepoint - (0x40 * highpart)
317 return string.char(0xC0 + highpart,
318 0x80 + lowpart)
319
320 elseif codepoint <= 65535 then
321 --
322 -- 1110yyyy 10yyyyxx 10xxxxxx
323 --
324 local highpart = math.floor(codepoint / 0x1000)
325 local remainder = codepoint - 0x1000 * highpart
326 local midpart = math.floor(remainder / 0x40)
327 local lowpart = remainder - 0x40 * midpart
328
329 highpart = 0xE0 + highpart
330 midpart = 0x80 + midpart
331 lowpart = 0x80 + lowpart
332
333 --
334 -- Check for an invalid character (thanks Andy R. at Adobe).
335 -- See table 3.7, page 93, in http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf#G28070
336 --
337 if ( highpart == 0xE0 and midpart < 0xA0 ) or
338 ( highpart == 0xED and midpart > 0x9F ) or
339 ( highpart == 0xF0 and midpart < 0x90 ) or
340 ( highpart == 0xF4 and midpart > 0x8F )
341 then
342 return "?"
343 else
344 return string.char(highpart,
345 midpart,
346 lowpart)
347 end
348
349 else
350 --
351 -- 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx
352 --
353 local highpart = math.floor(codepoint / 0x40000)
354 local remainder = codepoint - 0x40000 * highpart
355 local midA = math.floor(remainder / 0x1000)
356 remainder = remainder - 0x1000 * midA
357 local midB = math.floor(remainder / 0x40)
358 local lowpart = remainder - 0x40 * midB
359
360 return string.char(0xF0 + highpart,
361 0x80 + midA,
362 0x80 + midB,
363 0x80 + lowpart)
364 end
365end
366
367function OBJDEF:onDecodeError(message, text, location, etc)
368 if text then
369 if location then
370 message = string.format("%s at char %d of: %s", message, location, text)
371 else
372 message = string.format("%s: %s", message, text)
373 end
374 end
375
376 if etc ~= nil then
377 message = message .. " (" .. OBJDEF:encode(etc) .. ")"
378 end
379
380 if self.assert then
381 self.assert(false, message)
382 else
383 assert(false, message)
384 end
385end
386
387OBJDEF.onDecodeOfNilError = OBJDEF.onDecodeError
388OBJDEF.onDecodeOfHTMLError = OBJDEF.onDecodeError
389
390function OBJDEF:onEncodeError(message, etc)
391 if etc ~= nil then
392 message = message .. " (" .. OBJDEF:encode(etc) .. ")"
393 end
394
395 if self.assert then
396 self.assert(false, message)
397 else
398 assert(false, message)
399 end
400end
401
402local function grok_number(self, text, start, etc)
403 --
404 -- Grab the integer part
405 --
406 local integer_part = text:match('^-?[1-9]%d*', start)
407 or text:match("^-?0", start)
408
409 if not integer_part then
410 self:onDecodeError("expected number", text, start, etc)
411 end
412
413 local i = start + integer_part:len()
414
415 --
416 -- Grab an optional decimal part
417 --
418 local decimal_part = text:match('^%.%d+', i) or ""
419
420 i = i + decimal_part:len()
421
422 --
423 -- Grab an optional exponential part
424 --
425 local exponent_part = text:match('^[eE][-+]?%d+', i) or ""
426
427 i = i + exponent_part:len()
428
429 local full_number_text = integer_part .. decimal_part .. exponent_part
430 local as_number = tonumber(full_number_text)
431
432 if not as_number then
433 self:onDecodeError("bad number", text, start, etc)
434 end
435
436 return as_number, i
437end
438
439
440local function grok_string(self, text, start, etc)
441
442 if text:sub(start,start) ~= '"' then
443 self:onDecodeError("expected string's opening quote", text, start, etc)
444 end
445
446 local i = start + 1 -- +1 to bypass the initial quote
447 local text_len = text:len()
448 local VALUE = ""
449 while i <= text_len do
450 local c = text:sub(i,i)
451 if c == '"' then
452 return VALUE, i + 1
453 end
454 if c ~= '\\' then
455 VALUE = VALUE .. c
456 i = i + 1
457 elseif text:match('^\\b', i) then
458 VALUE = VALUE .. "\b"
459 i = i + 2
460 elseif text:match('^\\f', i) then
461 VALUE = VALUE .. "\f"
462 i = i + 2
463 elseif text:match('^\\n', i) then
464 VALUE = VALUE .. "\n"
465 i = i + 2
466 elseif text:match('^\\r', i) then
467 VALUE = VALUE .. "\r"
468 i = i + 2
469 elseif text:match('^\\t', i) then
470 VALUE = VALUE .. "\t"
471 i = i + 2
472 else
473 local hex = text:match('^\\u([0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF])', i)
474 if hex then
475 i = i + 6 -- bypass what we just read
476
477 -- We have a Unicode codepoint. It could be standalone, or if in the proper range and
478 -- followed by another in a specific range, it'll be a two-code surrogate pair.
479 local codepoint = tonumber(hex, 16)
480 if codepoint >= 0xD800 and codepoint <= 0xDBFF then
481 -- it's a hi surrogate... see whether we have a following low
482 local lo_surrogate = text:match('^\\u([dD][cdefCDEF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF])', i)
483 if lo_surrogate then
484 i = i + 6 -- bypass the low surrogate we just read
485 codepoint = 0x2400 + (codepoint - 0xD800) * 0x400 + tonumber(lo_surrogate, 16)
486 else
487 -- not a proper low, so we'll just leave the first codepoint as is and spit it out.
488 end
489 end
490 VALUE = VALUE .. unicode_codepoint_as_utf8(codepoint)
491
492 else
493
494 -- just pass through what's escaped
495 VALUE = VALUE .. text:match('^\\(.)', i)
496 i = i + 2
497 end
498 end
499 end
500
501 self:onDecodeError("unclosed string", text, start, etc)
502end
503
504local function skip_whitespace(text, start)
505
506 local _, match_end = text:find("^[ \n\r\t]+", start) -- [http://www.ietf.org/rfc/rfc4627.txt] Section 2
507 if match_end then
508 return match_end + 1
509 else
510 return start
511 end
512end
513
514local grok_one -- assigned later
515
516local function grok_object(self, text, start, etc)
517 if text:sub(start,start) ~= '{' then
518 self:onDecodeError("expected '{'", text, start, etc)
519 end
520
521 local i = skip_whitespace(text, start + 1) -- +1 to skip the '{'
522
523 local VALUE = self.strictTypes and self:newObject { } or { }
524
525 if text:sub(i,i) == '}' then
526 return VALUE, i + 1
527 end
528 local text_len = text:len()
529 while i <= text_len do
530 local key, new_i = grok_string(self, text, i, etc)
531
532 i = skip_whitespace(text, new_i)
533
534 if text:sub(i, i) ~= ':' then
535 self:onDecodeError("expected colon", text, i, etc)
536 end
537
538 i = skip_whitespace(text, i + 1)
539
540 local new_val, new_i = grok_one(self, text, i)
541
542 VALUE[key] = new_val
543
544 --
545 -- Expect now either '}' to end things, or a ',' to allow us to continue.
546 --
547 i = skip_whitespace(text, new_i)
548
549 local c = text:sub(i,i)
550
551 if c == '}' then
552 return VALUE, i + 1
553 end
554
555 if text:sub(i, i) ~= ',' then
556 self:onDecodeError("expected comma or '}'", text, i, etc)
557 end
558
559 i = skip_whitespace(text, i + 1)
560 end
561
562 self:onDecodeError("unclosed '{'", text, start, etc)
563end
564
565local function grok_array(self, text, start, etc)
566 if text:sub(start,start) ~= '[' then
567 self:onDecodeError("expected '['", text, start, etc)
568 end
569
570 local i = skip_whitespace(text, start + 1) -- +1 to skip the '['
571 local VALUE = self.strictTypes and self:newArray { } or { }
572 if text:sub(i,i) == ']' then
573 return VALUE, i + 1
574 end
575
576 local VALUE_INDEX = 1
577
578 local text_len = text:len()
579 while i <= text_len do
580 local val, new_i = grok_one(self, text, i)
581
582 -- can't table.insert(VALUE, val) here because it's a no-op if val is nil
583 VALUE[VALUE_INDEX] = val
584 VALUE_INDEX = VALUE_INDEX + 1
585
586 i = skip_whitespace(text, new_i)
587
588 --
589 -- Expect now either ']' to end things, or a ',' to allow us to continue.
590 --
591 local c = text:sub(i,i)
592 if c == ']' then
593 return VALUE, i + 1
594 end
595 if text:sub(i, i) ~= ',' then
596 self:onDecodeError("expected comma or '['", text, i, etc)
597 end
598 i = skip_whitespace(text, i + 1)
599 end
600 self:onDecodeError("unclosed '['", text, start, etc)
601end
602
603
604grok_one = function(self, text, start, etc)
605 -- Skip any whitespace
606 start = skip_whitespace(text, start)
607
608 if start > text:len() then
609 self:onDecodeError("unexpected end of string", text, nil, etc)
610 end
611
612 if text:find('^"', start) then
613 return grok_string(self, text, start, etc)
614
615 elseif text:find('^[-0123456789 ]', start) then
616 return grok_number(self, text, start, etc)
617
618 elseif text:find('^%{', start) then
619 return grok_object(self, text, start, etc)
620
621 elseif text:find('^%[', start) then
622 return grok_array(self, text, start, etc)
623
624 elseif text:find('^true', start) then
625 return true, start + 4
626
627 elseif text:find('^false', start) then
628 return false, start + 5
629
630 elseif text:find('^null', start) then
631 return nil, start + 4
632
633 else
634 self:onDecodeError("can't parse JSON", text, start, etc)
635 end
636end
637
638function OBJDEF:decode(text, etc)
639 if type(self) ~= 'table' or self.__index ~= OBJDEF then
640 OBJDEF:onDecodeError("JSON:decode must be called in method format", nil, nil, etc)
641 end
642
643 if text == nil then
644 self:onDecodeOfNilError(string.format("nil passed to JSON:decode()"), nil, nil, etc)
645 elseif type(text) ~= 'string' then
646 self:onDecodeError(string.format("expected string argument to JSON:decode(), got %s", type(text)), nil, nil, etc)
647 end
648
649 if text:match('^%s*$') then
650 return nil
651 end
652
653 if text:match('^%s*<') then
654 -- Can't be JSON... we'll assume it's HTML
655 self:onDecodeOfHTMLError(string.format("html passed to JSON:decode()"), text, nil, etc)
656 end
657
658 --
659 -- Ensure that it's not UTF-32 or UTF-16.
660 -- Those are perfectly valid encodings for JSON (as per RFC 4627 section 3),
661 -- but this package can't handle them.
662 --
663 if text:sub(1,1):byte() == 0 or (text:len() >= 2 and text:sub(2,2):byte() == 0) then
664 self:onDecodeError("JSON package groks only UTF-8, sorry", text, nil, etc)
665 end
666
667 local success, value = pcall(grok_one, self, text, 1, etc)
668
669 if success then
670 return value
671 else
672 -- if JSON:onDecodeError() didn't abort out of the pcall, we'll have received the error message here as "value", so pass it along as an assert.
673 if self.assert then
674 self.assert(false, value)
675 else
676 assert(false, value)
677 end
678 -- and if we're still here, return a nil and throw the error message on as a second arg
679 return nil, value
680 end
681end
682
683local function backslash_replacement_function(c)
684 if c == "\n" then
685 return "\\n"
686 elseif c == "\r" then
687 return "\\r"
688 elseif c == "\t" then
689 return "\\t"
690 elseif c == "\b" then
691 return "\\b"
692 elseif c == "\f" then
693 return "\\f"
694 elseif c == '"' then
695 return '\\"'
696 elseif c == '\\' then
697 return '\\\\'
698 else
699 return string.format("\\u%04x", c:byte())
700 end
701end
702
703local chars_to_be_escaped_in_JSON_string
704 = '['
705 .. '"' -- class sub-pattern to match a double quote
706 .. '%\\' -- class sub-pattern to match a backslash
707 .. '%z' -- class sub-pattern to match a null
708 .. '\001' .. '-' .. '\031' -- class sub-pattern to match control characters
709 .. ']'
710
711local function json_string_literal(value)
712 local newval = value:gsub(chars_to_be_escaped_in_JSON_string, backslash_replacement_function)
713 return '"' .. newval .. '"'
714end
715
716local function object_or_array(self, T, etc)
717 --
718 -- We need to inspect all the keys... if there are any strings, we'll convert to a JSON
719 -- object. If there are only numbers, it's a JSON array.
720 --
721 -- If we'll be converting to a JSON object, we'll want to sort the keys so that the
722 -- end result is deterministic.
723 --
724 local string_keys = { }
725 local number_keys = { }
726 local number_keys_must_be_strings = false
727 local maximum_number_key
728
729 for key in pairs(T) do
730 if type(key) == 'string' then
731 table.insert(string_keys, key)
732 elseif type(key) == 'number' then
733 table.insert(number_keys, key)
734 if key <= 0 or key >= math.huge then
735 number_keys_must_be_strings = true
736 elseif not maximum_number_key or key > maximum_number_key then
737 maximum_number_key = key
738 end
739 else
740 self:onEncodeError("can't encode table with a key of type " .. type(key), etc)
741 end
742 end
743
744 if #string_keys == 0 and not number_keys_must_be_strings then
745 --
746 -- An empty table, or a numeric-only array
747 --
748 if #number_keys > 0 then
749 return nil, maximum_number_key -- an array
750 elseif tostring(T) == "JSON array" then
751 return nil
752 elseif tostring(T) == "JSON object" then
753 return { }
754 else
755 -- have to guess, so we'll pick array, since empty arrays are likely more common than empty objects
756 return nil
757 end
758 end
759
760 table.sort(string_keys)
761
762 local map
763 if #number_keys > 0 then
764 --
765 -- If we're here then we have either mixed string/number keys, or numbers inappropriate for a JSON array
766 -- It's not ideal, but we'll turn the numbers into strings so that we can at least create a JSON object.
767 --
768
769 if self.noKeyConversion then
770 self:onEncodeError("a table with both numeric and string keys could be an object or array; aborting", etc)
771 end
772
773 --
774 -- Have to make a shallow copy of the source table so we can remap the numeric keys to be strings
775 --
776 map = { }
777 for key, val in pairs(T) do
778 map[key] = val
779 end
780
781 table.sort(number_keys)
782
783 --
784 -- Throw numeric keys in there as strings
785 --
786 for _, number_key in ipairs(number_keys) do
787 local string_key = tostring(number_key)
788 if map[string_key] == nil then
789 table.insert(string_keys , string_key)
790 map[string_key] = T[number_key]
791 else
792 self:onEncodeError("conflict converting table with mixed-type keys into a JSON object: key " .. number_key .. " exists both as a string and a number.", etc)
793 end
794 end
795 end
796
797 return string_keys, nil, map
798end
799
800--
801-- Encode
802--
803-- 'options' is nil, or a table with possible keys:
804-- pretty -- if true, return a pretty-printed version
805-- indent -- a string (usually of spaces) used to indent each nested level
806-- align_keys -- if true, align all the keys when formatting a table
807--
808local encode_value -- must predeclare because it calls itself
809function encode_value(self, value, parents, etc, options, indent)
810
811 if value == nil then
812 return 'null'
813
814 elseif type(value) == 'string' then
815 return json_string_literal(value)
816
817 elseif type(value) == 'number' then
818 if value ~= value then
819 --
820 -- NaN (Not a Number).
821 -- JSON has no NaN, so we have to fudge the best we can. This should really be a package option.
822 --
823 return "null"
824 elseif value >= math.huge then
825 --
826 -- Positive infinity. JSON has no INF, so we have to fudge the best we can. This should
827 -- really be a package option. Note: at least with some implementations, positive infinity
828 -- is both ">= math.huge" and "<= -math.huge", which makes no sense but that's how it is.
829 -- Negative infinity is properly "<= -math.huge". So, we must be sure to check the ">="
830 -- case first.
831 --
832 return "1e+9999"
833 elseif value <= -math.huge then
834 --
835 -- Negative infinity.
836 -- JSON has no INF, so we have to fudge the best we can. This should really be a package option.
837 --
838 return "-1e+9999"
839 else
840 return tostring(value)
841 end
842
843 elseif type(value) == 'boolean' then
844 return tostring(value)
845
846 elseif type(value) ~= 'table' then
847 self:onEncodeError("can't convert " .. type(value) .. " to JSON", etc)
848
849 else
850 --
851 -- A table to be converted to either a JSON object or array.
852 --
853 local T = value
854
855 if type(options) ~= 'table' then
856 options = {}
857 end
858 if type(indent) ~= 'string' then
859 indent = ""
860 end
861
862 if parents[T] then
863 self:onEncodeError("table " .. tostring(T) .. " is a child of itself", etc)
864 else
865 parents[T] = true
866 end
867
868 local result_value
869
870 local object_keys, maximum_number_key, map = object_or_array(self, T, etc)
871 if maximum_number_key then
872 --
873 -- An array...
874 --
875 local ITEMS = { }
876 for i = 1, maximum_number_key do
877 table.insert(ITEMS, encode_value(self, T[i], parents, etc, options, indent))
878 end
879
880 if options.pretty then
881 result_value = "[ " .. table.concat(ITEMS, ", ") .. " ]"
882 else
883 result_value = "[" .. table.concat(ITEMS, ",") .. "]"
884 end
885
886 elseif object_keys then
887 --
888 -- An object
889 --
890 local TT = map or T
891
892 if options.pretty then
893
894 local KEYS = { }
895 local max_key_length = 0
896 for _, key in ipairs(object_keys) do
897 local encoded = encode_value(self, tostring(key), parents, etc, options, indent)
898 if options.align_keys then
899 max_key_length = math.max(max_key_length, #encoded)
900 end
901 table.insert(KEYS, encoded)
902 end
903 local key_indent = indent .. tostring(options.indent or "")
904 local subtable_indent = key_indent .. string.rep(" ", max_key_length) .. (options.align_keys and " " or "")
905 local FORMAT = "%s%" .. string.format("%d", max_key_length) .. "s: %s"
906
907 local COMBINED_PARTS = { }
908 for i, key in ipairs(object_keys) do
909 local encoded_val = encode_value(self, TT[key], parents, etc, options, subtable_indent)
910 table.insert(COMBINED_PARTS, string.format(FORMAT, key_indent, KEYS[i], encoded_val))
911 end
912 result_value = "{\n" .. table.concat(COMBINED_PARTS, ",\n") .. "\n" .. indent .. "}"
913
914 else
915
916 local PARTS = { }
917 for _, key in ipairs(object_keys) do
918 local encoded_val = encode_value(self, TT[key], parents, etc, options, indent)
919 local encoded_key = encode_value(self, tostring(key), parents, etc, options, indent)
920 table.insert(PARTS, string.format("%s:%s", encoded_key, encoded_val))
921 end
922 result_value = "{" .. table.concat(PARTS, ",") .. "}"
923
924 end
925 else
926 --
927 -- An empty array/object... we'll treat it as an array, though it should really be an option
928 --
929 result_value = "[]"
930 end
931
932 parents[T] = false
933 return result_value
934 end
935end
936
937
938function OBJDEF:encode(value, etc, options)
939 if type(self) ~= 'table' or self.__index ~= OBJDEF then
940 OBJDEF:onEncodeError("JSON:encode must be called in method format", etc)
941 end
942 return encode_value(self, value, {}, etc, options or nil)
943end
944
945function OBJDEF:encode_pretty(value, etc, options)
946 if type(self) ~= 'table' or self.__index ~= OBJDEF then
947 OBJDEF:onEncodeError("JSON:encode_pretty must be called in method format", etc)
948 end
949 return encode_value(self, value, {}, etc, options or default_pretty_options)
950end
951
952function OBJDEF.__tostring()
953 return "JSON encode/decode package"
954end
955
956OBJDEF.__index = OBJDEF
957
958function OBJDEF:new(args)
959 local new = { }
960
961 if args then
962 for key, val in pairs(args) do
963 new[key] = val
964 end
965 end
966
967 return setmetatable(new, OBJDEF)
968end
969
970return OBJDEF:new()
971
972--
973-- Version history:
974--
975-- 20141223.14 The encode_pretty() routine produced fine results for small datasets, but isn't really
976-- appropriate for anything large, so with help from Alex Aulbach I've made the encode routines
977-- more flexible, and changed the default encode_pretty() to be more generally useful.
978--
979-- Added a third 'options' argument to the encode() and encode_pretty() routines, to control
980-- how the encoding takes place.
981--
982-- Updated docs to add assert() call to the loadfile() line, just as good practice so that
983-- if there is a problem loading JSON.lua, the appropriate error message will percolate up.
984--
985-- 20140920.13 Put back (in a way that doesn't cause warnings about unused variables) the author string,
986-- so that the source of the package, and its version number, are visible in compiled copies.
987--
988-- 20140911.12 Minor lua cleanup.
989-- Fixed internal reference to 'JSON.noKeyConversion' to reference 'self' instead of 'JSON'.
990-- (Thanks to SmugMug's David Parry for these.)
991--
992-- 20140418.11 JSON nulls embedded within an array were being ignored, such that
993-- ["1",null,null,null,null,null,"seven"],
994-- would return
995-- {1,"seven"}
996-- It's now fixed to properly return
997-- {1, nil, nil, nil, nil, nil, "seven"}
998-- Thanks to "haddock" for catching the error.
999--
1000-- 20140116.10 The user's JSON.assert() wasn't always being used. Thanks to "blue" for the heads up.
1001--
1002-- 20131118.9 Update for Lua 5.3... it seems that tostring(2/1) produces "2.0" instead of "2",
1003-- and this caused some problems.
1004--
1005-- 20131031.8 Unified the code for encode() and encode_pretty(); they had been stupidly separate,
1006-- and had of course diverged (encode_pretty didn't get the fixes that encode got, so
1007-- sometimes produced incorrect results; thanks to Mattie for the heads up).
1008--
1009-- Handle encoding tables with non-positive numeric keys (unlikely, but possible).
1010--
1011-- If a table has both numeric and string keys, or its numeric keys are inappropriate
1012-- (such as being non-positive or infinite), the numeric keys are turned into
1013-- string keys appropriate for a JSON object. So, as before,
1014-- JSON:encode({ "one", "two", "three" })
1015-- produces the array
1016-- ["one","two","three"]
1017-- but now something with mixed key types like
1018-- JSON:encode({ "one", "two", "three", SOMESTRING = "some string" }))
1019-- instead of throwing an error produces an object:
1020-- {"1":"one","2":"two","3":"three","SOMESTRING":"some string"}
1021--
1022-- To maintain the prior throw-an-error semantics, set
1023-- JSON.noKeyConversion = true
1024--
1025-- 20131004.7 Release under a Creative Commons CC-BY license, which I should have done from day one, sorry.
1026--
1027-- 20130120.6 Comment update: added a link to the specific page on my blog where this code can
1028-- be found, so that folks who come across the code outside of my blog can find updates
1029-- more easily.
1030--
1031-- 20111207.5 Added support for the 'etc' arguments, for better error reporting.
1032--
1033-- 20110731.4 More feedback from David Kolf on how to make the tests for Nan/Infinity system independent.
1034--
1035-- 20110730.3 Incorporated feedback from David Kolf at http://lua-users.org/wiki/JsonModules:
1036--
1037-- * When encoding lua for JSON, Sparse numeric arrays are now handled by
1038-- spitting out full arrays, such that
1039-- JSON:encode({"one", "two", [10] = "ten"})
1040-- returns
1041-- ["one","two",null,null,null,null,null,null,null,"ten"]
1042--
1043-- In 20100810.2 and earlier, only up to the first non-null value would have been retained.
1044--
1045-- * When encoding lua for JSON, numeric value NaN gets spit out as null, and infinity as "1+e9999".
1046-- Version 20100810.2 and earlier created invalid JSON in both cases.
1047--
1048-- * Unicode surrogate pairs are now detected when decoding JSON.
1049--
1050-- 20100810.2 added some checking to ensure that an invalid Unicode character couldn't leak in to the UTF-8 encoding
1051--
1052-- 20100731.1 initial public release
1053--