--- JSON-XS/XS.xs 2008/05/27 05:31:39 1.86 +++ JSON-XS/XS.xs 2009/02/22 06:55:28 1.95 @@ -81,7 +81,7 @@ INCR_M_JSON // outside anything, count nesting }; -#define INCR_DONE(json) (!(json)->incr_nest && (json)->incr_mode == INCR_M_JSON) +#define INCR_DONE(json) ((json)->incr_nest <= 0 && (json)->incr_mode == INCR_M_JSON) typedef struct { U32 flags; @@ -94,7 +94,7 @@ // for the incremental parser SV *incr_text; // the source text so far STRLEN incr_pos; // the current offset into the text - unsigned char incr_nest; // {[]}-nesting level + int incr_nest; // {[]}-nesting level unsigned char incr_mode; } JSON; @@ -123,6 +123,7 @@ shrink (SV *sv) { sv_utf8_downgrade (sv, 1); + if (SvLEN (sv) > SvCUR (sv) + 1) { #ifdef SvPV_shrink_to_cur @@ -195,8 +196,8 @@ { if (expect_false (enc->cur + len >= enc->end)) { - STRLEN cur = enc->cur - SvPVX (enc->sv); - SvGROW (enc->sv, cur + len + 1); + STRLEN cur = enc->cur - (char *)SvPVX (enc->sv); + SvGROW (enc->sv, cur + (len < (cur >> 2) ? cur >> 2 : len) + 1); enc->cur = SvPVX (enc->sv) + cur; enc->end = SvPVX (enc->sv) + SvLEN (enc->sv) - 1; } @@ -281,14 +282,13 @@ } else { - static char hexdigit [16] = "0123456789abcdef"; need (enc, len += 5); *enc->cur++ = '\\'; *enc->cur++ = 'u'; - *enc->cur++ = hexdigit [ uch >> 12 ]; - *enc->cur++ = hexdigit [(uch >> 8) & 15]; - *enc->cur++ = hexdigit [(uch >> 4) & 15]; - *enc->cur++ = hexdigit [(uch >> 0) & 15]; + *enc->cur++ = PL_hexdigit [ uch >> 12 ]; + *enc->cur++ = PL_hexdigit [(uch >> 8) & 15]; + *enc->cur++ = PL_hexdigit [(uch >> 4) & 15]; + *enc->cur++ = PL_hexdigit [(uch >> 0) & 15]; } str += clen; @@ -462,7 +462,7 @@ // for canonical output we have to sort by keys first // actually, this is mostly due to the stupid so-called - // security workaround added somewhere in 5.8.x. + // security workaround added somewhere in 5.8.x // that randomises hash orderings if (enc->json.flags & F_CANONICAL) { @@ -972,7 +972,11 @@ if (sv) { - SvGROW (sv, SvCUR (sv) + len + 1); + STRLEN cur = SvCUR (sv); + + if (SvLEN (sv) <= cur + len) + SvGROW (sv, cur + (len < (cur >> 2) ? cur >> 2 : len) + 1); + memcpy (SvPVX (sv) + SvCUR (sv), buf, len); SvCUR_set (sv, SvCUR (sv) + len); } @@ -1412,10 +1416,32 @@ STRLEN offset; SV *sv; - SvGETMAGIC (string); + /* work around bugs in 5.10 where manipulating magic values + * will perl ignore the magic in subsequent accesses + */ + /*SvGETMAGIC (string);*/ + if (SvMAGICAL (string)) + string = sv_2mortal (newSVsv (string)); + SvUPGRADE (string, SVt_PV); - if (SvCUR (string) > json->max_size && json->max_size) + /* work around a bug in perl 5.10, which causes SvCUR to fail an + * assertion with -DDEBUGGING, although SvCUR is documented to + * return the xpv_cur field which certainly exists after upgrading. + * according to nicholas clark, calling SvPOK fixes this. + * But it doesn't fix it, so try another workaround, call SvPV_nolen + * and hope for the best. + * Damnit, SvPV_nolen still trips over yet another assertion. This + * assertion business is seriously broken, try yet another workaround + * for the broken -DDEBUGGING. + */ +#ifdef DEBUGGING + offset = SvOK (string) ? sv_len (string) : 0; +#else + offset = SvCUR (string); +#endif + + if (offset > json->max_size && json->max_size) croak ("attempted decode of JSON text of %lu bytes size, but max_size is set to %lu", (unsigned long)SvCUR (string), (unsigned long)json->max_size); @@ -1592,7 +1618,7 @@ case ']': case '}': - if (!--self->incr_nest) + if (--self->incr_nest <= 0) goto interrupt; } } @@ -1785,7 +1811,11 @@ { STRLEN len; const char *str = SvPV (jsonstr, len); - SvGROW (self->incr_text, SvCUR (self->incr_text) + len + 1); + 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