… | |
… | |
8 | #include <stdio.h> |
8 | #include <stdio.h> |
9 | #include <limits.h> |
9 | #include <limits.h> |
10 | #include <float.h> |
10 | #include <float.h> |
11 | |
11 | |
12 | #include "ecb.h" |
12 | #include "ecb.h" |
|
|
13 | |
|
|
14 | // known tags |
|
|
15 | enum cbor_tag |
|
|
16 | { |
|
|
17 | // inofficial extensions (pending iana registration) |
|
|
18 | CBOR_TAG_PERL_OBJECT = 256, |
|
|
19 | CBOR_TAG_GENERIC_OBJECT = 257, |
|
|
20 | |
|
|
21 | // rfc7049 |
|
|
22 | CBOR_TAG_DATETIME = 0, // rfc4287, utf-8 |
|
|
23 | CBOR_TAG_TIMESTAMP = 1, // unix timestamp, any |
|
|
24 | CBOR_TAG_POS_BIGNUM = 2, // byte string |
|
|
25 | CBOR_TAG_NEG_BIGNUM = 3, // byte string |
|
|
26 | CBOR_TAG_DECIMAL = 4, // decimal fraction, array |
|
|
27 | CBOR_TAG_BIGFLOAT = 5, // array |
|
|
28 | |
|
|
29 | CBOR_TAG_CONV_B64U = 21, // base64url, any |
|
|
30 | CBOR_TAG_CONV_B64 = 22, // base64, any |
|
|
31 | CBOR_TAG_CONV_HEX = 23, // base16, any |
|
|
32 | CBOR_TAG_CBOR = 24, // embedded cbor, byte string |
|
|
33 | |
|
|
34 | CBOR_TAG_URI = 32, // URI rfc3986, utf-8 |
|
|
35 | CBOR_TAG_B64U = 33, // base64url rfc4648, utf-8 |
|
|
36 | CBOR_TAG_B64 = 34, // base6 rfc46484, utf-8 |
|
|
37 | CBOR_TAG_REGEX = 35, // regex pcre/ecma262, utf-8 |
|
|
38 | CBOR_TAG_MIME = 36, // mime message rfc2045, utf-8 |
|
|
39 | |
|
|
40 | CBOR_TAG_MAGIC = 55799 // self-describe cbor |
|
|
41 | }; |
13 | |
42 | |
14 | #define F_SHRINK 0x00000200UL |
43 | #define F_SHRINK 0x00000200UL |
15 | #define F_ALLOW_UNKNOWN 0x00002000UL |
44 | #define F_ALLOW_UNKNOWN 0x00002000UL |
16 | |
45 | |
17 | #define INIT_SIZE 32 // initial scalar size to be allocated |
46 | #define INIT_SIZE 32 // initial scalar size to be allocated |
… | |
… | |
31 | #else |
60 | #else |
32 | # define CBOR_SLOW 0 |
61 | # define CBOR_SLOW 0 |
33 | # define CBOR_STASH cbor_stash |
62 | # define CBOR_STASH cbor_stash |
34 | #endif |
63 | #endif |
35 | |
64 | |
36 | static HV *cbor_stash, *cbor_boolean_stash, *cbor_tagged_stash; // CBOR::XS:: |
65 | static HV *cbor_stash, *types_boolean_stash, *types_error_stash, *cbor_tagged_stash; // CBOR::XS:: |
37 | static SV *cbor_true, *cbor_false; |
66 | static SV *types_true, *types_false, *types_error; |
38 | |
67 | |
39 | typedef struct { |
68 | typedef struct { |
40 | U32 flags; |
69 | U32 flags; |
41 | U32 max_depth; |
70 | U32 max_depth; |
42 | STRLEN max_size; |
71 | STRLEN max_size; |
… | |
… | |
230 | SvGETMAGIC (sv); |
259 | SvGETMAGIC (sv); |
231 | svt = SvTYPE (sv); |
260 | svt = SvTYPE (sv); |
232 | |
261 | |
233 | if (ecb_expect_false (SvOBJECT (sv))) |
262 | if (ecb_expect_false (SvOBJECT (sv))) |
234 | { |
263 | { |
235 | HV *boolean_stash = !CBOR_SLOW || cbor_boolean_stash |
264 | HV *boolean_stash = !CBOR_SLOW || types_boolean_stash |
236 | ? cbor_boolean_stash |
265 | ? types_boolean_stash |
237 | : gv_stashpv ("CBOR::XS::Boolean", 1); |
266 | : gv_stashpv ("Types::Serialiser::Boolean", 1); |
|
|
267 | HV *error_stash = !CBOR_SLOW || types_error_stash |
|
|
268 | ? types_error_stash |
|
|
269 | : gv_stashpv ("Types::Serialiser::Error", 1); |
238 | HV *tagged_stash = !CBOR_SLOW || cbor_tagged_stash |
270 | HV *tagged_stash = !CBOR_SLOW || cbor_tagged_stash |
239 | ? cbor_tagged_stash |
271 | ? cbor_tagged_stash |
240 | : gv_stashpv ("CBOR::XS::Tagged" , 1); |
272 | : gv_stashpv ("CBOR::XS::Tagged" , 1); |
241 | |
273 | |
242 | if (SvSTASH (sv) == boolean_stash) |
274 | if (SvSTASH (sv) == boolean_stash) |
243 | encode_ch (enc, SvIV (sv) ? 0xe0 | 21 : 0xe0 | 20); |
275 | encode_ch (enc, SvIV (sv) ? 0xe0 | 21 : 0xe0 | 20); |
|
|
276 | else if (SvSTASH (sv) == error_stash) |
|
|
277 | encode_ch (enc, 0xe0 | 23); |
244 | else if (SvSTASH (sv) == tagged_stash) |
278 | else if (SvSTASH (sv) == tagged_stash) |
245 | { |
279 | { |
246 | if (svt != SVt_PVAV) |
280 | if (svt != SVt_PVAV) |
247 | croak ("encountered CBOR::XS::Tagged object that isn't an array"); |
281 | croak ("encountered CBOR::XS::Tagged object that isn't an array"); |
248 | |
282 | |
… | |
… | |
612 | decode_tagged (dec_t *dec) |
646 | decode_tagged (dec_t *dec) |
613 | { |
647 | { |
614 | UV tag = decode_uint (dec); |
648 | UV tag = decode_uint (dec); |
615 | SV *sv = decode_sv (dec); |
649 | SV *sv = decode_sv (dec); |
616 | |
650 | |
617 | if (tag == 55799) // 2.4.5 Self-Describe CBOR |
651 | if (tag == CBOR_TAG_MAGIC) |
618 | return sv; |
652 | return sv; |
|
|
653 | |
|
|
654 | if (tag == CBOR_TAG_PERL_OBJECT) |
|
|
655 | { |
|
|
656 | if (!SvROK (sv) || SvTYPE (SvRV (sv)) != SVt_PVAV) |
|
|
657 | ERR ("corrupted CBOR data (non-array perl object)"); |
|
|
658 | |
|
|
659 | // TODO |
|
|
660 | } |
619 | |
661 | |
620 | AV *av = newAV (); |
662 | AV *av = newAV (); |
621 | av_push (av, newSVuv (tag)); |
663 | av_push (av, newSVuv (tag)); |
622 | av_push (av, sv); |
664 | av_push (av, sv); |
623 | return newRV_noinc ((SV *)av); |
665 | |
|
|
666 | HV *tagged_stash = !CBOR_SLOW || cbor_tagged_stash |
|
|
667 | ? cbor_tagged_stash |
|
|
668 | : gv_stashpv ("CBOR::XS::Tagged" , 1); |
|
|
669 | |
|
|
670 | return sv_bless (newRV_noinc ((SV *)av), tagged_stash); |
|
|
671 | |
|
|
672 | fail: |
|
|
673 | SvREFCNT_dec (sv); |
|
|
674 | return &PL_sv_undef; |
624 | } |
675 | } |
625 | |
676 | |
626 | static SV * |
677 | static SV * |
627 | decode_sv (dec_t *dec) |
678 | decode_sv (dec_t *dec) |
628 | { |
679 | { |
… | |
… | |
647 | case 7: // misc |
698 | case 7: // misc |
648 | switch (*dec->cur++ & 31) |
699 | switch (*dec->cur++ & 31) |
649 | { |
700 | { |
650 | case 20: |
701 | case 20: |
651 | #if CBOR_SLOW |
702 | #if CBOR_SLOW |
652 | cbor_false = get_bool ("CBOR::XS::false"); |
703 | types_false = get_bool ("Types::Serialiser::false"); |
653 | #endif |
704 | #endif |
654 | return newSVsv (cbor_false); |
705 | return newSVsv (types_false); |
655 | case 21: |
706 | case 21: |
656 | #if CBOR_SLOW |
707 | #if CBOR_SLOW |
657 | cbor_true = get_bool ("CBOR::XS::true"); |
708 | types_true = get_bool ("Types::Serialiser::true"); |
658 | #endif |
709 | #endif |
659 | return newSVsv (cbor_true); |
710 | return newSVsv (types_true); |
660 | case 22: |
711 | case 22: |
661 | return newSVsv (&PL_sv_undef); |
712 | return newSVsv (&PL_sv_undef); |
|
|
713 | case 23: |
|
|
714 | #if CBOR_SLOW |
|
|
715 | types_error = get_bool ("Types::Serialiser::error"); |
|
|
716 | #endif |
|
|
717 | return newSVsv (types_error); |
662 | |
718 | |
663 | case 25: |
719 | case 25: |
664 | { |
720 | { |
665 | WANT (2); |
721 | WANT (2); |
666 | |
722 | |
… | |
… | |
782 | MODULE = CBOR::XS PACKAGE = CBOR::XS |
838 | MODULE = CBOR::XS PACKAGE = CBOR::XS |
783 | |
839 | |
784 | BOOT: |
840 | BOOT: |
785 | { |
841 | { |
786 | cbor_stash = gv_stashpv ("CBOR::XS" , 1); |
842 | cbor_stash = gv_stashpv ("CBOR::XS" , 1); |
787 | cbor_boolean_stash = gv_stashpv ("CBOR::XS::Boolean", 1); |
|
|
788 | cbor_tagged_stash = gv_stashpv ("CBOR::XS::Tagged" , 1); |
843 | cbor_tagged_stash = gv_stashpv ("CBOR::XS::Tagged" , 1); |
789 | |
844 | |
790 | cbor_true = get_bool ("CBOR::XS::true"); |
845 | types_boolean_stash = gv_stashpv ("Types::Serialiser::Boolean", 1); |
791 | cbor_false = get_bool ("CBOR::XS::false"); |
846 | types_error_stash = gv_stashpv ("Types::Serialiser::Error" , 1); |
|
|
847 | |
|
|
848 | types_true = get_bool ("Types::Serialiser::true" ); |
|
|
849 | types_false = get_bool ("Types::Serialiser::false"); |
|
|
850 | types_error = get_bool ("Types::Serialiser::error"); |
792 | } |
851 | } |
793 | |
852 | |
794 | PROTOTYPES: DISABLE |
853 | PROTOTYPES: DISABLE |
795 | |
854 | |
796 | void CLONE (...) |
855 | void CLONE (...) |
797 | CODE: |
856 | CODE: |
798 | cbor_stash = 0; |
857 | cbor_stash = 0; |
799 | cbor_boolean_stash = 0; |
|
|
800 | cbor_tagged_stash = 0; |
858 | cbor_tagged_stash = 0; |
|
|
859 | types_error_stash = 0; |
|
|
860 | types_boolean_stash = 0; |
801 | |
861 | |
802 | void new (char *klass) |
862 | void new (char *klass) |
803 | PPCODE: |
863 | PPCODE: |
804 | { |
864 | { |
805 | SV *pv = NEWSV (0, sizeof (CBOR)); |
865 | SV *pv = NEWSV (0, sizeof (CBOR)); |