xref: /redis-3.2.3/deps/lua/src/lua_cjson.c (revision 0ed2c601)
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