--- CBOR-XS/XS.xs 2013/11/20 16:29:02 1.24 +++ CBOR-XS/XS.xs 2013/11/22 15:28:38 1.27 @@ -81,12 +81,13 @@ #endif static HV *cbor_stash, *types_boolean_stash, *types_error_stash, *cbor_tagged_stash; // CBOR::XS:: -static SV *types_true, *types_false, *types_error, *sv_cbor; +static SV *types_true, *types_false, *types_error, *sv_cbor, *default_filter; typedef struct { U32 flags; U32 max_depth; STRLEN max_size; + SV *filter; } CBOR; ecb_inline void @@ -96,6 +97,12 @@ cbor->max_depth = 512; } +ecb_inline void +cbor_free (CBOR *cbor) +{ + SvREFCNT_dec (cbor->filter); +} + ///////////////////////////////////////////////////////////////////////////// // utility functions @@ -273,11 +280,6 @@ --enc->depth; } -ecb_inline void -encode_he (enc_t *enc, HE *he) -{ -} - static void encode_hv (enc_t *enc, HV *hv) { @@ -549,6 +551,7 @@ U32 maxdepth; // recursion depth limit AV *shareable; AV *stringref; + SV *decode_tagged; } dec_t; #define ERR(reason) SB if (!dec->err) dec->err = reason; goto fail; SE @@ -768,15 +771,15 @@ WANT (len); sv = newSVpvn (dec->cur, len); dec->cur += len; + + if (ecb_expect_false (dec->stringref) + && SvCUR (sv) >= minimum_string_length (AvFILLp (dec->stringref) + 1)) + av_push (dec->stringref, SvREFCNT_inc_NN (sv)); } if (utf8) SvUTF8_on (sv); - if (ecb_expect_false (dec->stringref) - && SvCUR (sv) >= minimum_string_length (AvFILLp (dec->stringref) + 1)) - av_push (dec->stringref, SvREFCNT_inc_NN (sv)); - return sv; fail: @@ -912,15 +915,42 @@ { sv = decode_sv (dec); - AV *av = newAV (); - av_push (av, newSVuv (tag)); - av_push (av, sv); - - HV *tagged_stash = !CBOR_SLOW || cbor_tagged_stash - ? cbor_tagged_stash - : gv_stashpv ("CBOR::XS::Tagged" , 1); + dSP; + ENTER; SAVETMPS; PUSHMARK (SP); + EXTEND (SP, 2); + PUSHs (newSVuv (tag)); + PUSHs (sv); + + PUTBACK; + int count = call_sv (dec->cbor.filter ? dec->cbor.filter : default_filter, G_ARRAY | G_EVAL); + SPAGAIN; + + if (SvTRUE (ERRSV)) + { + FREETMPS; LEAVE; + ERR (SvPVutf8_nolen (sv_2mortal (SvREFCNT_inc (ERRSV)))); + } + + if (count) + { + SvREFCNT_dec (sv); + sv = SvREFCNT_inc (POPs); + } + else + { + AV *av = newAV (); + av_push (av, newSVuv (tag)); + av_push (av, sv); + + HV *tagged_stash = !CBOR_SLOW || cbor_tagged_stash + ? cbor_tagged_stash + : gv_stashpv ("CBOR::XS::Tagged" , 1); + sv = sv_bless (newRV_noinc ((SV *)av), tagged_stash); + } + + PUTBACK; - sv = sv_bless (newRV_noinc ((SV *)av), tagged_stash); + FREETMPS; LEAVE; } break; } @@ -1076,6 +1106,8 @@ types_false = get_bool ("Types::Serialiser::false"); types_error = get_bool ("Types::Serialiser::error"); + default_filter = newSVpv ("CBOR::XS::default_filter", 0); + sv_cbor = newSVpv ("CBOR", 0); SvREADONLY_on (sv_cbor); } @@ -1148,6 +1180,18 @@ OUTPUT: RETVAL +void filter (CBOR *self, SV *filter = 0) + PPCODE: + SvREFCNT_dec (self->filter); + self->filter = filter ? newSVsv (filter) : filter; + XPUSHs (ST (0)); + +SV *get_filter (CBOR *self) + CODE: + RETVAL = self->filter ? self->filter : NEWSV (0, 0); + OUTPUT: + RETVAL + void encode (CBOR *self, SV *scalar) PPCODE: PUTBACK; scalar = encode_cbor (scalar, self); SPAGAIN; @@ -1169,6 +1213,10 @@ PUSHs (sv_2mortal (newSVuv (offset - SvPVX (cborstr)))); } +void DESTROY (CBOR *self) + PPCODE: + cbor_free (self); + PROTOTYPES: ENABLE void encode_cbor (SV *scalar)