• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2009 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28var $JSON = global.JSON;
29
30function ParseJSONUnfiltered(text) {
31  var s = $String(text);
32  var f = %CompileString(text, true);
33  return f();
34}
35
36function Revive(holder, name, reviver) {
37  var val = holder[name];
38  if (IS_OBJECT(val)) {
39    if (IS_ARRAY(val)) {
40      var length = val.length;
41      for (var i = 0; i < length; i++) {
42        var newElement = Revive(val, $String(i), reviver);
43        val[i] = newElement;
44      }
45    } else {
46      for (var p in val) {
47        if (ObjectHasOwnProperty.call(val, p)) {
48          var newElement = Revive(val, p, reviver);
49          if (IS_UNDEFINED(newElement)) {
50            delete val[p];
51          } else {
52            val[p] = newElement;
53          }
54        }
55      }
56    }
57  }
58  return reviver.call(holder, name, val);
59}
60
61function JSONParse(text, reviver) {
62  var unfiltered = ParseJSONUnfiltered(text);
63  if (IS_FUNCTION(reviver)) {
64    return Revive({'': unfiltered}, '', reviver);
65  } else {
66    return unfiltered;
67  }
68}
69
70var characterQuoteCache = {
71  '\"': '\\"',
72  '\\': '\\\\',
73  '/': '\\/',
74  '\b': '\\b',
75  '\f': '\\f',
76  '\n': '\\n',
77  '\r': '\\r',
78  '\t': '\\t',
79  '\x0B': '\\u000b'
80};
81
82function QuoteSingleJSONCharacter(c) {
83  if (c in characterQuoteCache) {
84    return characterQuoteCache[c];
85  }
86  var charCode = c.charCodeAt(0);
87  var result;
88  if (charCode < 16) result = '\\u000';
89  else if (charCode < 256) result = '\\u00';
90  else if (charCode < 4096) result = '\\u0';
91  else result = '\\u';
92  result += charCode.toString(16);
93  characterQuoteCache[c] = result;
94  return result;
95}
96
97function QuoteJSONString(str) {
98  var quotable = /[\\\"\x00-\x1f\x80-\uffff]/g;
99  return '"' + str.replace(quotable, QuoteSingleJSONCharacter) + '"';
100}
101
102function StackContains(stack, val) {
103  var length = stack.length;
104  for (var i = 0; i < length; i++) {
105    if (stack[i] === val) {
106      return true;
107    }
108  }
109  return false;
110}
111
112function SerializeArray(value, replacer, stack, indent, gap) {
113  if (StackContains(stack, value)) {
114    throw MakeTypeError('circular_structure', []);
115  }
116  stack.push(value);
117  var stepback = indent;
118  indent += gap;
119  var partial = [];
120  var len = value.length;
121  for (var i = 0; i < len; i++) {
122    var strP = JSONSerialize($String(i), value, replacer, stack,
123                             indent, gap);
124    if (IS_UNDEFINED(strP)) {
125      strP = "null";
126    }
127    partial.push(strP);
128  }
129  var final;
130  if (gap == "") {
131    final = "[" + partial.join(",") + "]";
132  } else if (partial.length > 0) {
133    var separator = ",\n" + indent;
134    final = "[\n" + indent + partial.join(separator) + "\n" +
135        stepback + "]";
136  } else {
137    final = "[]";
138  }
139  stack.pop();
140  return final;
141}
142
143function SerializeObject(value, replacer, stack, indent, gap) {
144  if (StackContains(stack, value)) {
145    throw MakeTypeError('circular_structure', []);
146  }
147  stack.push(value);
148  var stepback = indent;
149  indent += gap;
150  var partial = [];
151  if (IS_ARRAY(replacer)) {
152    var length = replacer.length;
153    for (var i = 0; i < length; i++) {
154      if (ObjectHasOwnProperty.call(replacer, i)) {
155        var p = replacer[i];
156        var strP = JSONSerialize(p, value, replacer, stack, indent, gap);
157        if (!IS_UNDEFINED(strP)) {
158          var member = QuoteJSONString(p) + ":";
159          if (gap != "") member += " ";
160          member += strP;
161          partial.push(member);
162        }
163      }
164    }
165  } else {
166    for (var p in value) {
167      if (ObjectHasOwnProperty.call(value, p)) {
168        var strP = JSONSerialize(p, value, replacer, stack, indent, gap);
169        if (!IS_UNDEFINED(strP)) {
170          var member = QuoteJSONString(p) + ":";
171          if (gap != "") member += " ";
172          member += strP;
173          partial.push(member);
174        }
175      }
176    }
177  }
178  var final;
179  if (gap == "") {
180    final = "{" + partial.join(",") + "}";
181  } else if (partial.length > 0) {
182    var separator = ",\n" + indent;
183    final = "{\n" + indent + partial.join(separator) + "\n" +
184        stepback + "}";
185  } else {
186    final = "{}";
187  }
188  stack.pop();
189  return final;
190}
191
192function JSONSerialize(key, holder, replacer, stack, indent, gap) {
193  var value = holder[key];
194  if (IS_OBJECT(value) && value) {
195    var toJSON = value.toJSON;
196    if (IS_FUNCTION(toJSON)) {
197      value = toJSON.call(value, key);
198    }
199  }
200  if (IS_FUNCTION(replacer)) {
201    value = replacer.call(holder, key, value);
202  }
203  // Unwrap value if necessary
204  if (IS_OBJECT(value)) {
205    if (IS_NUMBER_WRAPPER(value)) {
206      value = $Number(value);
207    } else if (IS_STRING_WRAPPER(value)) {
208      value = $String(value);
209    } else if (IS_BOOLEAN_WRAPPER(value)) {
210      value = $Boolean(value);
211    }
212  }
213  switch (typeof value) {
214    case "string":
215      return QuoteJSONString(value);
216    case "object":
217      if (!value) {
218        return "null";
219      } else if (IS_ARRAY(value)) {
220        return SerializeArray(value, replacer, stack, indent, gap);
221      } else {
222        return SerializeObject(value, replacer, stack, indent, gap);
223      }
224    case "number":
225      return $isFinite(value) ? $String(value) : "null";
226    case "boolean":
227      return value ? "true" : "false";
228  }
229}
230
231function JSONStringify(value, replacer, space) {
232  var stack = [];
233  var indent = "";
234  if (IS_OBJECT(space)) {
235    // Unwrap 'space' if it is wrapped
236    if (IS_NUMBER_WRAPPER(space)) {
237      space = $Number(space);
238    } else if (IS_STRING_WRAPPER(space)) {
239      space = $String(space);
240    }
241  }
242  var gap;
243  if (IS_NUMBER(space)) {
244    space = $Math.min(space, 10);
245    gap = "";
246    for (var i = 0; i < space; i++) {
247      gap += " ";
248    }
249  } else if (IS_STRING(space)) {
250    if (space.length > 10) {
251      gap = space.substring(0, 10);
252    } else {
253      gap = space;
254    }
255  } else {
256    gap = "";
257  }
258  return JSONSerialize('', {'': value}, replacer, stack, indent, gap);
259}
260
261function SetupJSON() {
262  InstallFunctions($JSON, DONT_ENUM, $Array(
263    "parse", JSONParse,
264    "stringify", JSONStringify
265  ));
266}
267
268SetupJSON();
269