--- JSON-XS/XS.xs 2007/06/25 04:08:17 1.44 +++ JSON-XS/XS.xs 2007/06/25 22:11:39 1.46 @@ -30,8 +30,11 @@ #define F_CONV_BLESSED 0x00000800UL // NYI #define F_MAXDEPTH 0xf8000000UL #define S_MAXDEPTH 27 +#define F_MAXSIZE 0x01f00000UL +#define S_MAXSIZE 20 #define DEC_DEPTH(flags) (1UL << ((flags & F_MAXDEPTH) >> S_MAXDEPTH)) +#define DEC_SIZE(flags) (1UL << ((flags & F_MAXSIZE ) >> S_MAXSIZE )) #define F_PRETTY F_INDENT | F_SPACE_BEFORE | F_SPACE_AFTER #define F_DEFAULT (9UL << S_MAXDEPTH) @@ -1022,25 +1025,62 @@ else for (;;) { - SV *key, *value; - decode_ws (dec); EXPECT_CH ('"'); - key = decode_str (dec); - if (!key) - goto fail; + // heuristic: assume that + // a) decode_str + hv_store_ent are abysmally slow + // b) most hash keys are short, simple ascii text + // so try to "fast-match" such strings to avoid + // the overhead of hv_store_ent. + { + SV *value; + char *p = dec->cur; + char *e = p + 24; // only try up to 24 bytes - decode_ws (dec); EXPECT_CH (':'); + for (;;) + { + if (p == e || *p < 0x20 || *p >= 0x80 || *p == '\\') + { + // slow path, back up and use decode_str + SV *key = decode_str (dec); + if (!key) + goto fail; - value = decode_sv (dec); - if (!value) - { - SvREFCNT_dec (key); - goto fail; - } + decode_ws (dec); EXPECT_CH (':'); - hv_store_ent (hv, key, value, 0); - SvREFCNT_dec (key); + value = decode_sv (dec); + if (!value) + { + SvREFCNT_dec (key); + goto fail; + } + + hv_store_ent (hv, key, value, 0); + SvREFCNT_dec (key); + + break; + } + else if (*p == '"') + { + // fast path, got a simple key + char *key = dec->cur; + int len = p - key; + dec->cur = p + 1; + + decode_ws (dec); EXPECT_CH (':'); + + value = decode_sv (dec); + if (!value) + goto fail; + + hv_store (hv, key, len, value, 0); + + break; + } + + ++p; + } + } decode_ws (dec); @@ -1135,6 +1175,10 @@ SvGETMAGIC (string); SvUPGRADE (string, SVt_PV); + if (flags & F_MAXSIZE && SvCUR (string) > DEC_SIZE (flags)) + croak ("attempted decode of JSON text of %lu bytes size, but max_size is set to %lu", + (unsigned long)SvCUR (string), (unsigned long)DEC_SIZE (flags)); + if (flags & F_UTF8) sv_utf8_downgrade (string, 0); else @@ -1275,6 +1319,25 @@ RETVAL = newSVsv (self); } + OUTPUT: + RETVAL + +SV *max_size (SV *self, UV max_size = 0) + CODE: +{ + UV *uv = SvJSON (self); + UV log2 = 0; + + if (max_size > 0x80000000UL) max_size = 0x80000000UL; + if (max_size == 1) max_size = 2; + + while ((1UL << log2) < max_size) + ++log2; + + *uv = *uv & ~F_MAXSIZE | (log2 << S_MAXSIZE); + + RETVAL = newSVsv (self); +} OUTPUT: RETVAL