зеркало из https://github.com/mozilla/pjs.git
Bug 462778. Fix JSON top crash. r=brendan
This commit is contained in:
Родитель
8b29d8ed16
Коммит
d813f67054
|
@ -0,0 +1,205 @@
|
|||
|
||||
// returns a list of [string, object] pairs to test encoding
|
||||
function getTestPairs() {
|
||||
var testPairs = [
|
||||
["{}", {}],
|
||||
["[]", []],
|
||||
['{"foo":"bar"}', {"foo":"bar"}],
|
||||
['{"null":null}', {"null":null}],
|
||||
['{"five":5}', {"five":5}],
|
||||
['{"five":5,"six":6}', {"five":5, "six":6}],
|
||||
['{"x":{"y":"z"}}', {"x":{"y":"z"}}],
|
||||
['{"w":{"x":{"y":"z"}}}', {"w":{"x":{"y":"z"}}}],
|
||||
['[1,2,3]', [1,2,3]],
|
||||
['{"w":{"x":{"y":[1,2,3]}}}', {"w":{"x":{"y":[1,2,3]}}}],
|
||||
['{"false":false}', {"false":false}],
|
||||
['{"true":true}', {"true":true}],
|
||||
['{"child has two members":{"this":"one","2":"and this one"}}',
|
||||
{"child has two members": {"this":"one", 2:"and this one"}}],
|
||||
['{"x":{"a":"b","c":{"y":"z"},"f":"g"}}',
|
||||
{"x":{"a":"b","c":{"y":"z"},"f":"g"}}],
|
||||
['{"x":[1,{"y":"z"},3]}', {"x":[1,{"y":"z"},3]}],
|
||||
['["hmm"]', [new String("hmm")]],
|
||||
['[true]', [new Boolean(true)]],
|
||||
['[42]', [new Number(42)]],
|
||||
['["1978-09-13T12:24:34.023Z"]', [new Date(Date.UTC(1978, 8, 13, 12, 24, 34, 23))]],
|
||||
['[1,null,3]',[1,,3]],
|
||||
['{"mm\\\"mm":"hmm"}',{"mm\"mm":"hmm"}],
|
||||
['{"mm\\\"mm\\\"mm":"hmm"}',{"mm\"mm\"mm":"hmm"}],
|
||||
['{"\\\"":"hmm"}',{'"':"hmm"}],
|
||||
['{"\\\\":"hmm"}',{'\\':"hmm"}],
|
||||
['{"mmm\\\\mmm":"hmm"}',{'mmm\\mmm':"hmm"}],
|
||||
['{"mmm\\\\mmm\\\\mmm":"hmm"}',{'mmm\\mmm\\mmm':"hmm"}],
|
||||
['{"mm\\u000bmm":"hmm"}',{"mm\u000bmm":"hmm"}],
|
||||
['{"mm\\u0000mm":"hmm"}',{"mm\u0000mm":"hmm"}]
|
||||
];
|
||||
|
||||
var x = {"free":"variable"}
|
||||
testPairs.push(['{"free":"variable"}', x]);
|
||||
testPairs.push(['{"y":{"free":"variable"}}', {"y":x}]);
|
||||
|
||||
// array prop
|
||||
var x = {
|
||||
a: [1,2,3]
|
||||
}
|
||||
testPairs.push(['{"a":[1,2,3]}', x])
|
||||
|
||||
var y = {
|
||||
foo: function(hmm) { return hmm; }
|
||||
}
|
||||
testPairs.push(['{"y":{}}',{"y":y}]);
|
||||
|
||||
// test toJSON
|
||||
var hmm = {
|
||||
toJSON: function() { return {"foo":"bar"}}
|
||||
}
|
||||
testPairs.push(['{"hmm":{"foo":"bar"}}', {"hmm":hmm}]);
|
||||
testPairs.push(['{"foo":"bar"}', hmm]); // on the root
|
||||
|
||||
// toJSON on prototype
|
||||
var Y = function() {
|
||||
this.d = "e";
|
||||
}
|
||||
Y.prototype = {
|
||||
not:"there?",
|
||||
toJSON: function() { return {"foo":"bar"}}
|
||||
};
|
||||
var y = new Y();
|
||||
testPairs.push(['{"foo":"bar"}', y.toJSON()]);
|
||||
testPairs.push(['{"foo":"bar"}', y]);
|
||||
|
||||
// return undefined from toJSON
|
||||
var hmm = {
|
||||
toJSON: function() { return; }
|
||||
}
|
||||
testPairs.push(['{}', {"hmm":hmm}]);
|
||||
|
||||
// array with named prop
|
||||
var x= new Array();
|
||||
x[0] = 1;
|
||||
x.foo = "bar";
|
||||
testPairs.push(['[1]', x]);
|
||||
|
||||
// prototype
|
||||
var X = function() { this.a = "b" }
|
||||
X.prototype = {c:"d"}
|
||||
var y = new X();
|
||||
testPairs.push(['{"a":"b","c":"d"}', y]);
|
||||
|
||||
// custom iterator: JS 1.7+
|
||||
var x = {
|
||||
"a": "foo",
|
||||
b: "not included",
|
||||
c: "bar",
|
||||
"4": "qux",
|
||||
__iterator__: function() { return (function() { yield "a"; yield "c"; yield 4; })() }
|
||||
}
|
||||
do_check_eq('{"a":"foo","c":"bar","4":"qux"}', JSON.stringify(x));
|
||||
|
||||
return testPairs;
|
||||
}
|
||||
|
||||
function testStringEncode() {
|
||||
var pairs = getTestPairs();
|
||||
for each(pair in pairs) {
|
||||
print(pair)
|
||||
var nativeResult = JSON.stringify(pair[1]);
|
||||
var crockfordResult = crockfordJSON.stringify(pair[1]);
|
||||
do_check_eq(pair[0], nativeResult);
|
||||
|
||||
// Don't follow json2.js handling of non-objects
|
||||
if (pair[1] && (typeof pair[1] == "object")) {
|
||||
do_check_eq(crockfordResult, nativeResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function decode_strings() {
|
||||
// empty object
|
||||
var x = JSON.parse("{}");
|
||||
do_check_eq(typeof x, "object");
|
||||
|
||||
// empty array
|
||||
x = JSON.parse("[]");
|
||||
do_check_eq(typeof x, "object");
|
||||
do_check_eq(x.length, 0);
|
||||
do_check_eq(x.constructor, Array);
|
||||
|
||||
// one element array
|
||||
x = JSON.parse("[[]]");
|
||||
do_check_eq(typeof x, "object");
|
||||
do_check_eq(x.length, 1);
|
||||
do_check_eq(x.constructor, Array);
|
||||
do_check_eq(x[0].constructor, Array);
|
||||
|
||||
// multiple arrays
|
||||
x = JSON.parse("[[],[],[]]");
|
||||
do_check_eq(typeof x, "object");
|
||||
do_check_eq(x.length, 3);
|
||||
do_check_eq(x.constructor, Array);
|
||||
do_check_eq(x[0].constructor, Array);
|
||||
do_check_eq(x[1].constructor, Array);
|
||||
do_check_eq(x[2].constructor, Array);
|
||||
|
||||
// array key/value
|
||||
x = JSON.parse('{"foo":[]}');
|
||||
do_check_eq(typeof x, "object");
|
||||
do_check_eq(typeof x.foo, "object");
|
||||
do_check_eq(x.foo.constructor, Array);
|
||||
x = JSON.parse('{"foo":[], "bar":[]}');
|
||||
do_check_eq(typeof x, "object");
|
||||
do_check_eq(typeof x.foo, "object");
|
||||
do_check_eq(x.foo.constructor, Array);
|
||||
do_check_eq(typeof x.bar, "object");
|
||||
do_check_eq(x.bar.constructor, Array);
|
||||
|
||||
// nesting
|
||||
x = JSON.parse('{"foo":[{}]}');
|
||||
do_check_eq(x.foo.constructor, Array);
|
||||
do_check_eq(x.foo.length, 1);
|
||||
do_check_eq(typeof x.foo[0], "object");
|
||||
x = JSON.parse('{"foo":[{"foo":[{"foo":{}}]}]}');
|
||||
do_check_eq(x.foo[0].foo[0].foo.constructor, Object);
|
||||
x = JSON.parse('{"foo":[{"foo":[{"foo":[]}]}]}');
|
||||
do_check_eq(x.foo[0].foo[0].foo.constructor, Array);
|
||||
|
||||
// strings
|
||||
x = JSON.parse('{"foo":"bar"}');
|
||||
do_check_eq(x.foo, "bar");
|
||||
x = JSON.parse('["foo", "bar", "baz"]');
|
||||
do_check_eq(x[0], "foo");
|
||||
do_check_eq(x[1], "bar");
|
||||
do_check_eq(x[2], "baz");
|
||||
|
||||
// numbers
|
||||
x = JSON.parse('{"foo":5.5, "bar":5}');
|
||||
do_check_eq(x.foo, 5.5);
|
||||
do_check_eq(x.bar, 5);
|
||||
|
||||
// keywords
|
||||
x = JSON.parse('{"foo": true, "bar":false, "baz":null}');
|
||||
do_check_eq(x.foo, true);
|
||||
do_check_eq(x.bar, false);
|
||||
do_check_eq(x.baz, null);
|
||||
|
||||
// short escapes
|
||||
x = JSON.parse('{"foo": "\\"", "bar":"\\\\", "baz":"\\b","qux":"\\f", "quux":"\\n", "quuux":"\\r","quuuux":"\\t"}');
|
||||
do_check_eq(x.foo, '"');
|
||||
do_check_eq(x.bar, '\\');
|
||||
do_check_eq(x.baz, '\b');
|
||||
do_check_eq(x.qux, '\f');
|
||||
do_check_eq(x.quux, "\n");
|
||||
do_check_eq(x.quuux, "\r");
|
||||
do_check_eq(x.quuuux, "\t");
|
||||
|
||||
// unicode escape
|
||||
x = JSON.parse('{"foo":"hmm\\u006dmm"}');
|
||||
do_check_eq("hmm\u006dmm", x.foo);
|
||||
|
||||
x = JSON.parse('{"JSON Test Pattern pass3": {"The outermost value": "must be an object or array.","In this test": "It is an object." }}');
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
testStringEncode();
|
||||
decode_strings();
|
||||
}
|
115
js/src/json.cpp
115
js/src/json.cpp
|
@ -83,14 +83,16 @@ js_json_parse(JSContext *cx, uintN argc, jsval *vp)
|
|||
}
|
||||
|
||||
if (!ok)
|
||||
JS_ReportError(cx, "Error parsing JSON.");
|
||||
JS_ReportError(cx, "Error parsing JSON");
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
struct StringifyClosure
|
||||
class StringifyClosure : JSAutoTempValueRooter
|
||||
{
|
||||
StringifyClosure(JSContext *aCx, jsval *str) : cx(aCx), s(str)
|
||||
public:
|
||||
StringifyClosure(JSContext *cx, size_t len, jsval *vec)
|
||||
: JSAutoTempValueRooter(cx, len, vec), cx(cx), s(vec)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -102,16 +104,20 @@ static JSBool
|
|||
WriteCallback(const jschar *buf, uint32 len, void *data)
|
||||
{
|
||||
StringifyClosure *sc = static_cast<StringifyClosure*>(data);
|
||||
JSString *s1 = JSVAL_TO_STRING(*sc->s);
|
||||
JSString *s1 = JSVAL_TO_STRING(sc->s[0]);
|
||||
JSString *s2 = js_NewStringCopyN(sc->cx, buf, len);
|
||||
if (!s2)
|
||||
return JS_FALSE;
|
||||
|
||||
sc->s[1] = STRING_TO_JSVAL(s2);
|
||||
|
||||
s1 = js_ConcatStrings(sc->cx, s1, s2);
|
||||
if (!s1)
|
||||
return JS_FALSE;
|
||||
|
||||
*sc->s = STRING_TO_JSVAL(s1);
|
||||
sc->s[0] = STRING_TO_JSVAL(s1);
|
||||
sc->s[1] = JSVAL_VOID;
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
@ -126,13 +132,15 @@ js_json_stringify(JSContext *cx, uintN argc, jsval *vp)
|
|||
return JS_FALSE;
|
||||
|
||||
// Only use objects and arrays as the root for now
|
||||
jsval v = OBJECT_TO_JSVAL(obj);
|
||||
JSBool ok = js_TryJSON(cx, &v);
|
||||
*vp = OBJECT_TO_JSVAL(obj);
|
||||
|
||||
JSBool ok = js_TryJSON(cx, vp);
|
||||
JSType type;
|
||||
if (!(ok && !JSVAL_IS_PRIMITIVE(v) &&
|
||||
(type = JS_TypeOfValue(cx, v)) != JSTYPE_FUNCTION &&
|
||||
type != JSTYPE_XML)) {
|
||||
JS_ReportError(cx, "Invalid argument.");
|
||||
if (!ok ||
|
||||
JSVAL_IS_PRIMITIVE(*vp) ||
|
||||
((type = JS_TypeOfValue(cx, *vp)) == JSTYPE_FUNCTION ||
|
||||
type == JSTYPE_XML)) {
|
||||
JS_ReportError(cx, "Invalid argument");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
|
@ -141,10 +149,10 @@ js_json_stringify(JSContext *cx, uintN argc, jsval *vp)
|
|||
ok = JS_FALSE;
|
||||
|
||||
if (ok) {
|
||||
jsval sv = STRING_TO_JSVAL(s);
|
||||
StringifyClosure sc(cx, &sv);
|
||||
JSAutoTempValueRooter tvr(cx, 1, sc.s);
|
||||
ok = js_Stringify(cx, &v, NULL, &WriteCallback, &sc, 0);
|
||||
jsval vec[2] = {STRING_TO_JSVAL(s), JSVAL_VOID};
|
||||
StringifyClosure sc(cx, 2, vec);
|
||||
JSAutoTempValueRooter resultTvr(cx, 1, sc.s);
|
||||
ok = js_Stringify(cx, vp, NULL, &WriteCallback, &sc, 0);
|
||||
*vp = *sc.s;
|
||||
}
|
||||
|
||||
|
@ -191,8 +199,11 @@ write_string(JSContext *cx, JSONWriteCallback callback, void *data, const jschar
|
|||
char ubuf[10];
|
||||
unsigned int len = JS_snprintf(ubuf, sizeof(ubuf), "%.2x", buf[i]);
|
||||
JS_ASSERT(len == 2);
|
||||
// TODO: don't allocate a JSString just to inflate (js_InflateStringToBuffer on static?)
|
||||
// FIXME: bug 463715 - don't allocate a JSString just to inflate
|
||||
// (js_InflateStringToBuffer on static?)
|
||||
JSString *us = JS_NewStringCopyN(cx, ubuf, len);
|
||||
if (!us)
|
||||
return JS_FALSE;
|
||||
if (!callback(JS_GetStringChars(us), len, data))
|
||||
return JS_FALSE;
|
||||
mark = i + 1;
|
||||
|
@ -246,7 +257,8 @@ js_Stringify(JSContext *cx, jsval *vp, JSObject *replacer,
|
|||
if (isArray) {
|
||||
if ((jsuint)i >= length)
|
||||
break;
|
||||
ok = JS_GetElement(cx, obj, i++, &outputValue);
|
||||
ok = OBJ_GET_PROPERTY(cx, obj, INT_TO_JSID(i), &outputValue);
|
||||
i++;
|
||||
} else {
|
||||
ok = js_CallIteratorNext(cx, iterObj, &key);
|
||||
if (!ok)
|
||||
|
@ -359,6 +371,11 @@ js_Stringify(JSContext *cx, jsval *vp, JSObject *replacer,
|
|||
break;
|
||||
}
|
||||
|
||||
if (!outputString) {
|
||||
ok = JS_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
ok = callback(JS_GetStringChars(outputString), JS_GetStringLength(outputString), data);
|
||||
}
|
||||
} while (ok);
|
||||
|
@ -370,7 +387,7 @@ js_Stringify(JSContext *cx, jsval *vp, JSObject *replacer,
|
|||
}
|
||||
|
||||
if (!ok) {
|
||||
JS_ReportError(cx, "Error during JSON encoding.");
|
||||
JS_ReportError(cx, "Error during JSON encoding");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
|
@ -410,7 +427,12 @@ js_BeginJSONParse(JSContext *cx, jsval *rootVal)
|
|||
jp->statep = jp->stateStack;
|
||||
*jp->statep = JSON_PARSE_STATE_INIT;
|
||||
jp->rootVal = rootVal;
|
||||
jp->objectKey = NULL;
|
||||
|
||||
jp->objectKey = (JSStringBuffer*) JS_malloc(cx, sizeof(JSStringBuffer));
|
||||
if (!jp->objectKey)
|
||||
goto bad;
|
||||
js_InitStringBuffer(jp->objectKey);
|
||||
|
||||
jp->buffer = (JSStringBuffer*) JS_malloc(cx, sizeof(JSStringBuffer));
|
||||
if (!jp->buffer)
|
||||
goto bad;
|
||||
|
@ -429,10 +451,14 @@ js_FinishJSONParse(JSContext *cx, JSONParser *jp)
|
|||
if (!jp)
|
||||
return JS_TRUE;
|
||||
|
||||
if (jp->objectKey)
|
||||
js_FinishStringBuffer(jp->objectKey);
|
||||
JS_free(cx, jp->objectKey);
|
||||
|
||||
if (jp->buffer)
|
||||
js_FinishStringBuffer(jp->buffer);
|
||||
|
||||
JS_free(cx, jp->buffer);
|
||||
|
||||
if (!js_RemoveRoot(cx->runtime, &jp->objectStack))
|
||||
return JS_FALSE;
|
||||
JSBool ok = *jp->statep == JSON_PARSE_STATE_FINISHED;
|
||||
|
@ -480,12 +506,16 @@ PushValue(JSContext *cx, JSONParser *jp, JSObject *parent, jsval value)
|
|||
if (OBJ_IS_ARRAY(cx, parent)) {
|
||||
jsuint len;
|
||||
ok = js_GetLengthProperty(cx, parent, &len);
|
||||
if (ok)
|
||||
ok = JS_SetElement(cx, parent, len, &value);
|
||||
if (ok) {
|
||||
ok = OBJ_DEFINE_PROPERTY(cx, parent, INT_TO_JSID(len), value,
|
||||
NULL, NULL, JSPROP_ENUMERATE, NULL);
|
||||
}
|
||||
} else {
|
||||
ok = JS_DefineUCProperty(cx, parent, JS_GetStringChars(jp->objectKey),
|
||||
JS_GetStringLength(jp->objectKey), value,
|
||||
ok = JS_DefineUCProperty(cx, parent, jp->objectKey->base,
|
||||
STRING_BUFFER_OFFSET(jp->objectKey), value,
|
||||
NULL, NULL, JSPROP_ENUMERATE);
|
||||
js_FinishStringBuffer(jp->objectKey);
|
||||
js_InitStringBuffer(jp->objectKey);
|
||||
}
|
||||
|
||||
return ok;
|
||||
|
@ -501,25 +531,33 @@ PushObject(JSContext *cx, JSONParser *jp, JSObject *obj)
|
|||
return JS_FALSE; // decoding error
|
||||
|
||||
jsval v = OBJECT_TO_JSVAL(obj);
|
||||
JSAutoTempValueRooter tvr(cx, v);
|
||||
|
||||
// Check if this is the root object
|
||||
if (len == 0) {
|
||||
*jp->rootVal = v;
|
||||
if (!JS_SetElement(cx, jp->objectStack, 0, jp->rootVal))
|
||||
// This property must be enumerable to keep the array dense
|
||||
if (!OBJ_DEFINE_PROPERTY(cx, jp->objectStack, INT_TO_JSID(0), *jp->rootVal,
|
||||
NULL, NULL, JSPROP_ENUMERATE, NULL)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
jsval p;
|
||||
if (!JS_GetElement(cx, jp->objectStack, len - 1, &p))
|
||||
if (!OBJ_GET_PROPERTY(cx, jp->objectStack, INT_TO_JSID(len - 1), &p))
|
||||
return JS_FALSE;
|
||||
|
||||
JS_ASSERT(JSVAL_IS_OBJECT(p));
|
||||
JSObject *parent = JSVAL_TO_OBJECT(p);
|
||||
if (!PushValue(cx, jp, parent, OBJECT_TO_JSVAL(obj)))
|
||||
return JS_FALSE;
|
||||
|
||||
if (!JS_SetElement(cx, jp->objectStack, len, &v))
|
||||
// This property must be enumerable to keep the array dense
|
||||
if (!OBJ_DEFINE_PROPERTY(cx, jp->objectStack, INT_TO_JSID(len), v,
|
||||
NULL, NULL, JSPROP_ENUMERATE, NULL)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
@ -532,7 +570,7 @@ GetTopOfObjectStack(JSContext *cx, JSONParser *jp)
|
|||
return NULL;
|
||||
|
||||
jsval o;
|
||||
if (!JS_GetElement(cx, jp->objectStack, length - 1, &o))
|
||||
if (!OBJ_GET_PROPERTY(cx, jp->objectStack, INT_TO_JSID(length - 1), &o))
|
||||
return NULL;
|
||||
|
||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(o));
|
||||
|
@ -633,26 +671,29 @@ HandleKeyword(JSContext *cx, JSONParser *jp, const jschar *buf, uint32 len)
|
|||
}
|
||||
|
||||
static JSBool
|
||||
HandleData(JSContext *cx, JSONParser *jp, JSONDataType type, const jschar *buf, uint32 len)
|
||||
HandleData(JSContext *cx, JSONParser *jp, JSONDataType type)
|
||||
{
|
||||
JSBool ok = JS_FALSE;
|
||||
|
||||
if (!STRING_BUFFER_OK(jp->buffer))
|
||||
return JS_FALSE;
|
||||
|
||||
switch (type) {
|
||||
case JSON_DATA_STRING:
|
||||
ok = HandleString(cx, jp, buf, len);
|
||||
ok = HandleString(cx, jp, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer));
|
||||
break;
|
||||
|
||||
case JSON_DATA_KEYSTRING:
|
||||
jp->objectKey = js_NewStringCopyN(cx, buf, len);
|
||||
ok = JS_TRUE;
|
||||
js_AppendUCString(jp->objectKey, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer));
|
||||
ok = STRING_BUFFER_OK(jp->objectKey);
|
||||
break;
|
||||
|
||||
case JSON_DATA_NUMBER:
|
||||
ok = HandleNumber(cx, jp, buf, len);
|
||||
ok = HandleNumber(cx, jp, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer));
|
||||
break;
|
||||
|
||||
case JSON_DATA_KEYWORD:
|
||||
ok = HandleKeyword(cx, jp, buf, len);
|
||||
ok = HandleKeyword(cx, jp, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer));
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -783,7 +824,7 @@ js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len
|
|||
} else {
|
||||
jdt = JSON_DATA_STRING;
|
||||
}
|
||||
if (!HandleData(cx, jp, jdt, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer)))
|
||||
if (!HandleData(cx, jp, jdt))
|
||||
return JS_FALSE;
|
||||
} else if (c == '\\') {
|
||||
*jp->statep = JSON_PARSE_STATE_STRING_ESCAPE;
|
||||
|
@ -845,7 +886,7 @@ js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len
|
|||
if (!PopState(jp))
|
||||
return JS_FALSE;
|
||||
|
||||
if (!HandleData(cx, jp, JSON_DATA_KEYWORD, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer)))
|
||||
if (!HandleData(cx, jp, JSON_DATA_KEYWORD))
|
||||
return JS_FALSE;
|
||||
}
|
||||
break;
|
||||
|
@ -858,7 +899,7 @@ js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len
|
|||
i--;
|
||||
if (!PopState(jp))
|
||||
return JS_FALSE;
|
||||
if (!HandleData(cx, jp, JSON_DATA_NUMBER, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer)))
|
||||
if (!HandleData(cx, jp, JSON_DATA_NUMBER))
|
||||
return JS_FALSE;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -88,7 +88,7 @@ struct JSONParser {
|
|||
JSONParserState *statep;
|
||||
JSONParserState stateStack[JSON_MAX_DEPTH];
|
||||
jsval *rootVal;
|
||||
JSString *objectKey;
|
||||
JSStringBuffer *objectKey;
|
||||
JSStringBuffer *buffer;
|
||||
JSObject *objectStack;
|
||||
};
|
||||
|
|
|
@ -749,6 +749,22 @@ js_AppendChar(JSStringBuffer *sb, jschar c)
|
|||
sb->ptr = bp;
|
||||
}
|
||||
|
||||
void
|
||||
js_AppendUCString(JSStringBuffer *sb, const jschar *buf, uintN len)
|
||||
{
|
||||
jschar *bp;
|
||||
|
||||
if (!STRING_BUFFER_OK(sb))
|
||||
return;
|
||||
if (len == 0 || !ENSURE_STRING_BUFFER(sb, len))
|
||||
return;
|
||||
bp = sb->ptr;
|
||||
js_strncpy(bp, buf, len);
|
||||
bp += len;
|
||||
*bp = 0;
|
||||
sb->ptr = bp;
|
||||
}
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
|
||||
void
|
||||
|
@ -786,19 +802,7 @@ js_AppendCString(JSStringBuffer *sb, const char *asciiz)
|
|||
void
|
||||
js_AppendJSString(JSStringBuffer *sb, JSString *str)
|
||||
{
|
||||
size_t length;
|
||||
jschar *bp;
|
||||
|
||||
if (!STRING_BUFFER_OK(sb))
|
||||
return;
|
||||
length = JSSTRING_LENGTH(str);
|
||||
if (length == 0 || !ENSURE_STRING_BUFFER(sb, length))
|
||||
return;
|
||||
bp = sb->ptr;
|
||||
js_strncpy(bp, JSSTRING_CHARS(str), length);
|
||||
bp += length;
|
||||
*bp = 0;
|
||||
sb->ptr = bp;
|
||||
js_AppendUCString(sb, JSSTRING_CHARS(str), JSSTRING_LENGTH(str));
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
|
|
@ -181,6 +181,9 @@ js_RepeatChar(JSStringBuffer *sb, jschar c, uintN count);
|
|||
extern void
|
||||
js_AppendCString(JSStringBuffer *sb, const char *asciiz);
|
||||
|
||||
extern void
|
||||
js_AppendUCString(JSStringBuffer *sb, const jschar *buf, uintN len);
|
||||
|
||||
extern void
|
||||
js_AppendJSString(JSStringBuffer *sb, JSString *str);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче