Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(709)

Side by Side Diff: chrome/browser/resources/access_chromevox/common/chromevox_json.js

Issue 6254007: Adding ChromeVox as a component extensions (enabled only for ChromeOS, for no... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:executable
+ *
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 goog.provide('cvox.ChromeVoxJSON');
6
7 /**
8 * @fileoverview A simple wrapper around the JSON APIs.
9 * If it is possible to use the browser's built in native JSON, then
10 * cvox.ChromeVoxJSON is the same as JSON.
11 * If the page has its own version of JSON, cvox.ChromeVoxJSON will use its
12 * own implementation (rather than the version of JSON on the page
13 * which may be outdated/broken).
14 */
15
16 if (!cvox.ChromeVoxJSON) {
17 /**
18 * @type {Object}
19 */
20 cvox.ChromeVoxJSON = {};
21 }
22
23 if (JSON.toString() == '[object JSON]') {
24 cvox.ChromeVoxJSON = JSON;
25 } else {
26 /*
27 * JSON implementation renamed to cvox.ChromeVoxJSON.
28 * This only gets called if the page has its own version of JSON.
29 *
30 * Based on:
31 * http://www.JSON.org/json2.js
32 * 2010-03-20
33 *
34 * Public Domain.
35 *
36 * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
37 *
38 * See http://www.JSON.org/js.html
39 */
40 (function() {
41 function f(n) {
42 // Format integers to have at least two digits.
43 return n < 10 ? '0' + n : n;
44 }
45
46 if (typeof Date.prototype.toJSON !== 'function') {
47
48 Date.prototype.toJSON = function(key) {
49
50 return isFinite(this.valueOf()) ?
51 this.getUTCFullYear() + '-' +
52 f(this.getUTCMonth() + 1) + '-' +
53 f(this.getUTCDate()) + 'T' +
54 f(this.getUTCHours()) + ':' +
55 f(this.getUTCMinutes()) + ':' +
56 f(this.getUTCSeconds()) + 'Z' : 'null';
57 };
58
59 String.prototype.toJSON =
60 Number.prototype.toJSON =
61 Boolean.prototype.toJSON = function(key) {
62 return this.valueOf();
63 };
64 }
65
66 var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u 202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
67 escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b 5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
68 gap,
69 indent,
70 meta = { // table of character substitutions
71 '\b': '\\b',
72 '\t': '\\t',
73 '\n': '\\n',
74 '\f': '\\f',
75 '\r': '\\r',
76 '"' : '\\"',
77 '\\': '\\\\'
78 },
79 rep;
80
81
82 function quote(string) {
83
84 // If the string contains no control characters, no quote characters, and
85 // no backslash characters, then we can safely slap some quotes around it.
86 // Otherwise we must also replace the offending characters with safe
87 // escape sequences.
88
89 escapable.lastIndex = 0;
90 return escapable.test(string) ?
91 '"' + string.replace(escapable, function(a) {
92 var c = meta[a];
93 return typeof c === 'string' ? c :
94 '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
95 }) + '"' :
96 '"' + string + '"';
97 }
98
99
100 function str(key, holder) {
101
102 // Produce a string from holder[key].
103
104 var i, // The loop counter.
105 k, // The member key.
106 v, // The member value.
107 length,
108 mind = gap,
109 partial,
110 value = holder[key];
111
112 // If the value has a toJSON method, call it to obtain a replacement
113 // value.
114
115 if (value && typeof value === 'object' &&
116 typeof value.toJSON === 'function') {
117 value = value.toJSON(key);
118 }
119
120 // If we were called with a replacer function, then call the replacer to
121 // obtain a replacement value.
122
123 if (typeof rep === 'function') {
124 value = rep.call(holder, key, value);
125 }
126
127 // What happens next depends on the value's type.
128
129 switch (typeof value) {
130 case 'string':
131 return quote(value);
132
133 case 'number':
134 // JSON numbers must be finite. Encode non-finite numbers as null.
135 return isFinite(value) ? String(value) : 'null';
136
137 case 'boolean':
138 case 'null':
139 // If the value is a boolean or null, convert it to a string. Note:
140 // typeof null does not produce 'null'. The case is included here in
141 // the remote chance that this gets fixed someday.
142 return String(value);
143
144 // If the type is 'object', we might be dealing with an object or an
145 // array or null.
146
147 case 'object':
148
149 // Due to a specification blunder in ECMAScript, typeof null is
150 // 'object', so watch out for that case.
151
152 if (!value) {
153 return 'null';
154 }
155
156 // Make an array to hold the partial results of stringifying this
157 // object value.
158
159 gap += indent;
160 partial = [];
161
162 // Is the value an array?
163
164 if (Object.prototype.toString.apply(value) === '[object Array]') {
165
166 // The value is an array. Stringify every element. Use null as a
167 // placeholder for non-JSON values.
168
169 length = value.length;
170 for (i = 0; i < length; i += 1) {
171 partial[i] = str(i, value) || 'null';
172 }
173
174 // Join all of the elements together, separated with commas, and
175 // wrap them in brackets.
176
177 v = partial.length === 0 ? '[]' :
178 gap ? '[\n' + gap +
179 partial.join(',\n' + gap) + '\n' +
180 mind + ']' :
181 '[' + partial.join(',') + ']';
182 gap = mind;
183 return v;
184 }
185
186 // If the replacer is an array, use it to select the members to be
187 // stringified.
188
189 if (rep && typeof rep === 'object') {
190 length = rep.length;
191 for (i = 0; i < length; i += 1) {
192 k = rep[i];
193 if (typeof k === 'string') {
194 v = str(k, value);
195 if (v) {
196 partial.push(quote(k) + (gap ? ': ' : ':') + v);
197 }
198 }
199 }
200 } else {
201
202 // Otherwise, iterate through all of the keys in the object.
203 for (k in value) {
204 if (Object.hasOwnProperty.call(value, k)) {
205 v = str(k, value);
206 if (v) {
207 partial.push(quote(k) + (gap ? ': ' : ':') + v);
208 }
209 }
210 }
211 }
212
213 // Join all of the member texts together, separated with commas,
214 // and wrap them in braces.
215
216 v = partial.length === 0 ? '{}' :
217 gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
218 mind + '}' : '{' + partial.join(',') + '}';
219 gap = mind;
220 return v;
221 }
222 }
223
224 // If the JSON object does not yet have a stringify method, give it one.
225
226 if (typeof cvox.ChromeVoxJSON.stringify !== 'function') {
227 cvox.ChromeVoxJSON.stringify = function(value, replacer, space) {
228
229 // The stringify method takes a value and an optional replacer, and an
230 // optional space parameter, and returns a JSON text. The replacer can
231 // be a function that can replace values, or an array of strings that
232 // will select the keys. A default replacer method can be provided. Use
233 // of the space parameter can produce text that is more easily readable.
234
235 var i;
236 gap = '';
237 indent = '';
238
239 // If the space parameter is a number, make an indent string containing
240 // that many spaces.
241
242 if (typeof space === 'number') {
243 for (i = 0; i < space; i += 1) {
244 indent += ' ';
245 }
246
247 // If the space parameter is a string, it will be used as the indent
248 // string.
249
250 } else if (typeof space === 'string') {
251 indent = space;
252 }
253
254 // If there is a replacer, it must be a function or an array.
255 // Otherwise, throw an error.
256
257 rep = replacer;
258 if (replacer && typeof replacer !== 'function' &&
259 (typeof replacer !== 'object' ||
260 typeof replacer.length !== 'number')) {
261 throw new Error('JSON.stringify');
262 }
263
264 // Make a fake root object containing our value under the key of ''.
265 // Return the result of stringifying the value.
266
267 return str('', {'': value});
268 };
269 }
270
271
272 // If the JSON object does not yet have a parse method, give it one.
273
274 if (typeof cvox.ChromeVoxJSON.parse !== 'function') {
275 cvox.ChromeVoxJSON.parse = function(text, reviver) {
276
277 // The parse method takes a text and an optional reviver function, and
278 // returns a JavaScript value if the text is a valid JSON text.
279
280 var j;
281
282 function walk(holder, key) {
283
284 // The walk method is used to recursively walk the resulting structure
285 // so that modifications can be made.
286
287 var k, v, value = holder[key];
288 if (value && typeof value === 'object') {
289 for (k in value) {
290 if (Object.hasOwnProperty.call(value, k)) {
291 v = walk(value, k);
292 if (v !== undefined) {
293 value[k] = v;
294 } else {
295 delete value[k];
296 }
297 }
298 }
299 }
300 return reviver.call(holder, key, value);
301 }
302
303
304 // Parsing happens in four stages. In the first stage, we replace
305 // certain Unicode characters with escape sequences. JavaScript handles
306 // many characters incorrectly, either silently deleting them, or
307 // treating them as line endings.
308
309 text = String(text);
310 cx.lastIndex = 0;
311 if (cx.test(text)) {
312 text = text.replace(cx, function(a) {
313 return '\\u' +
314 ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
315 });
316 }
317
318 // In the second stage, we run the text against regular expressions that
319 // look for non-JSON patterns. We are especially concerned with '()' and
320 // 'new' because they can cause invocation, and '=' because it can cause
321 // mutation. But just to be safe, we want to reject all unexpected
322 // forms.
323 // We split the second stage into 4 regexp operations in order to work
324 // around crippling inefficiencies in IE's and Safari's regexp engines.
325 // First we replace the JSON backslash pairs with '@' (a non-JSON
326 // character). Second, we replace all simple value tokens with ']'
327 // characters. Third, we delete all open brackets that follow a colon or
328 // comma or that begin the text. Finally, we look to see that the
329 // remaining characters are only whitespace or ']' or ',' or ':' or '{'
330 // or '}'. If that is so, then the text is safe for eval.
331
332 if (/^[\],:{}\s]*$/.
333 test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
334 replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)? /g, ']').
335 replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
336
337 // In the third stage we use the eval function to compile the text
338 // into a JavaScript structure. The '{' operator is subject to a
339 // syntactic ambiguity in JavaScript: it can begin a block or an
340 // object literal. We wrap the text in parens to eliminate the
341 // ambiguity.
342
343 j = eval('(' + text + ')');
344
345 // In the optional fourth stage, we recursively walk the new
346 // structure, passing each name/value pair to a reviver function for
347 // possible transformation.
348 return typeof reviver === 'function' ? walk({'': j}, '') : j;
349 }
350
351 // If the text is not JSON parseable, then a SyntaxError is thrown.
352
353 throw new SyntaxError('JSON.parse');
354 };
355 }
356 }());
357 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698