… | |
… | |
683 | // encode objects, arrays and special \0=false and \1=true values. |
683 | // encode objects, arrays and special \0=false and \1=true values. |
684 | static void |
684 | static void |
685 | encode_rv (enc_t *enc, SV *sv) |
685 | encode_rv (enc_t *enc, SV *sv) |
686 | { |
686 | { |
687 | svtype svt; |
687 | svtype svt; |
|
|
688 | GV *method; |
688 | |
689 | |
689 | SvGETMAGIC (sv); |
690 | SvGETMAGIC (sv); |
690 | svt = SvTYPE (sv); |
691 | svt = SvTYPE (sv); |
691 | |
692 | |
692 | if (expect_false (SvOBJECT (sv))) |
693 | if (expect_false (SvOBJECT (sv))) |
… | |
… | |
701 | if (SvIV (sv)) |
702 | if (SvIV (sv)) |
702 | encode_str (enc, "true", 4, 0); |
703 | encode_str (enc, "true", 4, 0); |
703 | else |
704 | else |
704 | encode_str (enc, "false", 5, 0); |
705 | encode_str (enc, "false", 5, 0); |
705 | } |
706 | } |
706 | else if (enc->json.flags & F_CONV_BLESSED) |
707 | else if ((enc->json.flags & F_ALLOW_TAGS) && (method = gv_fetchmethod_autoload (stash, "FREEZE", 0))) |
707 | { |
708 | { |
708 | GV *to_json = gv_fetchmethod_autoload (stash, "TO_JSON", 0); |
709 | int count; |
|
|
710 | dSP; |
709 | |
711 | |
|
|
712 | ENTER; SAVETMPS; PUSHMARK (SP); |
|
|
713 | EXTEND (SP, 2); |
|
|
714 | // we re-bless the reference to get overload and other niceties right |
|
|
715 | PUSHs (sv_bless (sv_2mortal (newRV_inc (sv)), stash)); |
710 | if (to_json) |
716 | PUSHs (sv_json); |
|
|
717 | |
|
|
718 | PUTBACK; |
|
|
719 | count = call_sv ((SV *)GvCV (method), G_ARRAY); |
|
|
720 | SPAGAIN; |
|
|
721 | |
|
|
722 | // catch this surprisingly common error |
|
|
723 | if (SvROK (TOPs) && SvRV (TOPs) == sv) |
|
|
724 | croak ("%s::TO_JSON method returned same object as was passed instead of a new one", HvNAME (SvSTASH (sv))); |
|
|
725 | |
|
|
726 | encode_ch (enc, '('); |
|
|
727 | encode_ch (enc, '"'); |
|
|
728 | encode_str (enc, HvNAME (stash), HvNAMELEN (stash), HvNAMEUTF8 (stash)); |
|
|
729 | encode_ch (enc, '"'); |
|
|
730 | encode_ch (enc, ')'); |
|
|
731 | encode_ch (enc, '['); |
|
|
732 | |
|
|
733 | while (count) |
711 | { |
734 | { |
712 | dSP; |
735 | encode_sv (enc, SP[1 - count--]); |
713 | |
736 | |
714 | ENTER; SAVETMPS; PUSHMARK (SP); |
737 | if (count) |
715 | // we re-bless the reference to get overload and other niceties right |
|
|
716 | XPUSHs (sv_bless (sv_2mortal (newRV_inc (sv)), stash)); |
|
|
717 | |
|
|
718 | // calling with G_SCALAR ensures that we always get a 1 return value |
|
|
719 | PUTBACK; |
|
|
720 | call_sv ((SV *)GvCV (to_json), G_SCALAR); |
|
|
721 | SPAGAIN; |
|
|
722 | |
|
|
723 | // catch this surprisingly common error |
|
|
724 | if (SvROK (TOPs) && SvRV (TOPs) == sv) |
|
|
725 | croak ("%s::TO_JSON method returned same object as was passed instead of a new one", HvNAME (SvSTASH (sv))); |
|
|
726 | |
|
|
727 | sv = POPs; |
|
|
728 | PUTBACK; |
|
|
729 | |
|
|
730 | encode_sv (enc, sv); |
738 | encode_ch (enc, ','); |
731 | |
|
|
732 | FREETMPS; LEAVE; |
|
|
733 | } |
739 | } |
734 | else if (enc->json.flags & F_ALLOW_BLESSED) |
740 | |
735 | encode_str (enc, "null", 4, 0); |
741 | encode_ch (enc, ']'); |
736 | else |
742 | |
737 | croak ("encountered object '%s' when conv_object is enabled, but TO_JSON is missing and allow_blessed disabled", |
743 | PUTBACK; |
738 | SvPV_nolen (sv_2mortal (newRV_inc (sv)))); |
744 | |
|
|
745 | FREETMPS; LEAVE; |
739 | } |
746 | } |
740 | else if (enc->json.flags & F_ALLOW_TAGS) |
747 | else if ((enc->json.flags & F_CONV_BLESSED) && (method = gv_fetchmethod_autoload (stash, "TO_JSON", 0))) |
741 | { |
748 | { |
742 | GV *method = gv_fetchmethod_autoload (stash, "FREEZE", 0); |
|
|
743 | |
|
|
744 | if (method) |
|
|
745 | { |
|
|
746 | int count; |
|
|
747 | dSP; |
749 | dSP; |
748 | |
750 | |
749 | ENTER; SAVETMPS; PUSHMARK (SP); |
751 | ENTER; SAVETMPS; PUSHMARK (SP); |
750 | EXTEND (SP, 2); |
|
|
751 | // we re-bless the reference to get overload and other niceties right |
752 | // we re-bless the reference to get overload and other niceties right |
752 | PUSHs (sv_bless (sv_2mortal (newRV_inc (sv)), stash)); |
753 | XPUSHs (sv_bless (sv_2mortal (newRV_inc (sv)), stash)); |
753 | PUSHs (sv_json); |
|
|
754 | |
754 | |
|
|
755 | // calling with G_SCALAR ensures that we always get a 1 return value |
755 | PUTBACK; |
756 | PUTBACK; |
756 | count = call_sv ((SV *)GvCV (method), G_ARRAY); |
757 | call_sv ((SV *)GvCV (method), G_SCALAR); |
757 | SPAGAIN; |
758 | SPAGAIN; |
758 | |
759 | |
759 | // catch this surprisingly common error |
760 | // catch this surprisingly common error |
760 | if (SvROK (TOPs) && SvRV (TOPs) == sv) |
761 | if (SvROK (TOPs) && SvRV (TOPs) == sv) |
761 | croak ("%s::TO_JSON method returned same object as was passed instead of a new one", HvNAME (SvSTASH (sv))); |
762 | croak ("%s::TO_JSON method returned same object as was passed instead of a new one", HvNAME (SvSTASH (sv))); |
762 | |
763 | |
763 | encode_ch (enc, '('); |
764 | sv = POPs; |
764 | encode_ch (enc, '"'); |
|
|
765 | encode_str (enc, HvNAME (stash), HvNAMELEN (stash), HvNAMEUTF8 (stash)); |
|
|
766 | encode_ch (enc, '"'); |
|
|
767 | encode_ch (enc, ')'); |
|
|
768 | encode_ch (enc, '['); |
|
|
769 | |
|
|
770 | while (count) |
|
|
771 | { |
|
|
772 | encode_sv (enc, SP[1 - count--]); |
|
|
773 | |
|
|
774 | if (count) |
|
|
775 | encode_ch (enc, ','); |
|
|
776 | } |
|
|
777 | |
|
|
778 | encode_ch (enc, ']'); |
|
|
779 | |
|
|
780 | PUTBACK; |
765 | PUTBACK; |
781 | |
766 | |
|
|
767 | encode_sv (enc, sv); |
|
|
768 | |
782 | FREETMPS; LEAVE; |
769 | FREETMPS; LEAVE; |
783 | } |
|
|
784 | else if (enc->json.flags & F_ALLOW_BLESSED) |
|
|
785 | encode_str (enc, "null", 4, 0); |
|
|
786 | else |
|
|
787 | croak ("encountered object '%s' when allow_tags is enabled, but FREEZE is missing and allow_blessed disabled", |
|
|
788 | SvPV_nolen (sv_2mortal (newRV_inc (sv)))); |
|
|
789 | } |
770 | } |
790 | else if (enc->json.flags & F_ALLOW_BLESSED) |
771 | else if (enc->json.flags & F_ALLOW_BLESSED) |
791 | encode_str (enc, "null", 4, 0); |
772 | encode_str (enc, "null", 4, 0); |
792 | else |
773 | else |
793 | croak ("encountered object '%s', but neither allow_blessed, convert_blessed nor allow_tags settings are enabled", |
774 | croak ("encountered object '%s', but neither allow_blessed, convert_blessed nor allow_tags settings are enabled (or TO_JSON/FREEZE method missing)", |
794 | SvPV_nolen (sv_2mortal (newRV_inc (sv)))); |
775 | SvPV_nolen (sv_2mortal (newRV_inc (sv)))); |
795 | } |
776 | } |
796 | else if (svt == SVt_PVHV) |
777 | else if (svt == SVt_PVHV) |
797 | encode_hv (enc, (HV *)sv); |
778 | encode_hv (enc, (HV *)sv); |
798 | else if (svt == SVt_PVAV) |
779 | else if (svt == SVt_PVAV) |