--- JSON-XS/XS.xs 2007/03/25 02:46:41 1.17 +++ JSON-XS/XS.xs 2007/03/25 21:19:13 1.18 @@ -6,21 +6,24 @@ #include "string.h" #include "stdlib.h" -#define F_ASCII 0x00000001 -#define F_UTF8 0x00000002 -#define F_INDENT 0x00000004 -#define F_CANONICAL 0x00000008 -#define F_SPACE_BEFORE 0x00000010 -#define F_SPACE_AFTER 0x00000020 -#define F_ALLOW_NONREF 0x00000080 -#define F_SHRINK 0x00000100 - -// F_SKIPINVALID? -// F_EXECCODEREF? -// F_SELFCONVERT? <=> { &__class__ => } +#define F_ASCII 0x00000001UL +#define F_UTF8 0x00000002UL +#define F_INDENT 0x00000004UL +#define F_CANONICAL 0x00000008UL +#define F_SPACE_BEFORE 0x00000010UL +#define F_SPACE_AFTER 0x00000020UL +#define F_ALLOW_NONREF 0x00000080UL +#define F_SHRINK 0x00000100UL +#define F_MAXDEPTH 0xf8000000UL +#define S_MAXDEPTH 27 + +#define DEC_DEPTH(flags) (1UL << ((flags & F_MAXDEPTH) >> S_MAXDEPTH)) + +// F_SELFCONVERT? <=> to_json/toJson +// F_BLESSED? <=> { $__class__$ => } #define F_PRETTY F_INDENT | F_SPACE_BEFORE | F_SPACE_AFTER -#define F_DEFAULT 0 +#define F_DEFAULT (13UL << S_MAXDEPTH) #define INIT_SIZE 32 // initial scalar size to be allocated #define INDENT_STEP 3 // spaces per indentation level @@ -87,9 +90,9 @@ char *cur; // SvPVX (sv) + current output position char *end; // SvEND (sv) SV *sv; // result scalar - UV flags; // F_* - int indent; // indentation level - int max_depth; // max. recursion level + U32 flags; // F_* + U32 indent; // indentation level + U32 maxdepth; // max. indentation/recursion level } enc_t; static void @@ -450,7 +453,7 @@ { SV *rv = SvRV (sv); - if (enc->indent >= enc->max_depth) + if (enc->indent >= enc->maxdepth) croak ("data structure too deep (hit recursion limit)"); switch (SvTYPE (rv)) @@ -471,7 +474,7 @@ } static SV * -encode_json (SV *scalar, UV flags) +encode_json (SV *scalar, U32 flags) { if (!(flags & F_ALLOW_NONREF) && !SvROK (scalar)) croak ("hash- or arrayref expected (not a simple scalar, use allow_nonref to allow this)"); @@ -482,7 +485,7 @@ enc.cur = SvPVX (enc.sv); enc.end = SvEND (enc.sv); enc.indent = 0; - enc.max_depth = 0x7fffffffUL; + enc.maxdepth = DEC_DEPTH (flags); SvPOK_only (enc.sv); encode_sv (&enc, scalar); @@ -507,7 +510,9 @@ char *cur; // current parser pointer char *end; // end of input string const char *err; // parse error, if != 0 - UV flags; // F_* + U32 flags; // F_* + U32 depth; // recursion depth + U32 maxdepth; // recursion depth limit } dec_t; static void @@ -526,12 +531,16 @@ } #define ERR(reason) SB dec->err = reason; goto fail; SE + #define EXPECT_CH(ch) SB \ if (*dec->cur != ch) \ ERR (# ch " expected"); \ ++dec->cur; \ SE +#define DEC_INC_DEPTH if (++dec->depth > dec->maxdepth) ERR ("json datastructure exceeds maximum nesting level (set a higher max_depth)") +#define DEC_DEC_DEPTH --dec->depth + static SV *decode_sv (dec_t *dec); static signed char decode_hexdigit[256]; @@ -784,7 +793,9 @@ { AV *av = newAV (); + DEC_INC_DEPTH; decode_ws (dec); + if (*dec->cur == ']') ++dec->cur; else @@ -812,10 +823,12 @@ ++dec->cur; } + DEC_DEC_DEPTH; return newRV_noinc ((SV *)av); fail: SvREFCNT_dec (av); + DEC_DEC_DEPTH; return 0; } @@ -824,7 +837,9 @@ { HV *hv = newHV (); + DEC_INC_DEPTH; decode_ws (dec); + if (*dec->cur == '}') ++dec->cur; else @@ -847,8 +862,8 @@ goto fail; } - //TODO: optimise hv_store_ent (hv, key, value, 0); + SvREFCNT_dec (key); decode_ws (dec); @@ -864,10 +879,12 @@ ++dec->cur; } + DEC_DEC_DEPTH; return newRV_noinc ((SV *)hv); fail: SvREFCNT_dec (hv); + DEC_DEC_DEPTH; return 0; } @@ -929,7 +946,7 @@ } static SV * -decode_json (SV *string, UV flags) +decode_json (SV *string, U32 flags) { SV *sv; @@ -941,11 +958,14 @@ SvGROW (string, SvCUR (string) + 1); // should basically be a NOP dec_t dec; - dec.flags = flags; - dec.cur = SvPVX (string); - dec.end = SvEND (string); - dec.err = 0; + dec.flags = flags; + dec.cur = SvPVX (string); + dec.end = SvEND (string); + dec.err = 0; + dec.depth = 0; + dec.maxdepth = DEC_DEPTH (dec.flags); + *SvEND (sv) = 0; // this shou[ld basically be a nop, too sv = decode_sv (&dec); if (!sv) @@ -988,14 +1008,13 @@ int i; memset (decode_hexdigit, 0xff, 256); - for (i = 10; i--; ) - decode_hexdigit ['0' + i] = i; - for (i = 7; i--; ) - { - decode_hexdigit ['a' + i] = 10 + i; - decode_hexdigit ['A' + i] = 10 + i; - } + for (i = 0; i < 256; ++i) + decode_hexdigit [i] = + i >= '0' && i <= '9' ? i - '0' + : i >= 'a' && i <= 'f' ? i - 'a' + 10 + : i >= 'A' && i <= 'F' ? i - 'A' + 10 + : -1; json_stash = gv_stashpv ("JSON::XS", 1); } @@ -1032,6 +1051,24 @@ OUTPUT: RETVAL +SV *max_depth (SV *self, int max_depth = 0x80000000UL) + CODE: +{ + UV *uv = SvJSON (self); + UV log2 = 0; + + if (max_depth > 0x80000000UL) max_depth = 0x80000000UL; + + while ((1UL << log2) < max_depth) + ++log2; + + *uv = *uv & ~F_MAXDEPTH | (log2 << S_MAXDEPTH); + + RETVAL = newSVsv (self); +} + OUTPUT: + RETVAL + void encode (SV *self, SV *scalar) PPCODE: XPUSHs (encode_json (scalar, *SvJSON (self))); @@ -1046,11 +1083,11 @@ ALIAS: objToJson = 0 PPCODE: - XPUSHs (encode_json (scalar, F_UTF8)); + XPUSHs (encode_json (scalar, F_DEFAULT | F_UTF8)); void from_json (SV *jsonstr) ALIAS: jsonToObj = 0 PPCODE: - XPUSHs (decode_json (jsonstr, F_UTF8)); + XPUSHs (decode_json (jsonstr, F_DEFAULT | F_UTF8));