PageRenderTime 17ms CodeModel.GetById 1ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 1ms

/src/com/google/maps/extras/arcgislink/json/JSONDecoder.as

http://gmaps-utility-library-flash.googlecode.com/
ActionScript | 329 lines | 171 code | 38 blank | 120 comment | 45 complexity | d7aeebbaf93b530404585b70443f9962 MD5 | raw file
  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//http://code.google.com/p/as3corelib/
 34//package com.adobe.serialization.json
 35package com.google.maps.extras.arcgislink.json
 36{
 37	
 38	public class JSONDecoder
 39	{	
 40	
 41		/** 
 42		 * Flag indicating if the parser should be strict about the format
 43		 * of the JSON string it is attempting to decode.
 44		 */
 45		private var strict:Boolean;
 46		
 47		/** The value that will get parsed from the JSON string */
 48		private var value:*;
 49		
 50		/** The tokenizer designated to read the JSON string */
 51		private var tokenizer:JSONTokenizer;
 52		
 53		/** The current token from the tokenizer */
 54		private var token:JSONToken;
 55		
 56		/**
 57		 * Constructs a new JSONDecoder to parse a JSON string 
 58		 * into a native object.
 59		 *
 60		 * @param s The JSON string to be converted
 61		 *		into a native object
 62		 * @param strict Flag indicating if the JSON string needs to
 63		 * 		strictly match the JSON standard or not.
 64		 * @langversion ActionScript 3.0
 65		 * @playerversion Flash 9.0
 66		 * @tiptext
 67		 */
 68		public function JSONDecoder( s:String, strict:Boolean )
 69		{	
 70			this.strict = strict;
 71			tokenizer = new JSONTokenizer( s, strict );
 72			
 73			nextToken();
 74			value = parseValue();
 75			
 76			// Make sure the input stream is empty
 77			if ( strict && nextToken() != null )
 78			{
 79				tokenizer.parseError( "Unexpected characters left in input stream" );
 80			}
 81		}
 82		
 83		/**
 84		 * Gets the internal object that was created by parsing
 85		 * the JSON string passed to the constructor.
 86		 *
 87		 * @return The internal object representation of the JSON
 88		 * 		string that was passed to the constructor
 89		 * @langversion ActionScript 3.0
 90		 * @playerversion Flash 9.0
 91		 * @tiptext
 92		 */
 93		public function getValue():*
 94		{
 95			return value;
 96		}
 97		
 98		/**
 99		 * Returns the next token from the tokenzier reading
100		 * the JSON string
101		 */
102		private function nextToken():JSONToken
103		{
104			return token = tokenizer.getNextToken();
105		}
106		
107		/**
108		 * Attempt to parse an array.
109		 */
110		private function parseArray():Array
111		{
112			// create an array internally that we're going to attempt
113			// to parse from the tokenizer
114			var a:Array = new Array();
115			
116			// grab the next token from the tokenizer to move
117			// past the opening [
118			nextToken();
119			
120			// check to see if we have an empty array
121			if ( token.type == JSONTokenType.RIGHT_BRACKET )
122			{
123				// we're done reading the array, so return it
124				return a;
125			}
126			// in non-strict mode an empty array is also a comma
127			// followed by a right bracket
128			else if ( !strict && token.type == JSONTokenType.COMMA )
129			{
130				// move past the comma
131				nextToken();
132				
133				// check to see if we're reached the end of the array
134				if ( token.type == JSONTokenType.RIGHT_BRACKET )
135				{
136					return a;	
137				}
138				else
139				{
140					tokenizer.parseError( "Leading commas are not supported.  Expecting ']' but found " + token.value );
141				}
142			}
143			
144			// deal with elements of the array, and use an "infinite"
145			// loop because we could have any amount of elements
146			while ( true )
147			{
148				// read in the value and add it to the array
149				a.push( parseValue() );
150			
151				// after the value there should be a ] or a ,
152				nextToken();
153				
154				if ( token.type == JSONTokenType.RIGHT_BRACKET )
155				{
156					// we're done reading the array, so return it
157					return a;
158				}
159				else if ( token.type == JSONTokenType.COMMA )
160				{
161					// move past the comma and read another value
162					nextToken();
163					
164					// Allow arrays to have a comma after the last element
165					// if the decoder is not in strict mode
166					if ( !strict )
167					{
168						// Reached ",]" as the end of the array, so return it
169						if ( token.type == JSONTokenType.RIGHT_BRACKET )
170						{
171							return a;
172						}
173					}
174				}
175				else
176				{
177					tokenizer.parseError( "Expecting ] or , but found " + token.value );
178				}
179			}
180            return null;
181		}
182		
183		/**
184		 * Attempt to parse an object.
185		 */
186		private function parseObject():Object
187		{
188			// create the object internally that we're going to
189			// attempt to parse from the tokenizer
190			var o:Object = new OrderedObject();//NL: changed  new Object();
191						
192			// store the string part of an object member so
193			// that we can assign it a value in the object
194			var key:String
195			
196			// grab the next token from the tokenizer
197			nextToken();
198			
199			// check to see if we have an empty object
200			if ( token.type == JSONTokenType.RIGHT_BRACE )
201			{
202				// we're done reading the object, so return it
203				return o;
204			}
205			// in non-strict mode an empty object is also a comma
206			// followed by a right bracket
207			else if ( !strict && token.type == JSONTokenType.COMMA )
208			{
209				// move past the comma
210				nextToken();
211				
212				// check to see if we're reached the end of the object
213				if ( token.type == JSONTokenType.RIGHT_BRACE )
214				{
215					return o;
216				}
217				else
218				{
219					tokenizer.parseError( "Leading commas are not supported.  Expecting '}' but found " + token.value );
220				}
221			}
222			
223			// deal with members of the object, and use an "infinite"
224			// loop because we could have any amount of members
225			while ( true )
226			{
227				if ( token.type == JSONTokenType.STRING )
228				{
229					// the string value we read is the key for the object
230					key = String( token.value );
231					
232					// move past the string to see what's next
233					nextToken();
234					
235					// after the string there should be a :
236					if ( token.type == JSONTokenType.COLON )
237					{	
238						// move past the : and read/assign a value for the key
239						nextToken();
240						o[key] = parseValue();	
241						
242						// move past the value to see what's next
243						nextToken();
244						
245						// after the value there's either a } or a ,
246						if ( token.type == JSONTokenType.RIGHT_BRACE )
247						{
248							// we're done reading the object, so return it
249							return o;	
250						}
251						else if ( token.type == JSONTokenType.COMMA )
252						{
253							// skip past the comma and read another member
254							nextToken();
255							
256							// Allow objects to have a comma after the last member
257							// if the decoder is not in strict mode
258							if ( !strict )
259							{
260								// Reached ",}" as the end of the object, so return it
261								if ( token.type == JSONTokenType.RIGHT_BRACE )
262								{
263									return o;
264								}
265							}
266						}
267						else
268						{
269							tokenizer.parseError( "Expecting } or , but found " + token.value );
270						}
271					}
272					else
273					{
274						tokenizer.parseError( "Expecting : but found " + token.value );
275					}
276				}
277				else
278				{	
279					tokenizer.parseError( "Expecting string but found " + token.value );
280				}
281			}
282            return null;
283		}
284		
285		/**
286		 * Attempt to parse a value
287		 */
288		private function parseValue():Object
289		{
290			// Catch errors when the input stream ends abruptly
291			if ( token == null )
292			{
293				tokenizer.parseError( "Unexpected end of input" );
294			}
295					
296			switch ( token.type )
297			{
298				case JSONTokenType.LEFT_BRACE:
299					return parseObject();
300					
301				case JSONTokenType.LEFT_BRACKET:
302					return parseArray();
303					
304				case JSONTokenType.STRING:
305				case JSONTokenType.NUMBER:
306				case JSONTokenType.TRUE:
307				case JSONTokenType.FALSE:
308				case JSONTokenType.NULL:
309					return token.value;
310					
311				case JSONTokenType.NAN:
312					if ( !strict )
313					{
314						return token.value;
315					}
316					else
317					{
318						tokenizer.parseError( "Unexpected " + token.value );
319					}
320
321				default:
322					tokenizer.parseError( "Unexpected " + token.value );
323					
324			}
325			
326            return null;
327		}
328	}
329}