--- JSON-XS/XS.xs 2007/03/22 18:10:29 1.3 +++ JSON-XS/XS.xs 2007/03/22 21:13:58 1.4 @@ -42,7 +42,7 @@ { char *cur; char *end; - char *err; + const char *err; UV flags; } dec_t; @@ -65,7 +65,7 @@ STRLEN cur = enc->cur - SvPVX (enc->sv); SvGROW (enc->sv, cur + len + 1); enc->cur = SvPVX (enc->sv) + cur; - enc->end = SvEND (enc->sv); + enc->end = SvPVX (enc->sv) + SvLEN (enc->sv); } } @@ -81,13 +81,44 @@ { char *end = str + len; + need (enc, len); + while (str < end) { unsigned char ch = *(unsigned char *)str; - if (ch >= 0x20 && ch < 0x80) // most common case + + if (ch == '"') + { + need (enc, len += 1); + *enc->cur++ = '\\'; + *enc->cur++ = '"'; + ++str; + } + else if (ch == '\\') + { + need (enc, len += 1); + *enc->cur++ = '\\'; + *enc->cur++ = '\\'; + ++str; + } + else if (ch >= 0x20 && ch < 0x80) // most common case { *enc->cur++ = ch; - str++; + ++str; + } + else if (ch == '\015') + { + need (enc, len += 1); + *enc->cur++ = '\\'; + *enc->cur++ = 'r'; + ++str; + } + else if (ch == '\012') + { + need (enc, len += 1); + *enc->cur++ = '\\'; + *enc->cur++ = 'n'; + ++str; } else { @@ -106,14 +137,11 @@ clen = 1; } - need (enc, len += 6); - - if (uch < 0xa0 || enc->flags & F_ASCII) + if (uch < 0x80 || enc->flags & F_ASCII) { if (uch > 0xFFFFUL) { - len += 6; - need (enc, len += 6); + need (enc, len += 11); sprintf (enc->cur, "\\u%04x\\u%04x", (uch - 0x10000) / 0x400 + 0xD800, (uch - 0x10000) % 0x400 + 0xDC00); @@ -121,19 +149,30 @@ } else { - sprintf (enc->cur, "\\u%04x", uch); - enc->cur += 6; + 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]; } + + str += clen; } else if (is_utf8) { - memcpy (enc->cur, str, clen); - enc->cur += clen; + need (enc, len += clen); + while (clen--) + *enc->cur++ = *str++; } else - enc->cur = uvuni_to_utf8_flags (enc->cur, uch, 0); - - str += clen; + { + need (enc, 10); // never more than 11 bytes needed + enc->cur = uvuni_to_utf8_flags (enc->cur, uch, 0); + ++str; + } } --len; @@ -194,7 +233,10 @@ { SV *sv = HeSVKEY (he); STRLEN len; - char *str = SvPV (sv, len); + char *str; + + SvGETMAGIC (sv); + str = SvPV (sv, len); encode_str (enc, str, len, SvUTF8 (sv)); } @@ -315,6 +357,8 @@ static void encode_sv (enc_t *enc, SV *sv) { + SvGETMAGIC (sv); + if (SvPOKp (sv)) { STRLEN len; @@ -404,11 +448,6 @@ static SV *decode_sv (dec_t *dec); -#define APPEND_CH(ch) SB \ - SvGROW (sv, cur + 1 + 1); \ - SvPVX (sv)[cur++] = (ch); \ - SE - static signed char decode_hexdigit[256]; static UV @@ -436,12 +475,28 @@ return (UV)-1; } +#define APPEND_GROW(n) SB \ + if (cur + (n) >= end) \ + { \ + STRLEN ofs = cur - SvPVX (sv); \ + SvGROW (sv, ofs + (n) + 1); \ + cur = SvPVX (sv) + ofs; \ + end = SvEND (sv); \ + } \ + SE + +#define APPEND_CH(ch) SB \ + APPEND_GROW (1); \ + *cur++ = (ch); \ + SE + static SV * decode_str (dec_t *dec) { SV *sv = NEWSV (0,2); - STRLEN cur = 0; int utf8 = 0; + char *cur = SvPVX (sv); + char *end = SvEND (sv); for (;;) { @@ -496,8 +551,8 @@ { utf8 = 1; - SvGROW (sv, cur + 4 + 1); // at most 4 bytes for 21 bits - cur = (char *)uvuni_to_utf8_flags (SvPVX (sv) + cur, hi, 0) - SvPVX (sv); + APPEND_GROW (4); // at most 4 bytes for 21 bits + cur = (char *)uvuni_to_utf8_flags (cur, hi, 0); } else APPEND_CH (hi); @@ -514,8 +569,9 @@ if (clen < 0) ERR ("malformed UTF-8 character in string, cannot convert to JSON"); - SvGROW (sv, cur + clen + 1); // at most 4 bytes for 21 bits - memcpy (SvPVX (sv) + cur, dec->cur, clen); + APPEND_GROW (clen); + memcpy (cur, dec->cur, clen); + cur += clen; dec->cur += clen; } else @@ -524,9 +580,9 @@ ++dec->cur; - SvPOK_only (sv); + SvCUR_set (sv, cur - SvPVX (sv)); - SvCUR_set (sv, cur); + SvPOK_only (sv); *SvEND (sv) = 0; if (utf8) @@ -796,7 +852,7 @@ for (i = 10; i--; ) decode_hexdigit ['0' + i] = i; - for (i = 6; --i; ) + for (i = 7; i--; ) { decode_hexdigit ['a' + i] = 10 + i; decode_hexdigit ['A' + i] = 10 + i; @@ -805,6 +861,8 @@ json_stash = gv_stashpv ("JSON::XS", 1); } +PROTOTYPES: DISABLE + SV *new (char *dummy) CODE: RETVAL = sv_bless (newRV_noinc (newSVuv (F_DEFAULT)), json_stash); @@ -843,6 +901,8 @@ PPCODE: XPUSHs (decode_json (jsonstr, *SvJSON (self))); +PROTOTYPES: ENABLE + void to_json (SV *scalar) PPCODE: XPUSHs (encode_json (scalar, F_UTF8));