summaryrefslogtreecommitdiff
path: root/ext/json/parser/parser.rl
diff options
context:
space:
mode:
Diffstat (limited to 'ext/json/parser/parser.rl')
-rw-r--r--ext/json/parser/parser.rl48
1 files changed, 40 insertions, 8 deletions
diff --git a/ext/json/parser/parser.rl b/ext/json/parser/parser.rl
index 1da70c544c..230d725236 100644
--- a/ext/json/parser/parser.rl
+++ b/ext/json/parser/parser.rl
@@ -452,17 +452,30 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul
}
}
-static VALUE json_string_unescape(VALUE result, char *string, char *stringEnd)
+static const size_t MAX_STACK_BUFFER_SIZE = 128;
+static VALUE json_string_unescape(char *string, char *stringEnd)
{
- char *p = string, *pe = string, *unescape;
+ VALUE result = Qnil;
+ size_t bufferSize = stringEnd - string;
+ char *p = string, *pe = string, *unescape, *bufferStart, *buffer;
int unescape_len;
char buf[4];
+ if (bufferSize > MAX_STACK_BUFFER_SIZE) {
+ buffer = xmalloc(bufferSize);
+ bufferStart = buffer;
+ } else {
+ bufferStart = buffer = alloca(bufferSize);
+ }
+
while (pe < stringEnd) {
if (*pe == '\\') {
unescape = (char *) "?";
unescape_len = 1;
- if (pe > p) rb_str_buf_cat(result, p, pe - p);
+ if (pe > p) {
+ MEMCPY(buffer, p, char, pe - p);
+ buffer += pe - p;
+ }
switch (*++pe) {
case 'n':
unescape = (char *) "\n";
@@ -487,6 +500,9 @@ static VALUE json_string_unescape(VALUE result, char *string, char *stringEnd)
break;
case 'u':
if (pe > stringEnd - 4) {
+ if (bufferSize > MAX_STACK_BUFFER_SIZE) {
+ free(bufferStart);
+ }
rb_enc_raise(
EXC_ENCODING eParserError,
"%u: incomplete unicode character escape sequence at '%s'", __LINE__, p
@@ -497,6 +513,9 @@ static VALUE json_string_unescape(VALUE result, char *string, char *stringEnd)
if (UNI_SUR_HIGH_START == (ch & 0xFC00)) {
pe++;
if (pe > stringEnd - 6) {
+ if (bufferSize > MAX_STACK_BUFFER_SIZE) {
+ free(bufferStart);
+ }
rb_enc_raise(
EXC_ENCODING eParserError,
"%u: incomplete surrogate pair at '%s'", __LINE__, p
@@ -520,13 +539,28 @@ static VALUE json_string_unescape(VALUE result, char *string, char *stringEnd)
p = pe;
continue;
}
- rb_str_buf_cat(result, unescape, unescape_len);
+ MEMCPY(buffer, unescape, char, unescape_len);
+ buffer += unescape_len;
p = ++pe;
} else {
pe++;
}
}
- rb_str_buf_cat(result, p, pe - p);
+
+ if (pe > p) {
+ MEMCPY(buffer, p, char, pe - p);
+ buffer += pe - p;
+ }
+
+ #ifdef HAVE_RUBY_ENCODING_H
+ result = rb_utf8_str_new(bufferStart, buffer - bufferStart);
+ #else
+ result = rb_str_new(bufferStart, buffer - bufferStart);
+ #endif
+
+ if (bufferSize > MAX_STACK_BUFFER_SIZE) {
+ free(bufferStart);
+ }
return result;
}
@@ -537,12 +571,11 @@ static VALUE json_string_unescape(VALUE result, char *string, char *stringEnd)
write data;
action parse_string {
- *result = json_string_unescape(*result, json->memo + 1, p);
+ *result = json_string_unescape(json->memo + 1, p);
if (NIL_P(*result)) {
fhold;
fbreak;
} else {
- FORCE_UTF8(*result);
fexec p + 1;
}
}
@@ -569,7 +602,6 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu
int cs = EVIL;
VALUE match_string;
- *result = rb_str_buf_new(0);
%% write init;
json->memo = p;
%% write exec;