6d4d752b19809fe6a841d924a5cabf1b215da52b
[project/luci.git] / libs / luci-lib-json / luasrc / json.lua
1 -- Copyright 2008 Steven Barth <steven@midlink.org>
2 -- Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
3 -- Licensed to the public under the Apache License 2.0.
4
5 local nixio     = require "nixio"
6 local util      = require "luci.util"
7 local table     = require "table"
8 local string    = require "string"
9 local coroutine = require "coroutine"
10
11 local assert    = assert
12 local tonumber  = tonumber
13 local tostring  = tostring
14 local error     = error
15 local type          = type
16 local pairs         = pairs
17 local ipairs    = ipairs
18 local next      = next
19 local pcall             = pcall
20
21 local band      = nixio.bit.band
22 local bor       = nixio.bit.bor
23 local rshift    = nixio.bit.rshift
24 local char      = string.char
25
26 local getmetatable = getmetatable
27
28 module "luci.json"
29
30
31 function decode(json, ...)
32         local a = ActiveDecoder(function() return nil end, ...)
33         a.chunk = json
34         local s, obj = pcall(a.get, a)
35         return s and obj or nil
36 end
37
38
39 function encode(obj, ...)
40         local out = {}
41         local e = Encoder(obj, 1, ...):source()
42         local chnk, err
43         repeat
44                 chnk, err = e()
45                 out[#out+1] = chnk
46         until not chnk
47         return not err and table.concat(out) or nil
48 end
49
50
51 function null()
52         return null
53 end
54
55 Encoder = util.class()
56
57 function Encoder.__init__(self, data, buffersize, fastescape)
58         self.data = data
59         self.buffersize = buffersize or 512
60         self.buffer = ""
61         self.fastescape = fastescape
62
63         getmetatable(self).__call = Encoder.source
64 end
65
66 function Encoder.source(self)
67         local source = coroutine.create(self.dispatch)
68         return function()
69                 local res, data = coroutine.resume(source, self, self.data, true)
70                 if res then
71                         return data
72                 else
73                         return nil, data
74                 end
75         end
76 end
77
78 function Encoder.dispatch(self, data, start)
79         local parser = self.parsers[type(data)]
80
81         parser(self, data)
82
83         if start then
84                 if #self.buffer > 0 then
85                         coroutine.yield(self.buffer)
86                 end
87
88                 coroutine.yield()
89         end
90 end
91
92 function Encoder.put(self, chunk)
93         if self.buffersize < 2 then
94                 coroutine.yield(chunk)
95         else
96                 if #self.buffer + #chunk > self.buffersize then
97                         local written = 0
98                         local fbuffer = self.buffersize - #self.buffer
99
100                         coroutine.yield(self.buffer .. chunk:sub(written + 1, fbuffer))
101                         written = fbuffer
102
103                         while #chunk - written > self.buffersize do
104                                 fbuffer = written + self.buffersize
105                                 coroutine.yield(chunk:sub(written + 1, fbuffer))
106                                 written = fbuffer
107                         end
108
109                         self.buffer = chunk:sub(written + 1)
110                 else
111                         self.buffer = self.buffer .. chunk
112                 end
113         end
114 end
115
116 function Encoder.parse_nil(self)
117         self:put("null")
118 end
119
120 function Encoder.parse_bool(self, obj)
121         self:put(obj and "true" or "false")
122 end
123
124 function Encoder.parse_number(self, obj)
125         self:put(tostring(obj))
126 end
127
128 function Encoder.parse_string(self, obj)
129         if self.fastescape then
130                 self:put('"' .. obj:gsub('\\', '\\\\'):gsub('"', '\\"') .. '"')
131         else
132                 self:put('"' ..
133                         obj:gsub('[%c\\"]',
134                                 function(char)
135                                         return '\\u00%02x' % char:byte()
136                                 end
137                         )
138                 .. '"')
139         end
140 end
141
142 function Encoder.parse_iter(self, obj)
143         if obj == null then
144                 return self:put("null")
145         end
146
147         if type(obj) == "table" and (#obj == 0 and next(obj)) then
148                 self:put("{")
149                 local first = true
150
151                 for key, entry in pairs(obj) do
152                         if key ~= null then
153                                 first = first or self:put(",")
154                                 first = first and false
155                                 self:parse_string(tostring(key))
156                                 self:put(":")
157                                 self:dispatch(entry)
158                         end
159                 end
160
161                 self:put("}")
162         else
163                 self:put("[")
164                 local first = true
165
166                 if type(obj) == "table" then
167                         for i=1, #obj do
168                                 first = first or self:put(",")
169                                 first = first and nil
170                                 self:dispatch(obj[i])
171                         end
172                 else
173                         for entry in obj do
174                                 first = first or self:put(",")
175                                 first = first and nil
176                                 self:dispatch(entry)
177                         end
178                 end
179
180                 self:put("]")
181         end
182 end
183
184 function Encoder.parse_udata(self, obj)
185         return self:parse_string(tostring(obj))
186 end
187
188 Encoder.parsers = {
189         ['nil']      = Encoder.parse_nil,
190         ['table']    = Encoder.parse_iter,
191         ['number']   = Encoder.parse_number,
192         ['string']   = Encoder.parse_string,
193         ['boolean']  = Encoder.parse_bool,
194         ['function'] = Encoder.parse_iter,
195         ['userdata'] = Encoder.parse_udata,
196 }
197
198
199 Decoder = util.class()
200
201 function Decoder.__init__(self, customnull)
202         self.cnull = customnull
203         getmetatable(self).__call = Decoder.sink
204 end
205
206 function Decoder.sink(self)
207         local sink = coroutine.create(self.dispatch)
208         return function(...)
209                 return coroutine.resume(sink, self, ...)
210         end
211 end
212
213
214 function Decoder.get(self)
215         return self.data
216 end
217
218 function Decoder.dispatch(self, chunk, src_err, strict)
219         local robject, object
220         local oset = false
221
222         while chunk do
223                 while chunk and #chunk < 1 do
224                         chunk = self:fetch()
225                 end
226
227                 assert(not strict or chunk, "Unexpected EOS")
228                 if not chunk then break end
229
230                 local char   = chunk:sub(1, 1)
231                 local parser = self.parsers[char]
232                  or (char:match("%s")     and self.parse_space)
233                  or (char:match("[0-9-]") and self.parse_number)
234                  or error("Unexpected char '%s'" % char)
235
236                 chunk, robject = parser(self, chunk)
237
238                 if parser ~= self.parse_space then
239                         assert(not oset, "Scope violation: Too many objects")
240                         object = robject
241                         oset = true
242
243                         if strict then
244                                 return chunk, object
245                         end
246                 end
247         end
248
249         assert(not src_err, src_err)
250         assert(oset, "Unexpected EOS")
251
252         self.data = object
253 end
254
255
256 function Decoder.fetch(self)
257         local tself, chunk, src_err = coroutine.yield()
258         assert(chunk or not src_err, src_err)
259         return chunk
260 end
261
262
263 function Decoder.fetch_atleast(self, chunk, bytes)
264         while #chunk < bytes do
265                 local nchunk = self:fetch()
266                 assert(nchunk, "Unexpected EOS")
267                 chunk = chunk .. nchunk
268         end
269
270         return chunk
271 end
272
273
274 function Decoder.fetch_until(self, chunk, pattern)
275         local start = chunk:find(pattern)
276
277         while not start do
278                 local nchunk = self:fetch()
279                 assert(nchunk, "Unexpected EOS")
280                 chunk = chunk .. nchunk
281                 start = chunk:find(pattern)
282         end
283
284         return chunk, start
285 end
286
287
288 function Decoder.parse_space(self, chunk)
289         local start = chunk:find("[^%s]")
290
291         while not start do
292                 chunk = self:fetch()
293                 if not chunk then
294                         return nil
295                 end
296                 start = chunk:find("[^%s]")
297         end
298
299         return chunk:sub(start)
300 end
301
302
303 function Decoder.parse_literal(self, chunk, literal, value)
304         chunk = self:fetch_atleast(chunk, #literal)
305         assert(chunk:sub(1, #literal) == literal, "Invalid character sequence")
306         return chunk:sub(#literal + 1), value
307 end
308
309
310 function Decoder.parse_null(self, chunk)
311         return self:parse_literal(chunk, "null", self.cnull and null)
312 end
313
314
315 function Decoder.parse_true(self, chunk)
316         return self:parse_literal(chunk, "true", true)
317 end
318
319
320 function Decoder.parse_false(self, chunk)
321         return self:parse_literal(chunk, "false", false)
322 end
323
324
325 function Decoder.parse_number(self, chunk)
326         local chunk, start = self:fetch_until(chunk, "[^0-9eE.+-]")
327         local number = tonumber(chunk:sub(1, start - 1))
328         assert(number, "Invalid number specification")
329         return chunk:sub(start), number
330 end
331
332
333 function Decoder.parse_string(self, chunk)
334         local str = ""
335         local object = nil
336         assert(chunk:sub(1, 1) == '"', 'Expected "')
337         chunk = chunk:sub(2)
338
339         while true do
340                 local spos = chunk:find('[\\"]')
341                 if spos then
342                         str = str .. chunk:sub(1, spos - 1)
343
344                         local char = chunk:sub(spos, spos)
345                         if char == '"' then                             -- String end
346                                 chunk = chunk:sub(spos + 1)
347                                 break
348                         elseif char == "\\" then                -- Escape sequence
349                                 chunk, object = self:parse_escape(chunk:sub(spos))
350                                 str = str .. object
351                         end
352                 else
353                         str = str .. chunk
354                         chunk = self:fetch()
355                         assert(chunk, "Unexpected EOS while parsing a string")
356                 end
357         end
358
359         return chunk, str
360 end
361
362
363 function Decoder.utf8_encode(self, s1, s2)
364         local n = s1 * 256 + s2
365
366         if n >= 0 and n <= 0x7F then
367                 return char(n)
368         elseif n >= 0 and n <= 0x7FF then
369                 return char(
370                         bor(band(rshift(n,  6), 0x1F), 0xC0),
371                         bor(band(n,             0x3F), 0x80)
372                 )
373         elseif n >= 0 and n <= 0xFFFF then
374                 return char(
375                         bor(band(rshift(n, 12), 0x0F), 0xE0),
376                         bor(band(rshift(n,  6), 0x3F), 0x80),
377                         bor(band(n,             0x3F), 0x80)
378                 )
379         elseif n >= 0 and n <= 0x10FFFF then
380                 return char(
381                         bor(band(rshift(n, 18), 0x07), 0xF0),
382                         bor(band(rshift(n, 12), 0x3F), 0x80),
383                         bor(band(rshift(n,  6), 0x3F), 0x80),
384                         bor(band(n,             0x3F), 0x80)
385                 )
386         else
387                 return "?"
388         end
389 end
390
391
392 function Decoder.parse_escape(self, chunk)
393         local str = ""
394         chunk = self:fetch_atleast(chunk:sub(2), 1)
395         local char = chunk:sub(1, 1)
396         chunk = chunk:sub(2)
397
398         if char == '"' then
399                 return chunk, '"'
400         elseif char == "\\" then
401                 return chunk, "\\"
402         elseif char == "u" then
403                 chunk = self:fetch_atleast(chunk, 4)
404                 local s1, s2 = chunk:sub(1, 2), chunk:sub(3, 4)
405                 s1, s2 = tonumber(s1, 16), tonumber(s2, 16)
406                 assert(s1 and s2, "Invalid Unicode character")
407
408                 return chunk:sub(5), self:utf8_encode(s1, s2)
409         elseif char == "/" then
410                 return chunk, "/"
411         elseif char == "b" then
412                 return chunk, "\b"
413         elseif char == "f" then
414                 return chunk, "\f"
415         elseif char == "n" then
416                 return chunk, "\n"
417         elseif char == "r" then
418                 return chunk, "\r"
419         elseif char == "t" then
420                 return chunk, "\t"
421         else
422                 error("Unexpected escaping sequence '\\%s'" % char)
423         end
424 end
425
426
427 function Decoder.parse_array(self, chunk)
428         chunk = chunk:sub(2)
429         local array = {}
430         local nextp = 1
431
432         local chunk, object = self:parse_delimiter(chunk, "%]")
433
434         if object then
435                 return chunk, array
436         end
437
438         repeat
439                 chunk, object = self:dispatch(chunk, nil, true)
440                 table.insert(array, nextp, object)
441                 nextp = nextp + 1
442
443                 chunk, object = self:parse_delimiter(chunk, ",%]")
444                 assert(object, "Delimiter expected")
445         until object == "]"
446
447         return chunk, array
448 end
449
450
451 function Decoder.parse_object(self, chunk)
452         chunk = chunk:sub(2)
453         local array = {}
454         local name
455
456         local chunk, object = self:parse_delimiter(chunk, "}")
457
458         if object then
459                 return chunk, array
460         end
461
462         repeat
463                 chunk = self:parse_space(chunk)
464                 assert(chunk, "Unexpected EOS")
465
466                 chunk, name   = self:parse_string(chunk)
467
468                 chunk, object = self:parse_delimiter(chunk, ":")
469                 assert(object, "Separator expected")
470
471                 chunk, object = self:dispatch(chunk, nil, true)
472                 array[name] = object
473
474                 chunk, object = self:parse_delimiter(chunk, ",}")
475                 assert(object, "Delimiter expected")
476         until object == "}"
477
478         return chunk, array
479 end
480
481
482 function Decoder.parse_delimiter(self, chunk, delimiter)
483         while true do
484                 chunk = self:fetch_atleast(chunk, 1)
485                 local char = chunk:sub(1, 1)
486                 if char:match("%s") then
487                         chunk = self:parse_space(chunk)
488                         assert(chunk, "Unexpected EOS")
489                 elseif char:match("[%s]" % delimiter) then
490                         return chunk:sub(2), char
491                 else
492                         return chunk, nil
493                 end
494         end
495 end
496
497
498 Decoder.parsers = {
499         ['"'] = Decoder.parse_string,
500         ['t'] = Decoder.parse_true,
501         ['f'] = Decoder.parse_false,
502         ['n'] = Decoder.parse_null,
503         ['['] = Decoder.parse_array,
504         ['{'] = Decoder.parse_object
505 }
506
507
508 ActiveDecoder = util.class(Decoder)
509
510 function ActiveDecoder.__init__(self, source, customnull)
511         Decoder.__init__(self, customnull)
512         self.source = source
513         self.chunk = nil
514         getmetatable(self).__call = self.get
515 end
516
517
518 function ActiveDecoder.get(self)
519         local chunk, src_err, object
520         if not self.chunk then
521                 chunk, src_err = self.source()
522         else
523                 chunk = self.chunk
524         end
525
526         self.chunk, object = self:dispatch(chunk, src_err, true)
527         return object
528 end
529
530
531 function ActiveDecoder.fetch(self)
532         local chunk, src_err = self.source()
533         assert(chunk or not src_err, src_err)
534         return chunk
535 end