1 | /*
|
---|
2 |
|
---|
3 | Licence
|
---|
4 |
|
---|
5 | Copyright (c) 2005 JSON.org
|
---|
6 |
|
---|
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
|
---|
8 | of this software and associated documentation files (the "Software"), to deal
|
---|
9 | in the Software without restriction, including without limitation the rights
|
---|
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
---|
11 | copies of the Software, and to permit persons to whom the Software is
|
---|
12 | furnished to do so, subject to the following conditions:
|
---|
13 |
|
---|
14 | The Software shall be used for Good, not Evil.
|
---|
15 |
|
---|
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
---|
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
---|
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
---|
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
---|
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
---|
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
---|
22 | SOFTWARE.
|
---|
23 |
|
---|
24 | Contributor(s) :
|
---|
25 |
|
---|
26 | - Ported to Actionscript May 2005 by Trannie Carter <tranniec@designvox.com>, wwww.designvox.com
|
---|
27 |
|
---|
28 | - Alcaraz Marc (aka eKameleon) 2006-01-24 <vegas@ekameleon.net>
|
---|
29 |
|
---|
30 | - Refactoring AS2 and MTASC Compatibilty
|
---|
31 |
|
---|
32 | - Add Hexa Digits in 'deserialize' method -
|
---|
33 |
|
---|
34 | NOTE : EDEN Hexa digits code inspiration -> http://www.burrrn.com/projects/eden.html
|
---|
35 |
|
---|
36 | */
|
---|
37 |
|
---|
38 | /* JSON
|
---|
39 |
|
---|
40 | AUTHOR
|
---|
41 |
|
---|
42 | Name : JSON
|
---|
43 | Package : vegas.string
|
---|
44 | Version : 1.0.0.0
|
---|
45 | Date : 2006-07-09
|
---|
46 | Author : ekameleon
|
---|
47 | URL : http://www.ekameleon.net
|
---|
48 | Mail : vegas@ekameleon.net
|
---|
49 |
|
---|
50 | DESCRIPTION
|
---|
51 |
|
---|
52 | JSON (JavaScript object Notation) is a lightweight data-interchange format.
|
---|
53 |
|
---|
54 | Serializer & deserializer in AS2.
|
---|
55 |
|
---|
56 | MORE INFORMATION IN : http://www.json.org/
|
---|
57 |
|
---|
58 | ADD HEXA DIGITS in deserialize method - EDEN inspiration : http://www.burrrn.com/projects/eden.html
|
---|
59 |
|
---|
60 | METHOD SUMMARY
|
---|
61 |
|
---|
62 | - static deserialize(source:String):*
|
---|
63 |
|
---|
64 | - static serialize(o:*):String
|
---|
65 |
|
---|
66 | EXAMPLE
|
---|
67 |
|
---|
68 | import vegas.string.JSON ;
|
---|
69 |
|
---|
70 | // --- Init
|
---|
71 | var a:Array = [2, true, "hello"] ;
|
---|
72 | var o:Object = { prop1 : 1 , prop2 : 2 } ;
|
---|
73 | var s:String = "hello world" ;
|
---|
74 | var n:Number = 4 ;
|
---|
75 | var b:Boolean = true ;
|
---|
76 |
|
---|
77 | trace ("*** Serialize") ;
|
---|
78 | trace("* a : " + JSON.serialize( a ) ) ;
|
---|
79 | trace("* o : " + JSON.serialize( o ) ) ;
|
---|
80 | trace("* s : " + JSON.serialize( s ) ) ;
|
---|
81 | trace("* n : " + JSON.serialize( n ) ) ;
|
---|
82 | trace("* b : " + JSON.serialize( b ) ) ;
|
---|
83 |
|
---|
84 | trace ("*** Deserialize") ;
|
---|
85 |
|
---|
86 | var source:String = '[ {"prop1":0xFF0000, "prop2":2, "prop3":"hello", "prop4":true} , 2, true, 3, [3, 2] ]' ;
|
---|
87 |
|
---|
88 | import vegas.util.ClassUtil ;
|
---|
89 |
|
---|
90 | var result:* = JSON.deserialize(source) ;
|
---|
91 | for (var prop:String in result)
|
---|
92 | {
|
---|
93 | trace(prop + " : " + result[prop] + " -> " + ClassUtil.getPath(result[prop])) ;
|
---|
94 | }
|
---|
95 |
|
---|
96 | trace ("*** JSONError") ;
|
---|
97 |
|
---|
98 | var source:String = "[3, 2," ; // test1
|
---|
99 | //var source:String = '{"prop1":coucou"}' ; // test2
|
---|
100 | var o = JSON.deserialize(source) ;
|
---|
101 | for (var prop:String in o) {
|
---|
102 | trace(prop + " : " + o[prop]) ;
|
---|
103 | }
|
---|
104 |
|
---|
105 |
|
---|
106 | Revision: 2008-07-24 DZ - Added allowing numbers with scientific notation
|
---|
107 | Revision: 2008-09-05 DZ - Allow comma before final brace/bracket of objects/arrays
|
---|
108 |
|
---|
109 | **/
|
---|
110 |
|
---|
111 | // TODO REFACTORING PLEASE - type and co... !!!!!!
|
---|
112 |
|
---|
113 | package com.serialization.json
|
---|
114 | {
|
---|
115 |
|
---|
116 | public class JSON
|
---|
117 | {
|
---|
118 |
|
---|
119 | // ----o Public Methods
|
---|
120 |
|
---|
121 | static public function deserialize(source:String):* {
|
---|
122 |
|
---|
123 | source = new String(source) ; // Speed
|
---|
124 | var at:Number = 0 ;
|
---|
125 | var ch:String = ' ';
|
---|
126 |
|
---|
127 | var _isDigit:Function ;
|
---|
128 | var _isHexDigit:Function ;
|
---|
129 | var _white:Function ;
|
---|
130 | var _string:Function ;
|
---|
131 | var _next:Function ;
|
---|
132 | var _array:Function ;
|
---|
133 | var _object:Function ;
|
---|
134 | var _number:Function ;
|
---|
135 | var _word:Function ;
|
---|
136 | var _value:Function ;
|
---|
137 | var _error:Function ;
|
---|
138 |
|
---|
139 | _isDigit = function( /*Char*/ c:String ):* {
|
---|
140 | return( ("0" <= c) && (c <= "9") );
|
---|
141 | } ;
|
---|
142 |
|
---|
143 | _isHexDigit = function( /*Char*/ c:String ):* {
|
---|
144 | return( _isDigit( c ) || (("A" <= c) && (c <= "F")) || (("a" <= c) && (c <= "f")) );
|
---|
145 | } ;
|
---|
146 |
|
---|
147 | _error = function(m:String):void {
|
---|
148 | //throw new JSONError( m, at - 1 , source) ;
|
---|
149 | throw new Error(m, at-1);
|
---|
150 | } ;
|
---|
151 |
|
---|
152 | _next = function():* {
|
---|
153 | ch = source.charAt(at);
|
---|
154 | at += 1;
|
---|
155 | return ch;
|
---|
156 | } ;
|
---|
157 |
|
---|
158 | _white = function ():void {
|
---|
159 | while (ch) {
|
---|
160 | if (ch <= ' ') {
|
---|
161 | _next();
|
---|
162 | } else if (ch == '/') {
|
---|
163 | switch (_next()) {
|
---|
164 | case '/':
|
---|
165 | while (_next() && ch != '\n' && ch != '\r') {}
|
---|
166 | break;
|
---|
167 | case '*':
|
---|
168 | _next();
|
---|
169 | for (;;) {
|
---|
170 | if (ch) {
|
---|
171 | if (ch == '*') {
|
---|
172 | if (_next() == '/') {
|
---|
173 | _next();
|
---|
174 | break;
|
---|
175 | }
|
---|
176 | } else {
|
---|
177 | _next();
|
---|
178 | }
|
---|
179 | } else {
|
---|
180 | _error("Unterminated Comment");
|
---|
181 | }
|
---|
182 | }
|
---|
183 | break;
|
---|
184 | default:
|
---|
185 | _error("Syntax Error");
|
---|
186 | }
|
---|
187 | } else {
|
---|
188 | break;
|
---|
189 | }
|
---|
190 | }
|
---|
191 | };
|
---|
192 |
|
---|
193 | _string = function ():* {
|
---|
194 |
|
---|
195 | var i:* = '' ;
|
---|
196 | var s:* = '' ;
|
---|
197 | var t:* ;
|
---|
198 | var u:* ;
|
---|
199 | var outer:Boolean = false;
|
---|
200 |
|
---|
201 | if (ch == '"') {
|
---|
202 |
|
---|
203 | while (_next()) {
|
---|
204 | if (ch == '"')
|
---|
205 | {
|
---|
206 | _next();
|
---|
207 | return s;
|
---|
208 | }
|
---|
209 | else if (ch == '\\')
|
---|
210 | {
|
---|
211 | switch (_next()) {
|
---|
212 | case 'b':
|
---|
213 | s += '\b';
|
---|
214 | break;
|
---|
215 | case 'f':
|
---|
216 | s += '\f';
|
---|
217 | break;
|
---|
218 | case 'n':
|
---|
219 | s += '\n';
|
---|
220 | break;
|
---|
221 | case 'r':
|
---|
222 | s += '\r';
|
---|
223 | break;
|
---|
224 | case 't':
|
---|
225 | s += '\t';
|
---|
226 | break;
|
---|
227 | case 'u':
|
---|
228 | u = 0;
|
---|
229 | for (i = 0; i < 4; i += 1) {
|
---|
230 | t = parseInt(_next(), 16);
|
---|
231 | if (!isFinite(t)) {
|
---|
232 | outer = true;
|
---|
233 | break;
|
---|
234 | }
|
---|
235 | u = u * 16 + t;
|
---|
236 | }
|
---|
237 | if(outer) {
|
---|
238 | outer = false;
|
---|
239 | break;
|
---|
240 | }
|
---|
241 | s += String.fromCharCode(u);
|
---|
242 | break;
|
---|
243 | default:
|
---|
244 | s += ch;
|
---|
245 | }
|
---|
246 | } else {
|
---|
247 | s += ch;
|
---|
248 | }
|
---|
249 | }
|
---|
250 | }
|
---|
251 | _error("Bad String");
|
---|
252 | return null ;
|
---|
253 | } ;
|
---|
254 |
|
---|
255 | _array = function():* {
|
---|
256 | var a:Array = [];
|
---|
257 | if (ch == '[') {
|
---|
258 | _next();
|
---|
259 | _white();
|
---|
260 | if (ch == ']') {
|
---|
261 | _next();
|
---|
262 | return a;
|
---|
263 | }
|
---|
264 | while (ch) {
|
---|
265 | a.push(_value());
|
---|
266 | _white();
|
---|
267 | if (ch == ']') {
|
---|
268 | _next();
|
---|
269 | return a;
|
---|
270 | } else if (ch != ',') {
|
---|
271 | break;
|
---|
272 | }
|
---|
273 | _next();
|
---|
274 | _white();
|
---|
275 | // Allow for an extra comma before ending bracket
|
---|
276 | if (ch == ']') {
|
---|
277 | _next();
|
---|
278 | return a;
|
---|
279 | }
|
---|
280 | }
|
---|
281 | }
|
---|
282 | _error("Bad Array");
|
---|
283 | return null ;
|
---|
284 | };
|
---|
285 |
|
---|
286 | _object = function ():* {
|
---|
287 | var k:* = {} ;
|
---|
288 | var o:* = {} ;
|
---|
289 | if (ch == '{') {
|
---|
290 |
|
---|
291 | _next();
|
---|
292 |
|
---|
293 | _white();
|
---|
294 |
|
---|
295 | if (ch == '}')
|
---|
296 | {
|
---|
297 | _next() ;
|
---|
298 | return o ;
|
---|
299 | }
|
---|
300 |
|
---|
301 | while (ch)
|
---|
302 | {
|
---|
303 | k = _string();
|
---|
304 | _white();
|
---|
305 | if (ch != ':')
|
---|
306 | {
|
---|
307 | break;
|
---|
308 | }
|
---|
309 | _next();
|
---|
310 | o[k] = _value();
|
---|
311 | _white();
|
---|
312 | if (ch == '}') {
|
---|
313 | _next();
|
---|
314 | return o;
|
---|
315 | } else if (ch != ',') {
|
---|
316 | break;
|
---|
317 | }
|
---|
318 | _next();
|
---|
319 | _white();
|
---|
320 | // Allow for an extra comma before ending brace
|
---|
321 | if (ch == '}') {
|
---|
322 | _next();
|
---|
323 | return o;
|
---|
324 | }
|
---|
325 | }
|
---|
326 | }
|
---|
327 | _error("Bad Object") ;
|
---|
328 | };
|
---|
329 |
|
---|
330 | _number = function ():* {
|
---|
331 |
|
---|
332 | var n:* = '' ;
|
---|
333 | var e:* = '' ;
|
---|
334 | var v:* ;
|
---|
335 | var exp:* ;
|
---|
336 | var hex:String = '' ;
|
---|
337 | var sign:String = '' ;
|
---|
338 |
|
---|
339 | if (ch == '-') {
|
---|
340 | n = '-';
|
---|
341 | sign = n ;
|
---|
342 | _next();
|
---|
343 | }
|
---|
344 |
|
---|
345 | if( ch == "0" ) {
|
---|
346 | _next() ;
|
---|
347 | if( ( ch == "x") || ( ch == "X") ) {
|
---|
348 | _next();
|
---|
349 | while( _isHexDigit( ch ) ) {
|
---|
350 | hex += ch ;
|
---|
351 | _next();
|
---|
352 | }
|
---|
353 | if( hex == "" ) {
|
---|
354 | _error("mal formed Hexadecimal") ;
|
---|
355 | } else {
|
---|
356 | return Number( sign + "0x" + hex ) ;
|
---|
357 | }
|
---|
358 | } else {
|
---|
359 | n += "0" ;
|
---|
360 | }
|
---|
361 | }
|
---|
362 |
|
---|
363 | while ( _isDigit(ch) ) {
|
---|
364 | n += ch;
|
---|
365 | _next();
|
---|
366 | }
|
---|
367 | if (ch == '.') {
|
---|
368 | n += '.';
|
---|
369 | while (_next() && ch >= '0' && ch <= '9') {
|
---|
370 | n += ch;
|
---|
371 | }
|
---|
372 | }
|
---|
373 | v = 1 * n ;
|
---|
374 | if (!isFinite(v)) {
|
---|
375 | _error("Bad Number");
|
---|
376 | } else {
|
---|
377 | if ((ch == 'e') || (ch == 'E'))
|
---|
378 | {
|
---|
379 | // Continue processing exponent
|
---|
380 | _next();
|
---|
381 | var expSign:int = (ch == '-') ? -1 : 1;
|
---|
382 | // allow for a digit without a + sign
|
---|
383 | if ((ch == '+') || (ch == '-'))
|
---|
384 | {
|
---|
385 | _next();
|
---|
386 | }
|
---|
387 | if (_isDigit(ch))
|
---|
388 | {
|
---|
389 | e += ch;
|
---|
390 | }
|
---|
391 | else
|
---|
392 | {
|
---|
393 | _error("Bad Exponent");
|
---|
394 | }
|
---|
395 | while (_next() && ch >= '0' && ch <= '9')
|
---|
396 | {
|
---|
397 | e += ch;
|
---|
398 | }
|
---|
399 | exp = expSign * e;
|
---|
400 | if (!isFinite(v))
|
---|
401 | {
|
---|
402 | _error("Bad Exponent");
|
---|
403 | }
|
---|
404 | else
|
---|
405 | {
|
---|
406 | v = v * Math.pow(10, exp);
|
---|
407 | //trace("JSON._number - have exponent: n=" + n + " e=" + e + " v=" + v);
|
---|
408 | }
|
---|
409 | }
|
---|
410 | return v;
|
---|
411 | }
|
---|
412 |
|
---|
413 | return NaN ;
|
---|
414 |
|
---|
415 | };
|
---|
416 |
|
---|
417 | _word = function ():* {
|
---|
418 | switch (ch) {
|
---|
419 | case 't':
|
---|
420 | if (_next() == 'r' && _next() == 'u' && _next() == 'e') {
|
---|
421 | _next();
|
---|
422 | return true;
|
---|
423 | }
|
---|
424 | break;
|
---|
425 | case 'f':
|
---|
426 | if (_next() == 'a' && _next() == 'l' && _next() == 's' && _next() == 'e') {
|
---|
427 | _next();
|
---|
428 | return false;
|
---|
429 | }
|
---|
430 | break;
|
---|
431 | case 'n':
|
---|
432 | if (_next() == 'u' && _next() == 'l' && _next() == 'l') {
|
---|
433 | _next();
|
---|
434 | return null;
|
---|
435 | }
|
---|
436 | break;
|
---|
437 | }
|
---|
438 | _error("Syntax Error");
|
---|
439 | return null ;
|
---|
440 | };
|
---|
441 |
|
---|
442 | _value = function ():* {
|
---|
443 | _white();
|
---|
444 | switch (ch) {
|
---|
445 | case '{':
|
---|
446 | return _object();
|
---|
447 | case '[':
|
---|
448 | return _array();
|
---|
449 | case '"':
|
---|
450 | return _string();
|
---|
451 | case '-':
|
---|
452 | return _number();
|
---|
453 | default:
|
---|
454 | return ch >= '0' && ch <= '9' ? _number() : _word();
|
---|
455 | }
|
---|
456 | };
|
---|
457 |
|
---|
458 | return _value() ;
|
---|
459 |
|
---|
460 | }
|
---|
461 |
|
---|
462 | static public function serialize(o:*):String {
|
---|
463 |
|
---|
464 | var c:String ; // char
|
---|
465 | var i:Number ;
|
---|
466 | var l:Number ;
|
---|
467 | var s:String = '' ;
|
---|
468 | var v:* ;
|
---|
469 |
|
---|
470 | switch (typeof o)
|
---|
471 | {
|
---|
472 |
|
---|
473 | case 'object' :
|
---|
474 |
|
---|
475 | if (o)
|
---|
476 | {
|
---|
477 | if (o is Array)
|
---|
478 | {
|
---|
479 |
|
---|
480 | l = o.length ;
|
---|
481 |
|
---|
482 | for (i = 0 ; i < l ; ++i)
|
---|
483 | {
|
---|
484 | v = serialize(o[i]);
|
---|
485 | if (s) s += ',' ;
|
---|
486 | s += v ;
|
---|
487 | }
|
---|
488 | return '[' + s + ']';
|
---|
489 |
|
---|
490 | }
|
---|
491 | else if (typeof(o.toString) != 'undefined')
|
---|
492 | {
|
---|
493 |
|
---|
494 | for (var prop:String in o)
|
---|
495 | {
|
---|
496 | v = o[prop];
|
---|
497 | if ( (typeof(v) != 'undefined') && (typeof(v) != 'function') )
|
---|
498 | {
|
---|
499 | v = serialize(v);
|
---|
500 | if (s) s += ',';
|
---|
501 | s += serialize(prop) + ':' + v ;
|
---|
502 | }
|
---|
503 | }
|
---|
504 | return "{" + s + "}";
|
---|
505 | }
|
---|
506 | }
|
---|
507 | return 'null';
|
---|
508 |
|
---|
509 | case 'number':
|
---|
510 |
|
---|
511 | return isFinite(o) ? String(o) : 'null' ;
|
---|
512 |
|
---|
513 | case 'string' :
|
---|
514 |
|
---|
515 | l = o.length ;
|
---|
516 | s = '"';
|
---|
517 | for (i = 0 ; i < l ; i += 1) {
|
---|
518 | c = o.charAt(i);
|
---|
519 | if (c >= ' ') {
|
---|
520 | if (c == '\\' || c == '"')
|
---|
521 | {
|
---|
522 | s += '\\';
|
---|
523 | }
|
---|
524 | s += c;
|
---|
525 | }
|
---|
526 | else
|
---|
527 | {
|
---|
528 | switch (c)
|
---|
529 | {
|
---|
530 |
|
---|
531 | case '\b':
|
---|
532 | s += '\\b';
|
---|
533 | break;
|
---|
534 | case '\f':
|
---|
535 | s += '\\f';
|
---|
536 | break;
|
---|
537 | case '\n':
|
---|
538 | s += '\\n';
|
---|
539 | break;
|
---|
540 | case '\r':
|
---|
541 | s += '\\r';
|
---|
542 | break;
|
---|
543 | case '\t':
|
---|
544 | s += '\\t';
|
---|
545 | break;
|
---|
546 | default:
|
---|
547 | var code:Number = c.charCodeAt() ;
|
---|
548 | s += '\\u00' + (Math.floor(code / 16).toString(16)) + ((code % 16).toString(16)) ;
|
---|
549 | }
|
---|
550 | }
|
---|
551 | }
|
---|
552 | return s + '"';
|
---|
553 |
|
---|
554 | case 'boolean':
|
---|
555 | return String(o);
|
---|
556 |
|
---|
557 | default:
|
---|
558 | return 'null';
|
---|
559 |
|
---|
560 | }
|
---|
561 | }
|
---|
562 | }
|
---|
563 | }
|
---|