= Lua CJSON 1.0devel Manual = Mark Pulford :revdate: November 30, 2011 Overview -------- The Lua CJSON library provides JSON support for Lua. .Features - Fast, standards compliant encoding/parsing routines - Full support for JSON with UTF-8, including decoding surrogate pairs - Optional run-time support for common exceptions to the JSON specification (NaN, Infinity,..) - No external dependencies .Caveats - UTF-16 and UTF-32 are not supported. Lua CJSON is covered by the MIT license. Review the file +LICENSE+ for details. The latest version of this software is available from the http://www.kyne.com.au/~mark/software/lua-cjson.php[Lua CJSON website]. Feel free to email me if you have any patches, suggestions, or comments. Installation Methods -------------------- Lua CJSON requires either http://www.lua.org[Lua] 5.1, Lua 5.2, or http://www.luajit.org[LuaJIT] to build. There are 4 build methods available: [horizontal] Make:: Unix (including Linux, BSD, Mac OSX & Solaris) CMake:: Unix, Windows RPM:: Linux LuaRocks:: Unix, Windows Make ~~~~ Review and update the included Makefile to suit your platform. Next, build and install the module: [source,sh] make install Or install manually: [source,sh] make cp cjson.so $your_lua_module_directory CMake ~~~~~ http://www.cmake.org[CMake] can generate build configuration for many different platforms (including Unix and Windows). [source,sh] mkdir build cd build cmake .. make cp cjson.so $your_lua_module_directory Review the http://www.cmake.org/cmake/help/documentation.html[CMake documentation] for further details. RPM ~~~ Linux distributions using RPM should be able to create a package via the included RPM spec file. Install the +rpm-build+ package (or similar) then: [source,sh] rpmbuild -tb lua-cjson-1.0devel.tar.gz rpm -Uvh $newly_built_lua_cjson_rpm LuaRocks ~~~~~~~~ http://luarocks.org[LuaRocks] can be used to install and manage Lua modules on a wide range of platforms (including Windows). Extract the Lua CJSON source package into a directory and run: [source,sh] cd lua-cjson-1.0devel luarocks make [NOTE] LuaRocks does not support platform specific configuration for Solaris. On Solaris, you may need to manually uncomment +USE_INTERNAL_ISINF+ in the rockspec before building this module. Review the http://luarocks.org/en/Documentation[LuaRocks documentation] for further details. Build Options (#define) ~~~~~~~~~~~~~~~~~~~~~~~ [horizontal] USE_INTERNAL_ISINF:: Workaround for Solaris platforms missing ++isinf++(3). DISABLE_CJSON_GLOBAL:: Do not store module table in global "cjson" variable. Redundant from Lua 5.2 onwards. DISABLE_INVALID_NUMBERS:: Recommended on platforms where ++strtod++(3) / ++sprintf++(3) are not POSIX compliant (Eg, Windows MinGW). Restricts the +cjson.refuse_invalid_numbers+ runtime configuration to +true+. Built-in dtoa() support ^^^^^^^^^^^^^^^^^^^^^^^ Lua CJSON may be built with David Gay's http://www.netlib.org/fp/[floating point conversion routines]. This can increase overall performance by 50% or more on some platforms when converting data number heavy data. However, this option reduces portability and is disabled by default. [horizontal] USE_INTERNAL_DTOA:: Enable internal number conversion routines. IEEE_BIG_ENDIAN:: Must be set on big endian architectures. MULTIPLE_THREADS:: Must be set when Lua CJSON may be used in a multi-threaded application. Requries _pthreads_. API (Functions) --------------- Synopsis ~~~~~~~~ [source,lua] ------------ -- Module initalisation methods local cjson = require "cjson" local cjson2 = cjson.new() -- Translate Lua value to/from JSON text = cjson.encode(value) value = cjson.decode(text) -- Get and/or set Lua CJSON configuration setting = cjson.refuse_invalid_numbers([setting]) depth = cjson.encode_max_depth([depth]) convert, ratio, safe = cjson.encode_sparse_array([convert[, ratio[, safe]]]) keep = cjson.encode_keep_buffer([keep]) ------------ Module Instantiation ~~~~~~~~~~~~~~~~~~~~ [source,lua] ------------ local cjson = require "cjson" local cjson2 = cjson.new() ------------ Lua CJSON can be loaded via the Lua +require+ function. A global +cjson+ module table is registered under Lua 5.1 to maintain backward compatibility. Lua CJSON does not register a global table under Lua 5.2 since this practice is discouraged. +cjson.new+ can be used to instantiate an independent copy of the Lua CJSON module. The new module has a separate persistent encoding buffer, and default settings. Lua CJSON can support Lua implementations using multiple pre-emptive threads within a single Lua state provided the persistent encoding buffer is not shared. This can be achieved by one of the following methods: - Disabling the persistent encoding buffer with +cjson.encode_keep_buffer+ - Ensuring each thread calls +cjson.encode+ at a time - Using a separate +cjson+ module table per pre-emptive thread (+cjson.new+) [NOTE] Lua CJSON uses ++strtod++(3) and ++snprintf++(3) to perform numeric conversion as they are usually well supported, fast and bug free. However, these functions require a workaround for JSON encoding/parsing under locales using a comma decimal separator. Lua CJSON detects the current locale during instantiation to determine whether a workaround is required. CJSON should be reinitialised via +cjson.new+ if the locale of the current process changes. Different locales per thread are not supported. decode ~~~~~~ [source,lua] ------------ value = cjson.decode(json_text) ------------ +cjson.decode+ will deserialise any UTF-8 JSON string into a Lua value or table. It may return any of the types that +cjson.encode+ supports. UTF-16 and UTF-32 JSON strings are not supported. +cjson.decode+ requires that any NULL (ASCII 0) and double quote (ASCII 34) characters are escaped within strings. All escape codes will be decoded and other characters will be passed transparently. UTF-8 characters are not validated during decoding and should be checked elsewhere if required. JSON +null+ will be converted to a NULL +lightuserdata+ value. This can be compared with +cjson.null+ for convenience. By default, numbers incompatible with the JSON specification (NaN, Infinity, Hexadecimal) can be decoded. This default can be changed with +cjson.refuse_invalid_numbers+. .Example: Decoding [source,lua] json_text = '[ true, { "foo": "bar" } ]' value = cjson.decode(json_text) -- Returns: { true, { foo = "bar" } } [CAUTION] Care must be taken when after decoding JSON objects with numeric keys. Each numeric key will be stored as a Lua +string+. Any code assuming type +number+ may break. encode ~~~~~~ [source,lua] ------------ json_text = cjson.encode(value) ------------ +cjson.encode+ will serialise a Lua value into a string containing the JSON representation. +cjson.encode+ supports the following types: - +boolean+ - +lightuserdata+ (NULL value only) - +nil+ - +number+ - +string+ - +table+ The remaining Lua types will generate an error: - +function+ - +lightuserdata+ (non-NULL values) - +thread+ - +userdata+ By default, numbers are encoded using the standard Lua number +printf+(3) format (+%.14g+). Lua CJSON will escape the following characters within each UTF-8 string: - Control characters (ASCII 0 - 31) - Double quote (ASCII 34) - Forward slash (ASCII 47) - Blackslash (ASCII 92) - Delete (ASCII 127) All other characters are passed transparently. [CAUTION] ========= Lua CJSON will successfully encode/decode binary strings, but this is technically not supported by JSON and may not be compatible with other JSON libraries. Applications should ensure all Lua strings passed to +cjson.encode+ are valid UTF-8 to ensure the output is valid JSON. Base64 is a common way to transport binary data through JSON. Lua Base64 routines can be found in the http://w3.impa.br/~diego/software/luasocket/[LuaSocket] and http://www.tecgraf.puc-rio.br/~lhf/ftp/lua/#lbase64[lbase64] packages. ========= Lua CJSON uses a heuristic to determine whether to encode a Lua table as a JSON array or an object. A Lua table with only positive integers keys of type +number+ will be encoded as a JSON array. All other tables will be encoded as a JSON object. Refer to <> for details on sparse array handling. Lua CJSON does not use metamethods when serialising tables. - +rawget+ is used to iterate over Lua arrays - +next+ is used to iterate over Lua objects JSON object keys are always strings. +cjson.encode+ can only handle table keys which are type +number+ or +string+. All other types will generate an error. [NOTE] Standards compliant JSON must be encapsulated in either an object (+{}+) or an array (+[]+). Hence a table must be passed to +cjson.encode+ to generate standards compliant JSON output. This may not be required by some applications. By default, the following Lua values will generate errors: - Numbers incompatible with the JSON specification (NaN, Infinity, Hexadecimal) - Tables nested more than 20 levels deep - Excessively sparse Lua arrays These defaults can be changed with: - <> - <> - <> .Example: Encoding [source,lua] value = { true, { foo = "bar" } } json_text = cjson.encode(value) -- Returns: '[true,{"foo":"bar"}]' encode_keep_buffer ~~~~~~~~~~~~~~~~~~ [source,lua] ------------ keep = cjson.encode_keep_buffer([keep]) -- "keep" must be a boolean ------------ By default, Lua CJSON will reuse the JSON encoding buffer to improve performance. The buffer will grow to the largest size required and is not freed until the Lua CJSON module is garbage collected. Setting this option to +false+ will cause the buffer to be freed after each call to +cjson.encode+. This setting is only changed when an argument is provided. The current setting is always returned. [[encode_max_depth]] encode_max_depth ~~~~~~~~~~~~~~~~ [source,lua] ------------ depth = cjson.encode_max_depth([depth]) -- "depth" must be a positive integer ------------ By default, Lua CJSON will reject data structures with more than 20 nested tables. This setting is only changed when an argument is provided. The current setting is always returned. This check prevents a deeply nested or recursive data structure from crashing the application. .Example: Recursive Lua tables [source,lua] a = {}; b = { a }; a[1] = b Once the maximum table depth has been reached Lua CJSON will throw an error. encode_number_precision ~~~~~~~~~~~~~~~~~~~~~~~ [source,lua] ------------ precision = cjson.encode_number_precision([precision]) -- "precision" must be between 1 and 14 (inclusive) ------------ By default, Lua CJSON will output 14 significant digits when converting a number to text. This setting is only changed when an argument is provided. The current setting is always returned. Reducing number precision to _3_ can improve performance of number heavy JSON conversions by up to 50%. [[encode_sparse_array]] encode_sparse_array ~~~~~~~~~~~~~~~~~~~ [source,lua] ------------ convert, ratio, safe = cjson.encode_sparse_array([convert[, ratio[, safe]]]) -- "convert" must be a boolean. Default: false. -- "ratio" must be a positive integer. Default: 2 -- "safe" must be a positive integer. Default: 10 ------------ Lua CJSON classifies Lua tables into 3 types when encoding as a JSON array. This is determined by the number of values missing for keys up to the maximum index: Each particular setting is only changed when that argument is provided. The current settings are always returned. [horizontal] Normal:: All values are available. Sparse:: At least 1 value is missing. Excessively sparse:: The number of values missing exceed the configured ratio. Lua CJSON encodes sparse Lua arrays by as JSON arrays using JSON +null+. .Example: Encoding a sparse array [source,lua] cjson.encode({ [3] = "data" }) -- Returns: '[null,null,"data"]' Lua CJSON checks for excessively sparse arrays when the maximum index is greater an the +safe+ limit and +ratio+ is greater than +0+. An array is _excessively sparse_ when: _maximum_index_ > _item_count_ * +ratio+ By default, attempting to encode excessively sparse arrays will generate an error. If +convert+ is set to +true+, excessively sparse arrays will be converted to a JSON object: .Example: Enabling conversion to a JSON object [source,lua] cjson.encode_sparse_array(true) cjson.encode({ [1000] = "excessively sparse" }) -- Returns: '{"1000":"excessively sparse"}' [[refuse_invalid_numbers]] refuse_invalid_numbers ~~~~~~~~~~~~~~~~~~~~~~ [source,lua] ------------ setting = cjson.refuse_invalid_numbers([setting]) -- "setting" must be on of: -- false, "encode", "decode", "both", true ------------ Lua CJSON can throw an error for numbers outside of the JSON specification (_invalid numbers_): - Infinity - NaN - Hexadecimal By default Lua CJSON will decode _invalid numbers_, but will refuse to encode them. This setting is only changed when an argument is provided. The current setting is always returned. This setting can be configured separately for encoding and/or decoding: [horizontal] Enabled:: An error will be generated if an _invalid number_ is found. Disabled for encoding:: NaN and Infinity can be encoded. Disabled for decoding:: All numbers supported by +strtod+(3) will be parsed. API (Variables) --------------- _NAME ~~~~~ The name of the Lua CJSON module (+"cjson"+). _VERSION ~~~~~~~~ The version number of the Lua CJSON module (Eg, +"1.0devel"+). null ~~~~ Lua CJSON decodes JSON +null+ as a Lua +lightuserdata+ NULL pointer. +cjson.null+ is provided for comparison. [sect1] References ---------- - http://tools.ietf.org/html/rfc4627[RFC 4627] - http://www.json.org/[JSON website] // vi:ft=asciidoc tw=70: