--- JSON-XS/XS.xs 2018/08/28 16:16:17 1.133 +++ JSON-XS/XS.xs 2019/02/24 04:21:05 1.137 @@ -52,7 +52,7 @@ #define F_PRETTY F_INDENT | F_SPACE_BEFORE | F_SPACE_AFTER -#define INIT_SIZE 32 // initial scalar size to be allocated +#define INIT_SIZE 64 // initial scalar size to be allocated #define INDENT_STEP 3 // spaces per indentation level #define SHORT_STRING_LEN 16384 // special-case strings of up to this size @@ -98,6 +98,8 @@ enum { INCR_M_WS = 0, // initial whitespace skipping, must be 0 + INCR_M_TFN, // inside true/false/null + INCR_M_NUM, // inside number INCR_M_STR, // inside string INCR_M_BS, // inside backslash INCR_M_C0, // inside comment in initial whitespace sequence @@ -127,8 +129,9 @@ INLINE void json_init (JSON *json) { - Zero (json, 1, JSON); - json->max_depth = 512; + static const JSON init = { F_ALLOW_NONREF, 512 }; + + *json = init; } ///////////////////////////////////////////////////////////////////////////// @@ -790,7 +793,6 @@ dSP; ENTER; SAVETMPS; - SAVESTACK_POS (); PUSHMARK (SP); EXTEND (SP, 2); // we re-bless the reference to get overload and other niceties right @@ -812,12 +814,18 @@ encode_ch (enc, ')'); encode_ch (enc, '['); - while (count) + if (count) { - encode_sv (enc, SP[1 - count--]); + int i; - if (count) - encode_ch (enc, ','); + for (i = 0; i < count - 1; ++i) + { + encode_sv (enc, SP[i + 1 - count]); + encode_ch (enc, ','); + } + + encode_sv (enc, TOPs); + SP -= count; } encode_ch (enc, ']'); @@ -1498,7 +1506,7 @@ sv = newRV_noinc ((SV *)hv); // check filter callbacks - if (dec->json.flags & F_HOOK) + if (expect_false (dec->json.flags & F_HOOK)) { if (dec->json.cb_sk_object && HvKEYS (hv) == 1) { @@ -1518,7 +1526,6 @@ int count; ENTER; SAVETMPS; - SAVESTACK_POS (); PUSHMARK (SP); XPUSHs (HeVAL (he)); sv_2mortal (sv); @@ -1531,6 +1538,8 @@ FREETMPS; LEAVE; return sv; } + else if (count) + croak ("filter_json_single_key_object callbacks must not return more than one scalar"); SvREFCNT_inc (sv); FREETMPS; LEAVE; @@ -1543,20 +1552,18 @@ int count; ENTER; SAVETMPS; - SAVESTACK_POS (); PUSHMARK (SP); XPUSHs (sv_2mortal (sv)); PUTBACK; count = call_sv (dec->json.cb_object, G_ARRAY); SPAGAIN; if (count == 1) - { - sv = newSVsv (POPs); - FREETMPS; LEAVE; - return sv; - } + sv = newSVsv (POPs); + else if (count == 0) + SvREFCNT_inc (sv); + else + croak ("filter_json_object callbacks must not return more than one scalar"); - SvREFCNT_inc (sv); FREETMPS; LEAVE; } } @@ -1789,7 +1796,7 @@ // check for trailing garbage decode_ws (&dec); - if (*dec.cur) + if (dec.cur != dec.end) { dec.err = "garbage after JSON object"; SvREFCNT_dec (sv); @@ -1837,9 +1844,17 @@ for (;;) { - //printf ("loop pod %d *p<%c><%s>, mode %d nest %d\n", p - SvPVX (self->incr_text), *p, p, self->incr_mode, self->incr_nest);//D switch (self->incr_mode) { + // reached end of a scalar, see if we are inside a nested structure or not + end_of_scalar: + self->incr_mode = INCR_M_JSON; + + if (self->incr_nest) // end of a scalar inside array, object or tag + goto incr_m_json; + else // end of scalar outside structure, json text ends here + goto interrupt; + // only used for initial whitespace skipping case INCR_M_WS: for (;;) @@ -1891,6 +1906,40 @@ break; + // inside true/false/null + case INCR_M_TFN: + incr_m_tfn: + for (;;) + switch (*p++) + { + case 'r': case 'u': case 'e': // tRUE, falsE, nUll + case 'a': case 'l': case 's': // fALSe, nuLL + // allowed + break; + + default: + --p; + goto end_of_scalar; + } + + // inside a number + case INCR_M_NUM: + incr_m_num: + for (;;) + switch (*p++) + { + case 'e': case 'E': case '.': case '+': + case '-': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + // allowed + break; + + default: + --p; + goto end_of_scalar; + } + // inside a string case INCR_M_STR: incr_m_str: @@ -1899,12 +1948,7 @@ if (*p == '"') { ++p; - self->incr_mode = INCR_M_JSON; - - if (!self->incr_nest) - goto interrupt; - - goto incr_m_json; + goto end_of_scalar; } else if (*p == '\\') { @@ -1944,6 +1988,21 @@ } break; + // the following three blocks handle scalars. this makes the parser + // more strict than required inside arrays or objects, and could + // be moved to a special case on the toplevel (except strings) + case 't': + case 'f': + case 'n': + self->incr_mode = INCR_M_TFN; + goto incr_m_tfn; + + case '-': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + self->incr_mode = INCR_M_NUM; + goto incr_m_num; + case '"': self->incr_mode = INCR_M_STR; goto incr_m_str; @@ -2149,20 +2208,18 @@ void encode (JSON *self, SV *scalar) PPCODE: - PUTBACK; scalar = encode_json (scalar, self); SPAGAIN; - XPUSHs (scalar); + PUTBACK; XPUSHs (encode_json (scalar, self)); void decode (JSON *self, SV *jsonstr) PPCODE: - PUTBACK; jsonstr = decode_json (jsonstr, self, 0); SPAGAIN; - XPUSHs (jsonstr); + PUTBACK; XPUSHs (decode_json (jsonstr, self, 0)); void decode_prefix (JSON *self, SV *jsonstr) PPCODE: { SV *sv; STRLEN offset; - PUTBACK; sv = decode_json (jsonstr, self, &offset); SPAGAIN; + PUTBACK; sv = decode_json (jsonstr, self, &offset); EXTEND (SP, 2); PUSHs (sv); PUSHs (sv_2mortal (newSVuv (ptr_to_index (jsonstr, SvPV_nolen (jsonstr) + offset)))); @@ -2245,7 +2302,7 @@ } } - PUTBACK; sv = decode_json (self->incr_text, self, &offset); SPAGAIN; + PUTBACK; sv = decode_json (self->incr_text, self, &offset); XPUSHs (sv); self->incr_pos -= offset; @@ -2307,8 +2364,7 @@ JSON json; json_init (&json); json.flags |= F_UTF8; - PUTBACK; scalar = encode_json (scalar, &json); SPAGAIN; - XPUSHs (scalar); + PUTBACK; XPUSHs (encode_json (scalar, &json)); } void decode_json (SV *jsonstr) @@ -2317,7 +2373,6 @@ JSON json; json_init (&json); json.flags |= F_UTF8; - PUTBACK; jsonstr = decode_json (jsonstr, &json, 0); SPAGAIN; - XPUSHs (jsonstr); + PUTBACK; XPUSHs (decode_json (jsonstr, &json, 0)); }