all: sets _ENV to nil using local _ENV = nil to avoid global writing
[luajson.git] / lua / json / encode / strings.lua
blob09d85a910051482c4f8b8727f94cc6f334175528
1 --[[
2 Licensed according to the included 'LICENSE' document
3 Author: Thomas Harning Jr <harningt@gmail.com>
4 ]]
5 local string_char = require("string").char
6 local pairs = pairs
8 local jsonutil = require("json.util")
9 local util_merge = jsonutil.merge
11 local _ENV = nil
13 local normalEncodingMap = {
14 ['"'] = '\\"',
15 ['\\'] = '\\\\',
16 ['/'] = '\\/',
17 ['\b'] = '\\b',
18 ['\f'] = '\\f',
19 ['\n'] = '\\n',
20 ['\r'] = '\\r',
21 ['\t'] = '\\t',
22 ['\v'] = '\\v' -- not in official spec, on report, removing
25 local xEncodingMap = {}
26 for char, encoded in pairs(normalEncodingMap) do
27 xEncodingMap[char] = encoded
28 end
30 -- Pre-encode the control characters to speed up encoding...
31 -- NOTE: UTF-8 may not work out right w/ JavaScript
32 -- JavaScript uses 2 bytes after a \u... yet UTF-8 is a
33 -- byte-stream encoding, not pairs of bytes (it does encode
34 -- some letters > 1 byte, but base case is 1)
35 for i = 0, 255 do
36 local c = string_char(i)
37 if c:match('[%z\1-\031\128-\255]') and not normalEncodingMap[c] then
38 -- WARN: UTF8 specializes values >= 0x80 as parts of sequences...
39 -- without \x encoding, do not allow encoding > 7F
40 normalEncodingMap[c] = ('\\u%.4X'):format(i)
41 xEncodingMap[c] = ('\\x%.2X'):format(i)
42 end
43 end
45 local defaultOptions = {
46 xEncode = false, -- Encode single-bytes as \xXX
47 processor = nil, -- Simple processor for the string prior to quoting
48 -- / is not required to be quoted but it helps with certain decoding
49 -- Required encoded characters, " \, and 00-1F (0 - 31)
50 encodeSet = '\\"/%z\1-\031',
51 encodeSetAppend = nil -- Chars to append to the default set
54 local modeOptions = {}
56 local function mergeOptions(options, mode)
57 jsonutil.doOptionMerge(options, false, 'strings', defaultOptions, mode and modeOptions[mode])
58 end
60 local function getEncoder(options)
61 options = options and util_merge({}, defaultOptions, options) or defaultOptions
62 local encodeSet = options.encodeSet
63 if options.encodeSetAppend then
64 encodeSet = encodeSet .. options.encodeSetAppend
65 end
66 local encodingMap = options.xEncode and xEncodingMap or normalEncodingMap
67 local encodeString
68 if options.processor then
69 local processor = options.processor
70 encodeString = function(s, state)
71 return '"' .. processor(s:gsub('[' .. encodeSet .. ']', encodingMap)) .. '"'
72 end
73 else
74 encodeString = function(s, state)
75 return '"' .. s:gsub('[' .. encodeSet .. ']', encodingMap) .. '"'
76 end
77 end
78 return {
79 string = encodeString
81 end
83 local strings = {
84 mergeOptions = mergeOptions,
85 getEncoder = getEncoder
88 return strings