--- JSON-XS/XS.xs 2007/07/01 22:20:00 1.48 +++ JSON-XS/XS.xs 2007/07/02 00:48:18 1.51 @@ -27,11 +27,12 @@ #define F_ALLOW_NONREF 0x00000100UL #define F_SHRINK 0x00000200UL #define F_ALLOW_BLESSED 0x00000400UL -#define F_CONV_BLESSED 0x00000800UL // NYI +#define F_CONV_BLESSED 0x00000800UL #define F_MAXDEPTH 0xf8000000UL #define S_MAXDEPTH 27 #define F_MAXSIZE 0x01f00000UL #define S_MAXSIZE 20 +#define F_HOOK 0x00080000UL // some hooks exist, so slow-path processing #define DEC_DEPTH(flags) (1UL << ((flags & F_MAXDEPTH) >> S_MAXDEPTH)) #define DEC_SIZE(flags) (1UL << ((flags & F_MAXSIZE ) >> S_MAXSIZE )) @@ -63,6 +64,7 @@ typedef struct { U32 flags; + SV *cb_object, *cb_sk_object; } JSON; ///////////////////////////////////////////////////////////////////////////// @@ -472,10 +474,10 @@ { if (SvSTASH (sv) == json_boolean_stash) { - if (SvIV (sv) == 0) - encode_str (enc, "false", 5, 0); - else + if (SvIV (sv)) encode_str (enc, "true", 4, 0); + else + encode_str (enc, "false", 5, 0); } else { @@ -492,10 +494,7 @@ if (to_json) { - dSP; - ENTER; - SAVETMPS; - PUSHMARK (SP); + dSP; ENTER; SAVETMPS; PUSHMARK (SP); XPUSHs (sv_bless (sv_2mortal (newRV_inc (sv)), SvSTASH (sv))); // calling with G_SCALAR ensures that we always get a 1 reutrn value @@ -506,8 +505,7 @@ encode_sv (enc, POPs); - FREETMPS; - LEAVE; + FREETMPS; LEAVE; } else if (enc->json.flags & F_ALLOW_BLESSED) encode_str (enc, "null", 4, 0); @@ -528,10 +526,13 @@ encode_av (enc, (AV *)sv); else if (svt < SVt_PVAV) { - if (SvNIOK (sv) && SvIV (sv) == 0) - encode_str (enc, "false", 5, 0); - else if (SvNIOK (sv) && SvIV (sv) == 1) + STRLEN len = 0; + char *pv = svt ? SvPV (sv, len) : 0; + + if (len == 1 && *pv == '1') encode_str (enc, "true", 4, 0); + else if (len == 1 && *pv == '0') + encode_str (enc, "false", 5, 0); else croak ("cannot encode reference to scalar '%s' unless the scalar is 0 or 1", SvPV_nolen (sv_2mortal (newRV_inc (sv)))); @@ -1010,6 +1011,7 @@ static SV * decode_hv (dec_t *dec) { + SV *sv; HV *hv = newHV (); DEC_INC_DEPTH; @@ -1093,7 +1095,54 @@ } DEC_DEC_DEPTH; - return newRV_noinc ((SV *)hv); + sv = newRV_noinc ((SV *)hv); + + // check filter callbacks + if (dec->json.flags & F_HOOK) + { + ENTER; SAVETMPS; + + if (dec->json.cb_sk_object && HvKEYS (hv) == 1) + { + int count; + + dSP; PUSHMARK (SP); + XPUSHs (sv_2mortal (sv)); + + PUTBACK; count = call_sv (dec->json.cb_sk_object, G_ARRAY); SPAGAIN; + + if (count == 1) + { + sv = newSVsv (POPs); + goto filter_ok; + } + + SvREFCNT_inc (sv); + } + + if (dec->json.cb_object) + { + int count; + + dSP; ENTER; SAVETMPS; PUSHMARK (SP); + XPUSHs (sv_2mortal (sv)); + + PUTBACK; count = call_sv (dec->json.cb_object, G_ARRAY); SPAGAIN; + + if (count == 1) + { + sv = newSVsv (POPs); + goto filter_ok; + } + + SvREFCNT_inc (sv); + } + +filter_ok: + FREETMPS; LEAVE; + } + + return sv; fail: SvREFCNT_dec (hv); @@ -1189,6 +1238,9 @@ dec.depth = 0; dec.maxdepth = DEC_DEPTH (dec.json.flags); + if (dec.json.cb_object || dec.json.cb_sk_object) + dec.json.flags |= F_HOOK; + *dec.end = 0; // this should basically be a nop, too, but make sure it's there sv = decode_sv (&dec); @@ -1272,7 +1324,7 @@ { SV *pv = NEWSV (0, sizeof (JSON)); SvPOK_only (pv); - Zero (SvPVX (pv), 1, sizeof (JSON)); + Zero (SvPVX (pv), 1, JSON); ((JSON *)SvPVX (pv))->flags = F_DEFAULT; XPUSHs (sv_2mortal (sv_bless (newRV_noinc (pv), json_stash))); } @@ -1331,6 +1383,32 @@ XPUSHs (ST (0)); } + +void filter_json_object (JSON *self, SV *cb = &PL_sv_undef) + ALIAS: + filter_json_single_key_object = 1 + PPCODE: +{ + SV **svp; + + if (!SvOK (cb)) + cb = 0; + else + cb = newSVsv (cb); + + switch (ix) + { + case 0: svp = &self->cb_object ; break; + case 1: svp = &self->cb_sk_object; break; + } + + if (*svp) + SvREFCNT_dec (*svp); + + *svp = cb; + + XPUSHs (ST (0)); +} void encode (JSON *self, SV *scalar) PPCODE: