--- CBOR-XS/XS.xs 2013/11/20 01:09:46 1.18 +++ CBOR-XS/XS.xs 2013/11/20 02:03:09 1.19 @@ -28,7 +28,7 @@ // inofficial extensions (pending iana registration) CBOR_TAG_PERL_OBJECT = 24, // http://cbor.schmorp.de/perl-object CBOR_TAG_GENERIC_OBJECT = 25, // http://cbor.schmorp.de/generic-object - CBOR_TAG_VALUE_SHARABLE = 26, // http://cbor.schmorp.de/value-sharing + CBOR_TAG_VALUE_SHAREABLE = 26, // http://cbor.schmorp.de/value-sharing CBOR_TAG_VALUE_SHAREDREF = 27, // http://cbor.schmorp.de/value-sharing CBOR_TAG_STRINGREF_NAMESPACE = 65537, // http://cbor.schmorp.de/stringref CBOR_TAG_STRINGREF = 28, // http://cbor.schmorp.de/stringref @@ -138,8 +138,8 @@ CBOR cbor; U32 depth; // recursion level HV *stringref; // string => index, or 0 - HV *sharable; // ptr => index, or 0 - HV *sharable_idx; + HV *shareable; // ptr => index, or 0 + UV shareable_idx; } enc_t; ecb_inline void @@ -216,40 +216,6 @@ encode_uint (enc, 0xc0, tag); } -static int -encode_sharable2 (enc_t *enc, SV *sv) -{ - if (!enc->sharable) - enc->sharable = (HV *)sv_2mortal ((SV *)newHV ()); - - SV **svp = hv_fetch (enc->sharable, &sv, sizeof (sv), 1); - - if (SvOK (*svp)) - { - encode_tag (enc, CBOR_TAG_VALUE_SHAREDREF); - encode_uint (enc, 0x00, SvUV (*svp)); - - return 1; - } - else - { - sv_setuv (*svp, enc->sharable_idx++); - encode_tag (enc, CBOR_TAG_VALUE_SHARABLE); - - return 0; - } -} - -ecb_inline int -encode_sharable (enc_t *enc, SV *sv) -{ - if (ecb_expect_false (enc->cbor.flags & F_ALLOW_SHARING) - && ecb_expect_false (SvREFCNT (sv) > 1)) - return encode_sharable2 (enc, sv); - - return 0; -} - static void encode_sv (enc_t *enc, SV *sv); static void @@ -311,13 +277,31 @@ static void encode_rv (enc_t *enc, SV *sv) { - svtype svt; - SvGETMAGIC (sv); - svt = SvTYPE (sv); - if (encode_sharable (enc, sv)) - return; + if (ecb_expect_false (enc->cbor.flags & F_ALLOW_SHARING) + && ecb_expect_false (SvREFCNT (sv) > 1)) + { + if (!enc->shareable) + enc->shareable = (HV *)sv_2mortal ((SV *)newHV ()); + + SV **svp = hv_fetch (enc->shareable, (char *)&sv, sizeof (sv), 1); + + if (SvOK (*svp)) + { + encode_tag (enc, CBOR_TAG_VALUE_SHAREDREF); + encode_uint (enc, 0x00, SvUV (*svp)); + return; + } + else + { + sv_setuv (*svp, enc->shareable_idx); + ++enc->shareable_idx; + encode_tag (enc, CBOR_TAG_VALUE_SHAREABLE); + } + } + + svtype svt = SvTYPE (sv); if (ecb_expect_false (SvOBJECT (sv))) { @@ -454,9 +438,6 @@ { SvGETMAGIC (sv); - if (encode_sharable (enc, sv)) - return; - if (SvPOKp (sv)) { STRLEN len; @@ -519,7 +500,7 @@ CBOR cbor; U32 depth; // recursion depth U32 maxdepth; // recursion depth limit - AV *sharable; + AV *shareable; } dec_t; #define ERR(reason) SB if (!dec->err) dec->err = reason; goto fail; SE @@ -745,40 +726,51 @@ static SV * decode_tagged (dec_t *dec) { + SV *sv = 0; UV tag = decode_uint (dec); - SV *sv = decode_sv (dec); + + WANT (1); switch (tag) { case CBOR_TAG_MAGIC: - return sv; + return decode_sv (dec); case CBOR_TAG_INDIRECTION: - return newRV_noinc (sv); + return newRV_noinc (decode_sv (dec)); - case CBOR_TAG_VALUE_SHARABLE: - if (ecb_expect_false (!dec->sharable)) - dec->sharable = (AV *)sv_2mortal ((SV *)newAV ()); + case CBOR_TAG_VALUE_SHAREABLE: + { + if (ecb_expect_false (!dec->shareable)) + dec->shareable = (AV *)sv_2mortal ((SV *)newAV ()); + + sv = newSV (0); + av_push (dec->shareable, SvREFCNT_inc_NN (sv)); - av_push (dec->sharable, SvREFCNT_inc_NN (sv)); + SV *osv = decode_sv (dec); + sv_setsv (sv, osv); + SvREFCNT_dec_NN (osv); + } return sv; case CBOR_TAG_VALUE_SHAREDREF: { - // TODO: should verify that the sv atcually was a CBOR unsigned integer - UV idx = SvUV (sv); + if ((*dec->cur >> 5) != 0) + ERR ("corrupted CBOR data (sharedref index not an unsigned integer)"); - if (!dec->sharable || idx > AvFILLp (dec->sharable)) - ERR ("corrupted CBOR data (sharedref index out of bounds)"); + UV idx = decode_uint (dec); - SvREFCNT_dec (sv); + if (!dec->shareable || idx > AvFILLp (dec->shareable)) + ERR ("corrupted CBOR data (sharedref index out of bounds)"); - return SvREFCNT_inc_NN (AvARRAY (dec->sharable)[idx]); + return SvREFCNT_inc_NN (AvARRAY (dec->shareable)[idx]); } case CBOR_TAG_PERL_OBJECT: { + sv = decode_sv (dec); + if (!SvROK (sv) || SvTYPE (SvRV (sv)) != SVt_PVAV) ERR ("corrupted CBOR data (non-array perl object)"); @@ -829,6 +821,8 @@ default: { + sv = decode_sv (dec); + AV *av = newAV (); av_push (av, newSVuv (tag)); av_push (av, sv);