зеркало из https://github.com/mozilla/pjs.git
Bug 387522. Native JSON support. r=crowder/jst, sr=brendan
This commit is contained in:
Родитель
aaefe7368f
Коммит
8ac060c9a0
|
@ -58,6 +58,7 @@ DIRS = \
|
|||
ls \
|
||||
xul \
|
||||
storage \
|
||||
json \
|
||||
offline
|
||||
|
||||
ifdef MOZ_SVG
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Mozilla Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2007
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Robert Sayre <sayrer@gmail.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = dom
|
||||
XPIDL_MODULE = dom_json
|
||||
GRE_MODULE = 1
|
||||
|
||||
XPIDLSRCS = \
|
||||
nsIJSON.idl \
|
||||
$(NULL)
|
||||
|
||||
SDK_XPIDLSRCS = \
|
||||
nsIJSON.idl \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
|
@ -0,0 +1,66 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2007
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Robert Sayre <sayrer@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "domstubs.idl"
|
||||
|
||||
interface nsIInputStream;
|
||||
interface nsIOutputStream;
|
||||
interface nsIScriptGlobalObject;
|
||||
|
||||
/**
|
||||
* Encode and decode JSON text.
|
||||
*/
|
||||
[scriptable, uuid(45464c36-efde-4cb5-8e00-07480533ff35)]
|
||||
interface nsIJSON : nsISupports
|
||||
{
|
||||
AString encode(/* in JSObject value,
|
||||
/* [optional] in JSObject whitelist */);
|
||||
|
||||
void encodeToStream(in nsIOutputStream stream,
|
||||
in string charset,
|
||||
in boolean writeBOM
|
||||
/* in JSObject value,
|
||||
/* [optional] in JSObject optFilter */);
|
||||
|
||||
void /* JSObject */ decode(in AString str
|
||||
/* , [optional] in JSObject whitelist */);
|
||||
|
||||
void /* JSObject */ decodeFromStream(in nsIInputStream stream,
|
||||
in long contentLength
|
||||
/*[optional] in JSObject optFilter */);
|
||||
};
|
|
@ -42,7 +42,7 @@ VPATH = @srcdir@
|
|||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = base jsurl events storage offline
|
||||
DIRS = base jsurl events storage offline json
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Mozilla Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2007
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Robert Sayre <sayrer@gmail.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = dom
|
||||
LIBRARY_NAME = json_s
|
||||
LIBXUL_LIBRARY = 1
|
||||
|
||||
REQUIRES = xpcom \
|
||||
string \
|
||||
content \
|
||||
caps \
|
||||
js \
|
||||
locale \
|
||||
layout \
|
||||
necko \
|
||||
pref \
|
||||
uconv \
|
||||
unicharutil \
|
||||
widget \
|
||||
xpconnect \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
nsJSON.cpp \
|
||||
$(NULL)
|
||||
|
||||
FORCE_STATIC_LIB = 1
|
||||
|
||||
LOCAL_INCLUDES = \
|
||||
-I$(srcdir)/../base \
|
||||
-I$(topsrcdir)/content/events/src
|
||||
|
||||
DEFINES += -D_IMPL_NS_LAYOUT
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
DIRS += test
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,164 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2007
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Robert Sayre <sayrer@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsJSON_h__
|
||||
#define nsJSON_h__
|
||||
|
||||
#include "jsprvtd.h"
|
||||
#include "nsIJSON.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsIUnicodeEncoder.h"
|
||||
#include "nsIUnicodeDecoder.h"
|
||||
#include "nsIRequestObserver.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#define JSON_MAX_DEPTH 2048
|
||||
#define JSON_PARSER_BUFSIZE 1024
|
||||
class nsJSONWriter
|
||||
{
|
||||
public:
|
||||
nsJSONWriter();
|
||||
nsJSONWriter(nsIOutputStream *aStream);
|
||||
virtual ~nsJSONWriter();
|
||||
nsresult SetCharset(const char *aCharset);
|
||||
nsString mBuffer;
|
||||
nsCOMPtr<nsIOutputStream> mStream;
|
||||
nsresult WriteString(const PRUnichar* aBuffer, PRUint32);
|
||||
nsresult Write(const PRUnichar *aBuffer, PRUint32 aLength);
|
||||
|
||||
protected:
|
||||
nsresult WriteToStream(nsIOutputStream *aStream, nsIUnicodeEncoder *encoder,
|
||||
const PRUnichar *aBuffer, PRUint32 aLength);
|
||||
|
||||
nsCOMPtr<nsIUnicodeEncoder> mEncoder;
|
||||
};
|
||||
|
||||
class nsJSON : public nsIJSON
|
||||
{
|
||||
public:
|
||||
nsJSON();
|
||||
virtual ~nsJSON();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIJSON
|
||||
|
||||
protected:
|
||||
JSBool ToJSON(JSContext *cx, jsval *vp);
|
||||
nsresult EncodeObject(JSContext *cx, jsval *vp, nsJSONWriter *writer,
|
||||
JSObject *whitelist, PRUint32 depth);
|
||||
nsresult EncodeInternal(nsJSONWriter *writer);
|
||||
nsresult DecodeInternal(nsIInputStream *aStream,
|
||||
PRInt32 aContentLength,
|
||||
PRBool aNeedsConverter);
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
NS_NewJSON(nsISupports* aOuter, REFNSIID aIID, void** aResult);
|
||||
|
||||
enum JSONParserState {
|
||||
JSON_PARSE_STATE_INIT,
|
||||
JSON_PARSE_STATE_VALUE,
|
||||
JSON_PARSE_STATE_OBJECT,
|
||||
JSON_PARSE_STATE_OBJECT_PAIR,
|
||||
JSON_PARSE_STATE_OBJECT_IN_PAIR,
|
||||
JSON_PARSE_STATE_ARRAY,
|
||||
JSON_PARSE_STATE_STRING,
|
||||
JSON_PARSE_STATE_STRING_ESCAPE,
|
||||
JSON_PARSE_STATE_STRING_HEX,
|
||||
JSON_PARSE_STATE_NUMBER,
|
||||
JSON_PARSE_STATE_KEYWORD,
|
||||
JSON_PARSE_STATE_FINISHED
|
||||
};
|
||||
|
||||
class nsJSONObjectStack : public nsTArray<JSObject *>,
|
||||
public JSTempValueRooter
|
||||
{
|
||||
};
|
||||
|
||||
class nsJSONListener : public nsIStreamListener
|
||||
{
|
||||
public:
|
||||
nsJSONListener(JSContext *cx, jsval *rootVal, PRBool needsConverter);
|
||||
virtual ~nsJSONListener();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
|
||||
protected:
|
||||
PRUint32 mLineNum;
|
||||
PRUint32 mColumn;
|
||||
|
||||
/* Used while handling \uNNNN in strings */
|
||||
PRUnichar mHexChar;
|
||||
PRUint8 mNumHex;
|
||||
|
||||
JSContext *mCx;
|
||||
jsval *mRootVal;
|
||||
PRBool mNeedsConverter;
|
||||
nsCOMPtr<nsIUnicodeDecoder> mDecoder;
|
||||
JSONParserState *mStatep;
|
||||
JSONParserState mStateStack[JSON_MAX_DEPTH];
|
||||
nsString mStringBuffer;
|
||||
nsCString mSniffBuffer;
|
||||
|
||||
nsresult PushState(JSONParserState state);
|
||||
nsresult PopState();
|
||||
nsresult ProcessBytes(const char* aBuffer, PRUint32 aByteLength);
|
||||
nsresult ConsumeConverted(const char* aBuffer, PRUint32 aByteLength);
|
||||
nsresult Consume(const PRUnichar *data, PRUint32 len);
|
||||
|
||||
// These handle parsed tokens. Could be split to separate interface.
|
||||
nsJSONObjectStack mObjectStack;
|
||||
|
||||
nsresult PushValue(JSObject *aParent, jsval aValue);
|
||||
nsresult PushObject(JSObject *aObj);
|
||||
nsresult OpenObject();
|
||||
nsresult CloseObject();
|
||||
nsresult OpenArray();
|
||||
nsresult CloseArray();
|
||||
nsresult HandleString();
|
||||
nsresult HandleNumber();
|
||||
nsresult HandleKeyword();
|
||||
nsString mObjectKey;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,49 @@
|
|||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Mozilla Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2007
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Robert Sayre <sayrer@gmail.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = json_test
|
||||
|
||||
XPCSHELL_TESTS = unit
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
|
@ -0,0 +1,263 @@
|
|||
/*
|
||||
json2.js
|
||||
2007-11-06
|
||||
|
||||
Public Domain
|
||||
|
||||
See http://www.JSON.org/js.html
|
||||
|
||||
This file creates a global JSON object containing two methods:
|
||||
|
||||
JSON.stringify(value, whitelist)
|
||||
value any JavaScript value, usually an object or array.
|
||||
|
||||
whitelist an optional that determines how object values are
|
||||
stringified.
|
||||
|
||||
This method produces a JSON text from a JavaScript value.
|
||||
There are three possible ways to stringify an object, depending
|
||||
on the optional whitelist parameter.
|
||||
|
||||
If an object has a toJSON method, then the toJSON() method will be
|
||||
called. The value returned from the toJSON method will be
|
||||
stringified.
|
||||
|
||||
Otherwise, if the optional whitelist parameter is an array, then
|
||||
the elements of the array will be used to select members of the
|
||||
object for stringification.
|
||||
|
||||
Otherwise, if there is no whitelist parameter, then all of the
|
||||
members of the object will be stringified.
|
||||
|
||||
Values that do not have JSON representaions, such as undefined or
|
||||
functions, will not be serialized. Such values in objects will be
|
||||
dropped, in arrays will be replaced with null. JSON.stringify()
|
||||
returns undefined. Dates will be stringified as quoted ISO dates.
|
||||
|
||||
Example:
|
||||
|
||||
var text = JSON.stringify(['e', {pluribus: 'unum'}]);
|
||||
// text is '["e",{"pluribus":"unum"}]'
|
||||
|
||||
JSON.parse(text, filter)
|
||||
This method parses a JSON text to produce an object or
|
||||
array. It can throw a SyntaxError exception.
|
||||
|
||||
The optional filter parameter is a function that can filter and
|
||||
transform the results. It receives each of the keys and values, and
|
||||
its return value is used instead of the original value. If it
|
||||
returns what it received, then structure is not modified. If it
|
||||
returns undefined then the member is deleted.
|
||||
|
||||
Example:
|
||||
|
||||
// Parse the text. If a key contains the string 'date' then
|
||||
// convert the value to a date.
|
||||
|
||||
myData = JSON.parse(text, function (key, value) {
|
||||
return key.indexOf('date') >= 0 ? new Date(value) : value;
|
||||
});
|
||||
|
||||
This is a reference implementation. You are free to copy, modify, or
|
||||
redistribute.
|
||||
|
||||
Use your own copy. It is extremely unwise to load third party
|
||||
code into your pages.
|
||||
*/
|
||||
|
||||
/*jslint evil: true */
|
||||
/*extern JSON */
|
||||
|
||||
if (!this.JSON) {
|
||||
|
||||
JSON = function () {
|
||||
|
||||
function f(n) { // Format integers to have at least two digits.
|
||||
return n < 10 ? '0' + n : n;
|
||||
}
|
||||
|
||||
Date.prototype.toJSON = function () {
|
||||
|
||||
// Eventually, this method will be based on the date.toISOString method.
|
||||
|
||||
return this.getUTCFullYear() + '-' +
|
||||
f(this.getUTCMonth() + 1) + '-' +
|
||||
f(this.getUTCDate()) + 'T' +
|
||||
f(this.getUTCHours()) + ':' +
|
||||
f(this.getUTCMinutes()) + ':' +
|
||||
f(this.getUTCSeconds()) + 'Z';
|
||||
};
|
||||
|
||||
|
||||
var m = { // table of character substitutions
|
||||
'\b': '\\b',
|
||||
'\t': '\\t',
|
||||
'\n': '\\n',
|
||||
'\f': '\\f',
|
||||
'\r': '\\r',
|
||||
'"' : '\\"',
|
||||
'\\': '\\\\'
|
||||
};
|
||||
|
||||
function stringify(value, whitelist) {
|
||||
var a, // The array holding the partial texts.
|
||||
i, // The loop counter.
|
||||
k, // The member key.
|
||||
l, // Length.
|
||||
r = /["\\\x00-\x1f\x7f-\x9f]/g,
|
||||
v; // The member value.
|
||||
|
||||
switch (typeof value) {
|
||||
case 'string':
|
||||
|
||||
// If the string contains no control characters, no quote characters, and no
|
||||
// backslash characters, then we can safely slap some quotes around it.
|
||||
// Otherwise we must also replace the offending characters with safe sequences.
|
||||
|
||||
return r.test(value) ?
|
||||
'"' + value.replace(r, function (a) {
|
||||
var c = m[a];
|
||||
if (c) {
|
||||
return c;
|
||||
}
|
||||
c = a.charCodeAt();
|
||||
return '\\u00' + Math.floor(c / 16).toString(16) +
|
||||
(c % 16).toString(16);
|
||||
}) + '"' :
|
||||
'"' + value + '"';
|
||||
|
||||
case 'number':
|
||||
|
||||
// JSON numbers must be finite. Encode non-finite numbers as null.
|
||||
|
||||
return isFinite(value) ? String(value) : 'null';
|
||||
|
||||
case 'boolean':
|
||||
case 'null':
|
||||
return String(value);
|
||||
|
||||
case 'object':
|
||||
|
||||
// Due to a specification blunder in ECMAScript,
|
||||
// typeof null is 'object', so watch out for that case.
|
||||
|
||||
if (!value) {
|
||||
return 'null';
|
||||
}
|
||||
|
||||
// If the object has a toJSON method, call it, and stringify the result.
|
||||
|
||||
if (typeof value.toJSON === 'function') {
|
||||
return stringify(value.toJSON());
|
||||
}
|
||||
a = [];
|
||||
if (typeof value.length === 'number' &&
|
||||
!(value.propertyIsEnumerable('length'))) {
|
||||
|
||||
// The object is an array. Stringify every element. Use null as a placeholder
|
||||
// for non-JSON values.
|
||||
|
||||
l = value.length;
|
||||
for (i = 0; i < l; i += 1) {
|
||||
a.push(stringify(value[i], whitelist) || 'null');
|
||||
}
|
||||
|
||||
// Join all of the elements together and wrap them in brackets.
|
||||
|
||||
return '[' + a.join(',') + ']';
|
||||
}
|
||||
if (whitelist) {
|
||||
|
||||
// If a whitelist (array of keys) is provided, use it to select the components
|
||||
// of the object.
|
||||
|
||||
l = whitelist.length;
|
||||
for (i = 0; i < l; i += 1) {
|
||||
k = whitelist[i];
|
||||
if (typeof k === 'string') {
|
||||
v = stringify(value[k], whitelist);
|
||||
if (v) {
|
||||
a.push(stringify(k) + ':' + v);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
// Otherwise, iterate through all of the keys in the object.
|
||||
|
||||
for (k in value) {
|
||||
if (typeof k === 'string') {
|
||||
v = stringify(value[k], whitelist);
|
||||
if (v) {
|
||||
a.push(stringify(k) + ':' + v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Join all of the member texts together and wrap them in braces.
|
||||
|
||||
return '{' + a.join(',') + '}';
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
stringify: stringify,
|
||||
parse: function (text, filter) {
|
||||
var j;
|
||||
|
||||
function walk(k, v) {
|
||||
var i, n;
|
||||
if (v && typeof v === 'object') {
|
||||
for (i in v) {
|
||||
if (Object.prototype.hasOwnProperty.apply(v, [i])) {
|
||||
n = walk(i, v[i]);
|
||||
if (n !== undefined) {
|
||||
v[i] = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return filter(k, v);
|
||||
}
|
||||
|
||||
|
||||
// Parsing happens in three stages. In the first stage, we run the text against
|
||||
// regular expressions that look for non-JSON patterns. We are especially
|
||||
// concerned with '()' and 'new' because they can cause invocation, and '='
|
||||
// because it can cause mutation. But just to be safe, we want to reject all
|
||||
// unexpected forms.
|
||||
|
||||
// We split the first stage into 4 regexp operations in order to work around
|
||||
// crippling inefficiencies in IE's and Safari's regexp engines. First we
|
||||
// replace all backslash pairs with '@' (a non-JSON character). Second, we
|
||||
// replace all simple value tokens with ']' characters. Third, we delete all
|
||||
// open brackets that follow a colon or comma or that begin the text. Finally,
|
||||
// we look to see that the remaining characters are only whitespace or ']' or
|
||||
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
|
||||
|
||||
if (/^[\],:{}\s]*$/.test(text.replace(/\\./g, '@').
|
||||
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(:?[eE][+\-]?\d+)?/g, ']').
|
||||
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
|
||||
|
||||
// In the second stage we use the eval function to compile the text into a
|
||||
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
|
||||
// in JavaScript: it can begin a block or an object literal. We wrap the text
|
||||
// in parens to eliminate the ambiguity.
|
||||
|
||||
j = eval('(' + text + ')');
|
||||
|
||||
// In the optional third stage, we recursively walk the new structure, passing
|
||||
// each name/value pair to a filter function for possible transformation.
|
||||
|
||||
return typeof filter === 'function' ? walk('', j) : j;
|
||||
}
|
||||
|
||||
// If the text is not JSON parseable, then a SyntaxError is thrown.
|
||||
|
||||
throw new SyntaxError('parseJSON');
|
||||
}
|
||||
};
|
||||
}();
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
[
|
||||
"JSON Test Pattern pass1",
|
||||
{"object with 1 member":["array with 1 element"]},
|
||||
{},
|
||||
[],
|
||||
-42,
|
||||
true,
|
||||
false,
|
||||
null,
|
||||
{
|
||||
"integer": 1234567890,
|
||||
"real": -9876.543210,
|
||||
"e": 0.123456789e-12,
|
||||
"E": 1.234567890E+34,
|
||||
"": 23456789012E66,
|
||||
"zero": 0,
|
||||
"one": 1,
|
||||
"space": " ",
|
||||
"quote": "\"",
|
||||
"backslash": "\\",
|
||||
"controls": "\b\f\n\r\t",
|
||||
"slash": "/ & \/",
|
||||
"alpha": "abcdefghijklmnopqrstuvwyz",
|
||||
"ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
|
||||
"digit": "0123456789",
|
||||
"0123456789": "digit",
|
||||
"special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
|
||||
"hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
|
||||
"true": true,
|
||||
"false": false,
|
||||
"null": null,
|
||||
"array":[ ],
|
||||
"object":{ },
|
||||
"address": "50 St. James Street",
|
||||
"url": "http://www.JSON.org/",
|
||||
"comment": "// /* <!-- --",
|
||||
"# -- --> */": " ",
|
||||
" s p a c e d " :[1,2 , 3
|
||||
|
||||
,
|
||||
|
||||
4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7],
|
||||
"jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
|
||||
"quotes": "" \u0022 %22 0x22 034 "",
|
||||
"\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
|
||||
: "A key can be any string"
|
||||
},
|
||||
0.5 ,98.6
|
||||
,
|
||||
99.44
|
||||
,
|
||||
|
||||
1066,
|
||||
1e1,
|
||||
0.1e1,
|
||||
1e-1,
|
||||
1e00,2e+00,2e-00
|
||||
,"rosebud"]
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"JSON Test Pattern pass3": {
|
||||
"The outermost value": "must be an object or array.",
|
||||
"In this test": "It is an object."
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
var Ci = Components.interfaces;
|
||||
var Cc = Components.classes;
|
||||
|
||||
var nativeJSON = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
|
||||
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
|
||||
var workingDir = dirSvc.get("TmpD", Ci.nsIFile);
|
||||
|
||||
var outputName = "json-test-output";
|
||||
var outputDir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||
outputDir.initWithFile(workingDir);
|
||||
outputDir.append(outputName);
|
||||
|
||||
if (!outputDir.exists()) {
|
||||
outputDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0777);
|
||||
} else if (!outputDir.isDirectory()) {
|
||||
do_throw(outputName + " is not a directory?")
|
||||
}
|
||||
var JSON = null;
|
||||
do_import_script("dom/src/json/test/json2.js");
|
|
@ -0,0 +1,161 @@
|
|||
function decode_strings() {
|
||||
// empty object
|
||||
var x = nativeJSON.decode("{}");
|
||||
do_check_eq(typeof x, "object");
|
||||
|
||||
// empty array
|
||||
x = nativeJSON.decode("[]");
|
||||
do_check_eq(typeof x, "object");
|
||||
do_check_eq(x.length, 0);
|
||||
do_check_eq(x.constructor, Array);
|
||||
|
||||
// one element array
|
||||
x = nativeJSON.decode("[[]]");
|
||||
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 = nativeJSON.decode("[[],[],[]]");
|
||||
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 = nativeJSON.decode('{"foo":[]}');
|
||||
do_check_eq(typeof x, "object");
|
||||
do_check_eq(typeof x.foo, "object");
|
||||
do_check_eq(x.foo.constructor, Array);
|
||||
x = nativeJSON.decode('{"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 = nativeJSON.decode('{"foo":[{}]}');
|
||||
do_check_eq(x.foo.constructor, Array);
|
||||
do_check_eq(x.foo.length, 1);
|
||||
do_check_eq(typeof x.foo[0], "object");
|
||||
x = nativeJSON.decode('{"foo":[{"foo":[{"foo":{}}]}]}');
|
||||
do_check_eq(x.foo[0].foo[0].foo.constructor, Object);
|
||||
x = nativeJSON.decode('{"foo":[{"foo":[{"foo":[]}]}]}');
|
||||
do_check_eq(x.foo[0].foo[0].foo.constructor, Array);
|
||||
|
||||
// strings
|
||||
x = nativeJSON.decode('{"foo":"bar"}');
|
||||
do_check_eq(x.foo, "bar");
|
||||
x = nativeJSON.decode('["foo", "bar", "baz"]');
|
||||
do_check_eq(x[0], "foo");
|
||||
do_check_eq(x[1], "bar");
|
||||
do_check_eq(x[2], "baz");
|
||||
|
||||
// numbers
|
||||
x = nativeJSON.decode('{"foo":5.5, "bar":5}');
|
||||
do_check_eq(x.foo, 5.5);
|
||||
do_check_eq(x.bar, 5);
|
||||
|
||||
// keywords
|
||||
x = nativeJSON.decode('{"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 = nativeJSON.decode('{"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 = nativeJSON.decode('{"foo":"hmm\\u006dmm"}');
|
||||
do_check_eq("hmm\u006dmm", x.foo);
|
||||
|
||||
x = nativeJSON.decode('{"JSON Test Pattern pass3": {"The outermost value": "must be an object or array.","In this test": "It is an object." }}');
|
||||
}
|
||||
|
||||
function test_files() {
|
||||
function read_file(path) {
|
||||
try {
|
||||
var f = do_get_file(path);
|
||||
var istream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
|
||||
istream.init(f, -1, -1, false);
|
||||
var x = nativeJSON.decodeFromStream(istream, istream.available());
|
||||
} finally {
|
||||
istream.close();
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
var x = read_file("/dom/src/json/test/pass3.json");
|
||||
do_check_eq(x["JSON Test Pattern pass3"]["The outermost value"], "must be an object or array.");
|
||||
do_check_eq(x["JSON Test Pattern pass3"]["In this test"], "It is an object.");
|
||||
|
||||
x = read_file("/dom/src/json/test/pass1.json");
|
||||
do_check_eq(x[0], "JSON Test Pattern pass1");
|
||||
do_check_eq(x[1]["object with 1 member"][0], "array with 1 element");
|
||||
do_check_eq(x[2].constructor, Object);
|
||||
do_check_eq(x[3].constructor, Array);
|
||||
do_check_eq(x[4], -42);
|
||||
do_check_eq(x[5], true);
|
||||
do_check_eq(x[6], false);
|
||||
do_check_eq(x[7], null);
|
||||
do_check_eq(x[8].constructor, Object);
|
||||
do_check_eq(x[8]["integer"], 1234567890);
|
||||
do_check_eq(x[8]["real"], -9876.543210);
|
||||
do_check_eq(x[8]["e"], 0.123456789e-12);
|
||||
do_check_eq(x[8]["E"], 1.234567890E+34);
|
||||
do_check_eq(x[8][""], 23456789012E66);
|
||||
do_check_eq(x[8]["zero"], 0);
|
||||
do_check_eq(x[8]["one"], 1);
|
||||
do_check_eq(x[8]["space"], " ");
|
||||
do_check_eq(x[8]["quote"], "\"");
|
||||
do_check_eq(x[8]["backslash"], "\\");
|
||||
do_check_eq(x[8]["controls"], "\b\f\n\r\t");
|
||||
do_check_eq(x[8]["slash"], "/ & /");
|
||||
do_check_eq(x[8]["alpha"], "abcdefghijklmnopqrstuvwyz");
|
||||
do_check_eq(x[8]["ALPHA"], "ABCDEFGHIJKLMNOPQRSTUVWYZ");
|
||||
do_check_eq(x[8]["digit"], "0123456789");
|
||||
do_check_eq(x[8]["0123456789"], "digit");
|
||||
do_check_eq(x[8]["special"], "`1~!@#$%^&*()_+-={':[,]}|;.</>?");
|
||||
do_check_eq(x[8]["hex"], "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A");
|
||||
do_check_eq(x[8]["true"], true);
|
||||
do_check_eq(x[8]["false"], false);
|
||||
do_check_eq(x[8]["null"], null);
|
||||
do_check_eq(x[8]["array"].length, 0);
|
||||
do_check_eq(x[8]["object"].constructor, Object);
|
||||
do_check_eq(x[8]["address"], "50 St. James Street");
|
||||
do_check_eq(x[8]["url"], "http://www.JSON.org/");
|
||||
do_check_eq(x[8]["comment"], "// /* <!-- --");
|
||||
do_check_eq(x[8]["# -- --> */"], " ");
|
||||
do_check_eq(x[8][" s p a c e d "].length, 7);
|
||||
do_check_eq(x[8]["compact"].length, 7);
|
||||
do_check_eq(x[8]["jsontext"], "{\"object with 1 member\":[\"array with 1 element\"]}");
|
||||
do_check_eq(x[8]["quotes"], "" \u0022 %22 0x22 034 "");
|
||||
do_check_eq(x[8]["\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"], "A key can be any string");
|
||||
do_check_eq(x[9], 0.5);
|
||||
do_check_eq(x[10], 98.6);
|
||||
do_check_eq(x[11], 99.44);
|
||||
do_check_eq(x[12], 1066);
|
||||
do_check_eq(x[13], 1e1);
|
||||
do_check_eq(x[14], 0.1e1);
|
||||
do_check_eq(x[15], 1e-1);
|
||||
do_check_eq(x[16], 1e00);
|
||||
do_check_eq(x[17], 2e+00);
|
||||
do_check_eq(x[18], 2e-00);
|
||||
do_check_eq(x[19], "rosebud");
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
decode_strings();
|
||||
test_files();
|
||||
}
|
|
@ -0,0 +1,237 @@
|
|||
// 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]}],
|
||||
//['{"0":"h","1":"m","2":"m"}', new String("hmm")],
|
||||
['[1,null,3]',[1,,3]],
|
||||
[null, function test(){}],
|
||||
[null, dump],
|
||||
['{"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]);
|
||||
|
||||
// useless roots will be dropped
|
||||
testPairs.push([null, null]);
|
||||
testPairs.push([null, ""]);
|
||||
testPairs.push([null, undefined]);
|
||||
testPairs.push([null, 5]);
|
||||
|
||||
// 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"}', nativeJSON.encode(x));
|
||||
|
||||
return testPairs;
|
||||
}
|
||||
|
||||
function testStringEncode() {
|
||||
// test empty arg
|
||||
do_check_eq(null, nativeJSON.encode());
|
||||
|
||||
var pairs = getTestPairs();
|
||||
for each(pair in pairs) {
|
||||
var nativeResult = nativeJSON.encode(pair[1]);
|
||||
var crockfordResult = JSON.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 testOutputStreams() {
|
||||
function writeToFile(obj, charset, writeBOM) {
|
||||
var jsonFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||
jsonFile.initWithFile(outputDir);
|
||||
jsonFile.append("test.json");
|
||||
jsonFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
|
||||
var stream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
|
||||
try {
|
||||
stream.init(jsonFile, 0x04 | 0x08 | 0x20, 0600, 0); // write, create, truncate
|
||||
nativeJSON.encodeToStream(stream, charset, writeBOM, obj);
|
||||
} finally {
|
||||
stream.close();
|
||||
}
|
||||
return jsonFile;
|
||||
}
|
||||
|
||||
var pairs = getTestPairs();
|
||||
for each(pair in pairs) {
|
||||
if (pair[1] && (typeof pair[1] == "object")) {
|
||||
var utf8File = writeToFile(pair[1], "UTF-8", false);
|
||||
var utf16LEFile = writeToFile(pair[1], "UTF-16LE", false);
|
||||
var utf16BEFile = writeToFile(pair[1], "UTF-16BE", false);
|
||||
var utf32LEFile = writeToFile(pair[1], "UTF-32LE", false);
|
||||
var utf32BEFile = writeToFile(pair[1], "UTF-32BE", false);
|
||||
|
||||
// all ascii with no BOMs, so this will work
|
||||
do_check_eq(utf16LEFile.fileSize / 2, utf8File.fileSize);
|
||||
do_check_eq(utf32LEFile.fileSize / 4, utf8File.fileSize);
|
||||
do_check_eq(utf16LEFile.fileSize, utf16BEFile.fileSize);
|
||||
do_check_eq(utf32LEFile.fileSize, utf32BEFile.fileSize);
|
||||
}
|
||||
}
|
||||
|
||||
// check BOMs
|
||||
var f = writeToFile({},"UTF-8", true);
|
||||
do_check_eq(f.fileSize, 5);
|
||||
var f = writeToFile({},"UTF-16LE", true);
|
||||
do_check_eq(f.fileSize, 6);
|
||||
var f = writeToFile({},"UTF-16BE", true);
|
||||
do_check_eq(f.fileSize, 6);
|
||||
var f = writeToFile({},"UTF-32LE", true);
|
||||
do_check_eq(f.fileSize, 12);
|
||||
var f = writeToFile({},"UTF-32BE", true);
|
||||
do_check_eq(f.fileSize, 12);
|
||||
|
||||
outputDir.remove(true);
|
||||
}
|
||||
|
||||
function throwingToJSON() {
|
||||
var a = {
|
||||
"b": 1,
|
||||
"c": 2,
|
||||
toJSON: function() { throw("uh oh"); }
|
||||
}
|
||||
try {
|
||||
var y = nativeJSON.encode(a);
|
||||
} catch (ex) {}
|
||||
}
|
||||
|
||||
function throwingIterator() {
|
||||
var a = {
|
||||
"b": 1,
|
||||
"c": 2,
|
||||
__iterator__: function() { yield "b"; throw("uh oh"); }
|
||||
}
|
||||
try {
|
||||
var y = nativeJSON.encode(a);
|
||||
} catch (ex) {}
|
||||
}
|
||||
|
||||
function deletingIter(x) {
|
||||
return function() {
|
||||
yield "dd";
|
||||
print("after first yield");
|
||||
delete x["a"]["c"];
|
||||
gc();
|
||||
print("about to yield second");
|
||||
yield "ddddd";
|
||||
}
|
||||
}
|
||||
|
||||
function deleteDuringEncode() {
|
||||
var x = {};
|
||||
x.a = {
|
||||
b: 1,
|
||||
bb: 2,
|
||||
bbb: 3,
|
||||
c: {
|
||||
cc: 2,
|
||||
ccc: 3,
|
||||
d: {
|
||||
dd: 2,
|
||||
ddd: 3,
|
||||
__iterator__: deletingIter(x),
|
||||
dddd: 4,
|
||||
ddddd: 5
|
||||
},
|
||||
cccc: 4,
|
||||
ccccc: 5
|
||||
},
|
||||
bbbb: 4,
|
||||
bbbbb: 5,
|
||||
bbbbbb: 6
|
||||
};
|
||||
var z = nativeJSON.encode(x);
|
||||
print(z);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
testStringEncode();
|
||||
testOutputStreams();
|
||||
throwingToJSON();
|
||||
throwingIterator();
|
||||
deleteDuringEncode();
|
||||
}
|
|
@ -136,6 +136,7 @@ EXPORTS = \
|
|||
jsdate.h \
|
||||
jsdbgapi.h \
|
||||
jsdhash.h \
|
||||
jsdtoa.h \
|
||||
jsemit.h \
|
||||
jsfun.h \
|
||||
jsgc.h \
|
||||
|
|
|
@ -328,7 +328,7 @@ js_GetNativeIteratorFlags(JSContext *cx, JSObject *iterobj)
|
|||
* Call ToObject(v).__iterator__(keyonly) if ToObject(v).__iterator__ exists.
|
||||
* Otherwise construct the defualt iterator.
|
||||
*/
|
||||
JSBool
|
||||
JS_FRIEND_API(JSBool)
|
||||
js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp)
|
||||
{
|
||||
JSObject *obj;
|
||||
|
@ -439,7 +439,7 @@ js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp)
|
|||
goto out;
|
||||
}
|
||||
|
||||
JSBool
|
||||
JS_FRIEND_API(JSBool)
|
||||
js_CloseIterator(JSContext *cx, jsval v)
|
||||
{
|
||||
JSObject *obj;
|
||||
|
@ -593,7 +593,7 @@ CallEnumeratorNext(JSContext *cx, JSObject *iterobj, uintN flags, jsval *rval)
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSBool
|
||||
JS_FRIEND_API(JSBool)
|
||||
js_CallIteratorNext(JSContext *cx, JSObject *iterobj, jsval *rval)
|
||||
{
|
||||
uintN flags;
|
||||
|
|
|
@ -58,17 +58,17 @@ JS_BEGIN_EXTERN_C
|
|||
* for-in semantics are required, and when the caller can guarantee that the
|
||||
* iterator will never be exposed to scripts.
|
||||
*/
|
||||
extern JSBool
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp);
|
||||
|
||||
extern JSBool
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
js_CloseIterator(JSContext *cx, jsval v);
|
||||
|
||||
/*
|
||||
* Given iterobj, call iterobj.next(). If the iterator stopped, set *rval to
|
||||
* JSVAL_HOLE. Otherwise set it to the result of the next call.
|
||||
*/
|
||||
extern JSBool
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
js_CallIteratorNext(JSContext *cx, JSObject *iterobj, jsval *rval);
|
||||
|
||||
/*
|
||||
|
|
|
@ -141,6 +141,7 @@ SHARED_LIBRARY_LIBS = \
|
|||
$(DEPTH)/view/src/$(LIB_PREFIX)gkview_s.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/dom/src/base/$(LIB_PREFIX)jsdombase_s.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/dom/src/events/$(LIB_PREFIX)jsdomevents_s.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/dom/src/json/$(LIB_PREFIX)json_s.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/dom/src/jsurl/$(LIB_PREFIX)jsurl_s.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/dom/src/storage/$(LIB_PREFIX)jsdomstorage_s.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/dom/src/offline/$(LIB_PREFIX)jsdomoffline_s.$(LIB_SUFFIX) \
|
||||
|
@ -277,6 +278,7 @@ LOCAL_INCLUDES += -I$(srcdir)/../base \
|
|||
-I$(topsrcdir)/content/xbl/src \
|
||||
-I$(topsrcdir)/view/src \
|
||||
-I$(topsrcdir)/dom/src/base \
|
||||
-I$(topsrcdir)/dom/src/json \
|
||||
-I$(topsrcdir)/dom/src/jsurl \
|
||||
-I$(topsrcdir)/dom/src/storage \
|
||||
-I$(topsrcdir)/dom/src/offline \
|
||||
|
|
|
@ -222,4 +222,7 @@
|
|||
#define NS_XULPOPUPMANAGER_CID \
|
||||
{ 0x14632191, 0xac21, 0x4bdf, { 0x83, 0xe7, 0x23, 0x63, 0xad, 0x17, 0xe8, 0x38 } }
|
||||
|
||||
// {93ad72a6-02cd-4716-9626-d47d5ec275ec}
|
||||
#define NS_DOMJSON_CID \
|
||||
{ 0x93ad72a6, 0x02cd, 0x4716, { 0x96, 0x26, 0xd4, 0x7d, 0x5e, 0xc2, 0x75, 0xec } }
|
||||
#endif /* nsLayoutCID_h__ */
|
||||
|
|
|
@ -125,6 +125,7 @@
|
|||
#include "nsIControllerContext.h"
|
||||
#include "nsDOMScriptObjectFactory.h"
|
||||
#include "nsDOMStorage.h"
|
||||
#include "nsJSON.h"
|
||||
|
||||
// Editor stuff
|
||||
#include "nsEditorCID.h"
|
||||
|
@ -1321,6 +1322,11 @@ static const nsModuleComponentInfo gComponents[] = {
|
|||
"@mozilla.org/dom/storagemanager;1",
|
||||
nsDOMStorageManagerConstructor },
|
||||
|
||||
{ "DOM JSON",
|
||||
NS_DOMJSON_CID,
|
||||
"@mozilla.org/dom/json;1",
|
||||
NS_NewJSON },
|
||||
|
||||
{ "Text Editor",
|
||||
NS_TEXTEDITOR_CID,
|
||||
"@mozilla.org/editor/texteditor;1",
|
||||
|
|
|
@ -463,34 +463,8 @@ static nsresult GetCharsetFromData(const unsigned char* aStyleSheetData,
|
|||
step = 1;
|
||||
pos = 0;
|
||||
}
|
||||
else if (aStyleSheetData[0] == 0xEF &&
|
||||
aStyleSheetData[1] == 0xBB &&
|
||||
aStyleSheetData[2] == 0xBF) {
|
||||
// UTF-8 BOM
|
||||
step = 1;
|
||||
pos = 3;
|
||||
aCharset = "UTF-8";
|
||||
}
|
||||
// Check for a 4-byte encoding BOM before checking for a 2-byte one,
|
||||
// since the latter can be a proper subset of the former.
|
||||
else if (aStyleSheetData[0] == 0x00 &&
|
||||
aStyleSheetData[1] == 0x00 &&
|
||||
aStyleSheetData[2] == 0xFE &&
|
||||
aStyleSheetData[3] == 0xFF) {
|
||||
// big-endian 4-byte encoding BOM
|
||||
step = 4;
|
||||
pos = 7;
|
||||
aCharset = "UTF-32BE";
|
||||
}
|
||||
else if (aStyleSheetData[0] == 0xFF &&
|
||||
aStyleSheetData[1] == 0xFE &&
|
||||
aStyleSheetData[2] == 0x00 &&
|
||||
aStyleSheetData[3] == 0x00) {
|
||||
// little-endian 4-byte encoding BOM
|
||||
step = 4;
|
||||
pos = 4;
|
||||
aCharset = "UTF-32LE";
|
||||
}
|
||||
else if (aStyleSheetData[0] == 0x00 &&
|
||||
aStyleSheetData[1] == 0x00 &&
|
||||
aStyleSheetData[2] == 0xFF &&
|
||||
|
@ -511,17 +485,28 @@ static nsresult GetCharsetFromData(const unsigned char* aStyleSheetData,
|
|||
pos = 5;
|
||||
aCharset = "UTF-32";
|
||||
}
|
||||
else if (aStyleSheetData[0] == 0xFE && aStyleSheetData[1] == 0xFF) {
|
||||
// big-endian 2-byte encoding BOM
|
||||
else if (nsContentUtils::CheckForBOM(aStyleSheetData,
|
||||
aDataLength, aCharset)) {
|
||||
if (aCharset.Equals("UTF-8")) {
|
||||
step = 1;
|
||||
pos = 3;
|
||||
}
|
||||
else if (aCharset.Equals("UTF-32BE")) {
|
||||
step = 4;
|
||||
pos = 7;
|
||||
}
|
||||
else if (aCharset.Equals("UTF-32LE")) {
|
||||
step = 4;
|
||||
pos = 4;
|
||||
}
|
||||
else if (aCharset.Equals("UTF-16BE")) {
|
||||
step = 2;
|
||||
pos = 3;
|
||||
aCharset = "UTF-16BE";
|
||||
}
|
||||
else if (aStyleSheetData[0] == 0xFF && aStyleSheetData[1] == 0xFE) {
|
||||
// little-endian 2-byte encoding BOM
|
||||
else if (aCharset.Equals("UTF-16LE")) {
|
||||
step = 2;
|
||||
pos = 2;
|
||||
aCharset = "UTF-16LE";
|
||||
}
|
||||
}
|
||||
else if (aStyleSheetData[0] == 0x00 &&
|
||||
aStyleSheetData[1] == 0x00 &&
|
||||
|
|
|
@ -111,7 +111,7 @@ done
|
|||
for t in $testdir/test_*.js
|
||||
do
|
||||
echo -n "$t: "
|
||||
NATIVE_TOPSRCDIR="$native_topsrcdir" TOPSRCDIR="$topsrcdir" $xpcshell -s $headfiles -f $t $tailfiles 2> $t.log 1>&2
|
||||
NATIVE_TOPSRCDIR="$native_topsrcdir" TOPSRCDIR="$topsrcdir" $xpcshell -v 180 -s $headfiles -f $t $tailfiles 2> $t.log 1>&2
|
||||
rv="$?"
|
||||
if [ ! "$rv" = "0" -o \
|
||||
`grep -c '\*\*\* PASS' $t.log` = 0 ]
|
||||
|
|
Загрузка…
Ссылка в новой задаче