… | |
… | |
26 | enum cbor_tag |
26 | enum cbor_tag |
27 | { |
27 | { |
28 | // inofficial extensions (pending iana registration) |
28 | // inofficial extensions (pending iana registration) |
29 | CBOR_TAG_PERL_OBJECT = 24, // http://cbor.schmorp.de/perl-object |
29 | CBOR_TAG_PERL_OBJECT = 24, // http://cbor.schmorp.de/perl-object |
30 | CBOR_TAG_GENERIC_OBJECT = 25, // http://cbor.schmorp.de/generic-object |
30 | CBOR_TAG_GENERIC_OBJECT = 25, // http://cbor.schmorp.de/generic-object |
31 | CBOR_TAG_VALUE_SHARABLE = 26, // http://cbor.schmorp.de/value-sharing |
31 | CBOR_TAG_VALUE_SHAREABLE = 26, // http://cbor.schmorp.de/value-sharing |
32 | CBOR_TAG_VALUE_SHAREDREF = 27, // http://cbor.schmorp.de/value-sharing |
32 | CBOR_TAG_VALUE_SHAREDREF = 27, // http://cbor.schmorp.de/value-sharing |
33 | CBOR_TAG_STRINGREF_NAMESPACE = 65537, // http://cbor.schmorp.de/stringref |
33 | CBOR_TAG_STRINGREF_NAMESPACE = 65537, // http://cbor.schmorp.de/stringref |
34 | CBOR_TAG_STRINGREF = 28, // http://cbor.schmorp.de/stringref |
34 | CBOR_TAG_STRINGREF = 28, // http://cbor.schmorp.de/stringref |
35 | CBOR_TAG_INDIRECTION = 22098, // http://cbor.schmorp.de/indirection |
35 | CBOR_TAG_INDIRECTION = 22098, // http://cbor.schmorp.de/indirection |
36 | |
36 | |
… | |
… | |
136 | char *end; // SvEND (sv) |
136 | char *end; // SvEND (sv) |
137 | SV *sv; // result scalar |
137 | SV *sv; // result scalar |
138 | CBOR cbor; |
138 | CBOR cbor; |
139 | U32 depth; // recursion level |
139 | U32 depth; // recursion level |
140 | HV *stringref; // string => index, or 0 |
140 | HV *stringref; // string => index, or 0 |
141 | HV *sharable; // ptr => index, or 0 |
141 | HV *shareable; // ptr => index, or 0 |
142 | HV *sharable_idx; |
142 | UV shareable_idx; |
143 | } enc_t; |
143 | } enc_t; |
144 | |
144 | |
145 | ecb_inline void |
145 | ecb_inline void |
146 | need (enc_t *enc, STRLEN len) |
146 | need (enc_t *enc, STRLEN len) |
147 | { |
147 | { |
… | |
… | |
214 | encode_tag (enc_t *enc, UV tag) |
214 | encode_tag (enc_t *enc, UV tag) |
215 | { |
215 | { |
216 | encode_uint (enc, 0xc0, tag); |
216 | encode_uint (enc, 0xc0, tag); |
217 | } |
217 | } |
218 | |
218 | |
219 | static int |
|
|
220 | encode_sharable2 (enc_t *enc, SV *sv) |
|
|
221 | { |
|
|
222 | if (!enc->sharable) |
|
|
223 | enc->sharable = (HV *)sv_2mortal ((SV *)newHV ()); |
|
|
224 | |
|
|
225 | SV **svp = hv_fetch (enc->sharable, &sv, sizeof (sv), 1); |
|
|
226 | |
|
|
227 | if (SvOK (*svp)) |
|
|
228 | { |
|
|
229 | encode_tag (enc, CBOR_TAG_VALUE_SHAREDREF); |
|
|
230 | encode_uint (enc, 0x00, SvUV (*svp)); |
|
|
231 | |
|
|
232 | return 1; |
|
|
233 | } |
|
|
234 | else |
|
|
235 | { |
|
|
236 | sv_setuv (*svp, enc->sharable_idx++); |
|
|
237 | encode_tag (enc, CBOR_TAG_VALUE_SHARABLE); |
|
|
238 | |
|
|
239 | return 0; |
|
|
240 | } |
|
|
241 | } |
|
|
242 | |
|
|
243 | ecb_inline int |
|
|
244 | encode_sharable (enc_t *enc, SV *sv) |
|
|
245 | { |
|
|
246 | if (ecb_expect_false (enc->cbor.flags & F_ALLOW_SHARING) |
|
|
247 | && ecb_expect_false (SvREFCNT (sv) > 1)) |
|
|
248 | return encode_sharable2 (enc, sv); |
|
|
249 | |
|
|
250 | return 0; |
|
|
251 | } |
|
|
252 | |
|
|
253 | static void encode_sv (enc_t *enc, SV *sv); |
219 | static void encode_sv (enc_t *enc, SV *sv); |
254 | |
220 | |
255 | static void |
221 | static void |
256 | encode_av (enc_t *enc, AV *av) |
222 | encode_av (enc_t *enc, AV *av) |
257 | { |
223 | { |
… | |
… | |
309 | |
275 | |
310 | // encode objects, arrays and special \0=false and \1=true values. |
276 | // encode objects, arrays and special \0=false and \1=true values. |
311 | static void |
277 | static void |
312 | encode_rv (enc_t *enc, SV *sv) |
278 | encode_rv (enc_t *enc, SV *sv) |
313 | { |
279 | { |
314 | svtype svt; |
|
|
315 | |
|
|
316 | SvGETMAGIC (sv); |
280 | SvGETMAGIC (sv); |
|
|
281 | |
|
|
282 | if (ecb_expect_false (enc->cbor.flags & F_ALLOW_SHARING) |
|
|
283 | && ecb_expect_false (SvREFCNT (sv) > 1)) |
|
|
284 | { |
|
|
285 | if (!enc->shareable) |
|
|
286 | enc->shareable = (HV *)sv_2mortal ((SV *)newHV ()); |
|
|
287 | |
|
|
288 | SV **svp = hv_fetch (enc->shareable, (char *)&sv, sizeof (sv), 1); |
|
|
289 | |
|
|
290 | if (SvOK (*svp)) |
|
|
291 | { |
|
|
292 | encode_tag (enc, CBOR_TAG_VALUE_SHAREDREF); |
|
|
293 | encode_uint (enc, 0x00, SvUV (*svp)); |
|
|
294 | return; |
|
|
295 | } |
|
|
296 | else |
|
|
297 | { |
|
|
298 | sv_setuv (*svp, enc->shareable_idx); |
|
|
299 | ++enc->shareable_idx; |
|
|
300 | encode_tag (enc, CBOR_TAG_VALUE_SHAREABLE); |
|
|
301 | } |
|
|
302 | } |
|
|
303 | |
317 | svt = SvTYPE (sv); |
304 | svtype svt = SvTYPE (sv); |
318 | |
|
|
319 | if (encode_sharable (enc, sv)) |
|
|
320 | return; |
|
|
321 | |
305 | |
322 | if (ecb_expect_false (SvOBJECT (sv))) |
306 | if (ecb_expect_false (SvOBJECT (sv))) |
323 | { |
307 | { |
324 | HV *boolean_stash = !CBOR_SLOW || types_boolean_stash |
308 | HV *boolean_stash = !CBOR_SLOW || types_boolean_stash |
325 | ? types_boolean_stash |
309 | ? types_boolean_stash |
… | |
… | |
452 | static void |
436 | static void |
453 | encode_sv (enc_t *enc, SV *sv) |
437 | encode_sv (enc_t *enc, SV *sv) |
454 | { |
438 | { |
455 | SvGETMAGIC (sv); |
439 | SvGETMAGIC (sv); |
456 | |
440 | |
457 | if (encode_sharable (enc, sv)) |
|
|
458 | return; |
|
|
459 | |
|
|
460 | if (SvPOKp (sv)) |
441 | if (SvPOKp (sv)) |
461 | { |
442 | { |
462 | STRLEN len; |
443 | STRLEN len; |
463 | char *str = SvPV (sv, len); |
444 | char *str = SvPV (sv, len); |
464 | encode_str (enc, SvUTF8 (sv), str, len); |
445 | encode_str (enc, SvUTF8 (sv), str, len); |
… | |
… | |
517 | U8 *end; // end of input string |
498 | U8 *end; // end of input string |
518 | const char *err; // parse error, if != 0 |
499 | const char *err; // parse error, if != 0 |
519 | CBOR cbor; |
500 | CBOR cbor; |
520 | U32 depth; // recursion depth |
501 | U32 depth; // recursion depth |
521 | U32 maxdepth; // recursion depth limit |
502 | U32 maxdepth; // recursion depth limit |
522 | AV *sharable; |
503 | AV *shareable; |
523 | } dec_t; |
504 | } dec_t; |
524 | |
505 | |
525 | #define ERR(reason) SB if (!dec->err) dec->err = reason; goto fail; SE |
506 | #define ERR(reason) SB if (!dec->err) dec->err = reason; goto fail; SE |
526 | |
507 | |
527 | #define WANT(len) if (ecb_expect_false (dec->cur + len > dec->end)) ERR ("unexpected end of CBOR data") |
508 | #define WANT(len) if (ecb_expect_false (dec->cur + len > dec->end)) ERR ("unexpected end of CBOR data") |
… | |
… | |
743 | } |
724 | } |
744 | |
725 | |
745 | static SV * |
726 | static SV * |
746 | decode_tagged (dec_t *dec) |
727 | decode_tagged (dec_t *dec) |
747 | { |
728 | { |
|
|
729 | SV *sv = 0; |
748 | UV tag = decode_uint (dec); |
730 | UV tag = decode_uint (dec); |
749 | SV *sv = decode_sv (dec); |
731 | |
|
|
732 | WANT (1); |
750 | |
733 | |
751 | switch (tag) |
734 | switch (tag) |
752 | { |
735 | { |
753 | case CBOR_TAG_MAGIC: |
736 | case CBOR_TAG_MAGIC: |
754 | return sv; |
737 | return decode_sv (dec); |
755 | |
738 | |
756 | case CBOR_TAG_INDIRECTION: |
739 | case CBOR_TAG_INDIRECTION: |
757 | return newRV_noinc (sv); |
740 | return newRV_noinc (decode_sv (dec)); |
758 | |
741 | |
759 | case CBOR_TAG_VALUE_SHARABLE: |
742 | case CBOR_TAG_VALUE_SHAREABLE: |
|
|
743 | { |
760 | if (ecb_expect_false (!dec->sharable)) |
744 | if (ecb_expect_false (!dec->shareable)) |
761 | dec->sharable = (AV *)sv_2mortal ((SV *)newAV ()); |
745 | dec->shareable = (AV *)sv_2mortal ((SV *)newAV ()); |
762 | |
746 | |
|
|
747 | sv = newSV (0); |
763 | av_push (dec->sharable, SvREFCNT_inc_NN (sv)); |
748 | av_push (dec->shareable, SvREFCNT_inc_NN (sv)); |
|
|
749 | |
|
|
750 | SV *osv = decode_sv (dec); |
|
|
751 | sv_setsv (sv, osv); |
|
|
752 | SvREFCNT_dec_NN (osv); |
|
|
753 | } |
764 | |
754 | |
765 | return sv; |
755 | return sv; |
766 | |
756 | |
767 | case CBOR_TAG_VALUE_SHAREDREF: |
757 | case CBOR_TAG_VALUE_SHAREDREF: |
768 | { |
758 | { |
769 | // TODO: should verify that the sv atcually was a CBOR unsigned integer |
759 | if ((*dec->cur >> 5) != 0) |
770 | UV idx = SvUV (sv); |
760 | ERR ("corrupted CBOR data (sharedref index not an unsigned integer)"); |
771 | |
761 | |
|
|
762 | UV idx = decode_uint (dec); |
|
|
763 | |
772 | if (!dec->sharable || idx > AvFILLp (dec->sharable)) |
764 | if (!dec->shareable || idx > AvFILLp (dec->shareable)) |
773 | ERR ("corrupted CBOR data (sharedref index out of bounds)"); |
765 | ERR ("corrupted CBOR data (sharedref index out of bounds)"); |
774 | |
766 | |
775 | SvREFCNT_dec (sv); |
|
|
776 | |
|
|
777 | return SvREFCNT_inc_NN (AvARRAY (dec->sharable)[idx]); |
767 | return SvREFCNT_inc_NN (AvARRAY (dec->shareable)[idx]); |
778 | } |
768 | } |
779 | |
769 | |
780 | case CBOR_TAG_PERL_OBJECT: |
770 | case CBOR_TAG_PERL_OBJECT: |
781 | { |
771 | { |
|
|
772 | sv = decode_sv (dec); |
|
|
773 | |
782 | if (!SvROK (sv) || SvTYPE (SvRV (sv)) != SVt_PVAV) |
774 | if (!SvROK (sv) || SvTYPE (SvRV (sv)) != SVt_PVAV) |
783 | ERR ("corrupted CBOR data (non-array perl object)"); |
775 | ERR ("corrupted CBOR data (non-array perl object)"); |
784 | |
776 | |
785 | AV *av = (AV *)SvRV (sv); |
777 | AV *av = (AV *)SvRV (sv); |
786 | int len = av_len (av) + 1; |
778 | int len = av_len (av) + 1; |
… | |
… | |
827 | return sv; |
819 | return sv; |
828 | } |
820 | } |
829 | |
821 | |
830 | default: |
822 | default: |
831 | { |
823 | { |
|
|
824 | sv = decode_sv (dec); |
|
|
825 | |
832 | AV *av = newAV (); |
826 | AV *av = newAV (); |
833 | av_push (av, newSVuv (tag)); |
827 | av_push (av, newSVuv (tag)); |
834 | av_push (av, sv); |
828 | av_push (av, sv); |
835 | |
829 | |
836 | HV *tagged_stash = !CBOR_SLOW || cbor_tagged_stash |
830 | HV *tagged_stash = !CBOR_SLOW || cbor_tagged_stash |