14fdcd213SMatt Stancliff /* Lua CJSON - JSON support for Lua
215108778Santirez *
34fdcd213SMatt Stancliff * Copyright (c) 2010-2012 Mark Pulford <[email protected]>
415108778Santirez *
515108778Santirez * Permission is hereby granted, free of charge, to any person obtaining
615108778Santirez * a copy of this software and associated documentation files (the
715108778Santirez * "Software"), to deal in the Software without restriction, including
815108778Santirez * without limitation the rights to use, copy, modify, merge, publish,
915108778Santirez * distribute, sublicense, and/or sell copies of the Software, and to
1015108778Santirez * permit persons to whom the Software is furnished to do so, subject to
1115108778Santirez * the following conditions:
1215108778Santirez *
1315108778Santirez * The above copyright notice and this permission notice shall be
1415108778Santirez * included in all copies or substantial portions of the Software.
1515108778Santirez *
1615108778Santirez * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1715108778Santirez * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1815108778Santirez * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1915108778Santirez * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
2015108778Santirez * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
2115108778Santirez * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
2215108778Santirez * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2315108778Santirez */
2415108778Santirez
2515108778Santirez /* Caveats:
2615108778Santirez * - JSON "null" values are represented as lightuserdata since Lua
2715108778Santirez * tables cannot contain "nil". Compare with cjson.null.
2815108778Santirez * - Invalid UTF-8 characters are not detected and will be passed
2915108778Santirez * untouched. If required, UTF-8 error checking should be done
3015108778Santirez * outside this library.
3115108778Santirez * - Javascript comments are not part of the JSON spec, and are not
3215108778Santirez * currently supported.
3315108778Santirez *
3415108778Santirez * Note: Decoding is slower than encoding. Lua spends significant
3515108778Santirez * time (30%) managing tables when parsing JSON since it is
3615108778Santirez * difficult to know object/array sizes ahead of time.
3715108778Santirez */
3815108778Santirez
3915108778Santirez #include <assert.h>
4015108778Santirez #include <string.h>
4115108778Santirez #include <math.h>
424fdcd213SMatt Stancliff #include <limits.h>
43*0ed2c601Santirez #include "lua.h"
44*0ed2c601Santirez #include "lauxlib.h"
4515108778Santirez
4615108778Santirez #include "strbuf.h"
474fdcd213SMatt Stancliff #include "fpconv.h"
4815108778Santirez
49a9900ad3SMatt Stancliff #include "../../../src/solarisfixes.h"
50a9900ad3SMatt Stancliff
514fdcd213SMatt Stancliff #ifndef CJSON_MODNAME
524fdcd213SMatt Stancliff #define CJSON_MODNAME "cjson"
534fdcd213SMatt Stancliff #endif
544fdcd213SMatt Stancliff
554fdcd213SMatt Stancliff #ifndef CJSON_VERSION
564fdcd213SMatt Stancliff #define CJSON_VERSION "2.1.0"
574fdcd213SMatt Stancliff #endif
584fdcd213SMatt Stancliff
594fdcd213SMatt Stancliff /* Workaround for Solaris platforms missing isinf() */
604fdcd213SMatt Stancliff #if !defined(isinf) && (defined(USE_INTERNAL_ISINF) || defined(MISSING_ISINF))
6115108778Santirez #define isinf(x) (!isnan(x) && isnan((x) - (x)))
6215108778Santirez #endif
6315108778Santirez
6415108778Santirez #define DEFAULT_SPARSE_CONVERT 0
6515108778Santirez #define DEFAULT_SPARSE_RATIO 2
6615108778Santirez #define DEFAULT_SPARSE_SAFE 10
674fdcd213SMatt Stancliff #define DEFAULT_ENCODE_MAX_DEPTH 1000
684fdcd213SMatt Stancliff #define DEFAULT_DECODE_MAX_DEPTH 1000
694fdcd213SMatt Stancliff #define DEFAULT_ENCODE_INVALID_NUMBERS 0
704fdcd213SMatt Stancliff #define DEFAULT_DECODE_INVALID_NUMBERS 1
7115108778Santirez #define DEFAULT_ENCODE_KEEP_BUFFER 1
724fdcd213SMatt Stancliff #define DEFAULT_ENCODE_NUMBER_PRECISION 14
734fdcd213SMatt Stancliff
744fdcd213SMatt Stancliff #ifdef DISABLE_INVALID_NUMBERS
754fdcd213SMatt Stancliff #undef DEFAULT_DECODE_INVALID_NUMBERS
764fdcd213SMatt Stancliff #define DEFAULT_DECODE_INVALID_NUMBERS 0
774fdcd213SMatt Stancliff #endif
7815108778Santirez
7915108778Santirez typedef enum {
8015108778Santirez T_OBJ_BEGIN,
8115108778Santirez T_OBJ_END,
8215108778Santirez T_ARR_BEGIN,
8315108778Santirez T_ARR_END,
8415108778Santirez T_STRING,
8515108778Santirez T_NUMBER,
8615108778Santirez T_BOOLEAN,
8715108778Santirez T_NULL,
8815108778Santirez T_COLON,
8915108778Santirez T_COMMA,
9015108778Santirez T_END,
9115108778Santirez T_WHITESPACE,
9215108778Santirez T_ERROR,
9315108778Santirez T_UNKNOWN
9415108778Santirez } json_token_type_t;
9515108778Santirez
9615108778Santirez static const char *json_token_type_name[] = {
9715108778Santirez "T_OBJ_BEGIN",
9815108778Santirez "T_OBJ_END",
9915108778Santirez "T_ARR_BEGIN",
10015108778Santirez "T_ARR_END",
10115108778Santirez "T_STRING",
10215108778Santirez "T_NUMBER",
10315108778Santirez "T_BOOLEAN",
10415108778Santirez "T_NULL",
10515108778Santirez "T_COLON",
10615108778Santirez "T_COMMA",
10715108778Santirez "T_END",
10815108778Santirez "T_WHITESPACE",
10915108778Santirez "T_ERROR",
11015108778Santirez "T_UNKNOWN",
11115108778Santirez NULL
11215108778Santirez };
11315108778Santirez
11415108778Santirez typedef struct {
11515108778Santirez json_token_type_t ch2token[256];
11615108778Santirez char escape2char[256]; /* Decoding */
1174fdcd213SMatt Stancliff
1184fdcd213SMatt Stancliff /* encode_buf is only allocated and used when
1194fdcd213SMatt Stancliff * encode_keep_buffer is set */
12015108778Santirez strbuf_t encode_buf;
12115108778Santirez
12215108778Santirez int encode_sparse_convert;
12315108778Santirez int encode_sparse_ratio;
12415108778Santirez int encode_sparse_safe;
12515108778Santirez int encode_max_depth;
1264fdcd213SMatt Stancliff int encode_invalid_numbers; /* 2 => Encode as "null" */
12715108778Santirez int encode_number_precision;
1284fdcd213SMatt Stancliff int encode_keep_buffer;
1294fdcd213SMatt Stancliff
1304fdcd213SMatt Stancliff int decode_invalid_numbers;
1314fdcd213SMatt Stancliff int decode_max_depth;
13215108778Santirez } json_config_t;
13315108778Santirez
13415108778Santirez typedef struct {
13515108778Santirez const char *data;
1364fdcd213SMatt Stancliff const char *ptr;
13715108778Santirez strbuf_t *tmp; /* Temporary storage for strings */
13815108778Santirez json_config_t *cfg;
1394fdcd213SMatt Stancliff int current_depth;
14015108778Santirez } json_parse_t;
14115108778Santirez
14215108778Santirez typedef struct {
14315108778Santirez json_token_type_t type;
14415108778Santirez int index;
14515108778Santirez union {
14615108778Santirez const char *string;
14715108778Santirez double number;
14815108778Santirez int boolean;
14915108778Santirez } value;
15015108778Santirez int string_len;
15115108778Santirez } json_token_t;
15215108778Santirez
15315108778Santirez static const char *char2escape[256] = {
15415108778Santirez "\\u0000", "\\u0001", "\\u0002", "\\u0003",
15515108778Santirez "\\u0004", "\\u0005", "\\u0006", "\\u0007",
15615108778Santirez "\\b", "\\t", "\\n", "\\u000b",
15715108778Santirez "\\f", "\\r", "\\u000e", "\\u000f",
15815108778Santirez "\\u0010", "\\u0011", "\\u0012", "\\u0013",
15915108778Santirez "\\u0014", "\\u0015", "\\u0016", "\\u0017",
16015108778Santirez "\\u0018", "\\u0019", "\\u001a", "\\u001b",
16115108778Santirez "\\u001c", "\\u001d", "\\u001e", "\\u001f",
16215108778Santirez NULL, NULL, "\\\"", NULL, NULL, NULL, NULL, NULL,
16315108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\\/",
16415108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
16515108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
16615108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
16715108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
16815108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
16915108778Santirez NULL, NULL, NULL, NULL, "\\\\", NULL, NULL, NULL,
17015108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
17115108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
17215108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
17315108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\\u007f",
17415108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
17515108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
17615108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
17715108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
17815108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
17915108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
18015108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
18115108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
18215108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
18315108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
18415108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
18515108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
18615108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
18715108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
18815108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
18915108778Santirez NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
19015108778Santirez };
19115108778Santirez
19215108778Santirez /* ===== CONFIGURATION ===== */
19315108778Santirez
json_fetch_config(lua_State * l)19415108778Santirez static json_config_t *json_fetch_config(lua_State *l)
19515108778Santirez {
19615108778Santirez json_config_t *cfg;
19715108778Santirez
1984fdcd213SMatt Stancliff cfg = lua_touserdata(l, lua_upvalueindex(1));
19915108778Santirez if (!cfg)
20015108778Santirez luaL_error(l, "BUG: Unable to fetch CJSON configuration");
20115108778Santirez
20215108778Santirez return cfg;
20315108778Santirez }
20415108778Santirez
2054fdcd213SMatt Stancliff /* Ensure the correct number of arguments have been provided.
2064fdcd213SMatt Stancliff * Pad with nil to allow other functions to simply check arg[i]
2074fdcd213SMatt Stancliff * to find whether an argument was provided */
json_arg_init(lua_State * l,int args)2084fdcd213SMatt Stancliff static json_config_t *json_arg_init(lua_State *l, int args)
20915108778Santirez {
21015108778Santirez luaL_argcheck(l, lua_gettop(l) <= args, args + 1,
21115108778Santirez "found too many arguments");
2124fdcd213SMatt Stancliff
2134fdcd213SMatt Stancliff while (lua_gettop(l) < args)
2144fdcd213SMatt Stancliff lua_pushnil(l);
2154fdcd213SMatt Stancliff
2164fdcd213SMatt Stancliff return json_fetch_config(l);
2174fdcd213SMatt Stancliff }
2184fdcd213SMatt Stancliff
2194fdcd213SMatt Stancliff /* Process integer options for configuration functions */
json_integer_option(lua_State * l,int optindex,int * setting,int min,int max)2204fdcd213SMatt Stancliff static int json_integer_option(lua_State *l, int optindex, int *setting,
2214fdcd213SMatt Stancliff int min, int max)
2224fdcd213SMatt Stancliff {
2234fdcd213SMatt Stancliff char errmsg[64];
2244fdcd213SMatt Stancliff int value;
2254fdcd213SMatt Stancliff
2264fdcd213SMatt Stancliff if (!lua_isnil(l, optindex)) {
2274fdcd213SMatt Stancliff value = luaL_checkinteger(l, optindex);
2284fdcd213SMatt Stancliff snprintf(errmsg, sizeof(errmsg), "expected integer between %d and %d", min, max);
2294fdcd213SMatt Stancliff luaL_argcheck(l, min <= value && value <= max, 1, errmsg);
2304fdcd213SMatt Stancliff *setting = value;
2314fdcd213SMatt Stancliff }
2324fdcd213SMatt Stancliff
2334fdcd213SMatt Stancliff lua_pushinteger(l, *setting);
2344fdcd213SMatt Stancliff
2354fdcd213SMatt Stancliff return 1;
2364fdcd213SMatt Stancliff }
2374fdcd213SMatt Stancliff
2384fdcd213SMatt Stancliff /* Process enumerated arguments for a configuration function */
json_enum_option(lua_State * l,int optindex,int * setting,const char ** options,int bool_true)2394fdcd213SMatt Stancliff static int json_enum_option(lua_State *l, int optindex, int *setting,
2404fdcd213SMatt Stancliff const char **options, int bool_true)
2414fdcd213SMatt Stancliff {
2424fdcd213SMatt Stancliff static const char *bool_options[] = { "off", "on", NULL };
2434fdcd213SMatt Stancliff
2444fdcd213SMatt Stancliff if (!options) {
2454fdcd213SMatt Stancliff options = bool_options;
2464fdcd213SMatt Stancliff bool_true = 1;
2474fdcd213SMatt Stancliff }
2484fdcd213SMatt Stancliff
2494fdcd213SMatt Stancliff if (!lua_isnil(l, optindex)) {
2504fdcd213SMatt Stancliff if (bool_true && lua_isboolean(l, optindex))
2514fdcd213SMatt Stancliff *setting = lua_toboolean(l, optindex) * bool_true;
2524fdcd213SMatt Stancliff else
2534fdcd213SMatt Stancliff *setting = luaL_checkoption(l, optindex, NULL, options);
2544fdcd213SMatt Stancliff }
2554fdcd213SMatt Stancliff
2564fdcd213SMatt Stancliff if (bool_true && (*setting == 0 || *setting == bool_true))
2574fdcd213SMatt Stancliff lua_pushboolean(l, *setting);
2584fdcd213SMatt Stancliff else
2594fdcd213SMatt Stancliff lua_pushstring(l, options[*setting]);
2604fdcd213SMatt Stancliff
2614fdcd213SMatt Stancliff return 1;
26215108778Santirez }
26315108778Santirez
26415108778Santirez /* Configures handling of extremely sparse arrays:
26515108778Santirez * convert: Convert extremely sparse arrays into objects? Otherwise error.
26615108778Santirez * ratio: 0: always allow sparse; 1: never allow sparse; >1: use ratio
26715108778Santirez * safe: Always use an array when the max index <= safe */
json_cfg_encode_sparse_array(lua_State * l)26815108778Santirez static int json_cfg_encode_sparse_array(lua_State *l)
26915108778Santirez {
2704fdcd213SMatt Stancliff json_config_t *cfg = json_arg_init(l, 3);
27115108778Santirez
2724fdcd213SMatt Stancliff json_enum_option(l, 1, &cfg->encode_sparse_convert, NULL, 1);
2734fdcd213SMatt Stancliff json_integer_option(l, 2, &cfg->encode_sparse_ratio, 0, INT_MAX);
2744fdcd213SMatt Stancliff json_integer_option(l, 3, &cfg->encode_sparse_safe, 0, INT_MAX);
27515108778Santirez
27615108778Santirez return 3;
27715108778Santirez }
27815108778Santirez
27915108778Santirez /* Configures the maximum number of nested arrays/objects allowed when
28015108778Santirez * encoding */
json_cfg_encode_max_depth(lua_State * l)28115108778Santirez static int json_cfg_encode_max_depth(lua_State *l)
28215108778Santirez {
2834fdcd213SMatt Stancliff json_config_t *cfg = json_arg_init(l, 1);
28415108778Santirez
2854fdcd213SMatt Stancliff return json_integer_option(l, 1, &cfg->encode_max_depth, 1, INT_MAX);
28615108778Santirez }
28715108778Santirez
2884fdcd213SMatt Stancliff /* Configures the maximum number of nested arrays/objects allowed when
2894fdcd213SMatt Stancliff * encoding */
json_cfg_decode_max_depth(lua_State * l)2904fdcd213SMatt Stancliff static int json_cfg_decode_max_depth(lua_State *l)
29115108778Santirez {
2924fdcd213SMatt Stancliff json_config_t *cfg = json_arg_init(l, 1);
2934fdcd213SMatt Stancliff
2944fdcd213SMatt Stancliff return json_integer_option(l, 1, &cfg->decode_max_depth, 1, INT_MAX);
29515108778Santirez }
29615108778Santirez
29715108778Santirez /* Configures number precision when converting doubles to text */
json_cfg_encode_number_precision(lua_State * l)29815108778Santirez static int json_cfg_encode_number_precision(lua_State *l)
29915108778Santirez {
3004fdcd213SMatt Stancliff json_config_t *cfg = json_arg_init(l, 1);
30115108778Santirez
3024fdcd213SMatt Stancliff return json_integer_option(l, 1, &cfg->encode_number_precision, 1, 14);
30315108778Santirez }
30415108778Santirez
30515108778Santirez /* Configures JSON encoding buffer persistence */
json_cfg_encode_keep_buffer(lua_State * l)30615108778Santirez static int json_cfg_encode_keep_buffer(lua_State *l)
30715108778Santirez {
3084fdcd213SMatt Stancliff json_config_t *cfg = json_arg_init(l, 1);
3094fdcd213SMatt Stancliff int old_value;
31015108778Santirez
3114fdcd213SMatt Stancliff old_value = cfg->encode_keep_buffer;
31215108778Santirez
3134fdcd213SMatt Stancliff json_enum_option(l, 1, &cfg->encode_keep_buffer, NULL, 1);
3144fdcd213SMatt Stancliff
3154fdcd213SMatt Stancliff /* Init / free the buffer if the setting has changed */
3164fdcd213SMatt Stancliff if (old_value ^ cfg->encode_keep_buffer) {
3174fdcd213SMatt Stancliff if (cfg->encode_keep_buffer)
3184fdcd213SMatt Stancliff strbuf_init(&cfg->encode_buf, 0);
3194fdcd213SMatt Stancliff else
3204fdcd213SMatt Stancliff strbuf_free(&cfg->encode_buf);
32115108778Santirez }
32215108778Santirez
32315108778Santirez return 1;
32415108778Santirez }
32515108778Santirez
3264fdcd213SMatt Stancliff #if defined(DISABLE_INVALID_NUMBERS) && !defined(USE_INTERNAL_FPCONV)
json_verify_invalid_number_setting(lua_State * l,int * setting)3274fdcd213SMatt Stancliff void json_verify_invalid_number_setting(lua_State *l, int *setting)
32815108778Santirez {
3294fdcd213SMatt Stancliff if (*setting == 1) {
3304fdcd213SMatt Stancliff *setting = 0;
3314fdcd213SMatt Stancliff luaL_error(l, "Infinity, NaN, and/or hexadecimal numbers are not supported.");
3324fdcd213SMatt Stancliff }
3334fdcd213SMatt Stancliff }
3344fdcd213SMatt Stancliff #else
3354fdcd213SMatt Stancliff #define json_verify_invalid_number_setting(l, s) do { } while(0)
3364fdcd213SMatt Stancliff #endif
33715108778Santirez
json_cfg_encode_invalid_numbers(lua_State * l)3384fdcd213SMatt Stancliff static int json_cfg_encode_invalid_numbers(lua_State *l)
3394fdcd213SMatt Stancliff {
3404fdcd213SMatt Stancliff static const char *options[] = { "off", "on", "null", NULL };
3414fdcd213SMatt Stancliff json_config_t *cfg = json_arg_init(l, 1);
34215108778Santirez
3434fdcd213SMatt Stancliff json_enum_option(l, 1, &cfg->encode_invalid_numbers, options, 1);
3444fdcd213SMatt Stancliff
3454fdcd213SMatt Stancliff json_verify_invalid_number_setting(l, &cfg->encode_invalid_numbers);
3464fdcd213SMatt Stancliff
3474fdcd213SMatt Stancliff return 1;
34815108778Santirez }
34915108778Santirez
json_cfg_decode_invalid_numbers(lua_State * l)3504fdcd213SMatt Stancliff static int json_cfg_decode_invalid_numbers(lua_State *l)
35115108778Santirez {
3524fdcd213SMatt Stancliff json_config_t *cfg = json_arg_init(l, 1);
35315108778Santirez
3544fdcd213SMatt Stancliff json_enum_option(l, 1, &cfg->decode_invalid_numbers, NULL, 1);
35515108778Santirez
3564fdcd213SMatt Stancliff json_verify_invalid_number_setting(l, &cfg->encode_invalid_numbers);
35715108778Santirez
35815108778Santirez return 1;
35915108778Santirez }
36015108778Santirez
json_destroy_config(lua_State * l)36115108778Santirez static int json_destroy_config(lua_State *l)
36215108778Santirez {
36315108778Santirez json_config_t *cfg;
36415108778Santirez
36515108778Santirez cfg = lua_touserdata(l, 1);
36615108778Santirez if (cfg)
36715108778Santirez strbuf_free(&cfg->encode_buf);
36815108778Santirez cfg = NULL;
36915108778Santirez
37015108778Santirez return 0;
37115108778Santirez }
37215108778Santirez
json_create_config(lua_State * l)37315108778Santirez static void json_create_config(lua_State *l)
37415108778Santirez {
37515108778Santirez json_config_t *cfg;
37615108778Santirez int i;
37715108778Santirez
37815108778Santirez cfg = lua_newuserdata(l, sizeof(*cfg));
37915108778Santirez
38015108778Santirez /* Create GC method to clean up strbuf */
38115108778Santirez lua_newtable(l);
38215108778Santirez lua_pushcfunction(l, json_destroy_config);
38315108778Santirez lua_setfield(l, -2, "__gc");
38415108778Santirez lua_setmetatable(l, -2);
38515108778Santirez
38615108778Santirez cfg->encode_sparse_convert = DEFAULT_SPARSE_CONVERT;
38715108778Santirez cfg->encode_sparse_ratio = DEFAULT_SPARSE_RATIO;
38815108778Santirez cfg->encode_sparse_safe = DEFAULT_SPARSE_SAFE;
3894fdcd213SMatt Stancliff cfg->encode_max_depth = DEFAULT_ENCODE_MAX_DEPTH;
3904fdcd213SMatt Stancliff cfg->decode_max_depth = DEFAULT_DECODE_MAX_DEPTH;
3914fdcd213SMatt Stancliff cfg->encode_invalid_numbers = DEFAULT_ENCODE_INVALID_NUMBERS;
3924fdcd213SMatt Stancliff cfg->decode_invalid_numbers = DEFAULT_DECODE_INVALID_NUMBERS;
39315108778Santirez cfg->encode_keep_buffer = DEFAULT_ENCODE_KEEP_BUFFER;
3944fdcd213SMatt Stancliff cfg->encode_number_precision = DEFAULT_ENCODE_NUMBER_PRECISION;
3954fdcd213SMatt Stancliff
3964fdcd213SMatt Stancliff #if DEFAULT_ENCODE_KEEP_BUFFER > 0
3974fdcd213SMatt Stancliff strbuf_init(&cfg->encode_buf, 0);
3984fdcd213SMatt Stancliff #endif
39915108778Santirez
40015108778Santirez /* Decoding init */
40115108778Santirez
40215108778Santirez /* Tag all characters as an error */
40315108778Santirez for (i = 0; i < 256; i++)
40415108778Santirez cfg->ch2token[i] = T_ERROR;
40515108778Santirez
40615108778Santirez /* Set tokens that require no further processing */
40715108778Santirez cfg->ch2token['{'] = T_OBJ_BEGIN;
40815108778Santirez cfg->ch2token['}'] = T_OBJ_END;
40915108778Santirez cfg->ch2token['['] = T_ARR_BEGIN;
41015108778Santirez cfg->ch2token[']'] = T_ARR_END;
41115108778Santirez cfg->ch2token[','] = T_COMMA;
41215108778Santirez cfg->ch2token[':'] = T_COLON;
41315108778Santirez cfg->ch2token['\0'] = T_END;
41415108778Santirez cfg->ch2token[' '] = T_WHITESPACE;
41515108778Santirez cfg->ch2token['\t'] = T_WHITESPACE;
41615108778Santirez cfg->ch2token['\n'] = T_WHITESPACE;
41715108778Santirez cfg->ch2token['\r'] = T_WHITESPACE;
41815108778Santirez
41915108778Santirez /* Update characters that require further processing */
42015108778Santirez cfg->ch2token['f'] = T_UNKNOWN; /* false? */
42115108778Santirez cfg->ch2token['i'] = T_UNKNOWN; /* inf, ininity? */
42215108778Santirez cfg->ch2token['I'] = T_UNKNOWN;
42315108778Santirez cfg->ch2token['n'] = T_UNKNOWN; /* null, nan? */
42415108778Santirez cfg->ch2token['N'] = T_UNKNOWN;
42515108778Santirez cfg->ch2token['t'] = T_UNKNOWN; /* true? */
42615108778Santirez cfg->ch2token['"'] = T_UNKNOWN; /* string? */
42715108778Santirez cfg->ch2token['+'] = T_UNKNOWN; /* number? */
42815108778Santirez cfg->ch2token['-'] = T_UNKNOWN;
42915108778Santirez for (i = 0; i < 10; i++)
43015108778Santirez cfg->ch2token['0' + i] = T_UNKNOWN;
43115108778Santirez
43215108778Santirez /* Lookup table for parsing escape characters */
43315108778Santirez for (i = 0; i < 256; i++)
43415108778Santirez cfg->escape2char[i] = 0; /* String error */
43515108778Santirez cfg->escape2char['"'] = '"';
43615108778Santirez cfg->escape2char['\\'] = '\\';
43715108778Santirez cfg->escape2char['/'] = '/';
43815108778Santirez cfg->escape2char['b'] = '\b';
43915108778Santirez cfg->escape2char['t'] = '\t';
44015108778Santirez cfg->escape2char['n'] = '\n';
44115108778Santirez cfg->escape2char['f'] = '\f';
44215108778Santirez cfg->escape2char['r'] = '\r';
44315108778Santirez cfg->escape2char['u'] = 'u'; /* Unicode parsing required */
44415108778Santirez }
44515108778Santirez
44615108778Santirez /* ===== ENCODING ===== */
44715108778Santirez
json_encode_exception(lua_State * l,json_config_t * cfg,strbuf_t * json,int lindex,const char * reason)4484fdcd213SMatt Stancliff static void json_encode_exception(lua_State *l, json_config_t *cfg, strbuf_t *json, int lindex,
44915108778Santirez const char *reason)
45015108778Santirez {
45115108778Santirez if (!cfg->encode_keep_buffer)
4524fdcd213SMatt Stancliff strbuf_free(json);
45315108778Santirez luaL_error(l, "Cannot serialise %s: %s",
45415108778Santirez lua_typename(l, lua_type(l, lindex)), reason);
45515108778Santirez }
45615108778Santirez
45715108778Santirez /* json_append_string args:
45815108778Santirez * - lua_State
45915108778Santirez * - JSON strbuf
46015108778Santirez * - String (Lua stack index)
46115108778Santirez *
46215108778Santirez * Returns nothing. Doesn't remove string from Lua stack */
json_append_string(lua_State * l,strbuf_t * json,int lindex)46315108778Santirez static void json_append_string(lua_State *l, strbuf_t *json, int lindex)
46415108778Santirez {
46515108778Santirez const char *escstr;
46615108778Santirez int i;
46715108778Santirez const char *str;
46815108778Santirez size_t len;
46915108778Santirez
47015108778Santirez str = lua_tolstring(l, lindex, &len);
47115108778Santirez
47215108778Santirez /* Worst case is len * 6 (all unicode escapes).
47315108778Santirez * This buffer is reused constantly for small strings
47415108778Santirez * If there are any excess pages, they won't be hit anyway.
47515108778Santirez * This gains ~5% speedup. */
47615108778Santirez strbuf_ensure_empty_length(json, len * 6 + 2);
47715108778Santirez
47815108778Santirez strbuf_append_char_unsafe(json, '\"');
47915108778Santirez for (i = 0; i < len; i++) {
48015108778Santirez escstr = char2escape[(unsigned char)str[i]];
48115108778Santirez if (escstr)
48215108778Santirez strbuf_append_string(json, escstr);
48315108778Santirez else
48415108778Santirez strbuf_append_char_unsafe(json, str[i]);
48515108778Santirez }
48615108778Santirez strbuf_append_char_unsafe(json, '\"');
48715108778Santirez }
48815108778Santirez
48915108778Santirez /* Find the size of the array on the top of the Lua stack
49015108778Santirez * -1 object (not a pure array)
49115108778Santirez * >=0 elements in array
49215108778Santirez */
lua_array_length(lua_State * l,json_config_t * cfg,strbuf_t * json)4934fdcd213SMatt Stancliff static int lua_array_length(lua_State *l, json_config_t *cfg, strbuf_t *json)
49415108778Santirez {
49515108778Santirez double k;
49615108778Santirez int max;
49715108778Santirez int items;
49815108778Santirez
49915108778Santirez max = 0;
50015108778Santirez items = 0;
50115108778Santirez
50215108778Santirez lua_pushnil(l);
50315108778Santirez /* table, startkey */
50415108778Santirez while (lua_next(l, -2) != 0) {
50515108778Santirez /* table, key, value */
50615108778Santirez if (lua_type(l, -2) == LUA_TNUMBER &&
50715108778Santirez (k = lua_tonumber(l, -2))) {
50815108778Santirez /* Integer >= 1 ? */
50915108778Santirez if (floor(k) == k && k >= 1) {
51015108778Santirez if (k > max)
51115108778Santirez max = k;
51215108778Santirez items++;
51315108778Santirez lua_pop(l, 1);
51415108778Santirez continue;
51515108778Santirez }
51615108778Santirez }
51715108778Santirez
51815108778Santirez /* Must not be an array (non integer key) */
51915108778Santirez lua_pop(l, 2);
52015108778Santirez return -1;
52115108778Santirez }
52215108778Santirez
52315108778Santirez /* Encode excessively sparse arrays as objects (if enabled) */
52415108778Santirez if (cfg->encode_sparse_ratio > 0 &&
52515108778Santirez max > items * cfg->encode_sparse_ratio &&
52615108778Santirez max > cfg->encode_sparse_safe) {
52715108778Santirez if (!cfg->encode_sparse_convert)
5284fdcd213SMatt Stancliff json_encode_exception(l, cfg, json, -1, "excessively sparse array");
52915108778Santirez
53015108778Santirez return -1;
53115108778Santirez }
53215108778Santirez
53315108778Santirez return max;
53415108778Santirez }
53515108778Santirez
json_check_encode_depth(lua_State * l,json_config_t * cfg,int current_depth,strbuf_t * json)5364fdcd213SMatt Stancliff static void json_check_encode_depth(lua_State *l, json_config_t *cfg,
5374fdcd213SMatt Stancliff int current_depth, strbuf_t *json)
53815108778Santirez {
5394fdcd213SMatt Stancliff /* Ensure there are enough slots free to traverse a table (key,
5404fdcd213SMatt Stancliff * value) and push a string for a potential error message.
5414fdcd213SMatt Stancliff *
5424fdcd213SMatt Stancliff * Unlike "decode", the key and value are still on the stack when
5434fdcd213SMatt Stancliff * lua_checkstack() is called. Hence an extra slot for luaL_error()
5444fdcd213SMatt Stancliff * below is required just in case the next check to lua_checkstack()
5454fdcd213SMatt Stancliff * fails.
5464fdcd213SMatt Stancliff *
5474fdcd213SMatt Stancliff * While this won't cause a crash due to the EXTRA_STACK reserve
5484fdcd213SMatt Stancliff * slots, it would still be an improper use of the API. */
5494fdcd213SMatt Stancliff if (current_depth <= cfg->encode_max_depth && lua_checkstack(l, 3))
5504fdcd213SMatt Stancliff return;
55115108778Santirez
55215108778Santirez if (!cfg->encode_keep_buffer)
5534fdcd213SMatt Stancliff strbuf_free(json);
5544fdcd213SMatt Stancliff
55515108778Santirez luaL_error(l, "Cannot serialise, excessive nesting (%d)",
5564fdcd213SMatt Stancliff current_depth);
55715108778Santirez }
55815108778Santirez
5594fdcd213SMatt Stancliff static void json_append_data(lua_State *l, json_config_t *cfg,
5604fdcd213SMatt Stancliff int current_depth, strbuf_t *json);
56115108778Santirez
56215108778Santirez /* json_append_array args:
56315108778Santirez * - lua_State
56415108778Santirez * - JSON strbuf
56515108778Santirez * - Size of passwd Lua array (top of stack) */
json_append_array(lua_State * l,json_config_t * cfg,int current_depth,strbuf_t * json,int array_length)5664fdcd213SMatt Stancliff static void json_append_array(lua_State *l, json_config_t *cfg, int current_depth,
5674fdcd213SMatt Stancliff strbuf_t *json, int array_length)
56815108778Santirez {
56915108778Santirez int comma, i;
57015108778Santirez
57115108778Santirez strbuf_append_char(json, '[');
57215108778Santirez
57315108778Santirez comma = 0;
57415108778Santirez for (i = 1; i <= array_length; i++) {
57515108778Santirez if (comma)
57615108778Santirez strbuf_append_char(json, ',');
57715108778Santirez else
57815108778Santirez comma = 1;
57915108778Santirez
58015108778Santirez lua_rawgeti(l, -1, i);
5814fdcd213SMatt Stancliff json_append_data(l, cfg, current_depth, json);
58215108778Santirez lua_pop(l, 1);
58315108778Santirez }
58415108778Santirez
58515108778Santirez strbuf_append_char(json, ']');
58615108778Santirez }
58715108778Santirez
json_append_number(lua_State * l,json_config_t * cfg,strbuf_t * json,int lindex)5884fdcd213SMatt Stancliff static void json_append_number(lua_State *l, json_config_t *cfg,
5894fdcd213SMatt Stancliff strbuf_t *json, int lindex)
59015108778Santirez {
5914fdcd213SMatt Stancliff double num = lua_tonumber(l, lindex);
5924fdcd213SMatt Stancliff int len;
59315108778Santirez
5944fdcd213SMatt Stancliff if (cfg->encode_invalid_numbers == 0) {
5954fdcd213SMatt Stancliff /* Prevent encoding invalid numbers */
5964fdcd213SMatt Stancliff if (isinf(num) || isnan(num))
5974fdcd213SMatt Stancliff json_encode_exception(l, cfg, json, lindex, "must not be NaN or Inf");
5984fdcd213SMatt Stancliff } else if (cfg->encode_invalid_numbers == 1) {
5994fdcd213SMatt Stancliff /* Encode invalid numbers, but handle "nan" separately
6004fdcd213SMatt Stancliff * since some platforms may encode as "-nan". */
6014fdcd213SMatt Stancliff if (isnan(num)) {
6024fdcd213SMatt Stancliff strbuf_append_mem(json, "nan", 3);
6034fdcd213SMatt Stancliff return;
6044fdcd213SMatt Stancliff }
6054fdcd213SMatt Stancliff } else {
6064fdcd213SMatt Stancliff /* Encode invalid numbers as "null" */
6074fdcd213SMatt Stancliff if (isinf(num) || isnan(num)) {
6084fdcd213SMatt Stancliff strbuf_append_mem(json, "null", 4);
6094fdcd213SMatt Stancliff return;
6104fdcd213SMatt Stancliff }
6114fdcd213SMatt Stancliff }
61215108778Santirez
6134fdcd213SMatt Stancliff strbuf_ensure_empty_length(json, FPCONV_G_FMT_BUFSIZE);
6144fdcd213SMatt Stancliff len = fpconv_g_fmt(strbuf_empty_ptr(json), num, cfg->encode_number_precision);
6154fdcd213SMatt Stancliff strbuf_extend_length(json, len);
61615108778Santirez }
61715108778Santirez
json_append_object(lua_State * l,json_config_t * cfg,int current_depth,strbuf_t * json)61815108778Santirez static void json_append_object(lua_State *l, json_config_t *cfg,
6194fdcd213SMatt Stancliff int current_depth, strbuf_t *json)
62015108778Santirez {
62115108778Santirez int comma, keytype;
62215108778Santirez
62315108778Santirez /* Object */
62415108778Santirez strbuf_append_char(json, '{');
62515108778Santirez
62615108778Santirez lua_pushnil(l);
62715108778Santirez /* table, startkey */
62815108778Santirez comma = 0;
62915108778Santirez while (lua_next(l, -2) != 0) {
63015108778Santirez if (comma)
63115108778Santirez strbuf_append_char(json, ',');
63215108778Santirez else
63315108778Santirez comma = 1;
63415108778Santirez
63515108778Santirez /* table, key, value */
63615108778Santirez keytype = lua_type(l, -2);
63715108778Santirez if (keytype == LUA_TNUMBER) {
63815108778Santirez strbuf_append_char(json, '"');
6394fdcd213SMatt Stancliff json_append_number(l, cfg, json, -2);
64015108778Santirez strbuf_append_mem(json, "\":", 2);
64115108778Santirez } else if (keytype == LUA_TSTRING) {
64215108778Santirez json_append_string(l, json, -2);
64315108778Santirez strbuf_append_char(json, ':');
64415108778Santirez } else {
6454fdcd213SMatt Stancliff json_encode_exception(l, cfg, json, -2,
64615108778Santirez "table key must be a number or string");
64715108778Santirez /* never returns */
64815108778Santirez }
64915108778Santirez
65015108778Santirez /* table, key, value */
6514fdcd213SMatt Stancliff json_append_data(l, cfg, current_depth, json);
65215108778Santirez lua_pop(l, 1);
65315108778Santirez /* table, key */
65415108778Santirez }
65515108778Santirez
65615108778Santirez strbuf_append_char(json, '}');
65715108778Santirez }
65815108778Santirez
65915108778Santirez /* Serialise Lua data into JSON string. */
json_append_data(lua_State * l,json_config_t * cfg,int current_depth,strbuf_t * json)6604fdcd213SMatt Stancliff static void json_append_data(lua_State *l, json_config_t *cfg,
6614fdcd213SMatt Stancliff int current_depth, strbuf_t *json)
66215108778Santirez {
66315108778Santirez int len;
66415108778Santirez
66515108778Santirez switch (lua_type(l, -1)) {
66615108778Santirez case LUA_TSTRING:
66715108778Santirez json_append_string(l, json, -1);
66815108778Santirez break;
66915108778Santirez case LUA_TNUMBER:
6704fdcd213SMatt Stancliff json_append_number(l, cfg, json, -1);
67115108778Santirez break;
67215108778Santirez case LUA_TBOOLEAN:
67315108778Santirez if (lua_toboolean(l, -1))
67415108778Santirez strbuf_append_mem(json, "true", 4);
67515108778Santirez else
67615108778Santirez strbuf_append_mem(json, "false", 5);
67715108778Santirez break;
67815108778Santirez case LUA_TTABLE:
6794fdcd213SMatt Stancliff current_depth++;
6804fdcd213SMatt Stancliff json_check_encode_depth(l, cfg, current_depth, json);
6814fdcd213SMatt Stancliff len = lua_array_length(l, cfg, json);
68215108778Santirez if (len > 0)
6834fdcd213SMatt Stancliff json_append_array(l, cfg, current_depth, json, len);
68415108778Santirez else
6854fdcd213SMatt Stancliff json_append_object(l, cfg, current_depth, json);
68615108778Santirez break;
68715108778Santirez case LUA_TNIL:
68815108778Santirez strbuf_append_mem(json, "null", 4);
68915108778Santirez break;
69015108778Santirez case LUA_TLIGHTUSERDATA:
69115108778Santirez if (lua_touserdata(l, -1) == NULL) {
69215108778Santirez strbuf_append_mem(json, "null", 4);
69315108778Santirez break;
69415108778Santirez }
69515108778Santirez default:
69615108778Santirez /* Remaining types (LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD,
69715108778Santirez * and LUA_TLIGHTUSERDATA) cannot be serialised */
6984fdcd213SMatt Stancliff json_encode_exception(l, cfg, json, -1, "type not supported");
69915108778Santirez /* never returns */
70015108778Santirez }
70115108778Santirez }
70215108778Santirez
json_encode(lua_State * l)70315108778Santirez static int json_encode(lua_State *l)
70415108778Santirez {
7054fdcd213SMatt Stancliff json_config_t *cfg = json_fetch_config(l);
7064fdcd213SMatt Stancliff strbuf_t local_encode_buf;
7074fdcd213SMatt Stancliff strbuf_t *encode_buf;
70815108778Santirez char *json;
70915108778Santirez int len;
71015108778Santirez
71115108778Santirez luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument");
71215108778Santirez
7134fdcd213SMatt Stancliff if (!cfg->encode_keep_buffer) {
7144fdcd213SMatt Stancliff /* Use private buffer */
7154fdcd213SMatt Stancliff encode_buf = &local_encode_buf;
7164fdcd213SMatt Stancliff strbuf_init(encode_buf, 0);
7174fdcd213SMatt Stancliff } else {
7184fdcd213SMatt Stancliff /* Reuse existing buffer */
7194fdcd213SMatt Stancliff encode_buf = &cfg->encode_buf;
7204fdcd213SMatt Stancliff strbuf_reset(encode_buf);
7214fdcd213SMatt Stancliff }
72215108778Santirez
7234fdcd213SMatt Stancliff json_append_data(l, cfg, 0, encode_buf);
7244fdcd213SMatt Stancliff json = strbuf_string(encode_buf, &len);
72515108778Santirez
72615108778Santirez lua_pushlstring(l, json, len);
72715108778Santirez
72815108778Santirez if (!cfg->encode_keep_buffer)
7294fdcd213SMatt Stancliff strbuf_free(encode_buf);
73015108778Santirez
73115108778Santirez return 1;
73215108778Santirez }
73315108778Santirez
73415108778Santirez /* ===== DECODING ===== */
73515108778Santirez
73615108778Santirez static void json_process_value(lua_State *l, json_parse_t *json,
73715108778Santirez json_token_t *token);
73815108778Santirez
hexdigit2int(char hex)73915108778Santirez static int hexdigit2int(char hex)
74015108778Santirez {
74115108778Santirez if ('0' <= hex && hex <= '9')
74215108778Santirez return hex - '0';
74315108778Santirez
74415108778Santirez /* Force lowercase */
74515108778Santirez hex |= 0x20;
74615108778Santirez if ('a' <= hex && hex <= 'f')
74715108778Santirez return 10 + hex - 'a';
74815108778Santirez
74915108778Santirez return -1;
75015108778Santirez }
75115108778Santirez
decode_hex4(const char * hex)75215108778Santirez static int decode_hex4(const char *hex)
75315108778Santirez {
75415108778Santirez int digit[4];
75515108778Santirez int i;
75615108778Santirez
75715108778Santirez /* Convert ASCII hex digit to numeric digit
75815108778Santirez * Note: this returns an error for invalid hex digits, including
75915108778Santirez * NULL */
76015108778Santirez for (i = 0; i < 4; i++) {
76115108778Santirez digit[i] = hexdigit2int(hex[i]);
76215108778Santirez if (digit[i] < 0) {
76315108778Santirez return -1;
76415108778Santirez }
76515108778Santirez }
76615108778Santirez
76715108778Santirez return (digit[0] << 12) +
76815108778Santirez (digit[1] << 8) +
76915108778Santirez (digit[2] << 4) +
77015108778Santirez digit[3];
77115108778Santirez }
77215108778Santirez
77315108778Santirez /* Converts a Unicode codepoint to UTF-8.
77415108778Santirez * Returns UTF-8 string length, and up to 4 bytes in *utf8 */
codepoint_to_utf8(char * utf8,int codepoint)77515108778Santirez static int codepoint_to_utf8(char *utf8, int codepoint)
77615108778Santirez {
77715108778Santirez /* 0xxxxxxx */
77815108778Santirez if (codepoint <= 0x7F) {
77915108778Santirez utf8[0] = codepoint;
78015108778Santirez return 1;
78115108778Santirez }
78215108778Santirez
78315108778Santirez /* 110xxxxx 10xxxxxx */
78415108778Santirez if (codepoint <= 0x7FF) {
78515108778Santirez utf8[0] = (codepoint >> 6) | 0xC0;
78615108778Santirez utf8[1] = (codepoint & 0x3F) | 0x80;
78715108778Santirez return 2;
78815108778Santirez }
78915108778Santirez
79015108778Santirez /* 1110xxxx 10xxxxxx 10xxxxxx */
79115108778Santirez if (codepoint <= 0xFFFF) {
79215108778Santirez utf8[0] = (codepoint >> 12) | 0xE0;
79315108778Santirez utf8[1] = ((codepoint >> 6) & 0x3F) | 0x80;
79415108778Santirez utf8[2] = (codepoint & 0x3F) | 0x80;
79515108778Santirez return 3;
79615108778Santirez }
79715108778Santirez
79815108778Santirez /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
79915108778Santirez if (codepoint <= 0x1FFFFF) {
80015108778Santirez utf8[0] = (codepoint >> 18) | 0xF0;
80115108778Santirez utf8[1] = ((codepoint >> 12) & 0x3F) | 0x80;
80215108778Santirez utf8[2] = ((codepoint >> 6) & 0x3F) | 0x80;
80315108778Santirez utf8[3] = (codepoint & 0x3F) | 0x80;
80415108778Santirez return 4;
80515108778Santirez }
80615108778Santirez
80715108778Santirez return 0;
80815108778Santirez }
80915108778Santirez
81015108778Santirez
81115108778Santirez /* Called when index pointing to beginning of UTF-16 code escape: \uXXXX
81215108778Santirez * \u is guaranteed to exist, but the remaining hex characters may be
81315108778Santirez * missing.
81415108778Santirez * Translate to UTF-8 and append to temporary token string.
81515108778Santirez * Must advance index to the next character to be processed.
81615108778Santirez * Returns: 0 success
81715108778Santirez * -1 error
81815108778Santirez */
json_append_unicode_escape(json_parse_t * json)81915108778Santirez static int json_append_unicode_escape(json_parse_t *json)
82015108778Santirez {
82115108778Santirez char utf8[4]; /* Surrogate pairs require 4 UTF-8 bytes */
82215108778Santirez int codepoint;
82315108778Santirez int surrogate_low;
82415108778Santirez int len;
82515108778Santirez int escape_len = 6;
82615108778Santirez
82715108778Santirez /* Fetch UTF-16 code unit */
8284fdcd213SMatt Stancliff codepoint = decode_hex4(json->ptr + 2);
82915108778Santirez if (codepoint < 0)
83015108778Santirez return -1;
83115108778Santirez
83215108778Santirez /* UTF-16 surrogate pairs take the following 2 byte form:
83315108778Santirez * 11011 x yyyyyyyyyy
83415108778Santirez * When x = 0: y is the high 10 bits of the codepoint
83515108778Santirez * x = 1: y is the low 10 bits of the codepoint
83615108778Santirez *
83715108778Santirez * Check for a surrogate pair (high or low) */
83815108778Santirez if ((codepoint & 0xF800) == 0xD800) {
83915108778Santirez /* Error if the 1st surrogate is not high */
84015108778Santirez if (codepoint & 0x400)
84115108778Santirez return -1;
84215108778Santirez
84315108778Santirez /* Ensure the next code is a unicode escape */
8444fdcd213SMatt Stancliff if (*(json->ptr + escape_len) != '\\' ||
8454fdcd213SMatt Stancliff *(json->ptr + escape_len + 1) != 'u') {
84615108778Santirez return -1;
84715108778Santirez }
84815108778Santirez
84915108778Santirez /* Fetch the next codepoint */
8504fdcd213SMatt Stancliff surrogate_low = decode_hex4(json->ptr + 2 + escape_len);
85115108778Santirez if (surrogate_low < 0)
85215108778Santirez return -1;
85315108778Santirez
85415108778Santirez /* Error if the 2nd code is not a low surrogate */
85515108778Santirez if ((surrogate_low & 0xFC00) != 0xDC00)
85615108778Santirez return -1;
85715108778Santirez
85815108778Santirez /* Calculate Unicode codepoint */
85915108778Santirez codepoint = (codepoint & 0x3FF) << 10;
86015108778Santirez surrogate_low &= 0x3FF;
86115108778Santirez codepoint = (codepoint | surrogate_low) + 0x10000;
86215108778Santirez escape_len = 12;
86315108778Santirez }
86415108778Santirez
86515108778Santirez /* Convert codepoint to UTF-8 */
86615108778Santirez len = codepoint_to_utf8(utf8, codepoint);
86715108778Santirez if (!len)
86815108778Santirez return -1;
86915108778Santirez
87015108778Santirez /* Append bytes and advance parse index */
87115108778Santirez strbuf_append_mem_unsafe(json->tmp, utf8, len);
8724fdcd213SMatt Stancliff json->ptr += escape_len;
87315108778Santirez
87415108778Santirez return 0;
87515108778Santirez }
87615108778Santirez
json_set_token_error(json_token_t * token,json_parse_t * json,const char * errtype)87715108778Santirez static void json_set_token_error(json_token_t *token, json_parse_t *json,
87815108778Santirez const char *errtype)
87915108778Santirez {
88015108778Santirez token->type = T_ERROR;
8814fdcd213SMatt Stancliff token->index = json->ptr - json->data;
88215108778Santirez token->value.string = errtype;
88315108778Santirez }
88415108778Santirez
json_next_string_token(json_parse_t * json,json_token_t * token)88515108778Santirez static void json_next_string_token(json_parse_t *json, json_token_t *token)
88615108778Santirez {
88715108778Santirez char *escape2char = json->cfg->escape2char;
88815108778Santirez char ch;
88915108778Santirez
89015108778Santirez /* Caller must ensure a string is next */
8914fdcd213SMatt Stancliff assert(*json->ptr == '"');
89215108778Santirez
89315108778Santirez /* Skip " */
8944fdcd213SMatt Stancliff json->ptr++;
89515108778Santirez
89615108778Santirez /* json->tmp is the temporary strbuf used to accumulate the
8974fdcd213SMatt Stancliff * decoded string value.
8984fdcd213SMatt Stancliff * json->tmp is sized to handle JSON containing only a string value.
8994fdcd213SMatt Stancliff */
90015108778Santirez strbuf_reset(json->tmp);
9014fdcd213SMatt Stancliff
9024fdcd213SMatt Stancliff while ((ch = *json->ptr) != '"') {
90315108778Santirez if (!ch) {
90415108778Santirez /* Premature end of the string */
90515108778Santirez json_set_token_error(token, json, "unexpected end of string");
90615108778Santirez return;
90715108778Santirez }
90815108778Santirez
90915108778Santirez /* Handle escapes */
91015108778Santirez if (ch == '\\') {
91115108778Santirez /* Fetch escape character */
9124fdcd213SMatt Stancliff ch = *(json->ptr + 1);
91315108778Santirez
91415108778Santirez /* Translate escape code and append to tmp string */
91515108778Santirez ch = escape2char[(unsigned char)ch];
91615108778Santirez if (ch == 'u') {
91715108778Santirez if (json_append_unicode_escape(json) == 0)
91815108778Santirez continue;
91915108778Santirez
92015108778Santirez json_set_token_error(token, json,
92115108778Santirez "invalid unicode escape code");
92215108778Santirez return;
92315108778Santirez }
92415108778Santirez if (!ch) {
92515108778Santirez json_set_token_error(token, json, "invalid escape code");
92615108778Santirez return;
92715108778Santirez }
92815108778Santirez
92915108778Santirez /* Skip '\' */
9304fdcd213SMatt Stancliff json->ptr++;
93115108778Santirez }
93215108778Santirez /* Append normal character or translated single character
93315108778Santirez * Unicode escapes are handled above */
93415108778Santirez strbuf_append_char_unsafe(json->tmp, ch);
9354fdcd213SMatt Stancliff json->ptr++;
93615108778Santirez }
9374fdcd213SMatt Stancliff json->ptr++; /* Eat final quote (") */
93815108778Santirez
93915108778Santirez strbuf_ensure_null(json->tmp);
94015108778Santirez
94115108778Santirez token->type = T_STRING;
94215108778Santirez token->value.string = strbuf_string(json->tmp, &token->string_len);
94315108778Santirez }
94415108778Santirez
94515108778Santirez /* JSON numbers should take the following form:
94615108778Santirez * -?(0|[1-9]|[1-9][0-9]+)(.[0-9]+)?([eE][-+]?[0-9]+)?
94715108778Santirez *
94815108778Santirez * json_next_number_token() uses strtod() which allows other forms:
94915108778Santirez * - numbers starting with '+'
95015108778Santirez * - NaN, -NaN, infinity, -infinity
9514fdcd213SMatt Stancliff * - hexadecimal numbers
95215108778Santirez * - numbers with leading zeros
95315108778Santirez *
95415108778Santirez * json_is_invalid_number() detects "numbers" which may pass strtod()'s
95515108778Santirez * error checking, but should not be allowed with strict JSON.
95615108778Santirez *
95715108778Santirez * json_is_invalid_number() may pass numbers which cause strtod()
95815108778Santirez * to generate an error.
95915108778Santirez */
json_is_invalid_number(json_parse_t * json)96015108778Santirez static int json_is_invalid_number(json_parse_t *json)
96115108778Santirez {
9624fdcd213SMatt Stancliff const char *p = json->ptr;
96315108778Santirez
96415108778Santirez /* Reject numbers starting with + */
9654fdcd213SMatt Stancliff if (*p == '+')
96615108778Santirez return 1;
96715108778Santirez
96815108778Santirez /* Skip minus sign if it exists */
9694fdcd213SMatt Stancliff if (*p == '-')
9704fdcd213SMatt Stancliff p++;
97115108778Santirez
97215108778Santirez /* Reject numbers starting with 0x, or leading zeros */
9734fdcd213SMatt Stancliff if (*p == '0') {
9744fdcd213SMatt Stancliff int ch2 = *(p + 1);
97515108778Santirez
97615108778Santirez if ((ch2 | 0x20) == 'x' || /* Hex */
97715108778Santirez ('0' <= ch2 && ch2 <= '9')) /* Leading zero */
97815108778Santirez return 1;
97915108778Santirez
98015108778Santirez return 0;
9814fdcd213SMatt Stancliff } else if (*p <= '9') {
98215108778Santirez return 0; /* Ordinary number */
98315108778Santirez }
98415108778Santirez
98515108778Santirez /* Reject inf/nan */
9864fdcd213SMatt Stancliff if (!strncasecmp(p, "inf", 3))
98715108778Santirez return 1;
9884fdcd213SMatt Stancliff if (!strncasecmp(p, "nan", 3))
98915108778Santirez return 1;
99015108778Santirez
99115108778Santirez /* Pass all other numbers which may still be invalid, but
99215108778Santirez * strtod() will catch them. */
99315108778Santirez return 0;
99415108778Santirez }
99515108778Santirez
json_next_number_token(json_parse_t * json,json_token_t * token)99615108778Santirez static void json_next_number_token(json_parse_t *json, json_token_t *token)
99715108778Santirez {
99815108778Santirez char *endptr;
99915108778Santirez
100015108778Santirez token->type = T_NUMBER;
10014fdcd213SMatt Stancliff token->value.number = fpconv_strtod(json->ptr, &endptr);
10024fdcd213SMatt Stancliff if (json->ptr == endptr)
100315108778Santirez json_set_token_error(token, json, "invalid number");
100415108778Santirez else
10054fdcd213SMatt Stancliff json->ptr = endptr; /* Skip the processed number */
100615108778Santirez
100715108778Santirez return;
100815108778Santirez }
100915108778Santirez
101015108778Santirez /* Fills in the token struct.
101115108778Santirez * T_STRING will return a pointer to the json_parse_t temporary string
10124fdcd213SMatt Stancliff * T_ERROR will leave the json->ptr pointer at the error.
101315108778Santirez */
json_next_token(json_parse_t * json,json_token_t * token)101415108778Santirez static void json_next_token(json_parse_t *json, json_token_t *token)
101515108778Santirez {
10164fdcd213SMatt Stancliff const json_token_type_t *ch2token = json->cfg->ch2token;
101715108778Santirez int ch;
101815108778Santirez
10194fdcd213SMatt Stancliff /* Eat whitespace. */
10204fdcd213SMatt Stancliff while (1) {
10214fdcd213SMatt Stancliff ch = (unsigned char)*(json->ptr);
10224fdcd213SMatt Stancliff token->type = ch2token[ch];
10234fdcd213SMatt Stancliff if (token->type != T_WHITESPACE)
10244fdcd213SMatt Stancliff break;
10254fdcd213SMatt Stancliff json->ptr++;
10264fdcd213SMatt Stancliff }
102715108778Santirez
10284fdcd213SMatt Stancliff /* Store location of new token. Required when throwing errors
10294fdcd213SMatt Stancliff * for unexpected tokens (syntax errors). */
10304fdcd213SMatt Stancliff token->index = json->ptr - json->data;
103115108778Santirez
103215108778Santirez /* Don't advance the pointer for an error or the end */
103315108778Santirez if (token->type == T_ERROR) {
103415108778Santirez json_set_token_error(token, json, "invalid token");
103515108778Santirez return;
103615108778Santirez }
103715108778Santirez
103815108778Santirez if (token->type == T_END) {
103915108778Santirez return;
104015108778Santirez }
104115108778Santirez
104215108778Santirez /* Found a known single character token, advance index and return */
104315108778Santirez if (token->type != T_UNKNOWN) {
10444fdcd213SMatt Stancliff json->ptr++;
104515108778Santirez return;
104615108778Santirez }
104715108778Santirez
10484fdcd213SMatt Stancliff /* Process characters which triggered T_UNKNOWN
10494fdcd213SMatt Stancliff *
10504fdcd213SMatt Stancliff * Must use strncmp() to match the front of the JSON string.
105115108778Santirez * JSON identifier must be lowercase.
105215108778Santirez * When strict_numbers if disabled, either case is allowed for
105315108778Santirez * Infinity/NaN (since we are no longer following the spec..) */
105415108778Santirez if (ch == '"') {
105515108778Santirez json_next_string_token(json, token);
105615108778Santirez return;
105715108778Santirez } else if (ch == '-' || ('0' <= ch && ch <= '9')) {
10584fdcd213SMatt Stancliff if (!json->cfg->decode_invalid_numbers && json_is_invalid_number(json)) {
105915108778Santirez json_set_token_error(token, json, "invalid number");
106015108778Santirez return;
106115108778Santirez }
106215108778Santirez json_next_number_token(json, token);
106315108778Santirez return;
10644fdcd213SMatt Stancliff } else if (!strncmp(json->ptr, "true", 4)) {
106515108778Santirez token->type = T_BOOLEAN;
106615108778Santirez token->value.boolean = 1;
10674fdcd213SMatt Stancliff json->ptr += 4;
106815108778Santirez return;
10694fdcd213SMatt Stancliff } else if (!strncmp(json->ptr, "false", 5)) {
107015108778Santirez token->type = T_BOOLEAN;
107115108778Santirez token->value.boolean = 0;
10724fdcd213SMatt Stancliff json->ptr += 5;
107315108778Santirez return;
10744fdcd213SMatt Stancliff } else if (!strncmp(json->ptr, "null", 4)) {
107515108778Santirez token->type = T_NULL;
10764fdcd213SMatt Stancliff json->ptr += 4;
107715108778Santirez return;
10784fdcd213SMatt Stancliff } else if (json->cfg->decode_invalid_numbers &&
107915108778Santirez json_is_invalid_number(json)) {
10804fdcd213SMatt Stancliff /* When decode_invalid_numbers is enabled, only attempt to process
108115108778Santirez * numbers we know are invalid JSON (Inf, NaN, hex)
108215108778Santirez * This is required to generate an appropriate token error,
108315108778Santirez * otherwise all bad tokens will register as "invalid number"
108415108778Santirez */
108515108778Santirez json_next_number_token(json, token);
108615108778Santirez return;
108715108778Santirez }
108815108778Santirez
108915108778Santirez /* Token starts with t/f/n but isn't recognised above. */
109015108778Santirez json_set_token_error(token, json, "invalid token");
109115108778Santirez }
109215108778Santirez
109315108778Santirez /* This function does not return.
109415108778Santirez * DO NOT CALL WITH DYNAMIC MEMORY ALLOCATED.
109515108778Santirez * The only supported exception is the temporary parser string
109615108778Santirez * json->tmp struct.
109715108778Santirez * json and token should exist on the stack somewhere.
109815108778Santirez * luaL_error() will long_jmp and release the stack */
json_throw_parse_error(lua_State * l,json_parse_t * json,const char * exp,json_token_t * token)109915108778Santirez static void json_throw_parse_error(lua_State *l, json_parse_t *json,
110015108778Santirez const char *exp, json_token_t *token)
110115108778Santirez {
110215108778Santirez const char *found;
110315108778Santirez
110415108778Santirez strbuf_free(json->tmp);
110515108778Santirez
110615108778Santirez if (token->type == T_ERROR)
110715108778Santirez found = token->value.string;
110815108778Santirez else
110915108778Santirez found = json_token_type_name[token->type];
111015108778Santirez
111115108778Santirez /* Note: token->index is 0 based, display starting from 1 */
111215108778Santirez luaL_error(l, "Expected %s but found %s at character %d",
111315108778Santirez exp, found, token->index + 1);
111415108778Santirez }
111515108778Santirez
json_decode_ascend(json_parse_t * json)11164fdcd213SMatt Stancliff static inline void json_decode_ascend(json_parse_t *json)
111715108778Santirez {
11184fdcd213SMatt Stancliff json->current_depth--;
11194fdcd213SMatt Stancliff }
11204fdcd213SMatt Stancliff
json_decode_descend(lua_State * l,json_parse_t * json,int slots)11214fdcd213SMatt Stancliff static void json_decode_descend(lua_State *l, json_parse_t *json, int slots)
11224fdcd213SMatt Stancliff {
11234fdcd213SMatt Stancliff json->current_depth++;
11244fdcd213SMatt Stancliff
11254fdcd213SMatt Stancliff if (json->current_depth <= json->cfg->decode_max_depth &&
11264fdcd213SMatt Stancliff lua_checkstack(l, slots)) {
112715108778Santirez return;
11284fdcd213SMatt Stancliff }
112915108778Santirez
113015108778Santirez strbuf_free(json->tmp);
11314fdcd213SMatt Stancliff luaL_error(l, "Found too many nested data structures (%d) at character %d",
11324fdcd213SMatt Stancliff json->current_depth, json->ptr - json->data);
113315108778Santirez }
113415108778Santirez
json_parse_object_context(lua_State * l,json_parse_t * json)113515108778Santirez static void json_parse_object_context(lua_State *l, json_parse_t *json)
113615108778Santirez {
113715108778Santirez json_token_t token;
113815108778Santirez
113915108778Santirez /* 3 slots required:
114015108778Santirez * .., table, key, value */
11414fdcd213SMatt Stancliff json_decode_descend(l, json, 3);
114215108778Santirez
114315108778Santirez lua_newtable(l);
114415108778Santirez
114515108778Santirez json_next_token(json, &token);
114615108778Santirez
114715108778Santirez /* Handle empty objects */
114815108778Santirez if (token.type == T_OBJ_END) {
11494fdcd213SMatt Stancliff json_decode_ascend(json);
115015108778Santirez return;
115115108778Santirez }
115215108778Santirez
115315108778Santirez while (1) {
115415108778Santirez if (token.type != T_STRING)
115515108778Santirez json_throw_parse_error(l, json, "object key string", &token);
115615108778Santirez
115715108778Santirez /* Push key */
115815108778Santirez lua_pushlstring(l, token.value.string, token.string_len);
115915108778Santirez
116015108778Santirez json_next_token(json, &token);
116115108778Santirez if (token.type != T_COLON)
116215108778Santirez json_throw_parse_error(l, json, "colon", &token);
116315108778Santirez
116415108778Santirez /* Fetch value */
116515108778Santirez json_next_token(json, &token);
116615108778Santirez json_process_value(l, json, &token);
116715108778Santirez
116815108778Santirez /* Set key = value */
116915108778Santirez lua_rawset(l, -3);
117015108778Santirez
117115108778Santirez json_next_token(json, &token);
117215108778Santirez
11734fdcd213SMatt Stancliff if (token.type == T_OBJ_END) {
11744fdcd213SMatt Stancliff json_decode_ascend(json);
117515108778Santirez return;
11764fdcd213SMatt Stancliff }
117715108778Santirez
117815108778Santirez if (token.type != T_COMMA)
117915108778Santirez json_throw_parse_error(l, json, "comma or object end", &token);
118015108778Santirez
118115108778Santirez json_next_token(json, &token);
118215108778Santirez }
118315108778Santirez }
118415108778Santirez
118515108778Santirez /* Handle the array context */
json_parse_array_context(lua_State * l,json_parse_t * json)118615108778Santirez static void json_parse_array_context(lua_State *l, json_parse_t *json)
118715108778Santirez {
118815108778Santirez json_token_t token;
118915108778Santirez int i;
119015108778Santirez
119115108778Santirez /* 2 slots required:
119215108778Santirez * .., table, value */
11934fdcd213SMatt Stancliff json_decode_descend(l, json, 2);
119415108778Santirez
119515108778Santirez lua_newtable(l);
119615108778Santirez
119715108778Santirez json_next_token(json, &token);
119815108778Santirez
119915108778Santirez /* Handle empty arrays */
12004fdcd213SMatt Stancliff if (token.type == T_ARR_END) {
12014fdcd213SMatt Stancliff json_decode_ascend(json);
120215108778Santirez return;
12034fdcd213SMatt Stancliff }
120415108778Santirez
120515108778Santirez for (i = 1; ; i++) {
120615108778Santirez json_process_value(l, json, &token);
120715108778Santirez lua_rawseti(l, -2, i); /* arr[i] = value */
120815108778Santirez
120915108778Santirez json_next_token(json, &token);
121015108778Santirez
12114fdcd213SMatt Stancliff if (token.type == T_ARR_END) {
12124fdcd213SMatt Stancliff json_decode_ascend(json);
121315108778Santirez return;
12144fdcd213SMatt Stancliff }
121515108778Santirez
121615108778Santirez if (token.type != T_COMMA)
121715108778Santirez json_throw_parse_error(l, json, "comma or array end", &token);
121815108778Santirez
121915108778Santirez json_next_token(json, &token);
122015108778Santirez }
122115108778Santirez }
122215108778Santirez
122315108778Santirez /* Handle the "value" context */
json_process_value(lua_State * l,json_parse_t * json,json_token_t * token)122415108778Santirez static void json_process_value(lua_State *l, json_parse_t *json,
122515108778Santirez json_token_t *token)
122615108778Santirez {
122715108778Santirez switch (token->type) {
122815108778Santirez case T_STRING:
122915108778Santirez lua_pushlstring(l, token->value.string, token->string_len);
123015108778Santirez break;;
123115108778Santirez case T_NUMBER:
123215108778Santirez lua_pushnumber(l, token->value.number);
123315108778Santirez break;;
123415108778Santirez case T_BOOLEAN:
123515108778Santirez lua_pushboolean(l, token->value.boolean);
123615108778Santirez break;;
123715108778Santirez case T_OBJ_BEGIN:
123815108778Santirez json_parse_object_context(l, json);
123915108778Santirez break;;
124015108778Santirez case T_ARR_BEGIN:
124115108778Santirez json_parse_array_context(l, json);
124215108778Santirez break;;
124315108778Santirez case T_NULL:
124415108778Santirez /* In Lua, setting "t[k] = nil" will delete k from the table.
124515108778Santirez * Hence a NULL pointer lightuserdata object is used instead */
124615108778Santirez lua_pushlightuserdata(l, NULL);
124715108778Santirez break;;
124815108778Santirez default:
124915108778Santirez json_throw_parse_error(l, json, "value", token);
125015108778Santirez }
125115108778Santirez }
125215108778Santirez
json_decode(lua_State * l)12534fdcd213SMatt Stancliff static int json_decode(lua_State *l)
125415108778Santirez {
125515108778Santirez json_parse_t json;
125615108778Santirez json_token_t token;
12574fdcd213SMatt Stancliff size_t json_len;
12584fdcd213SMatt Stancliff
12594fdcd213SMatt Stancliff luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument");
126015108778Santirez
126115108778Santirez json.cfg = json_fetch_config(l);
12624fdcd213SMatt Stancliff json.data = luaL_checklstring(l, 1, &json_len);
12634fdcd213SMatt Stancliff json.current_depth = 0;
12644fdcd213SMatt Stancliff json.ptr = json.data;
12654fdcd213SMatt Stancliff
12664fdcd213SMatt Stancliff /* Detect Unicode other than UTF-8 (see RFC 4627, Sec 3)
12674fdcd213SMatt Stancliff *
12684fdcd213SMatt Stancliff * CJSON can support any simple data type, hence only the first
12694fdcd213SMatt Stancliff * character is guaranteed to be ASCII (at worst: '"'). This is
12704fdcd213SMatt Stancliff * still enough to detect whether the wrong encoding is in use. */
12714fdcd213SMatt Stancliff if (json_len >= 2 && (!json.data[0] || !json.data[1]))
12724fdcd213SMatt Stancliff luaL_error(l, "JSON parser does not support UTF-16 or UTF-32");
127315108778Santirez
127415108778Santirez /* Ensure the temporary buffer can hold the entire string.
127515108778Santirez * This means we no longer need to do length checks since the decoded
127615108778Santirez * string must be smaller than the entire json string */
127715108778Santirez json.tmp = strbuf_new(json_len);
127815108778Santirez
127915108778Santirez json_next_token(&json, &token);
128015108778Santirez json_process_value(l, &json, &token);
128115108778Santirez
128215108778Santirez /* Ensure there is no more input left */
128315108778Santirez json_next_token(&json, &token);
128415108778Santirez
128515108778Santirez if (token.type != T_END)
128615108778Santirez json_throw_parse_error(l, &json, "the end", &token);
128715108778Santirez
128815108778Santirez strbuf_free(json.tmp);
128915108778Santirez
129015108778Santirez return 1;
129115108778Santirez }
129215108778Santirez
129315108778Santirez /* ===== INITIALISATION ===== */
129415108778Santirez
12954fdcd213SMatt Stancliff #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 502
12964fdcd213SMatt Stancliff /* Compatibility for Lua 5.1.
12974fdcd213SMatt Stancliff *
12984fdcd213SMatt Stancliff * luaL_setfuncs() is used to create a module table where the functions have
12994fdcd213SMatt Stancliff * json_config_t as their first upvalue. Code borrowed from Lua 5.2 source. */
luaL_setfuncs(lua_State * l,const luaL_Reg * reg,int nup)13004fdcd213SMatt Stancliff static void luaL_setfuncs (lua_State *l, const luaL_Reg *reg, int nup)
13014fdcd213SMatt Stancliff {
13024fdcd213SMatt Stancliff int i;
13034fdcd213SMatt Stancliff
13044fdcd213SMatt Stancliff luaL_checkstack(l, nup, "too many upvalues");
13054fdcd213SMatt Stancliff for (; reg->name != NULL; reg++) { /* fill the table with given functions */
13064fdcd213SMatt Stancliff for (i = 0; i < nup; i++) /* copy upvalues to the top */
13074fdcd213SMatt Stancliff lua_pushvalue(l, -nup);
13084fdcd213SMatt Stancliff lua_pushcclosure(l, reg->func, nup); /* closure with those upvalues */
13094fdcd213SMatt Stancliff lua_setfield(l, -(nup + 2), reg->name);
13104fdcd213SMatt Stancliff }
13114fdcd213SMatt Stancliff lua_pop(l, nup); /* remove upvalues */
13124fdcd213SMatt Stancliff }
13134fdcd213SMatt Stancliff #endif
13144fdcd213SMatt Stancliff
13154fdcd213SMatt Stancliff /* Call target function in protected mode with all supplied args.
13164fdcd213SMatt Stancliff * Assumes target function only returns a single non-nil value.
13174fdcd213SMatt Stancliff * Convert and return thrown errors as: nil, "error message" */
json_protect_conversion(lua_State * l)13184fdcd213SMatt Stancliff static int json_protect_conversion(lua_State *l)
13194fdcd213SMatt Stancliff {
13204fdcd213SMatt Stancliff int err;
13214fdcd213SMatt Stancliff
13224fdcd213SMatt Stancliff /* Deliberately throw an error for invalid arguments */
13234fdcd213SMatt Stancliff luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument");
13244fdcd213SMatt Stancliff
13254fdcd213SMatt Stancliff /* pcall() the function stored as upvalue(1) */
13264fdcd213SMatt Stancliff lua_pushvalue(l, lua_upvalueindex(1));
13274fdcd213SMatt Stancliff lua_insert(l, 1);
13284fdcd213SMatt Stancliff err = lua_pcall(l, 1, 1, 0);
13294fdcd213SMatt Stancliff if (!err)
13304fdcd213SMatt Stancliff return 1;
13314fdcd213SMatt Stancliff
13324fdcd213SMatt Stancliff if (err == LUA_ERRRUN) {
13334fdcd213SMatt Stancliff lua_pushnil(l);
13344fdcd213SMatt Stancliff lua_insert(l, -2);
13354fdcd213SMatt Stancliff return 2;
13364fdcd213SMatt Stancliff }
13374fdcd213SMatt Stancliff
13384fdcd213SMatt Stancliff /* Since we are not using a custom error handler, the only remaining
13394fdcd213SMatt Stancliff * errors are memory related */
13404fdcd213SMatt Stancliff return luaL_error(l, "Memory allocation error in CJSON protected call");
13414fdcd213SMatt Stancliff }
13424fdcd213SMatt Stancliff
13434fdcd213SMatt Stancliff /* Return cjson module table */
lua_cjson_new(lua_State * l)13444fdcd213SMatt Stancliff static int lua_cjson_new(lua_State *l)
134515108778Santirez {
134615108778Santirez luaL_Reg reg[] = {
134715108778Santirez { "encode", json_encode },
134815108778Santirez { "decode", json_decode },
134915108778Santirez { "encode_sparse_array", json_cfg_encode_sparse_array },
135015108778Santirez { "encode_max_depth", json_cfg_encode_max_depth },
13514fdcd213SMatt Stancliff { "decode_max_depth", json_cfg_decode_max_depth },
135215108778Santirez { "encode_number_precision", json_cfg_encode_number_precision },
135315108778Santirez { "encode_keep_buffer", json_cfg_encode_keep_buffer },
13544fdcd213SMatt Stancliff { "encode_invalid_numbers", json_cfg_encode_invalid_numbers },
13554fdcd213SMatt Stancliff { "decode_invalid_numbers", json_cfg_decode_invalid_numbers },
13564fdcd213SMatt Stancliff { "new", lua_cjson_new },
135715108778Santirez { NULL, NULL }
135815108778Santirez };
135915108778Santirez
13604fdcd213SMatt Stancliff /* Initialise number conversions */
13614fdcd213SMatt Stancliff fpconv_init();
136215108778Santirez
13634fdcd213SMatt Stancliff /* cjson module table */
13644fdcd213SMatt Stancliff lua_newtable(l);
13654fdcd213SMatt Stancliff
13664fdcd213SMatt Stancliff /* Register functions with config data as upvalue */
13674fdcd213SMatt Stancliff json_create_config(l);
13684fdcd213SMatt Stancliff luaL_setfuncs(l, reg, 1);
136915108778Santirez
137015108778Santirez /* Set cjson.null */
137115108778Santirez lua_pushlightuserdata(l, NULL);
137215108778Santirez lua_setfield(l, -2, "null");
137315108778Santirez
13744fdcd213SMatt Stancliff /* Set module name / version fields */
13754fdcd213SMatt Stancliff lua_pushliteral(l, CJSON_MODNAME);
13764fdcd213SMatt Stancliff lua_setfield(l, -2, "_NAME");
13774fdcd213SMatt Stancliff lua_pushliteral(l, CJSON_VERSION);
13784fdcd213SMatt Stancliff lua_setfield(l, -2, "_VERSION");
13794fdcd213SMatt Stancliff
13804fdcd213SMatt Stancliff return 1;
13814fdcd213SMatt Stancliff }
13824fdcd213SMatt Stancliff
13834fdcd213SMatt Stancliff /* Return cjson.safe module table */
lua_cjson_safe_new(lua_State * l)13844fdcd213SMatt Stancliff static int lua_cjson_safe_new(lua_State *l)
13854fdcd213SMatt Stancliff {
13864fdcd213SMatt Stancliff const char *func[] = { "decode", "encode", NULL };
13874fdcd213SMatt Stancliff int i;
13884fdcd213SMatt Stancliff
13894fdcd213SMatt Stancliff lua_cjson_new(l);
13904fdcd213SMatt Stancliff
13914fdcd213SMatt Stancliff /* Fix new() method */
13924fdcd213SMatt Stancliff lua_pushcfunction(l, lua_cjson_safe_new);
13934fdcd213SMatt Stancliff lua_setfield(l, -2, "new");
13944fdcd213SMatt Stancliff
13954fdcd213SMatt Stancliff for (i = 0; func[i]; i++) {
13964fdcd213SMatt Stancliff lua_getfield(l, -1, func[i]);
13974fdcd213SMatt Stancliff lua_pushcclosure(l, json_protect_conversion, 1);
13984fdcd213SMatt Stancliff lua_setfield(l, -2, func[i]);
13994fdcd213SMatt Stancliff }
14004fdcd213SMatt Stancliff
14014fdcd213SMatt Stancliff return 1;
14024fdcd213SMatt Stancliff }
14034fdcd213SMatt Stancliff
luaopen_cjson(lua_State * l)14044fdcd213SMatt Stancliff int luaopen_cjson(lua_State *l)
14054fdcd213SMatt Stancliff {
14064fdcd213SMatt Stancliff lua_cjson_new(l);
14074fdcd213SMatt Stancliff
14084fdcd213SMatt Stancliff #ifdef ENABLE_CJSON_GLOBAL
14094fdcd213SMatt Stancliff /* Register a global "cjson" table. */
14104fdcd213SMatt Stancliff lua_pushvalue(l, -1);
14114fdcd213SMatt Stancliff lua_setglobal(l, CJSON_MODNAME);
14124fdcd213SMatt Stancliff #endif
141315108778Santirez
141415108778Santirez /* Return cjson table */
141515108778Santirez return 1;
141615108778Santirez }
141715108778Santirez
luaopen_cjson_safe(lua_State * l)14184fdcd213SMatt Stancliff int luaopen_cjson_safe(lua_State *l)
14194fdcd213SMatt Stancliff {
14204fdcd213SMatt Stancliff lua_cjson_safe_new(l);
14214fdcd213SMatt Stancliff
14224fdcd213SMatt Stancliff /* Return cjson.safe table */
14234fdcd213SMatt Stancliff return 1;
14244fdcd213SMatt Stancliff }
14254fdcd213SMatt Stancliff
142615108778Santirez /* vi:ai et sw=4 ts=4:
142715108778Santirez */
1428