Hello, The tools is very impressive and worked for the most part except that I am getting two errors that I am not able to fix. Any help with this is greatly appreciated.
ERROR: type must be determined for 'as array' cast for:
C:/HaxeToolkit/as3hx/./out/com/flashdynamix/motion/TweensyTimeline.hx
ERRORS: These files were not written due to source parsing errors:
In C:/HaxeToolkit/as3hx/projects/flash/com/adobe/serialization/json/JSONEncoder.as(278) : Unexpected *
In C:/HaxeToolkit/as3hx/projects/flash/com/adobe/serialization/json/JSONTokenizer.as(101) : Unexpected :
attached are the two files that are causing the issues. content is tagged with "file start" and "file end" for attachment reasons.
Thank you,
sam
--------------- file start TweensyTimeline.as -----------------------
/**
.______ __ ___
/__ \ /'__\ /'___
\
//\ / __ __ __ __ __ ___ ____ __ __ /\ /\ \ /\ /\ \
...\ \ \ /\ /\ /\ \ /'**\ /'**
\ /' \ /',**\ /\ \/\ \ \ \ \ \ \ \/_/// /** ....\ \ \ \ _/ _/ \/\ **/ /\ __/ /\ \/\ \ /\**,
\ \ _\ \ \ \ _\ \ __ // /\
.....\ _\ _x/'\ _\ _\ _\ _\/_/ /____ \ \ _**_//\_\/____**/ ......\/_/ \/__//**/ \/__**/ \/____/ \/_/\/_/ \/**_/
/**/> \ /**/ ///__**/
............................................................//
............................................................//
................. Tweening since 1998 ......................
............................................................
/
package com.flashdynamix.motion {
import com.flashdynamix.motion.plugins.AbstractTween;
import com.flashdynamix.motion.plugins.TweensyPluginList;
/*
* TweensyTimeline groups instances of tweens which are animating for the same duration. It's important
* to know that these Tweens can be animating their own unique properties and from to targets
*
* TweensyTimelines are especially efficient for bulk tweening (1000+ Objects) because of their
* capability of grouping instances with a common timeline.
*
* The TweensyTimeline Class has events for:
*
* - onComplete - When all tweens in the TweensyTimeline Class are done
* - onUpdate - When all animations in the TweensyTimeline Class have been updated.
* - onRepeat - When the animation REPLAYs in the TweensyTimeline Class.
*
* These events allow for predefined params to be applied when they are executed.
* Tweensy favours this method as it allows for predefining the event and the params it requires
* without all the fussiness of Event listeners.
/
public class TweensyTimeline {
/*
*
@see com.flashdynamix.motion.TweensyTimeline#repeatType
/
public static const YOYO : String = "yoyo";
/*
*
@see com.flashdynamix.motion.TweensyTimeline#repeatType
/
public static const REPLAY : String = "replay";
/*
*
@see com.flashdynamix.motion.TweensyTimeline#repeatType
/
public static const LOOP : String = "loop";
/*
*
@see com.flashdynamix.motion.TweensyTimeline#repeatType
/
public static const NONE : String = null;
/*
* The default tween which will be used when none is provided using a to, from and fromTo method.
*
*
@see com.flashdynamix.motion.TweensyTimeline#ease TweensyTimeline.ease
/
public static var defaultTween : Function = easeOut;
private static var defaultArgs : Array = [0, 0, 1, 0];
/*
* Defines the ease equation you would like to use. By default this is Quintic.easeOut or the defaultTween.
*
*
@see com.flashdynamix.motion.TweensyTimeline#defaultTween
/
public var ease : Function = defaultTween;
/*
* Defines the delay in seconds at the start of the animation.
* By default this value is 0 seconds.
/
public var delayStart : Number = 0;
/*
* Defines the delay in seconds at the end of the animation.
* By default this value is 0 seconds.
/
public var delayEnd : Number = 0;
/*
* Defines the repeat type for the animation. By default this is TweensyTimeline.NONE
* Options include :
*
* - TweensyTimeline.NONE
* - TweensyTimeline.YOYO
* - TweensyTimeline.REPLAY
* - TweensyTimeline.LOOP
*
*
*
@see com.flashdynamix.motion.TweensyTimeline#repeats
*
@see com.flashdynamix.motion.TweensyTimeline#repeatCount
*
@see com.flashdynamix.motion.TweensyTimeline#NONE
*
@see com.flashdynamix.motion.TweensyTimeline#YOYO
*
@see com.flashdynamix.motion.TweensyTimeline#REPLAY
*
@see com.flashdynamix.motion.TweensyTimeline#LOOP
/
public var repeatType : String;
/*
* The number of repeats to use. If -1 is used then the animation will repeat indefinitely.
*
*
@see com.flashdynamix.motion.TweensyTimeline#repeats
*
@see com.flashdynamix.motion.TweensyTimeline#repeatType
/
public var repeats : int = -1;
/*
* The count of the number of repeats which have occured.
*
*
@see com.flashdynamix.motion.TweensyTimeline#repeats
*
@see com.flashdynamix.motion.TweensyTimeline#repeatType
/
public var repeatCount : int = 0;
/*
* This contains a list of ease Functions to use on each repeat for the tween animation.
* i.e. [Quintic.easeIn, Quintic.easeOut]
* This will then use each of these ease Functions on each repeat.
* By default this is null when this property is null this functionality is ignored.
*
*
@see com.flashdynamix.motion.TweensyTimeline#repeats
*
@see com.flashdynamix.motion.TweensyTimeline#repeatType
/
public var repeatEase : Array;
/*
* Whether the timelines contained within the TweensyTimeline class will use smart rotation or not.
* Smart rotation will make the rotation turn in the direction which is the shortest in degrees
* fixing what may otherwise appear as a visual glitch even though mathimatically it is correct.
/
public var smartRotate : Boolean = true;
/*
* Whether the tweens contained within the TweensyTimeline class will snap tweened properties to the closest whole number.
/
public var snapToClosest : Boolean = false;
public var autoHide : Boolean = false;
/*
* Executed on each update to the TweensyTimeline animation.
*
*
@see com.flashdynamix.motion.TweensyTimeline#onUpdateParams
/
public var onUpdate : Function;
/*
* Parameters applied to the onUpdate Function.
*
*
@see com.flashdynamix.motion.TweensyTimeline#onUpdate
/
public var onUpdateParams : Array;
/*
* Executed when the TweensyTimeline animation is complete.
*
*
@see com.flashdynamix.motion.TweensyTimeline#onCompleteParams
/
public var onComplete : Function;
/*
* Parameters applied to the onComplete Function.
*
*
@see com.flashdynamix.motion.TweensyTimeline#onComplete
/
public var onCompleteParams : Array;
/*
* Executed when the TweensyTimeline animation repeats.
*
*
@see com.flashdynamix.motion.TweensyTimeline#onRepeatParams
/
public var onRepeat : Function;
/*
* Parameters applied to the onRepeat Function.
*
*
@see com.flashdynamix.motion.TweensyTimeline#onRepeat
/
public var onRepeatParams : Array;
/*
@Private /
internal var manager : TweensyGroup;
/*
@Private /
internal var next : TweensyTimeline;
/*
@Private /
internal var previous : TweensyTimeline;
/*
@Private _/
internal var _onComplete : Function;
private var _instances : Array = [];
private var _tweens : int = 0;
private var _time : Number = 0;
private var _paused : Boolean = false;
private var args : Array = defaultArgs.concat();
private var
duration : Number;
private var list : Array;
private var disposed : Boolean = false;
public function TweensyTimeline() {
list = [];
}
/*
* Adds a to based tween to the properties defined in the target Object.
*
*
@param instance The instance Object to be tweened or multiple _instances if using the type Array e.g.
timeline.to([item1, item2], {x:50, y:50});
*
@param to An Object containing the properties you would like to tween to e.g.
{x:50, y:25}
* or this can be relative e.g. {x:'50', y:'-25'} or can be a random position e.g.
{x:'-50, 50', y:'-25, 25'}
*
@param update This param is used when tweening a property in a Object which needs to be applied onto another Object each time
* the tween occurs.
* For example
timeline.to(new DropShadowFilter(), {alpha:0}, myDisplayItem);
* Will apply the tweening DropShadowFilter onto the DisplayObject
'myDisplayItem'
.
*/
public function to(instance : Object, to : Object, update : Object = null) : void {
var tween : AbstractTween;
if(instance is Array) {
var i : int = 0;
var len : int = (instance as Array).length;
for(i < 0;i < len; i++) {
if(instance[i] is Number || instance[i] is String) {
if(!tween) tween = add(instance, update);
tween.add(i.toString(), to[i], false);
} else {
this.to(instance[i], to, update);
}
}
} else {
tween = add(instance, update);
tween.toTarget(to);
}
}
/**
* Adds a from based tween to the properties defined in the target Object.
*
* @param instance The instance Object to be tweened or multiple _instances if using the type Array e.g. <code>timeline.from([item1, item2], {x:50, y:50})</code>;
* @param from An Object containing the properties you would like to tween from e.g. <code>{x:50, y:25}</code>
* or this can be relative e.g. {x:'50', y:'-25'} or can be a random position e.g. <code>{x:'-50, 50', y:'-25, 25'}</code>
* @param update This param is used when tweening a property in a Object which needs to be applied onto another Object each time
* the tween occurs.<BR>
* For example <code>timeline.from(new DropShadowFilter(), {alpha:0}, myDisplayItem);</code><BR>
* Will apply the tweening DropShadowFilter onto the DisplayObject <code>'myDisplayItem'</code>.
*/
public function from(instance : Object, from : Object, update : Object = null) : void {
var tween : AbstractTween;
if(instance is Array) {
var i : int = 0;
var len : int = (instance as Array).length;
for(i < 0;i < len; i++) {
if(instance[i] is Number || instance[i] is String) {
if(!tween) tween = add(instance, update);
tween.add(i.toString(), from[i], true);
} else {
this.from(instance[i], from, update);
}
}
} else {
tween = add(instance, update);
tween.fromTarget(from);
tween.apply();
}
}
/**
* Adds a from to based tween to the properties defined in the target Object.
*
* @param instance The instance Object to be tweened or multiple _instances if using the type Array e.g. <code>timeline.fromTo([item1, item2], {x:50, y:50});</code>
* @param from An Object containing the properties you would like to tween from e.g. <code>{x:50, y:25}</code>
* or this can be relative e.g. {x:'50', y:'-25'} or can be a random position e.g. <code>{x:'-50, 50', y:'-25, 25'}</code>
* @param to An Object containing the properties you would like to tween to e.g. <code>{x:50, y:25}</code>
* or this can be relative e.g. {x:'50', y:'-25'} or can be a random position e.g. <code>{x:'-50, 50', y:'-25, 25'}</code>
* @param update This param is used when tweening a property in a Object which needs to be applied onto another Object each time
* the tween occurs.<BR>
* For example <code>timeline.fromTo(new DropShadowFilter(), {alpha:0}, {alpha:1}, myDisplayItem)</code><BR>
* Will apply the tweening DropShadowFilter onto the DisplayObject <code>'myDisplayItem'</code>
*/
public function fromTo(instance : Object, from : Object, to : Object, update : Object = null) : void {
var tween : AbstractTween;
if(instance is Array) {
var i : int = 0;
var len : int = (instance as Array).length;
for(i < 0;i < len; i++) {
if(instance[i] is Number || instance[i] is String) {
if(!tween) tween = add(instance, update);
tween.add(i.toString(), from[i], true);
tween.add(i.toString(), to[i], false);
} else {
this.fromTo(instance[i], from, to, update);
}
}
} else {
tween = add(instance, update);
tween.fromTarget(from);
tween.toTarget(to);
tween.apply();
}
}
/**
* Updates a tween for the instance Object to the new target properties defined in the to Object.<BR>
* The value of this instance depends on wether the 'update' param is used i.e.<BR>
* <code>timeline.to(new DropShadowFilter(), {alpha:0}, myDisplayItem);</code> the instance parameter will be myDisplayItem.<BR>
* <code>timeline.to(new DropShadowFilter(), {alpha:0});</code> the instance parameter will be the filter
*/
public function updateTo(instance : Object, to : Object) : void {
var position : Number = ease.apply(null, args);
var tween : AbstractTween;
for each(tween in list) {
if(tween.instance == instance) tween.updateTo(position, to);
}
}
/**
* Allows for removing tweens via an instance or tween props by the following methods :
* <ul>
* <li><code>timeline.stop(instance);</code> - stops all property tweens for this instance.</li>
* <li><code>timeline.stop(instance, "x", "y");</code> - stops all x,y property tweens for this instance.</li>
* <li><code>timeline.stop([instance1, instance2]);</code> - stops all property tweens for these _instances.</li>
* <li><code>timeline.stop([instance1, instance2], "x", "y");</code> - stops all x,y property tweens for these _instances.</li>
* <li><code>timeline.stop(null, "x", "y");</code> - stops all x,y property tweens.</li>
* <li><code>timeline.stop();</code> - stops all tweens though it is recommended to use the stopAll method as this is more efficient.</li>
* </ul>
*/
public function stop(instance : * = null, ...props : Array) : void {
var _instances : Array = (instance is Array) ? instance : (instance == null) ? null : [instance];
var tween : AbstractTween;
var i : int;
for (i = _tweens - 1;i >= 0; i--) {
tween = list[i];
if(_instances == null || _instances.indexOf(tween.instance) != -1) {
if(props.length == 0) {
tween.stopAll();
} else {
tween.stop.apply(null, props);
}
if(!tween.hasAnimations) {
remove(tween);
list.splice(i, 1);
}
}
}
if(!hasTweens && manager) manager.remove(this);
}
public function stopAll() : void {
removeAll();
if(manager) manager.remove(this);
}
/**
* Updates the TweensyTimeline by the specified amout of time in seconds.<BR>
* This function is intended for use by the Tweensy class which is controlling this timeline animation.<BR>
* Though calling this function will update the timeline independtly of the mananger allowing for custom control
* over timelines.
*
* @return Whether the TweensyTimeline animation has finished playing.
*/
public function update(secs : Number) : Boolean {
if(paused) return false;
_time += secs;
var played : Number = _time - delayStart;
var done : Boolean = false;
if(played > 0) {
done = finished;
played = (played > _duration) ? _duration : played;
args[0] = played;
var position : Number = ease.apply(null, args);
var tween : AbstractTween;
var i : int;
for (i = 0;i < _tweens; i++) {
tween = list[i];
tween.update(position);
}
if(onUpdate != null) {
onUpdate.apply(null, onUpdateParams);
done = finished;
}
if(done) {
if(canRepeat) {
if(repeatType == YOYO) {
yoyo();
} else if(repeatType == REPLAY) {
replay();
} else if(repeatType == LOOP) {
loop();
}
if(onRepeat != null) onRepeat.apply(null, onRepeatParams);
done = finished;
}
if(done) {
if(onComplete != null) onComplete.apply(null, onCompleteParams);
done = finished && !canRepeat;
if(done && _onComplete != null) _onComplete();
}
}
}
return done;
}
/**
* Pauses a playing TweensyTimeline
*/
public function pause() : void {
if(paused) return;
_paused = true;
}
/**
* Resumes a paused TweensyTimeline
*/
public function resume() : void {
if(!paused) return;
_paused = false;
}
/**
* Forces a timeline tween to loop the animation.<BR>
* A looped animation will swap the delays (delayStart & delayEnd) so that the to and from animations have the same delays.
*
* @see com.flashdynamix.motion.TweensyTimeline#repeats
* @see com.flashdynamix.motion.TweensyTimeline#repeatCount
* @see com.flashdynamix.motion.TweensyTimeline#NONE
* @see com.flashdynamix.motion.TweensyTimeline#YOYO
* @see com.flashdynamix.motion.TweensyTimeline#REPLAY
* @see com.flashdynamix.motion.TweensyTimeline#LOOP
*/
public function loop() : void {
var tween : AbstractTween;
for each(tween in list) tween.swapToFrom();
var oldStart : Number = delayStart;
delayStart = delayEnd;
delayEnd = oldStart;
doRepeat();
}
/**
* Forces a timeline tween to do a yoyo animation.<BR>
* A yoyo will use the same delayStart and delayEnd on the to and fro animation.
*
* @see com.flashdynamix.motion.TweensyTimeline#repeats
* @see com.flashdynamix.motion.TweensyTimeline#repeatCount
* @see com.flashdynamix.motion.TweensyTimeline#NONE
* @see com.flashdynamix.motion.TweensyTimeline#YOYO
* @see com.flashdynamix.motion.TweensyTimeline#REPLAY
* @see com.flashdynamix.motion.TweensyTimeline#LOOP
*/
public function yoyo() : void {
var tween : AbstractTween;
for each(tween in list) tween.swapToFrom();
doRepeat();
}
/**
* Plays a timeline animation at its start position on each repeat.
*
* @see com.flashdynamix.motion.TweensyTimeline#repeats
* @see com.flashdynamix.motion.TweensyTimeline#repeatCount
* @see com.flashdynamix.motion.TweensyTimeline#NONE
* @see com.flashdynamix.motion.TweensyTimeline#YOYO
* @see com.flashdynamix.motion.TweensyTimeline#REPLAY
* @see com.flashdynamix.motion.TweensyTimeline#LOOP
*/
public function replay() : void {
var tween : AbstractTween;
for each(tween in list) tween.update(0);
doRepeat();
}
/**
* Defines whether the TweensyTimeline repeats.
*/
public function get canRepeat() : Boolean {
return (repeatType != NONE && (repeats == -1 || repeatCount < repeats));
}
public function set position(index : Number) : void {
var dif : Number = (index * totalDuration) - _time;
update(dif);
}
/**
* Seeks and returns the animation to a position from 0 to 1, start to end.
*/
public function get position() : Number {
return (_time / totalDuration);
}
/**
* Determines whether or not the TweensyTimeline animation has finished.
*/
public function get finished() : Boolean {
return (_time >= totalDuration);
}
/**
* The total duration of the TweensyTimeline animation in seconds.<BR>
* This is the sum of delayStart, duration and delayEnd.
*/
public function get totalDuration() : Number {
return (delayStart + _duration + delayEnd);
}
public function set time(seconds : Number) : void {
_time = seconds;
}
/**
* The time in seconds the TweensyTimeline has been running for
*/
public function get time() : Number {
return _time;
}
public function set duration(secs : Number) : void {
args[3] = secs;
_duration = secs;
}
/**
* Sets and gets the current tween duration for the TweensyTimeline in seconds.
*/
public function get duration() : Number {
return _duration;
}
/**
* Sets the ease params. These params are used on Back, Bounce and Elastic ease functions.<BR>
* These parameters lessen or exaggerate the effect of these particular ease functions.<BR>
* i.e. [0.7] will lessen the effect of a Back equation
*/
public function set easeParams(value : Array) : void {
args = args.slice(0, 4).concat(value);
}
/**
* Whether the TweensyTimeline is paused.
*/
public function get paused() : Boolean {
return (_paused);
}
/**
* This is when the animation is after the delay start and before its delay end.
*
* @return Whether the TweensyTimeline is playing.
*/
public function get playing() : Boolean {
return (_time > delayStart && _time < delayEnd);
}
/**
* Number of tweens added to the TweensyTimeline Class.
*/
public function get tweens() : int {
return _tweens;
}
/**
* Whether the TweensyTimeline has any animations.
*/
public function get hasTweens() : Boolean {
return (_tweens > 0);
}
public function get instances() : Array {
return _instances;
}
/** @private */
internal function removeAll() : void {
var tween : AbstractTween;
for each(tween in list) remove(tween);
list.length = 0;
_instances.length = 0;
}
/** @private */
internal function removeOverlap(timeline : TweensyTimeline) : void {
if(this != timeline && intersects(timeline)) {
var i : int;
var tweenA : AbstractTween;
var tweenB : AbstractTween;
for each(tweenA in timeline.list) {
for (i = _tweens - 1;i >= 0; i--) {
tweenB = list[i];
tweenB.removeOverlap(tweenA);
if(!tweenB.hasAnimations) {
remove(tweenB);
list.splice(i, 1);
}
}
}
if(!hasTweens) manager.remove(this);
}
}
/** @private */
internal function clear() : void {
removeAll();
next = null;
previous = null;
args = defaultArgs.concat();
manager = null;
onUpdate = null;
onUpdateParams = null;
onComplete = null;
onCompleteParams = null;
onRepeat = null;
onRepeatParams = null;
_onComplete = null;
ease = defaultTween;
delayStart = 0;
delayEnd = 0;
repeatType = NONE;
repeats = -1;
repeatEase = null;
disposed = false;
_time = 0;
_paused = false;
repeatCount = 0;
}
private function add(instance : Object, update : Object = null) : AbstractTween {
var tween : AbstractTween = TweensyPluginList.checkOut(instance);
tween.timeline = this;
tween.construct(instance, update);
_instances.push(tween.instance);
list[_tweens++] = tween;
return tween;
}
private function remove(tween : AbstractTween) : void {
tween.clear();
TweensyPluginList.checkIn(tween);
if(manager) manager.removeInstance(tween.instance, this);
_instances.splice(_instances.indexOf(tween.instance));
_tweens--;
}
private function intersects(timeline : TweensyTimeline) : Boolean {
return (timeline.delayStart < (totalDuration - time));
}
private function doRepeat() : void {
_time = 0;
repeatCount++;
if(repeatEase) ease = repeatEase[repeatCount % repeatEase.length];
}
public static function empty() : void {
TweensyPluginList.empty();
}
private static function easeOut(t : Number, b : Number, c : Number, d : Number) : Number {
return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
}
/**
* Disposes the TweensyTimeline Class instance ready for garbage collection.
*/
public function dispose() : void {
if(disposed) return;
disposed = true;
stopAll();
next = null;
previous = null;
args = null;
list = null;
manager = null;
ease = null;
repeatEase = null;
onUpdate = null;
onUpdateParams = null;
onComplete = null;
onCompleteParams = null;
onRepeat = null;
onRepeatParams = null;
}
public function toString() : String {
return "TweensyTimeline " + Tweensy.version + " {tweens:" + _tweens + "}";
}
}
}
--------------file end TweensyTimeline.as -------------------
------------------file start jsonencoder.as --------------------------
/*
Copyright (c) 2008, Adobe Systems Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
-
Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
-
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
-
Neither the name of Adobe Systems Incorporated nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.adobe.serialization.json
{
import flash.utils.describeType;
public class JSONEncoder {
/** The string that is going to represent the object we're encoding */
private var jsonString:String;
/**
* Creates a new JSONEncoder.
*
* @param o The object to encode as a JSON string
* @langversion ActionScript 3.0
* @playerversion Flash 9.0
* @tiptext
*/
public function JSONEncoder( value:* ) {
jsonString = convertToString( value );
}
/**
* Gets the JSON string from the encoder.
*
* @return The JSON string representation of the object
* that was passed to the constructor
* @langversion ActionScript 3.0
* @playerversion Flash 9.0
* @tiptext
*/
public function getString():String {
return jsonString;
}
/**
* Converts a value to it's JSON string equivalent.
*
* @param value The value to convert. Could be any
* type (object, number, array, etc)
*/
private function convertToString( value:* ):String {
// determine what value is and convert it based on it's type
if ( value is String ) {
// escape the string so it's formatted correctly
return escapeString( value as String );
} else if ( value is Number ) {
// only encode numbers that finate
return isFinite( value as Number) ? value.toString() : "null";
} else if ( value is Boolean ) {
// convert boolean to string easily
return value ? "true" : "false";
} else if ( value is Array ) {
// call the helper method to convert an array
return arrayToString( value as Array );
} else if ( value is Object && value != null ) {
// call the helper method to convert an object
return objectToString( value );
}
return "null";
}
/**
* Escapes a string accoding to the JSON specification.
*
* @param str The string to be escaped
* @return The string with escaped special characters
* according to the JSON specification
*/
private function escapeString( str:String ):String {
// create a string to store the string's jsonstring value
var s:String = "";
// current character in the string we're processing
var ch:String;
// store the length in a local variable to reduce lookups
var len:Number = str.length;
// loop over all of the characters in the string
for ( var i:int = 0; i < len; i++ ) {
// examine the character to determine if we have to escape it
ch = str.charAt( i );
switch ( ch ) {
case '"': // quotation mark
s += "\\\"";
break;
//case '/': // solidus
// s += "\\/";
// break;
case '\\': // reverse solidus
s += "\\\\";
break;
case '\b': // bell
s += "\\b";
break;
case '\f': // form feed
s += "\\f";
break;
case '\n': // newline
s += "\\n";
break;
case '\r': // carriage return
s += "\\r";
break;
case '\t': // horizontal tab
s += "\\t";
break;
default: // everything else
// check for a control character and escape as unicode
if ( ch < ' ' ) {
// get the hex digit(s) of the character (either 1 or 2 digits)
var hexCode:String = ch.charCodeAt( 0 ).toString( 16 );
// ensure that there are 4 digits by adjusting
// the # of zeros accordingly.
var zeroPad:String = hexCode.length == 2 ? "00" : "000";
// create the unicode escape sequence with 4 hex digits
s += "\\u" + zeroPad + hexCode;
} else {
// no need to do any special encoding, just pass-through
s += ch;
}
} // end switch
} // end for loop
return "\"" + s + "\"";
}
/**
* Converts an array to it's JSON string equivalent
*
* @param a The array to convert
* @return The JSON string representation of <code>a</code>
*/
private function arrayToString( a:Array ):String {
// 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 += ","
}
// convert the value to a string
s += convertToString( a[i] );
}
// KNOWN ISSUE: In ActionScript, Arrays can also be associative
// objects and you can put anything in them, ie:
// myArray["foo"] = "bar";
//
// These properties aren't picked up in the for loop above because
// the properties don't correspond to indexes. However, we're
// sort of out luck because the JSON specification doesn't allow
// these types of array properties.
//
// So, if the array was also used as an associative object, there
// may be some values in the array that don't get properly encoded.
//
// A possible solution is to instead encode the Array as an Object
// but then it won't get decoded correctly (and won't be an
// Array instance)
// close the array and return it's string value
return "[" + s + "]";
}
/**
* Converts an object to it's JSON string equivalent
*
* @param o The object to convert
* @return The JSON string representation of <code>o</code>
*/
private function objectToString( o:Object ):String
{
// 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 ( [email protected]() == "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 += ","
}
s += escapeString( key ) + ":" + 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"
// 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
// no comma is necessary
if ( s.length > 0 ) {
// We've already added an item, so add the comma separator
s += ","
}
s += escapeString( [email protected]() ) + ":"
+ convertToString( o[ v.@name ] );
}
}
return "{" + s + "}";
}
}
}
------------------file end jsonencoder.as ---------------------------