--- JSON-XS/XS.xs 2007/07/02 02:57:11 1.52 +++ JSON-XS/XS.xs 2007/07/26 11:33:35 1.56 @@ -2,10 +2,11 @@ #include "perl.h" #include "XSUB.h" -#include "assert.h" -#include "string.h" -#include "stdlib.h" -#include "stdio.h" +#include +#include +#include +#include +#include #if defined(__BORLANDC__) || defined(_MSC_VER) # define snprintf _snprintf // C compilers have this in stdio.h @@ -308,8 +309,14 @@ for (i = 0; i <= len; ++i) { + SV **svp = av_fetch (av, i, 0); + encode_indent (enc); - encode_sv (enc, *av_fetch (av, i, 0)); + + if (svp) + encode_sv (enc, *svp); + else + encode_str (enc, "null", 4, 0); if (i < len) encode_comma (enc); @@ -491,20 +498,29 @@ if (enc->json.flags & F_CONV_BLESSED) { // we re-bless the reference to get overload and other niceties right - GV *to_json = gv_fetchmethod_autoload (SvSTASH (sv), "TO_JSON", 1); + GV *to_json = gv_fetchmethod_autoload (SvSTASH (sv), "TO_JSON", 0); if (to_json) { - dSP; ENTER; SAVETMPS; PUSHMARK (SP); + int count; + dSP; + + ENTER; SAVETMPS; PUSHMARK (SP); XPUSHs (sv_bless (sv_2mortal (newRV_inc (sv)), SvSTASH (sv))); - // calling with G_SCALAR ensures that we always get a 1 reutrn value - // check anyways. + // calling with G_SCALAR ensures that we always get a 1 return value PUTBACK; - assert (1 == call_sv ((SV *)GvCV (to_json), G_SCALAR)); + call_sv ((SV *)GvCV (to_json), G_SCALAR); SPAGAIN; - encode_sv (enc, POPs); + // catch this surprisingly common error + if (SvROK (TOPs) && SvRV (TOPs) == sv) + croak ("%s::TO_JSON method returned same object as was passed instead of a new one", HvNAME (SvSTASH (sv))); + + sv = POPs; + PUTBACK; + + encode_sv (enc, sv); FREETMPS; LEAVE; } @@ -924,9 +940,11 @@ if (!is_nv) { + int len = dec->cur - start; + // special case the rather common 1..4-digit-int case, assumes 32 bit ints or so if (*start == '-') - switch (dec->cur - start) + switch (len) { case 2: return newSViv (-( start [1] - '0' * 1)); case 3: return newSViv (-( start [1] * 10 + start [2] - '0' * 11)); @@ -934,7 +952,7 @@ case 5: return newSViv (-(start [1] * 1000 + start [2] * 100 + start [3] * 10 + start [4] - '0' * 1111)); } else - switch (dec->cur - start) + switch (len) { case 1: return newSViv ( start [0] - '0' * 1); case 2: return newSViv ( start [0] * 10 + start [1] - '0' * 11); @@ -944,7 +962,7 @@ { UV uv; - int numtype = grok_number (start, dec->cur - start, &uv); + int numtype = grok_number (start, len, &uv); if (numtype & IS_NUMBER_IN_UV) if (numtype & IS_NUMBER_NEG) { @@ -953,12 +971,24 @@ } else return newSVuv (uv); - - // here would likely be the place for bigint support } + + len -= *start == '-' ? 1 : 0; + + // does not fit into IV or UV, try NV + if ((sizeof (NV) == sizeof (double) && DBL_DIG >= len) + #if defined (LDBL_DIG) + || (sizeof (NV) == sizeof (long double) && LDBL_DIG >= len) + #endif + ) + // fits into NV without loss of precision + return newSVnv (Atof (start)); + + // everything else fails, convert it to a string + return newSVpvn (start, dec->cur - start); } - // if we ever support bigint or bigfloat, this is the place for bigfloat + // loss of precision here return newSVnv (Atof (start)); fail: @@ -1115,10 +1145,10 @@ if (cb) { + dSP; int count; - ENTER; SAVETMPS; - dSP; PUSHMARK (SP); + ENTER; SAVETMPS; PUSHMARK (SP); XPUSHs (HeVAL (he)); PUTBACK; count = call_sv (HeVAL (cb), G_ARRAY); SPAGAIN; @@ -1136,10 +1166,10 @@ if (dec->json.cb_object) { + dSP; int count; - ENTER; SAVETMPS; - dSP; ENTER; SAVETMPS; PUSHMARK (SP); + ENTER; SAVETMPS; PUSHMARK (SP); XPUSHs (sv_2mortal (sv)); PUTBACK; count = call_sv (dec->json.cb_object, G_ARRAY); SPAGAIN;