Cpanel-JSON-XS
view release on metacpan or search on metacpan
case '#':
self->incr_mode = INCR_M_C1;
goto incr_m_c;
}
}
}
}
interrupt:
self->incr_pos = p - SvPVX (self->incr_text);
/*printf ("interrupt<%.*s>\n", self->incr_pos, SvPVX(self->incr_text));//D */
/*printf ("return pos %d mode %d nest %d\n", self->incr_pos, self->incr_mode, self->incr_nest);//D */
}
/*/////////////////////////////////////////////////////////////////////////// */
/* XS interface functions */
MODULE = Cpanel::JSON::XS PACKAGE = Cpanel::JSON::XS
#if PERL_VERSION > 7
# define NODEBUG_ON \
CvNODEBUG_on (get_cv ("Cpanel::JSON::XS::incr_text", 0));
#else
# define NODEBUG_ON
#endif
BOOT:
{
HV *stash;
MY_CXT_INIT;
init_MY_CXT(aTHX_ &MY_CXT);
stash = gv_stashpvs(JSON_TYPE_CLASS, GV_ADD);
newCONSTSUB(stash, "JSON_TYPE_BOOL", newSViv(JSON_TYPE_BOOL));
newCONSTSUB(stash, "JSON_TYPE_INT", newSViv(JSON_TYPE_INT));
newCONSTSUB(stash, "JSON_TYPE_FLOAT", newSViv(JSON_TYPE_FLOAT));
newCONSTSUB(stash, "JSON_TYPE_STRING", newSViv(JSON_TYPE_STRING));
newCONSTSUB(stash, "JSON_TYPE_NULL", newSViv(JSON_TYPE_NULL));
newCONSTSUB(stash, "JSON_TYPE_INT_OR_NULL", newSViv(JSON_TYPE_INT | JSON_TYPE_CAN_BE_NULL));
newCONSTSUB(stash, "JSON_TYPE_BOOL_OR_NULL", newSViv(JSON_TYPE_BOOL | JSON_TYPE_CAN_BE_NULL));
newCONSTSUB(stash, "JSON_TYPE_FLOAT_OR_NULL", newSViv(JSON_TYPE_FLOAT | JSON_TYPE_CAN_BE_NULL));
newCONSTSUB(stash, "JSON_TYPE_STRING_OR_NULL", newSViv(JSON_TYPE_STRING | JSON_TYPE_CAN_BE_NULL));
newCONSTSUB(stash, "JSON_TYPE_CAN_BE_NULL", newSViv(JSON_TYPE_CAN_BE_NULL));
newCONSTSUB(stash, "JSON_TYPE_ARRAYOF_CLASS", newSVpvs(JSON_TYPE_ARRAYOF_CLASS));
newCONSTSUB(stash, "JSON_TYPE_HASHOF_CLASS", newSVpvs(JSON_TYPE_HASHOF_CLASS));
newCONSTSUB(stash, "JSON_TYPE_ANYOF_CLASS", newSVpvs(JSON_TYPE_ANYOF_CLASS));
NODEBUG_ON; /* the debugger completely breaks lvalue subs */
}
PROTOTYPES: DISABLE
#_if PERL_IMPLICIT_CONTEXT for embedding, but no ithreads, then CLONE is never
# called
#ifdef USE_ITHREADS
void CLONE (...)
PPCODE:
MY_CXT_CLONE; /* possible declaration */
init_MY_CXT(aTHX_ &MY_CXT);
/* skip implicit PUTBACK, returning @_ to caller, more efficient*/
return;
#endif
void END(...)
PREINIT:
dMY_CXT;
SV * sv;
PPCODE:
sv = MY_CXT.sv_json;
MY_CXT.sv_json = NULL;
if (sv && SvOK (sv))
SvREFCNT_dec_NN (sv);
/* skip implicit PUTBACK, returning @_ to caller, more efficient*/
return;
void new (char *klass)
PREINIT:
HV *stash;
PPCODE:
dMY_CXT;
SV *pv = NEWSV (0, sizeof (JSON));
SvPOK_only (pv);
json_init ((JSON *)SvPVX (pv));
if (SvROK (ST(0))) {
/* called as $obj->new â extract real class name from the object */
stash = SvSTASH (SvRV (ST(0)));
if (!stash)
croak ("Cannot create a %s object from an unblessed reference", klass);
} else {
stash = strEQc (klass, "Cpanel::JSON::XS") ? JSON_STASH : gv_stashpv (klass, 1);
}
XPUSHs (sv_2mortal (sv_bless (
newRV_noinc (pv), stash
)));
void ascii (JSON *self, int enable = 1)
ALIAS:
ascii = F_ASCII
latin1 = F_LATIN1
binary = F_BINARY
utf8 = F_UTF8
indent = F_INDENT
canonical = F_CANONICAL
space_before = F_SPACE_BEFORE
space_after = F_SPACE_AFTER
pretty = F_PRETTY
allow_nonref = F_ALLOW_NONREF
shrink = F_SHRINK
allow_blessed = F_ALLOW_BLESSED
convert_blessed = F_CONV_BLESSED
relaxed = SET_RELAXED
allow_unknown = F_ALLOW_UNKNOWN
allow_tags = F_ALLOW_TAGS
allow_barekey = F_ALLOW_BAREKEY
allow_singlequote = F_ALLOW_SQUOTE
allow_bignum = F_ALLOW_BIGNUM
escape_slash = F_ESCAPE_SLASH
allow_stringify = F_ALLOW_STRINGIFY
unblessed_bool = F_UNBLESSED_BOOL
allow_dupkeys = F_ALLOW_DUPKEYS
require_types = F_REQUIRE_TYPES
type_all_string = F_TYPE_ALL_STRING
dupkeys_as_arrayref = F_DUPKEYS_AS_AREF
PPCODE:
if (enable)
self->flags |= ix;
else
self->flags &= ~ix;
# Turning on DUPKEYS_AS_AREF also turns on ALLOW_DUPKEYS
# But turning off DUPKEYS_AS_AREF does not
if (ix == F_DUPKEYS_AS_AREF && enable != 0)
self->flags |= F_ALLOW_DUPKEYS;
XPUSHs (ST (0));
void get_ascii (JSON *self)
ALIAS:
get_ascii = F_ASCII
get_latin1 = F_LATIN1
get_binary = F_BINARY
get_utf8 = F_UTF8
get_indent = F_INDENT
get_canonical = F_CANONICAL
get_space_before = F_SPACE_BEFORE
get_space_after = F_SPACE_AFTER
get_allow_nonref = F_ALLOW_NONREF
get_shrink = F_SHRINK
get_allow_blessed = F_ALLOW_BLESSED
get_convert_blessed = F_CONV_BLESSED
get_relaxed = F_RELAXED
get_allow_unknown = F_ALLOW_UNKNOWN
get_allow_tags = F_ALLOW_TAGS
get_allow_barekey = F_ALLOW_BAREKEY
get_allow_singlequote = F_ALLOW_SQUOTE
get_allow_bignum = F_ALLOW_BIGNUM
get_escape_slash = F_ESCAPE_SLASH
get_allow_stringify = F_ALLOW_STRINGIFY
get_unblessed_bool = F_UNBLESSED_BOOL
get_allow_dupkeys = F_ALLOW_DUPKEYS
get_require_types = F_REQUIRE_TYPES
get_type_all_string = F_TYPE_ALL_STRING
get_dupkeys_as_arrayref = F_DUPKEYS_AS_AREF
PPCODE:
XPUSHs (boolSV (self->flags & ix));
void indent_length (JSON *self, int val = INDENT_STEP)
PPCODE:
if (0 <= val && val <= 15) {
self->indent_length = val;
} else {
warn("The acceptable range of indent_length() is 0 to 15.");
}
XPUSHs (ST (0));
U32 get_indent_length (JSON *self)
CODE:
RETVAL = self->indent_length;
OUTPUT:
RETVAL
void max_depth (JSON *self, U32 max_depth = 0x80000000UL)
PPCODE:
self->max_depth = max_depth;
XPUSHs (ST (0));
U32 get_max_depth (JSON *self)
CODE:
RETVAL = self->max_depth;
OUTPUT:
RETVAL
void max_size (JSON *self, U32 max_size = 0)
PPCODE:
self->max_size = max_size;
XPUSHs (ST (0));
int get_max_size (JSON *self)
CODE:
RETVAL = self->max_size;
OUTPUT:
RETVAL
void stringify_infnan (JSON *self, IV infnan_mode = 1)
PPCODE:
if (infnan_mode > 3 || infnan_mode < 0) {
croak ("invalid stringify_infnan mode %d. Must be 0, 1, 2 or 3", (int)infnan_mode);
}
self->infnan_mode = (unsigned char)infnan_mode;
XPUSHs (ST (0));
int get_stringify_infnan (JSON *self)
CODE:
RETVAL = (int)self->infnan_mode;
OUTPUT:
RETVAL
void sort_by (JSON *self, SV* cb = &PL_sv_yes)
PPCODE:
{
SvREFCNT_dec (self->cb_sort_by);
self->cb_sort_by = SvOK (cb) ? newSVsv (cb) : 0;
if (self->cb_sort_by)
self->flags |= F_CANONICAL;
XPUSHs (ST (0));
}
void filter_json_object (JSON *self, SV *cb = &PL_sv_undef)
PPCODE:
{
SvREFCNT_dec (self->cb_object);
self->cb_object = SvOK (cb) ? newSVsv (cb) : 0;
XPUSHs (ST (0));
}
void filter_json_single_key_object (JSON *self, SV *key, SV *cb = &PL_sv_undef)
PPCODE:
{
if (!self->cb_sk_object)
self->cb_sk_object = newHV ();
if (SvOK (cb))
(void)hv_store_ent (self->cb_sk_object, key, newSVsv (cb), 0);
else
{
(void)hv_delete_ent (self->cb_sk_object, key, G_DISCARD, 0);
if (!HvKEYS (self->cb_sk_object))
{
SvREFCNT_dec (self->cb_sk_object);
self->cb_sk_object = 0;
}
}
XPUSHs (ST (0));
}
void encode (JSON *self, SV *scalar, SV *typesv = &PL_sv_undef)
PPCODE:
PUTBACK; scalar = encode_json (aTHX_ scalar, self, typesv); SPAGAIN;
XPUSHs (scalar);
void decode (JSON *self, SV *jsonstr, SV *typesv = NULL)
PPCODE:
PUTBACK; jsonstr = decode_json (aTHX_ jsonstr, self, 0, typesv); SPAGAIN;
XPUSHs (jsonstr);
void decode_prefix (JSON *self, SV *jsonstr, SV *typesv = NULL)
PPCODE:
{
SV *sv;
STRLEN offset;
PUTBACK; sv = decode_json (aTHX_ jsonstr, self, &offset, typesv); SPAGAIN;
EXTEND (SP, 2);
PUSHs (sv);
PUSHs (sv_2mortal (newSVuv (ptr_to_index (aTHX_ jsonstr, offset))));
}
void incr_parse (JSON *self, SV *jsonstr = 0)
PPCODE:
{
if (!self->incr_text)
self->incr_text = newSVpvn ("", 0);
/* if utf8-ness doesn't match the decoder, need to upgrade/downgrade */
if (!DECODE_WANTS_OCTETS (self) == !SvUTF8 (self->incr_text)) {
if (DECODE_WANTS_OCTETS (self))
{
if (self->incr_pos)
self->incr_pos = utf8_length ((U8 *)SvPVX (self->incr_text),
(U8 *)SvPVX (self->incr_text) + self->incr_pos);
sv_utf8_downgrade (self->incr_text, 0);
}
else
{
sv_utf8_upgrade (self->incr_text);
if (self->incr_pos)
self->incr_pos = utf8_hop ((U8 *)SvPVX (self->incr_text), self->incr_pos)
- (U8 *)SvPVX (self->incr_text);
}
}
/* append data, if any */
if (jsonstr)
{
/* make sure both strings have same encoding */
if (SvUTF8 (jsonstr) != SvUTF8 (self->incr_text)) {
if (SvUTF8 (jsonstr))
sv_utf8_downgrade (jsonstr, 0);
else
sv_utf8_upgrade (jsonstr);
}
/* and then just blindly append */
{
STRLEN len;
const char *str = SvPV (jsonstr, len);
STRLEN cur = SvCUR (self->incr_text);
if (SvLEN (self->incr_text) <= cur + len)
SvGROW (self->incr_text, cur + (len < (cur >> 2) ? cur >> 2 : len) + 1);
Move (str, SvEND (self->incr_text), len, char);
SvCUR_set (self->incr_text, SvCUR (self->incr_text) + len);
*SvEND (self->incr_text) = 0; /* this should basically be a nop, too, but make sure it's there */
}
}
if (GIMME_V != G_VOID)
do
{
SV *sv;
STRLEN offset;
char *endp;
if (!INCR_DONE (self))
{
incr_parse (self);
if (UNLIKELY(self->incr_pos > self->max_size && self->max_size))
croak ("attempted decode of JSON text of %lu bytes size, but max_size is set to %lu",
(unsigned long)self->incr_pos, (unsigned long)self->max_size);
if (!INCR_DONE (self))
{
/* as an optimisation, do not accumulate white space in the incr buffer */
if (self->incr_mode == INCR_M_WS && self->incr_pos)
{
self->incr_pos = 0;
SvCUR_set (self->incr_text, 0);
}
break;
}
}
PUTBACK; sv = decode_json (aTHX_ self->incr_text, self, &offset, NULL); SPAGAIN;
XPUSHs (sv);
endp = SvPVX(self->incr_text) + offset;
self->incr_pos -= offset;
self->incr_nest = 0;
self->incr_mode = 0;
#if PERL_VERSION > 9
sv_chop (self->incr_text, (const char* const)endp);
#else
sv_chop (self->incr_text, (char*)endp);
#endif
}
while (GIMME_V == G_ARRAY);
}
#if PERL_VERSION > 6
SV *incr_text (JSON *self)
ATTRS: lvalue
PPCODE:
{
PERL_UNUSED_VAR(RETVAL);
if (UNLIKELY(self->incr_pos))
{
/* We might want to return a copy of the rest.
But incr_parse already chops the start at the end, so this can
only happen on concurrent accesses to incr_parse */
croak ("incr_text can not be called when the incremental parser already started parsing");
}
ST(0) = self->incr_text ? self->incr_text : &PL_sv_undef;
XSRETURN(1);
}
#else
SV *incr_text (JSON *self)
PPCODE:
{
if (UNLIKELY(self->incr_pos))
croak ("incr_text can not be called when the incremental parser already started parsing");
ST(0) = self->incr_text ? self->incr_text : &PL_sv_undef;
XSRETURN(1);
}
#endif
void incr_skip (JSON *self)
CODE:
{
if (self->incr_pos)
{
sv_chop (self->incr_text, SvPV_nolen (self->incr_text) + self->incr_pos);
self->incr_pos = 0;
self->incr_nest = 0;
self->incr_mode = 0;
}
}
void incr_reset (JSON *self)
CODE:
{
if (self->incr_text)
SvREFCNT_dec (self->incr_text);
self->incr_text = NULL;
self->incr_pos = 0;
self->incr_nest = 0;
self->incr_mode = 0;
}
void DESTROY (JSON *self)
CODE:
if (!json_validate (self))
return;
# verify cb_sk_object for a valid HV
if (self->cb_sk_object && (SvTYPE (self->cb_sk_object) == SVt_PVHV))
SvREFCNT_dec (self->cb_sk_object);
if (self->cb_object && SvOK (self->cb_object))
SvREFCNT_dec (self->cb_object);
if (self->cb_sort_by && SvOK (self->cb_sort_by))
SvREFCNT_dec (self->cb_sort_by);
if (self->incr_text)
SvREFCNT_dec (self->incr_text);
PROTOTYPES: ENABLE
void encode_json (SV *scalar, SV *typesv = &PL_sv_undef)
ALIAS:
_to_json = 0
encode_json = F_UTF8
PPCODE:
{
JSON json;
json_init (&json);
json.flags |= ix;
PUTBACK; scalar = encode_json (aTHX_ scalar, &json, typesv); SPAGAIN;
XPUSHs (scalar);
}
void decode_json (SV *jsonstr, SV *allow_nonref = NULL, SV *typesv = NULL)
ALIAS:
_from_json = 0
decode_json = F_UTF8
PPCODE:
{
JSON json;
json_init (&json);
json.flags |= ix;
if (items > 1) {
/* allow_nonref arg explicitly given: override the default */
if (!SvTRUE (allow_nonref))
json.flags &= ~F_ALLOW_NONREF;
}
PUTBACK; jsonstr = decode_json (aTHX_ jsonstr, &json, 0, typesv); SPAGAIN;
XPUSHs (jsonstr);
}
( run in 0.526 second using v1.01-cache-2.11-cpan-71847e10f99 )