comparison bindings/as3/ext/com/adobe/serialization/json/JSONDecoder.as @ 732:3a0b9700b3d2

* Initial AS3 commit
author mas01mj
date Tue, 14 Sep 2010 16:47:10 +0000
parents
children
comparison
equal deleted inserted replaced
731:65134dd772fc 732:3a0b9700b3d2
1 /*
2 Copyright (c) 2008, Adobe Systems Incorporated
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8
9 * Redistributions of source code must retain the above copyright notice,
10 this list of conditions and the following disclaimer.
11
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15
16 * Neither the name of Adobe Systems Incorporated nor the names of its
17 contributors may be used to endorse or promote products derived from
18 this software without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 package com.adobe.serialization.json
34 {
35
36 public class JSONDecoder
37 {
38
39 /**
40 * Flag indicating if the parser should be strict about the format
41 * of the JSON string it is attempting to decode.
42 */
43 private var strict:Boolean;
44
45 /** The value that will get parsed from the JSON string */
46 private var value:*;
47
48 /** The tokenizer designated to read the JSON string */
49 private var tokenizer:JSONTokenizer;
50
51 /** The current token from the tokenizer */
52 private var token:JSONToken;
53
54 /**
55 * Constructs a new JSONDecoder to parse a JSON string
56 * into a native object.
57 *
58 * @param s The JSON string to be converted
59 * into a native object
60 * @param strict Flag indicating if the JSON string needs to
61 * strictly match the JSON standard or not.
62 * @langversion ActionScript 3.0
63 * @playerversion Flash 9.0
64 * @tiptext
65 */
66 public function JSONDecoder( s:String, strict:Boolean )
67 {
68 this.strict = strict;
69 tokenizer = new JSONTokenizer( s, strict );
70
71 nextToken();
72 value = parseValue();
73
74 // Make sure the input stream is empty
75 if ( strict && nextToken() != null )
76 {
77 tokenizer.parseError( "Unexpected characters left in input stream" );
78 }
79 }
80
81 /**
82 * Gets the internal object that was created by parsing
83 * the JSON string passed to the constructor.
84 *
85 * @return The internal object representation of the JSON
86 * string that was passed to the constructor
87 * @langversion ActionScript 3.0
88 * @playerversion Flash 9.0
89 * @tiptext
90 */
91 public function getValue():*
92 {
93 return value;
94 }
95
96 /**
97 * Returns the next token from the tokenzier reading
98 * the JSON string
99 */
100 private function nextToken():JSONToken
101 {
102 return token = tokenizer.getNextToken();
103 }
104
105 /**
106 * Attempt to parse an array.
107 */
108 private function parseArray():Array
109 {
110 // create an array internally that we're going to attempt
111 // to parse from the tokenizer
112 var a:Array = new Array();
113
114 // grab the next token from the tokenizer to move
115 // past the opening [
116 nextToken();
117
118 // check to see if we have an empty array
119 if ( token.type == JSONTokenType.RIGHT_BRACKET )
120 {
121 // we're done reading the array, so return it
122 return a;
123 }
124 // in non-strict mode an empty array is also a comma
125 // followed by a right bracket
126 else if ( !strict && token.type == JSONTokenType.COMMA )
127 {
128 // move past the comma
129 nextToken();
130
131 // check to see if we're reached the end of the array
132 if ( token.type == JSONTokenType.RIGHT_BRACKET )
133 {
134 return a;
135 }
136 else
137 {
138 tokenizer.parseError( "Leading commas are not supported. Expecting ']' but found " + token.value );
139 }
140 }
141
142 // deal with elements of the array, and use an "infinite"
143 // loop because we could have any amount of elements
144 while ( true )
145 {
146 // read in the value and add it to the array
147 a.push( parseValue() );
148
149 // after the value there should be a ] or a ,
150 nextToken();
151
152 if ( token.type == JSONTokenType.RIGHT_BRACKET )
153 {
154 // we're done reading the array, so return it
155 return a;
156 }
157 else if ( token.type == JSONTokenType.COMMA )
158 {
159 // move past the comma and read another value
160 nextToken();
161
162 // Allow arrays to have a comma after the last element
163 // if the decoder is not in strict mode
164 if ( !strict )
165 {
166 // Reached ",]" as the end of the array, so return it
167 if ( token.type == JSONTokenType.RIGHT_BRACKET )
168 {
169 return a;
170 }
171 }
172 }
173 else
174 {
175 tokenizer.parseError( "Expecting ] or , but found " + token.value );
176 }
177 }
178 return null;
179 }
180
181 /**
182 * Attempt to parse an object.
183 */
184 private function parseObject():Object
185 {
186 // create the object internally that we're going to
187 // attempt to parse from the tokenizer
188 var o:Object = new Object();
189
190 // store the string part of an object member so
191 // that we can assign it a value in the object
192 var key:String
193
194 // grab the next token from the tokenizer
195 nextToken();
196
197 // check to see if we have an empty object
198 if ( token.type == JSONTokenType.RIGHT_BRACE )
199 {
200 // we're done reading the object, so return it
201 return o;
202 }
203 // in non-strict mode an empty object is also a comma
204 // followed by a right bracket
205 else if ( !strict && token.type == JSONTokenType.COMMA )
206 {
207 // move past the comma
208 nextToken();
209
210 // check to see if we're reached the end of the object
211 if ( token.type == JSONTokenType.RIGHT_BRACE )
212 {
213 return o;
214 }
215 else
216 {
217 tokenizer.parseError( "Leading commas are not supported. Expecting '}' but found " + token.value );
218 }
219 }
220
221 // deal with members of the object, and use an "infinite"
222 // loop because we could have any amount of members
223 while ( true )
224 {
225 if ( token.type == JSONTokenType.STRING )
226 {
227 // the string value we read is the key for the object
228 key = String( token.value );
229
230 // move past the string to see what's next
231 nextToken();
232
233 // after the string there should be a :
234 if ( token.type == JSONTokenType.COLON )
235 {
236 // move past the : and read/assign a value for the key
237 nextToken();
238 o[key] = parseValue();
239
240 // move past the value to see what's next
241 nextToken();
242
243 // after the value there's either a } or a ,
244 if ( token.type == JSONTokenType.RIGHT_BRACE )
245 {
246 // we're done reading the object, so return it
247 return o;
248 }
249 else if ( token.type == JSONTokenType.COMMA )
250 {
251 // skip past the comma and read another member
252 nextToken();
253
254 // Allow objects to have a comma after the last member
255 // if the decoder is not in strict mode
256 if ( !strict )
257 {
258 // Reached ",}" as the end of the object, so return it
259 if ( token.type == JSONTokenType.RIGHT_BRACE )
260 {
261 return o;
262 }
263 }
264 }
265 else
266 {
267 tokenizer.parseError( "Expecting } or , but found " + token.value );
268 }
269 }
270 else
271 {
272 tokenizer.parseError( "Expecting : but found " + token.value );
273 }
274 }
275 else
276 {
277 tokenizer.parseError( "Expecting string but found " + token.value );
278 }
279 }
280 return null;
281 }
282
283 /**
284 * Attempt to parse a value
285 */
286 private function parseValue():Object
287 {
288 // Catch errors when the input stream ends abruptly
289 if ( token == null )
290 {
291 tokenizer.parseError( "Unexpected end of input" );
292 }
293
294 switch ( token.type )
295 {
296 case JSONTokenType.LEFT_BRACE:
297 return parseObject();
298
299 case JSONTokenType.LEFT_BRACKET:
300 return parseArray();
301
302 case JSONTokenType.STRING:
303 case JSONTokenType.NUMBER:
304 case JSONTokenType.TRUE:
305 case JSONTokenType.FALSE:
306 case JSONTokenType.NULL:
307 return token.value;
308
309 case JSONTokenType.NAN:
310 if ( !strict )
311 {
312 return token.value;
313 }
314 else
315 {
316 tokenizer.parseError( "Unexpected " + token.value );
317 }
318
319 default:
320 tokenizer.parseError( "Unexpected " + token.value );
321
322 }
323
324 return null;
325 }
326 }
327 }