Merge pull request #437 from fkooman/issue-436
[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 Encoder.parsers = {
185         ['nil']      = Encoder.parse_nil,
186         ['table']    = Encoder.parse_iter,
187         ['number']   = Encoder.parse_number,
188         ['string']   = Encoder.parse_string,
189         ['boolean']  = Encoder.parse_bool,
190         ['function'] = Encoder.parse_iter
191 }
192
193
194 Decoder = util.class()
195
196 function Decoder.__init__(self, customnull)
197         self.cnull = customnull
198         getmetatable(self).__call = Decoder.sink
199 end
200
201 function Decoder.sink(self)
202         local sink = coroutine.create(self.dispatch)
203         return function(...)
204                 return coroutine.resume(sink, self, ...)
205         end
206 end
207
208
209 function Decoder.get(self)
210         return self.data
211 end
212
213 function Decoder.dispatch(self, chunk, src_err, strict)
214         local robject, object
215         local oset = false
216
217         while chunk do
218                 while chunk and #chunk < 1 do
219                         chunk = self:fetch()
220                 end
221
222                 assert(not strict or chunk, "Unexpected EOS")
223                 if not chunk then break end
224
225                 local char   = chunk:sub(1, 1)
226                 local parser = self.parsers[char]
227                  or (char:match("%s")     and self.parse_space)
228                  or (char:match("[0-9-]") and self.parse_number)
229                  or error("Unexpected char '%s'" % char)
230
231                 chunk, robject = parser(self, chunk)
232
233                 if parser ~= self.parse_space then
234                         assert(not oset, "Scope violation: Too many objects")
235                         object = robject
236                         oset = true
237
238                         if strict then
239                                 return chunk, object
240                         end
241                 end
242         end
243
244         assert(not src_err, src_err)
245         assert(oset, "Unexpected EOS")
246
247         self.data = object
248 end
249
250
251 function Decoder.fetch(self)
252         local tself, chunk, src_err = coroutine.yield()
253         assert(chunk or not src_err, src_err)
254         return chunk
255 end
256
257
258 function Decoder.fetch_atleast(self, chunk, bytes)
259         while #chunk < bytes do
260                 local nchunk = self:fetch()
261                 assert(nchunk, "Unexpected EOS")
262                 chunk = chunk .. nchunk
263         end
264
265         return chunk
266 end
267
268
269 function Decoder.fetch_until(self, chunk, pattern)
270         local start = chunk:find(pattern)
271
272         while not start do
273                 local nchunk = self:fetch()
274                 assert(nchunk, "Unexpected EOS")
275                 chunk = chunk .. nchunk
276                 start = chunk:find(pattern)
277         end
278
279         return chunk, start
280 end
281
282
283 function Decoder.parse_space(self, chunk)
284         local start = chunk:find("[^%s]")
285
286         while not start do
287                 chunk = self:fetch()
288                 if not chunk then
289                         return nil
290                 end
291                 start = chunk:find("[^%s]")
292         end
293
294         return chunk:sub(start)
295 end
296
297
298 function Decoder.parse_literal(self, chunk, literal, value)
299         chunk = self:fetch_atleast(chunk, #literal)
300         assert(chunk:sub(1, #literal) == literal, "Invalid character sequence")
301         return chunk:sub(#literal + 1), value
302 end
303
304
305 function Decoder.parse_null(self, chunk)
306         return self:parse_literal(chunk, "null", self.cnull and null)
307 end
308
309
310 function Decoder.parse_true(self, chunk)
311         return self:parse_literal(chunk, "true", true)
312 end
313
314
315 function Decoder.parse_false(self, chunk)
316         return self:parse_literal(chunk, "false", false)
317 end
318
319
320 function Decoder.parse_number(self, chunk)
321         local chunk, start = self:fetch_until(chunk, "[^0-9eE.+-]")
322         local number = tonumber(chunk:sub(1, start - 1))
323         assert(number, "Invalid number specification")
324         return chunk:sub(start), number
325 end
326
327
328 function Decoder.parse_string(self, chunk)
329         local str = ""
330         local object = nil
331         assert(chunk:sub(1, 1) == '"', 'Expected "')
332         chunk = chunk:sub(2)
333
334         while true do
335                 local spos = chunk:find('[\\"]')
336                 if spos then
337                         str = str .. chunk:sub(1, spos - 1)
338
339                         local char = chunk:sub(spos, spos)
340                         if char == '"' then                             -- String end
341                                 chunk = chunk:sub(spos + 1)
342                                 break
343                         elseif char == "\\" then                -- Escape sequence
344                                 chunk, object = self:parse_escape(chunk:sub(spos))
345                                 str = str .. object
346                         end
347                 else
348                         str = str .. chunk
349                         chunk = self:fetch()
350                         assert(chunk, "Unexpected EOS while parsing a string")
351                 end
352         end
353
354         return chunk, str
355 end
356
357
358 function Decoder.utf8_encode(self, s1, s2)
359         local n = s1 * 256 + s2
360
361         if n >= 0 and n <= 0x7F then
362                 return char(n)
363         elseif n >= 0 and n <= 0x7FF then
364                 return char(
365                         bor(band(rshift(n,  6), 0x1F), 0xC0),
366                         bor(band(n,             0x3F), 0x80)
367                 )
368         elseif n >= 0 and n <= 0xFFFF then
369                 return char(
370                         bor(band(rshift(n, 12), 0x0F), 0xE0),
371                         bor(band(rshift(n,  6), 0x3F), 0x80),
372                         bor(band(n,             0x3F), 0x80)
373                 )
374         elseif n >= 0 and n <= 0x10FFFF then
375                 return char(
376                         bor(band(rshift(n, 18), 0x07), 0xF0),
377                         bor(band(rshift(n, 12), 0x3F), 0x80),
378                         bor(band(rshift(n,  6), 0x3F), 0x80),
379                         bor(band(n,             0x3F), 0x80)
380                 )
381         else
382                 return "?"
383         end
384 end
385
386
387 function Decoder.parse_escape(self, chunk)
388         local str = ""
389         chunk = self:fetch_atleast(chunk:sub(2), 1)
390         local char = chunk:sub(1, 1)
391         chunk = chunk:sub(2)
392
393         if char == '"' then
394                 return chunk, '"'
395         elseif char == "\\" then
396                 return chunk, "\\"
397         elseif char == "u" then
398                 chunk = self:fetch_atleast(chunk, 4)
399                 local s1, s2 = chunk:sub(1, 2), chunk:sub(3, 4)
400                 s1, s2 = tonumber(s1, 16), tonumber(s2, 16)
401                 assert(s1 and s2, "Invalid Unicode character")
402
403                 return chunk:sub(5), self:utf8_encode(s1, s2)
404         elseif char == "/" then
405                 return chunk, "/"
406         elseif char == "b" then
407                 return chunk, "\b"
408         elseif char == "f" then
409                 return chunk, "\f"
410         elseif char == "n" then
411                 return chunk, "\n"
412         elseif char == "r" then
413                 return chunk, "\r"
414         elseif char == "t" then
415                 return chunk, "\t"
416         else
417                 error("Unexpected escaping sequence '\\%s'" % char)
418         end
419 end
420
421
422 function Decoder.parse_array(self, chunk)
423         chunk = chunk:sub(2)
424         local array = {}
425         local nextp = 1
426
427         local chunk, object = self:parse_delimiter(chunk, "%]")
428
429         if object then
430                 return chunk, array
431         end
432
433         repeat
434                 chunk, object = self:dispatch(chunk, nil, true)
435                 table.insert(array, nextp, object)
436                 nextp = nextp + 1
437
438                 chunk, object = self:parse_delimiter(chunk, ",%]")
439                 assert(object, "Delimiter expected")
440         until object == "]"
441
442         return chunk, array
443 end
444
445
446 function Decoder.parse_object(self, chunk)
447         chunk = chunk:sub(2)
448         local array = {}
449         local name
450
451         local chunk, object = self:parse_delimiter(chunk, "}")
452
453         if object then
454                 return chunk, array
455         end
456
457         repeat
458                 chunk = self:parse_space(chunk)
459                 assert(chunk, "Unexpected EOS")
460
461                 chunk, name   = self:parse_string(chunk)
462
463                 chunk, object = self:parse_delimiter(chunk, ":")
464                 assert(object, "Separator expected")
465
466                 chunk, object = self:dispatch(chunk, nil, true)
467                 array[name] = object
468
469                 chunk, object = self:parse_delimiter(chunk, ",}")
470                 assert(object, "Delimiter expected")
471         until object == "}"
472
473         return chunk, array
474 end
475
476
477 function Decoder.parse_delimiter(self, chunk, delimiter)
478         while true do
479                 chunk = self:fetch_atleast(chunk, 1)
480                 local char = chunk:sub(1, 1)
481                 if char:match("%s") then
482                         chunk = self:parse_space(chunk)
483                         assert(chunk, "Unexpected EOS")
484                 elseif char:match("[%s]" % delimiter) then
485                         return chunk:sub(2), char
486                 else
487                         return chunk, nil
488                 end
489         end
490 end
491
492
493 Decoder.parsers = {
494         ['"'] = Decoder.parse_string,
495         ['t'] = Decoder.parse_true,
496         ['f'] = Decoder.parse_false,
497         ['n'] = Decoder.parse_null,
498         ['['] = Decoder.parse_array,
499         ['{'] = Decoder.parse_object
500 }
501
502
503 ActiveDecoder = util.class(Decoder)
504
505 function ActiveDecoder.__init__(self, source, customnull)
506         Decoder.__init__(self, customnull)
507         self.source = source
508         self.chunk = nil
509         getmetatable(self).__call = self.get
510 end
511
512
513 function ActiveDecoder.get(self)
514         local chunk, src_err, object
515         if not self.chunk then
516                 chunk, src_err = self.source()
517         else
518                 chunk = self.chunk
519         end
520
521         self.chunk, object = self:dispatch(chunk, src_err, true)
522         return object
523 end
524
525
526 function ActiveDecoder.fetch(self)
527         local chunk, src_err = self.source()
528         assert(chunk or not src_err, src_err)
529         return chunk
530 end