package com.adobe.serialization.json
{
public class JSONDecoder
{
/**
* Flag indicating if the parser should be strict about the format
* of the JSON string it is attempting to decode.
*/
private var strict:Boolean;
/** The value that will get parsed from the JSON string */
private var value:*;
/** The tokenizer designated to read the JSON string */
private var tokenizer:JSONTokenizer;
/** The current token from the tokenizer */
private var token:JSONToken;
/**
* Constructs a new JSONDecoder to parse a JSON string
* into a native object.
*
* @param s The JSON string to be converted
* into a native object
* @param strict Flag indicating if the JSON string needs to
* strictly match the JSON standard or not.
* @langversion ActionScript 3.0
* @playerversion Flash 9.0
* @tiptext
*/
public function JSONDecoder( s:String, strict:Boolean )
{
this.strict = strict;
tokenizer = new JSONTokenizer( s, strict );
nextToken();
value = parseValue();
if ( strict && nextToken() != null )
{
tokenizer.parseError( "Unexpected characters left in input stream" );
}
}
/**
* Gets the internal object that was created by parsing
* the JSON string passed to the constructor.
*
* @return The internal object representation of the JSON
* string that was passed to the constructor
* @langversion ActionScript 3.0
* @playerversion Flash 9.0
* @tiptext
*/
public function getValue():*
{
return value;
}
/**
* Returns the next token from the tokenzier reading
* the JSON string
*/
private final function nextToken():JSONToken
{
return token = tokenizer.getNextToken();
}
/**
* Returns the next token from the tokenizer reading
* the JSON string and verifies that the token is valid.
*/
private final function nextValidToken():JSONToken
{
token = tokenizer.getNextToken();
checkValidToken();
return token;
}
/**
* Verifies that the token is valid.
*/
private final function checkValidToken():void
{
if ( token == null )
{
tokenizer.parseError( "Unexpected end of input" );
}
}
/**
* Attempt to parse an array.
*/
private final function parseArray():Array
{
var a:Array = new Array();
nextValidToken();
if ( token.type == JSONTokenType.RIGHT_BRACKET )
{
return a;
}
else if ( !strict && token.type == JSONTokenType.COMMA )
{
nextValidToken();
if ( token.type == JSONTokenType.RIGHT_BRACKET )
{
return a;
}
else
{
tokenizer.parseError( "Leading commas are not supported. Expecting ']' but found " + token.value );
}
}
while ( true )
{
a.push( parseValue() );
nextValidToken();
if ( token.type == JSONTokenType.RIGHT_BRACKET )
{
return a;
}
else if ( token.type == JSONTokenType.COMMA )
{
nextToken();
if ( !strict )
{
checkValidToken();
if ( token.type == JSONTokenType.RIGHT_BRACKET )
{
return a;
}
}
}
else
{
tokenizer.parseError( "Expecting ] or , but found " + token.value );
}
}
return null;
}
/**
* Attempt to parse an object.
*/
private final function parseObject():Object
{
var o:Object = new Object();
var key:String
nextValidToken();
if ( token.type == JSONTokenType.RIGHT_BRACE )
{
return o;
}
else if ( !strict && token.type == JSONTokenType.COMMA )
{
nextValidToken();
if ( token.type == JSONTokenType.RIGHT_BRACE )
{
return o;
}
else
{
tokenizer.parseError( "Leading commas are not supported. Expecting '}' but found " + token.value );
}
}
while ( true )
{
if ( token.type == JSONTokenType.STRING )
{
key = String( token.value );
nextValidToken();
if ( token.type == JSONTokenType.COLON )
{
nextToken();
o[ key ] = parseValue();
nextValidToken();
if ( token.type == JSONTokenType.RIGHT_BRACE )
{
return o;
}
else if ( token.type == JSONTokenType.COMMA )
{
nextToken();
if ( !strict )
{
checkValidToken();
if ( token.type == JSONTokenType.RIGHT_BRACE )
{
return o;
}
}
}
else
{
tokenizer.parseError( "Expecting } or , but found " + token.value );
}
}
else
{
tokenizer.parseError( "Expecting : but found " + token.value );
}
}
else
{
tokenizer.parseError( "Expecting string but found " + token.value );
}
}
return null;
}
/**
* Attempt to parse a value
*/
private final function parseValue():Object
{
checkValidToken();
switch ( token.type )
{
case JSONTokenType.LEFT_BRACE:
return parseObject();
case JSONTokenType.LEFT_BRACKET:
return parseArray();
case JSONTokenType.STRING:
case JSONTokenType.NUMBER:
case JSONTokenType.TRUE:
case JSONTokenType.FALSE:
case JSONTokenType.NULL:
return token.value;
case JSONTokenType.NAN:
if ( !strict )
{
return token.value;
}
else
{
tokenizer.parseError( "Unexpected " + token.value );
}
default:
tokenizer.parseError( "Unexpected " + token.value );
}
return null;
}
}
}