--- JSON-XS/XS.xs 2007/08/13 16:06:25 1.58 +++ JSON-XS/XS.xs 2007/08/27 01:49:01 1.63 @@ -29,6 +29,8 @@ #define F_SHRINK 0x00000200UL #define F_ALLOW_BLESSED 0x00000400UL #define F_CONV_BLESSED 0x00000800UL +#define F_RELAXED 0x00001000UL + #define F_MAXDEPTH 0xf8000000UL #define S_MAXDEPTH 27 #define F_MAXSIZE 0x01f00000UL @@ -62,8 +64,10 @@ #ifdef USE_ITHREADS # define JSON_SLOW 1 +# define JSON_STASH (json_stash ? json_stash : gv_stashpv ("JSON::XS", 1)) #else # define JSON_SLOW 0 +# define JSON_STASH json_stash #endif static HV *json_stash, *json_boolean_stash; // JSON::XS:: @@ -335,7 +339,7 @@ } static void -encode_he (enc_t *enc, HE *he) +encode_hk (enc_t *enc, HE *he) { encode_ch (enc, '"'); @@ -358,7 +362,6 @@ if (enc->json.flags & F_SPACE_BEFORE) encode_space (enc); encode_ch (enc, ':'); if (enc->json.flags & F_SPACE_AFTER ) encode_space (enc); - encode_sv (enc, HeVAL (he)); } // compare hash entries, used when all keys are bytestrings @@ -373,8 +376,8 @@ STRLEN la = HeKLEN (a); STRLEN lb = HeKLEN (b); - if (!(cmp = memcmp (HeKEY (a), HeKEY (b), la < lb ? la : lb))) - cmp = la - lb; + if (!(cmp = memcmp (HeKEY (b), HeKEY (a), lb < la ? lb : la))) + cmp = lb - la; return cmp; } @@ -383,29 +386,45 @@ static int he_cmp_slow (const void *a, const void *b) { - return sv_cmp (HeSVKEY_force (*(HE **)a), HeSVKEY_force (*(HE **)b)); + return sv_cmp (HeSVKEY_force (*(HE **)b), HeSVKEY_force (*(HE **)a)); } static void encode_hv (enc_t *enc, HV *hv) { - int count, i; + HE *he; + int count; if (enc->indent >= enc->maxdepth) croak ("data structure too deep (hit recursion limit)"); encode_ch (enc, '{'); encode_nl (enc); ++enc->indent; - if ((count = hv_iterinit (hv))) + // for canonical output we have to sort by keys first + // actually, this is mostly due to the stupid so-called + // security workaround added somewhere in 5.8.x. + // that randomises hash orderings + if (enc->json.flags & F_CANONICAL) { - // for canonical output we have to sort by keys first - // actually, this is mostly due to the stupid so-called - // security workaround added somewhere in 5.8.x. - // that randomises hash orderings - if (enc->json.flags & F_CANONICAL) + int count = hv_iterinit (hv); + + if (SvMAGICAL (hv)) + { + // need to count by iterating. could improve by dynamically building the vector below + // but I don't care for the speed of this special case. + // note also that we will run into undefined behaviour when the two iterations + // do not result in the same count, something I might care for in some later release. + + count = 0; + while (hv_iternext (hv)) + ++count; + + hv_iterinit (hv); + } + + if (count) { - int fast = 1; - HE *he; + int i, fast = 1; #if defined(__BORLANDC__) || defined(_MSC_VER) HE **hes = _alloca (count * sizeof (HE)); #else @@ -442,36 +461,37 @@ LEAVE; } - for (i = 0; i < count; ++i) + while (count--) { encode_indent (enc); - encode_he (enc, hes [i]); + he = hes [count]; + encode_hk (enc, he); + encode_sv (enc, expect_false (SvMAGICAL (hv)) ? hv_iterval (hv, he) : HeVAL (he)); - if (i < count - 1) + if (count) encode_comma (enc); } - - encode_nl (enc); } - else - { - HE *he = hv_iternext (hv); - + } + else + { + if (hv_iterinit (hv) || SvMAGICAL (hv)) + if ((he = hv_iternext (hv))) for (;;) { encode_indent (enc); - encode_he (enc, he); + encode_hk (enc, he); + encode_sv (enc, expect_false (SvMAGICAL (hv)) ? hv_iterval (hv, he) : HeVAL (he)); if (!(he = hv_iternext (hv))) break; encode_comma (enc); } - - encode_nl (enc); - } } + encode_nl (enc); + --enc->indent; encode_indent (enc); encode_ch (enc, '}'); } @@ -692,6 +712,9 @@ || (ch != 0x20 && ch != 0x0a && ch != 0x0d && ch != 0x09)) break; + if (ch == '#' && dec->json.flags & F_RELAXED) + ++dec->cur; + ++dec->cur; } } @@ -1037,6 +1060,14 @@ ERR (", or ] expected while parsing array"); ++dec->cur; + + decode_ws (dec); + + if (*dec->cur == ']' && dec->json.flags & F_RELAXED) + { + ++dec->cur; + break; + } } DEC_DEC_DEPTH; @@ -1062,7 +1093,7 @@ else for (;;) { - decode_ws (dec); EXPECT_CH ('"'); + EXPECT_CH ('"'); // heuristic: assume that // a) decode_str + hv_store_ent are abysmally slow. @@ -1086,6 +1117,7 @@ decode_ws (dec); EXPECT_CH (':'); + decode_ws (dec); value = decode_sv (dec); if (!value) { @@ -1107,6 +1139,7 @@ decode_ws (dec); EXPECT_CH (':'); + decode_ws (dec); value = decode_sv (dec); if (!value) goto fail; @@ -1132,6 +1165,14 @@ ERR (", or } expected while parsing object/hash"); ++dec->cur; + + decode_ws (dec); + + if (*dec->cur == '}' && dec->json.flags & F_RELAXED) + { + ++dec->cur; + break; + } } DEC_DEC_DEPTH; @@ -1206,8 +1247,6 @@ static SV * decode_sv (dec_t *dec) { - decode_ws (dec); - // the beauty of JSON: you need exactly one character lookahead // to parse anything. switch (*dec->cur) @@ -1225,6 +1264,9 @@ if (dec->end - dec->cur >= 4 && !memcmp (dec->cur, "true", 4)) { dec->cur += 4; +#if JSON_SLOW + json_true = get_sv ("JSON::XS::true", 1); SvREADONLY_on (json_true); +#endif return SvREFCNT_inc (json_true); } else @@ -1236,6 +1278,9 @@ if (dec->end - dec->cur >= 5 && !memcmp (dec->cur, "false", 5)) { dec->cur += 5; +#if JSON_SLOW + json_false = get_sv ("JSON::XS::false", 1); SvREADONLY_on (json_false); +#endif return SvREFCNT_inc (json_false); } else @@ -1295,6 +1340,8 @@ dec.json.flags |= F_HOOK; *dec.end = 0; // this should basically be a nop, too, but make sure it's there + + decode_ws (&dec); sv = decode_sv (&dec); if (!(offset_return || !sv)) @@ -1380,14 +1427,11 @@ void new (char *klass) PPCODE: { - HV *stash = !JSON_SLOW || json_stash - ? json_stash - : gv_stashpv ("JSON::XS", 1); SV *pv = NEWSV (0, sizeof (JSON)); SvPOK_only (pv); Zero (SvPVX (pv), 1, JSON); ((JSON *)SvPVX (pv))->flags = F_DEFAULT; - XPUSHs (sv_2mortal (sv_bless (newRV_noinc (pv), stash))); + XPUSHs (sv_2mortal (sv_bless (newRV_noinc (pv), JSON_STASH))); } void ascii (JSON *self, int enable = 1) @@ -1404,6 +1448,7 @@ shrink = F_SHRINK allow_blessed = F_ALLOW_BLESSED convert_blessed = F_CONV_BLESSED + relaxed = F_RELAXED PPCODE: { if (enable)