pretty print json output
This commit is contained in:
parent
975949f3ff
commit
7a684c14bc
|
@ -42,7 +42,7 @@ package
|
||||||
import net.flashpunk.utils.Key;
|
import net.flashpunk.utils.Key;
|
||||||
import net.flashpunk.World;
|
import net.flashpunk.World;
|
||||||
import net.flashpunk.utils.Input;
|
import net.flashpunk.utils.Input;
|
||||||
import com.adobe.serialization.json.JSON;
|
import com.maccherone.json.JSON;
|
||||||
/**
|
/**
|
||||||
* ...
|
* ...
|
||||||
* @author jjp
|
* @author jjp
|
||||||
|
@ -361,7 +361,7 @@ package
|
||||||
{
|
{
|
||||||
var stream: FileStream = new FileStream();
|
var stream: FileStream = new FileStream();
|
||||||
stream.open(new File(UabFromUrf(urff)), FileMode.WRITE);
|
stream.open(new File(UabFromUrf(urff)), FileMode.WRITE);
|
||||||
stream.writeUTFBytes(JSON.encode(GenJSON()));
|
stream.writeUTFBytes(JSON.encode(GenJSON(), true, 80));
|
||||||
stream.close();
|
stream.close();
|
||||||
ShowMsg("Saved.");
|
ShowMsg("Saved.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
/*
|
/*
|
||||||
|
Copyright (c) 2009, Lawrence S. Maccherone, Jr.
|
||||||
|
|
||||||
Copyright (c) 2008, Adobe Systems Incorporated
|
Copyright (c) 2008, Adobe Systems Incorporated
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
|
@ -30,7 +32,7 @@
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.adobe.serialization.json
|
package com.maccherone.json
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -56,9 +58,9 @@ package com.adobe.serialization.json
|
||||||
* @playerversion Flash 9.0
|
* @playerversion Flash 9.0
|
||||||
* @tiptext
|
* @tiptext
|
||||||
*/
|
*/
|
||||||
public static function encode( o:Object ):String
|
public static function encode( o:Object, pretty:Boolean=false, maxLength:int=60 ):String
|
||||||
{
|
{
|
||||||
return new JSONEncoder( o ).getString();
|
return new JSONEncoder( o, pretty, maxLength ).getString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -30,7 +30,7 @@
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.adobe.serialization.json
|
package com.maccherone.json
|
||||||
{
|
{
|
||||||
|
|
||||||
public class JSONDecoder
|
public class JSONDecoder
|
|
@ -1,4 +1,6 @@
|
||||||
/*
|
/*
|
||||||
|
Copyright (c) 2009, Lawrence S. Maccherone, Jr.
|
||||||
|
|
||||||
Copyright (c) 2008, Adobe Systems Incorporated
|
Copyright (c) 2008, Adobe Systems Incorporated
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
|
@ -30,7 +32,7 @@
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.adobe.serialization.json
|
package com.maccherone.json
|
||||||
{
|
{
|
||||||
|
|
||||||
import flash.utils.describeType;
|
import flash.utils.describeType;
|
||||||
|
@ -40,6 +42,17 @@ package com.adobe.serialization.json
|
||||||
/** The string that is going to represent the object we're encoding */
|
/** The string that is going to represent the object we're encoding */
|
||||||
private var jsonString:String;
|
private var jsonString:String;
|
||||||
|
|
||||||
|
/** The current level */
|
||||||
|
private var level:int;
|
||||||
|
|
||||||
|
/** Above this length, an object or array will be split into multiple lines. Any value 2 or below will always split. */
|
||||||
|
private var maxLength:int;
|
||||||
|
|
||||||
|
/** When true, the encoder will add spaces and split Arrays and Objects over maxLength into multiple lines */
|
||||||
|
private var pretty:Boolean;
|
||||||
|
|
||||||
|
static private const tabWidth:int = 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new JSONEncoder.
|
* Creates a new JSONEncoder.
|
||||||
*
|
*
|
||||||
|
@ -48,9 +61,15 @@ package com.adobe.serialization.json
|
||||||
* @playerversion Flash 9.0
|
* @playerversion Flash 9.0
|
||||||
* @tiptext
|
* @tiptext
|
||||||
*/
|
*/
|
||||||
public function JSONEncoder( value:* ) {
|
public function JSONEncoder( value:*, pretty:Boolean=false, maxLength:int=60 ) {
|
||||||
|
level = 0;
|
||||||
|
this.pretty = pretty;
|
||||||
|
if (pretty) {
|
||||||
|
this.maxLength = maxLength;
|
||||||
|
} else {
|
||||||
|
this.maxLength = int.MAX_VALUE;
|
||||||
|
}
|
||||||
jsonString = convertToString( value );
|
jsonString = convertToString( value );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,6 +93,8 @@ package com.adobe.serialization.json
|
||||||
*/
|
*/
|
||||||
private function convertToString( value:* ):String {
|
private function convertToString( value:* ):String {
|
||||||
|
|
||||||
|
var temp:String;
|
||||||
|
|
||||||
// determine what value is and convert it based on it's type
|
// determine what value is and convert it based on it's type
|
||||||
if ( value is String ) {
|
if ( value is String ) {
|
||||||
|
|
||||||
|
@ -82,7 +103,7 @@ package com.adobe.serialization.json
|
||||||
|
|
||||||
} else if ( value is Number ) {
|
} else if ( value is Number ) {
|
||||||
|
|
||||||
// only encode numbers that finate
|
// only encode numbers that are finite
|
||||||
return isFinite( value as Number) ? value.toString() : "null";
|
return isFinite( value as Number) ? value.toString() : "null";
|
||||||
|
|
||||||
} else if ( value is Boolean ) {
|
} else if ( value is Boolean ) {
|
||||||
|
@ -92,13 +113,28 @@ package com.adobe.serialization.json
|
||||||
|
|
||||||
} else if ( value is Array ) {
|
} else if ( value is Array ) {
|
||||||
|
|
||||||
|
if (maxLength <= 2) {
|
||||||
|
temp = arrayToStringPretty( value as Array );
|
||||||
|
} else {
|
||||||
// call the helper method to convert an array
|
// call the helper method to convert an array
|
||||||
return arrayToString( value as Array );
|
temp = arrayToString( value as Array );
|
||||||
|
if (temp.length > maxLength) {
|
||||||
|
temp = arrayToStringPretty( value as Array );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return temp;
|
||||||
|
|
||||||
} else if ( value is Object && value != null ) {
|
} else if ( value is Object && value != null ) {
|
||||||
|
if (maxLength <= 2) {
|
||||||
|
temp = objectToStringPretty( value );
|
||||||
|
} else {
|
||||||
// call the helper method to convert an object
|
// call the helper method to convert an object
|
||||||
return objectToString( value );
|
temp = objectToString( value );
|
||||||
|
if (temp.length > maxLength) {
|
||||||
|
temp = objectToStringPretty( value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return temp;
|
||||||
}
|
}
|
||||||
return "null";
|
return "null";
|
||||||
}
|
}
|
||||||
|
@ -201,6 +237,9 @@ package com.adobe.serialization.json
|
||||||
if ( s.length > 0 ) {
|
if ( s.length > 0 ) {
|
||||||
// we've already added an element, so add the comma separator
|
// we've already added an element, so add the comma separator
|
||||||
s += ","
|
s += ","
|
||||||
|
if (pretty) {
|
||||||
|
s += " "
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert the value to a string
|
// convert the value to a string
|
||||||
|
@ -227,6 +266,37 @@ package com.adobe.serialization.json
|
||||||
return "[" + s + "]";
|
return "[" + s + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an array to it's JSON string equivalent using multiple lines
|
||||||
|
*
|
||||||
|
* @param a The array to convert
|
||||||
|
* @return The JSON string representation of <code>a</code>
|
||||||
|
*/
|
||||||
|
private function arrayToStringPretty( a:Array ):String {
|
||||||
|
level++;
|
||||||
|
|
||||||
|
// create a string to store the array's jsonstring value
|
||||||
|
var s:String = "";
|
||||||
|
|
||||||
|
// loop over the elements in the array and add their converted
|
||||||
|
// values to the string
|
||||||
|
for ( var i:int = 0; i < a.length; i++ ) {
|
||||||
|
// when the length is 0 we're adding the first element so
|
||||||
|
// no comma is necessary
|
||||||
|
if ( s.length > 0 ) {
|
||||||
|
// we've already added an element, so add the comma separator
|
||||||
|
s += ",\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert the value to a string
|
||||||
|
s += getPadding(level) + convertToString( a[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// close the array and return it's string value
|
||||||
|
level--;
|
||||||
|
return "[" + "\n" + s + "\n" + getPadding(level) + "]";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts an object to it's JSON string equivalent
|
* Converts an object to it's JSON string equivalent
|
||||||
*
|
*
|
||||||
|
@ -266,39 +336,39 @@ package com.adobe.serialization.json
|
||||||
if ( s.length > 0 ) {
|
if ( s.length > 0 ) {
|
||||||
// we've already added an item, so add the comma separator
|
// we've already added an item, so add the comma separator
|
||||||
s += ","
|
s += ","
|
||||||
|
if (pretty) {
|
||||||
|
s += " "
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s += escapeString( key ) + ":" + convertToString( value );
|
s += escapeString( key ) + ":"
|
||||||
|
if (pretty) {
|
||||||
|
s += " "
|
||||||
|
}
|
||||||
|
s += convertToString( value );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // o is a class instance
|
else // o is a class instance
|
||||||
{
|
{
|
||||||
// Loop over all of the variables and accessors in the class and
|
// Loop over all of the variables and accessors in the class and
|
||||||
// serialize them along with their values.
|
// serialize them along with their values.
|
||||||
for each ( var v:XML in classInfo..*.(
|
for each ( var v:XML in classInfo..*.( name() == "variable" || name() == "accessor" ) )
|
||||||
name() == "variable"
|
|
||||||
||
|
|
||||||
(
|
|
||||||
name() == "accessor"
|
|
||||||
// Issue #116 - Make sure accessors are readable
|
|
||||||
&& attribute( "access" ).charAt( 0 ) == "r" )
|
|
||||||
) )
|
|
||||||
{
|
{
|
||||||
// Issue #110 - If [Transient] metadata exists, then we should skip
|
|
||||||
if ( v.metadata && v.metadata.( @name == "Transient" ).length() > 0 )
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// When the length is 0 we're adding the first item so
|
// When the length is 0 we're adding the first item so
|
||||||
// no comma is necessary
|
// no comma is necessary
|
||||||
if ( s.length > 0 ) {
|
if ( s.length > 0 ) {
|
||||||
// We've already added an item, so add the comma separator
|
// We've already added an item, so add the comma separator
|
||||||
s += ","
|
s += ","
|
||||||
|
if (pretty) {
|
||||||
|
s += " "
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s += escapeString( v.@name.toString() ) + ":"
|
s += escapeString( v.@name.toString() ) + ":"
|
||||||
+ convertToString( o[ v.@name ] );
|
if (pretty) {
|
||||||
|
s += " "
|
||||||
|
}
|
||||||
|
s += convertToString( o[ v.@name ] );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -306,6 +376,91 @@ package com.adobe.serialization.json
|
||||||
return "{" + s + "}";
|
return "{" + s + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an object to it's JSON string equivalent with multiple lines
|
||||||
|
*
|
||||||
|
* @param o The object to convert
|
||||||
|
* @return The JSON string representation of <code>o</code>
|
||||||
|
*/
|
||||||
|
private function objectToStringPretty( o:Object ):String
|
||||||
|
{
|
||||||
|
level++;
|
||||||
|
|
||||||
|
// create a string to store the object's jsonstring value
|
||||||
|
var s:String = "";
|
||||||
|
|
||||||
|
// determine if o is a class instance or a plain object
|
||||||
|
var classInfo:XML = describeType( o );
|
||||||
|
if ( classInfo.@name.toString() == "Object" )
|
||||||
|
{
|
||||||
|
// the value of o[key] in the loop below - store this
|
||||||
|
// as a variable so we don't have to keep looking up o[key]
|
||||||
|
// when testing for valid values to convert
|
||||||
|
var value:Object;
|
||||||
|
|
||||||
|
// loop over the keys in the object and add their converted
|
||||||
|
// values to the string
|
||||||
|
for ( var key:String in o )
|
||||||
|
{
|
||||||
|
// assign value to a variable for quick lookup
|
||||||
|
value = o[key];
|
||||||
|
|
||||||
|
// don't add function's to the JSON string
|
||||||
|
if ( value is Function )
|
||||||
|
{
|
||||||
|
// skip this key and try another
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// when the length is 0 we're adding the first item so
|
||||||
|
// no comma is necessary
|
||||||
|
if ( s.length > 0 ) {
|
||||||
|
// we've already added an item, so add the comma separator
|
||||||
|
s += ",\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
s += getPadding(level) + escapeString( key ) + ":"
|
||||||
|
if (pretty) {
|
||||||
|
s += " "
|
||||||
|
}
|
||||||
|
s += convertToString( value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // o is a class instance
|
||||||
|
{
|
||||||
|
// Loop over all of the variables and accessors in the class and
|
||||||
|
// serialize them along with their values.
|
||||||
|
for each ( var v:XML in classInfo..*.( name() == "variable" || name() == "accessor" ) )
|
||||||
|
{
|
||||||
|
// When the length is 0 we're adding the first item so
|
||||||
|
// no comma is necessary
|
||||||
|
if ( s.length > 0 ) {
|
||||||
|
// We've already added an item, so add the comma separator
|
||||||
|
s += ",\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
s += getPadding(level) + escapeString( v.@name.toString() ) + ":"
|
||||||
|
if (pretty) {
|
||||||
|
s += " "
|
||||||
|
}
|
||||||
|
s += convertToString( o[ v.@name ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
level--;
|
||||||
|
return "{" + "\n" + s + "\n" + getPadding(level) + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getPadding(level:int):String {
|
||||||
|
var length:int = level * tabWidth;
|
||||||
|
var s:String = "";
|
||||||
|
for (var i:int=1; i<=length; i++) {
|
||||||
|
s += " ";
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.adobe.serialization.json {
|
package com.maccherone.json {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
|
@ -30,7 +30,7 @@
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.adobe.serialization.json {
|
package com.maccherone.json {
|
||||||
|
|
||||||
public class JSONToken {
|
public class JSONToken {
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.adobe.serialization.json {
|
package com.maccherone.json {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class containing constant values for the different types
|
* Class containing constant values for the different types
|
|
@ -30,7 +30,7 @@
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.adobe.serialization.json {
|
package com.maccherone.json {
|
||||||
|
|
||||||
public class JSONTokenizer {
|
public class JSONTokenizer {
|
||||||
|
|
||||||
|
@ -54,12 +54,6 @@ package com.adobe.serialization.json {
|
||||||
/** The current character in the JSON string during parsing */
|
/** The current character in the JSON string during parsing */
|
||||||
private var ch:String;
|
private var ch:String;
|
||||||
|
|
||||||
/**
|
|
||||||
* The regular expression used to make sure the string does not
|
|
||||||
* contain invalid control characters.
|
|
||||||
*/
|
|
||||||
private var controlCharsRegExp:RegExp = /[\x00-\x1F]/;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new JSONDecoder to parse a JSON string
|
* Constructs a new JSONDecoder to parse a JSON string
|
||||||
* into a native object.
|
* into a native object.
|
||||||
|
@ -228,158 +222,119 @@ package com.adobe.serialization.json {
|
||||||
*/
|
*/
|
||||||
private function readString():JSONToken
|
private function readString():JSONToken
|
||||||
{
|
{
|
||||||
// Rather than examine the string character-by-character, it's
|
// the string to store the string we'll try to read
|
||||||
// faster to use indexOf to try to and find the closing quote character
|
var string:String = "";
|
||||||
// and then replace escape sequences after the fact.
|
|
||||||
|
|
||||||
// Start at the current input stream position
|
// advance past the first "
|
||||||
var quoteIndex:int = loc;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
// Find the next quote in the input stream
|
|
||||||
quoteIndex = jsonString.indexOf( "\"", quoteIndex );
|
|
||||||
|
|
||||||
if ( quoteIndex >= 0 )
|
|
||||||
{
|
|
||||||
// We found the next double quote character in the string, but we need
|
|
||||||
// to make sure it is not part of an escape sequence.
|
|
||||||
|
|
||||||
// Keep looping backwards while the previous character is a backslash
|
|
||||||
var backspaceCount:int = 0;
|
|
||||||
var backspaceIndex:int = quoteIndex - 1;
|
|
||||||
while ( jsonString.charAt( backspaceIndex ) == "\\" )
|
|
||||||
{
|
|
||||||
backspaceCount++;
|
|
||||||
backspaceIndex--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have an even number of backslashes, that means this is the ending quote
|
|
||||||
if ( backspaceCount % 2 == 0 )
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// At this point, the quote was determined to be part of an escape sequence
|
|
||||||
// so we need to move past the quote index to look for the next one
|
|
||||||
quoteIndex++;
|
|
||||||
}
|
|
||||||
else // There are no more quotes in the string and we haven't found the end yet
|
|
||||||
{
|
|
||||||
parseError( "Unterminated string literal" );
|
|
||||||
}
|
|
||||||
} while ( true );
|
|
||||||
|
|
||||||
// Unescape the string
|
|
||||||
// the token for the string we'll try to read
|
|
||||||
var token:JSONToken = new JSONToken();
|
|
||||||
token.type = JSONTokenType.STRING;
|
|
||||||
// Attach resulting string to the token to return it
|
|
||||||
token.value = unescapeString( jsonString.substr( loc, quoteIndex - loc ) );
|
|
||||||
|
|
||||||
// Move past the closing quote in the input string. This updates the next
|
|
||||||
// character in the input stream to be the character one after the closing quote
|
|
||||||
loc = quoteIndex + 1;
|
|
||||||
nextChar();
|
nextChar();
|
||||||
|
|
||||||
return token;
|
while ( ch != '"' && ch != '' )
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert all JavaScript escape characters into normal characters
|
|
||||||
*
|
|
||||||
* @param input The input string to convert
|
|
||||||
* @return Original string with escape characters replaced by real characters
|
|
||||||
*/
|
|
||||||
public function unescapeString( input:String ):String
|
|
||||||
{
|
{
|
||||||
// Issue #104 - If the string contains any unescaped control characters, this
|
// unescape the escape sequences in the string
|
||||||
// is an error in strict mode
|
if ( ch == '\\' )
|
||||||
if ( strict && controlCharsRegExp.test( input ) )
|
|
||||||
{
|
{
|
||||||
parseError( "String contains unescaped control character (0x00-0x1F)" );
|
// get the next character so we know what
|
||||||
}
|
// to unescape
|
||||||
|
nextChar();
|
||||||
|
|
||||||
var result:String = "";
|
switch ( ch )
|
||||||
var backslashIndex:int = 0;
|
|
||||||
var nextSubstringStartPosition:int = 0;
|
|
||||||
var len:int = input.length;
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
// Find the next backslash in the input
|
case '"': // quotation mark
|
||||||
backslashIndex = input.indexOf( '\\', nextSubstringStartPosition );
|
string += '"';
|
||||||
|
break;
|
||||||
|
|
||||||
if ( backslashIndex >= 0 )
|
case '/': // solidus
|
||||||
{
|
string += "/";
|
||||||
result += input.substr( nextSubstringStartPosition, backslashIndex - nextSubstringStartPosition );
|
break;
|
||||||
|
|
||||||
// Move past the backslash and next character (all escape sequences are
|
case '\\': // reverse solidus
|
||||||
// two characters, except for \u, which will advance this further)
|
string += '\\';
|
||||||
nextSubstringStartPosition = backslashIndex + 2;
|
break;
|
||||||
|
|
||||||
// Check the next character so we know what to escape
|
case 'b': // bell
|
||||||
var afterBackslashIndex:int = backslashIndex + 1;
|
string += '\b';
|
||||||
var escapedChar:String = input.charAt( afterBackslashIndex );
|
break;
|
||||||
switch ( escapedChar )
|
|
||||||
{
|
|
||||||
// Try to list the most common expected cases first to improve performance
|
|
||||||
|
|
||||||
case '"': result += '"'; break; // quotation mark
|
case 'f': // form feed
|
||||||
case '\\': result += '\\'; break; // reverse solidus
|
string += '\f';
|
||||||
case 'n': result += '\n'; break; // newline
|
break;
|
||||||
case 'r': result += '\r'; break; // carriage return
|
|
||||||
case 't': result += '\t'; break; // horizontal tab
|
case 'n': // newline
|
||||||
|
string += '\n';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'r': // carriage return
|
||||||
|
string += '\r';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 't': // horizontal tab
|
||||||
|
string += '\t'
|
||||||
|
break;
|
||||||
|
|
||||||
// Convert a unicode escape sequence to it's character value
|
|
||||||
case 'u':
|
case 'u':
|
||||||
|
// convert a unicode escape sequence
|
||||||
|
// to it's character value - expecting
|
||||||
|
// 4 hex digits
|
||||||
|
|
||||||
// Save the characters as a string we'll convert to an int
|
// save the characters as a string we'll convert to an int
|
||||||
var hexValue:String = "";
|
var hexValue:String = "";
|
||||||
|
|
||||||
// Make sure there are enough characters in the string leftover
|
// try to find 4 hex characters
|
||||||
if ( nextSubstringStartPosition + 4 > len )
|
for ( var i:int = 0; i < 4; i++ )
|
||||||
{
|
|
||||||
parseError( "Unexpected end of input. Expecting 4 hex digits after \\u." );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to find 4 hex characters
|
|
||||||
for ( var i:int = nextSubstringStartPosition; i < nextSubstringStartPosition + 4; i++ )
|
|
||||||
{
|
{
|
||||||
// get the next character and determine
|
// get the next character and determine
|
||||||
// if it's a valid hex digit or not
|
// if it's a valid hex digit or not
|
||||||
var possibleHexChar:String = input.charAt( i );
|
if ( !isHexDigit( nextChar() ) )
|
||||||
if ( !isHexDigit( possibleHexChar ) )
|
|
||||||
{
|
{
|
||||||
parseError( "Excepted a hex digit, but found: " + possibleHexChar );
|
parseError( " Excepted a hex digit, but found: " + ch );
|
||||||
|
}
|
||||||
|
// valid, add it to the value
|
||||||
|
hexValue += ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Valid hex digit, add it to the value
|
// convert hexValue to an integer, and use that
|
||||||
hexValue += possibleHexChar;
|
// integrer value to create a character to add
|
||||||
}
|
|
||||||
|
|
||||||
// Convert hexValue to an integer, and use that
|
|
||||||
// integer value to create a character to add
|
|
||||||
// to our string.
|
// to our string.
|
||||||
result += String.fromCharCode( parseInt( hexValue, 16 ) );
|
string += String.fromCharCode( parseInt( hexValue, 16 ) );
|
||||||
// Move past the 4 hex digits that we just read
|
|
||||||
nextSubstringStartPosition += 4;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'f': result += '\f'; break; // form feed
|
default:
|
||||||
case '/': result += '/'; break; // solidus
|
// couldn't unescape the sequence, so just
|
||||||
case 'b': result += '\b'; break; // bell
|
// pass it through
|
||||||
default: result += '\\' + escapedChar; // Couldn't unescape the sequence, so just pass it through
|
string += '\\' + ch;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// No more backslashes to replace, append the rest of the string
|
// didn't have to unescape, so add the character to the string
|
||||||
result += input.substr( nextSubstringStartPosition );
|
string += ch;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} while ( nextSubstringStartPosition < len );
|
// move to the next character
|
||||||
|
nextChar();
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
// we read past the end of the string without closing it, which
|
||||||
|
// is a parse error
|
||||||
|
if ( ch == '' )
|
||||||
|
{
|
||||||
|
parseError( "Unterminated string literal" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// move past the closing " in the input string
|
||||||
|
nextChar();
|
||||||
|
|
||||||
|
// the token for the string we've just read
|
||||||
|
var token:JSONToken = new JSONToken();
|
||||||
|
token.type = JSONTokenType.STRING;
|
||||||
|
// attach to the string to the token so we can return it
|
||||||
|
token.value = string;
|
||||||
|
|
||||||
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -653,18 +608,7 @@ package com.adobe.serialization.json {
|
||||||
*/
|
*/
|
||||||
private function isWhiteSpace( ch:String ):Boolean
|
private function isWhiteSpace( ch:String ):Boolean
|
||||||
{
|
{
|
||||||
// Check for the whitespace defined in the spec
|
return ( ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' );
|
||||||
if ( ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' )
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// If we're not in strict mode, we also accept non-breaking space
|
|
||||||
else if ( !strict && ch.charCodeAt( 0 ) == 160 )
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -678,13 +622,19 @@ package com.adobe.serialization.json {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if a character is a hex digit [0-9A-Fa-f].
|
* Determines if a character is a digit [0-9].
|
||||||
*
|
*
|
||||||
* @return True if the character passed in is a hex digit
|
* @return True if the character passed in is a digit
|
||||||
*/
|
*/
|
||||||
private function isHexDigit( ch:String ):Boolean
|
private function isHexDigit( ch:String ):Boolean
|
||||||
{
|
{
|
||||||
return ( isDigit( ch ) || ( ch >= 'A' && ch <= 'F' ) || ( ch >= 'a' && ch <= 'f' ) );
|
// get the uppercase value of ch so we only have
|
||||||
|
// to compare the value between 'A' and 'F'
|
||||||
|
var uc:String = ch.toUpperCase();
|
||||||
|
|
||||||
|
// a hex digit is a digit of A-F, inclusive ( using
|
||||||
|
// our uppercase constraint )
|
||||||
|
return ( isDigit( ch ) || ( uc >= 'A' && uc <= 'F' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
3
todo.txt
3
todo.txt
|
@ -1,6 +1,5 @@
|
||||||
- decide on a license
|
- decide on a license
|
||||||
- push to github
|
- push to github
|
||||||
- human-readable JSON output
|
|
||||||
|
|
||||||
- finalize "library" notion
|
- finalize "library" notion
|
||||||
- text objects
|
- text objects
|
||||||
|
@ -19,4 +18,4 @@ DONE:
|
||||||
- create a readme
|
- create a readme
|
||||||
- quit to menu
|
- quit to menu
|
||||||
- fixed-sized factories
|
- fixed-sized factories
|
||||||
- JSON output?
|
- human-readable JSON output
|
||||||
|
|
Loading…
Reference in a new issue