/* libsswf_actions.c++ -- written by Alexis WILKE for Made to Order Software Corp. (c) 2002-2008 */

/*

Copyright (c) 2002-2008 Made to Order Software Corp.

Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and
associated documentation files (the "Software"), to
deal in the Software without restriction, including
without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the
following conditions:

The above copyright notice and this permission notice
shall be included in all copies or substantial
portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

*/

/** \file
 *
 * \brief The implementation of the sswf::Action and derived classes.
 *
 * This file declares the body of the functions which are not
 * inline. It is part of the SSWF library.
 */

#include	"sswf/libsswf.h"

using namespace sswf;



/////////////////////////////////////////// Action

/** \class sswf::Action
 *
 * \brief Holds an action.
 *
 * The Action class is used to hold ONE action. An array of actions
 * can be used to generate an ActionScript.
 *
 * The Action class represents one SWF raw action (i.e. no JavaScript!)
 *
 * The organization of actions to create a valid script is described in my
 * <a href="../SWFalexref.html#tag_doaction">Alexis' SWF Reference&mdash;Do Action</a>
 * document.
 *
 * Actions are ItemBase objects which can thus be added in a Vectors
 * array. Tags which support actions will usually expose the vector
 * used to save actions in it. Also, some actions can have sub-actions.
 * Similarly, you have the sswf::Action::SubList(void) function which
 * can be used to retrieve the sub-actions of a given action.
 *
 * Note that newer action script code is much different from the old
 * one. This applies to movies version 9 or better when setup to run
 * ActionScript version 3 (see the
 * <a href="../abcFormat.html">abcFormat.html</a> document.)
 *
 * \warning
 * Most actions which support sub-actions are limited to about 64Kb
 * of sub-action data (depending on the actions used, some actions
 * save data in the action list and can use a lot more than 1 byte,
 * especially the sswf::Action::ACTION_PUSH_DATA action!)
 *
 * \par
 * The sswf::Action::ACTION_WAIT_FOR_FRAME and sswf::Action::ACTION_WAIT_FOR_FRAME2
 * are limited to 255 bytes. Also, they branch as long as the frame
 * is not reached which is somewhat the opposite of what we would
 * usually need.
 *
 * \sa <a href="../SWFalexref.html#tag_doaction">Alexis' SWF Reference&mdash;Do Action</a>
 */



/** \enum sswf::Action::action_t
 *
 * \brief List all the actions supported by SSWF.
 *
 * These action enumeration variables are used whenever you create
 * an action object. All the actions which do not require any data
 * are created using the Action object. In this case you must specify
 * the action enumeration variable.
 *
 * Actions which require some additional data will automatically
 * receive a default (i.e. sswf::ActionBranch is set to ACTION_BRANCH_ALWAYS
 * by default.) Some cannot actually be changed by you (i.e. sswf::ActionCallFrame).
 * All of them can only receive a very few set of values. Trying to set
 * another value will generate an error on creation.
 */


/** \var sswf::Action::ACTION_UNKNOWN
 *
 * \brief The special unknown value.
 *
 * This special action number can be used to mark an entry as
 * unknown. You cannot create and save an unknown action
 * in an SWF file.
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_LABEL
 *
 * \brief A label to branch to.
 *
 * This special action repesents a label. A specific object
 * must be created to use an ACTION_LABEL the sswf::ActionLabel
 * object. You should name labels and then use their name with
 * sswf::ActionBranch to jump to the
 * instructions appearing after that label.
 *
 * It is legal to create multiple labels one after another
 * without adding other instructions in between, in effect
 * creating one label and aliases.
 *
 * \sa sswf::ActionBranch
 * \sa sswf::ActionBranch::SetLabel(const char *label)
 * \sa sswf::ActionLabel
 * \sa sswf::ActionLabel::SetLabel(const char *label)
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_min
 *
 * \brief Very first valid action.
 *
 * The ACTION_min value represents the smallest valid action
 * which can be saved in an SWF file.
 *
 * \sa sswf::Action::ACTION_max
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_END
 *
 * \brief End the current list of actions.
 *
 * The ACTION_END is for programs execution what the '\\0' is for
 * C string: it represents the end of actions.
 *
 * It is in general not necessary for your to add this action as
 * the system takes care of that for you automatically. It
 * usually makes it simpler not to add the ACTION_END actions.
 *
 * Note that this is used once to end the entire list of actions.
 * Actions within a function or other groups of actions are not
 * terminated by an ACTION_END. Instead they have a size in bytes
 * to skip their body and at the same time determine the end of
 * actions to execute as required.
 *
 * \sa <a href="../SWFalexref.html#action_end">SWF Alexis' Reference&mdash;End</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_NEXT_FRAME
 *
 * \brief Skip the next Show Frame.
 *
 * The ACTION_NEXT_FRAME is useful whenever you stop the playback
 * and thus the program pointer remains within one frame. This
 * action forces the animation to move to the next frame and
 * display it.
 *
 * \sa sswf::Action::ACTION_PLAY
 * \sa sswf::Action::ACTION_STOP
 * \sa <a href="../SWFalexref.html#action_next_frame">SWF Alexis' Reference&mdash;Next Frame</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_PREVIOUS_FRAME
 *
 * \brief Jump back one frame; before the previous ShowFrame.
 *
 * The ACTION_PREVIOUS_FRAME is useful whenever you stop the playback
 * and thus the program pointer remains within one frame. This
 * action forces the animation to move to the previous frame and
 * display it.
 *
 * \sa sswf::Action::ACTION_PLAY
 * \sa sswf::Action::ACTION_STOP
 * \sa <a href="../SWFalexref.html#action_previous_frame">SWF Alexis' Reference&mdash;Next Frame</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_PLAY
 *
 * \brief Start playing the animation.
 *
 * The ACTION_PLAY restart the playback of an animation. It is possible
 * stop an animation with ACTION_STOP. The last of ACTION_PLAY or
 * ACTION_STOP encountered in a frame is the one in effect.
 *
 * \sa ACTION_STOP
 * \sa <a href="../SWFalexref.html#action_play">SWF Alexis' Reference&mdash;Play</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_STOP
 *
 * \brief Start playing the animation.
 *
 * The ACTION_STOP stops the playback of an animation. It is possible
 * restart an animation with ACTION_PLAY. The last of ACTION_PLAY or
 * ACTION_STOP encountered in a frame is the one in effect.
 *
 * When a movie is marked as stopped, its current frame is displayed
 * but no script is played. To restart the animation, you either have
 * a button or another \e thread (i.e. a sprite) still running.
 *
 * Each sprite has its own loop and thus they can be considered threads
 * thought each one's script will be executed serially.
 *
 * \sa ACTION_PLAY
 * \sa <a href="../SWFalexref.html#action_stop">SWF Alexis' Reference&mdash;Stop</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_TOGGLE_QUALITY
 *
 * \brief Switch between low and high quality rendering.
 *
 * The ACTION_TOGGLE_QUALITY is used to switch between the different
 * quality modes available. In general, you shouldn't do that. However,
 * if you detect that the realtime frame rate is much lower than it
 * should be, you can request the quality to drop in order to increase
 * the frame rate to reasonable levels.
 *
 * This tag should not be used anymore since you cannot know exactly
 * what you are doing without first querying for the quality. Instead
 * you can use a function call.
 *
 * \sa sswf::Action::ACTION_CALL_FUNCTION
 * \sa <a href="../SWFalexref.html#action_toggle_quality">SWF Alexis' Reference&mdash;ToggleQuality</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_STOP_SOUND
 *
 * \brief Stop play sounds.
 *
 * The ACTION_STOP_SOUND requests that the player stops playing any
 * sound in the current movie. This means used in a sprite, it stops
 * the sounds of that sprite and not the entire animation.
 *
 * \sa sswf::Action::ACTION_CALL_FUNCTION
 * \sa <a href="../SWFalexref.html#action_stop_sound">SWF Alexis' Reference&mdash;StopSound</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_ADD
 *
 * \brief Add two values on the stack.
 *
 * The ACTION_ADD pops two values from the stack, add them together
 * and pushes the result back onto the stack.
 *
 * \note
 * This action should not be used anymore. It was deprecated. Instead, you should use
 * the ACTION_ADD_TYPED action which ensures proper casting (as expected in the
 * JavaScript reference&mdash;ECMA).
 *
 * \par
 * This is particularly important if you are mixing strings and numbers.
 *
 * \sa sswf::Action::ACTION_ADD_TYPED
 * \sa sswf::Action::ACTION_SUBTRACT
 * \sa <a href="../SWFalexref.html#action_add">SWF Alexis' Reference&mdash;Add</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_SUBTRACT
 *
 * \brief Subtract two values on the stack.
 *
 * The ACTION_SUBTRACT pops two values from the stack, subtract one
 * from the other and pushes the result back onto the stack.
 *
 * \sa sswf::Action::ACTION_ADD
 * \sa <a href="../SWFalexref.html#action_subtract">SWF Alexis' Reference&mdash;Subtract</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_MULTIPLY
 *
 * \brief Multiply two values on the stack.
 *
 * The ACTION_MULTIPLY pops two values from the stack, multiply them
 * together and pushes the result back onto the stack.
 *
 * \sa sswf::Action::ACTION_DIVIDE
 * \sa sswf::Action::ACTION_MODULO
 * \sa <a href="../SWFalexref.html#action_multiply">SWF Alexis' Reference&mdash;Multiply</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_DIVIDE
 *
 * \brief Divide two values on the stack.
 *
 * The ACTION_DIVIDE pops two values from the stack, divide one by the
 * other and pushes the result back onto the stack.
 *
 * \sa sswf::Action::ACTION_MULTIPLY
 * \sa sswf::Action::ACTION_MODULO
 * \sa <a href="../SWFalexref.html#action_divide">SWF Alexis' Reference&mdash;Divide</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_EQUAL
 *
 * \brief Test whether two objects are equal.
 *
 * The ACTION_EQUAL pops two values from the stack, compare them for equality
 * and pushes the result back on the stack.
 *
 * There is not action \e not \e equal. Instead you need to use this action and
 * an ACTION_LOGICAL_NOT.
 *
 * \note
 * This action should not be used anymore. It was deprecated. Instead, you should use
 * the ACTION_EQUAL_TYPED action which ensures proper casting (as expected in the
 * JavaScript reference&mdash;ECMA).
 *
 * \sa sswf::Action::ACTION_EQUAL_TYPED
 * \sa sswf::Action::ACTION_STRICT_EQUAL
 * \sa sswf::Action::ACTION_LESS_THAN
 * \sa sswf::Action::ACTION_LESS_THAN_TYPED
 * \sa sswf::Action::ACTION_GREATER_THAN_TYPED
 * \sa sswf::Action::ACTION_LOGICAL_NOT
 * \sa sswf::Action::ACTION_LOGICAL_AND
 * \sa sswf::Action::ACTION_LOGICAL_OR
 * \sa <a href="../SWFalexref.html#action_equal">SWF Alexis' Reference&mdash;Equal</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_LESS_THAN
 *
 * \brief Test whether two objects are ordered.
 *
 * The ACTION_LESS_THAN pops two values from the stack, compare them for order
 * and pushes the result back on the stack.
 *
 * Note that in older versions you only had a \c less \c than. In new SWF versions there is a
 * \c greater \c than which makes it simpler to compare either side. With only a \c less
 * \c than instruction, you need to use the ACTION_SWAP and the ACTION_LOGICAL_NOT to
 * obtain all the possible behaviors.
 *
 * \note
 * This action should not be used anymore. It was deprecated. Instead, you should use
 * the ACTION_LESS_THAN_TYPED action which ensures proper casting (as expected in the
 * JavaScript reference&mdash;ECMA).
 *
 * \sa sswf::Action::ACTION_EQUAL
 * \sa sswf::Action::ACTION_EQUAL_TYPED
 * \sa sswf::Action::ACTION_STRICT_EQUAL
 * \sa sswf::Action::ACTION_LESS_THAN_TYPED
 * \sa sswf::Action::ACTION_GREATER_THAN_TYPED
 * \sa sswf::Action::ACTION_LOGICAL_NOT
 * \sa sswf::Action::ACTION_LOGICAL_AND
 * \sa sswf::Action::ACTION_LOGICAL_OR
 * \sa <a href="../SWFalexref.html#action_less_than">SWF Alexis' Reference&mdash;Less Than</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_LOGICAL_AND
 *
 * \brief Test whether two objects are true.
 *
 * The ACTION_LOGICAL_AND pops two values from the stack, casts them to a
 * boolean value, computes the result (if both values are true, then the
 * result is true, otherwise it is false) and pushes the result back on
 * the stack.
 *
 * \sa sswf::Action::ACTION_EQUAL
 * \sa sswf::Action::ACTION_EQUAL_TYPED
 * \sa sswf::Action::ACTION_STRICT_EQUAL
 * \sa sswf::Action::ACTION_LESS_THAN
 * \sa sswf::Action::ACTION_LESS_THAN_TYPED
 * \sa sswf::Action::ACTION_GREATER_THAN_TYPED
 * \sa sswf::Action::ACTION_LOGICAL_NOT
 * \sa sswf::Action::ACTION_LOGICAL_OR
 * \sa sswf::Action::ACTION_AND
 * \sa sswf::Action::ACTION_OR
 * \sa sswf::Action::ACTION_XOR
 * \sa <a href="../SWFalexref.html#action_logical_and">SWF Alexis' Reference&mdash;Logical And</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_LOGICAL_OR
 *
 * \brief Combines two boolean value with an OR.
 *
 * The ACTION_LOGICAL_OR pops two values from the stack, cast them to boolean
 * values, compute a logical or (i.e. if at least one value is true, use true
 * otherwise use false) and pushes the result back on the stack.
 *
 * \sa sswf::Action::ACTION_EQUAL
 * \sa sswf::Action::ACTION_EQUAL_TYPED
 * \sa sswf::Action::ACTION_STRICT_EQUAL
 * \sa sswf::Action::ACTION_LESS_THAN
 * \sa sswf::Action::ACTION_LESS_THAN_TYPED
 * \sa sswf::Action::ACTION_GREATER_THAN_TYPED
 * \sa sswf::Action::ACTION_LOGICAL_NOT
 * \sa sswf::Action::ACTION_LOGICAL_AND
 * \sa sswf::Action::ACTION_AND
 * \sa sswf::Action::ACTION_OR
 * \sa sswf::Action::ACTION_XOR
 * \sa <a href="../SWFalexref.html#action_logical_or">SWF Alexis' Reference&mdash;Logical Or</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_LOGICAL_NOT
 *
 * \brief Apply a logical not to the value on the stack.
 *
 * The ACTION_LOGICAL_NOT pops one object from the stack, cast it to a boolean
 * value if necessary, then pushes \c true on the stack when the value is \c false
 * and vice versa.
 *
 * This action is particularly useful when branching since SWF
 * only supports a <i>branch if true</i> action (i.e. no <i>branch
 * if false</i> action!)
 *
 * \sa sswf::Action::ACTION_BRANCH_IF_TRUE
 * \sa sswf::Action::ACTION_EQUAL
 * \sa sswf::Action::ACTION_EQUAL_TYPED
 * \sa sswf::Action::ACTION_STRICT_EQUAL
 * \sa sswf::Action::ACTION_LESS_THAN
 * \sa sswf::Action::ACTION_LESS_THAN_TYPED
 * \sa sswf::Action::ACTION_GREATER_THAN_TYPED
 * \sa sswf::Action::ACTION_LOGICAL_AND
 * \sa sswf::Action::ACTION_LOGICAL_OR
 * \sa sswf::Action::ACTION_AND
 * \sa sswf::Action::ACTION_OR
 * \sa sswf::Action::ACTION_XOR
 * \sa <a href="../SWFalexref.html#action_logical_not">SWF Alexis' Reference&mdash;Logical Not</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_STRING_EQUAL
 *
 * \brief Test whether two strings are equal.
 *
 * The ACTION_STRING_EQUAL pops two strings from the stack, compare them for equality
 * and pushes the result back on the stack.
 *
 * This action will ensure that two strings which represent numbers are still compared
 * as strings and not numbers.
 *
 * \note
 * This action should not be used anymore. It was deprecated. Instead, you should use
 * the ACTION_EQUAL_TYPED action which ensures proper casting (as expected in the
 * JavaScript reference&mdash;ECMA).
 *
 * \sa sswf::Action::ACTION_EQUAL_TYPED
 * \sa sswf::Action::ACTION_STRICT_EQUAL
 * \sa sswf::Action::ACTION_STRING_LESS_THAN
 * \sa sswf::Action::ACTION_STRING_GREATER_THAN
 * \sa <a href="../SWFalexref.html#action_string_equal">SWF Alexis' Reference&mdash;String Equal</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_STRING_LENGTH
 *
 * \brief Compute the length of a string in characters.
 *
 * The ACTION_STRING_LENGTH pops one string, counts the number of characters
 * and pushes the result back on the stack.
 *
 * \note
 * This action should not be used anymore. It was deprecated. Instead, you should use
 * the ACTION_MBSTRING_LENGTH action which ensures the proper length for a UTF-8 string.
 *
 * \sa sswf::Action::ACTION_MBSTRING_LENGTH
 * \sa <a href="../SWFalexref.html#action_string_length">SWF Alexis' Reference&mdash;String Length</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_SUB_STRING
 *
 * \brief Retrieve part of a string.
 *
 * The ACTION_SUB_STRING pops one string and two numbers: one position
 * and one length; then it generates a new string from the sub-string
 * starting at that position and for that many characters; this is the
 * result which is pushed backed on the stack.
 *
 * \note
 * This action should not be used anymore. It was deprecated. Instead, you should use
 * the ACTION_SUB_MBSTRING action which ensures the proper position and length for a
 * UTF-8 string.
 *
 * \sa sswf::Action::ACTION_SUB_MBSTRING
 * \sa <a href="../SWFalexref.html#action_substring">SWF Alexis' Reference&mdash;SubString</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_POP
 *
 * \brief Pop one element from the stack.
 *
 * The ACTION_POP action is used to \e forget about the result of a function
 * call.
 *
 * \sa sswf::Action::ACTION_DUPLICATE
 * \sa sswf::Action::ACTION_SWAP
 * \sa <a href="../SWFalexref.html#action_pop">SWF Alexis' Reference&mdash;Pop</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_INTEGRAL_PART
 *
 * \brief Remove the fractional part of a float.
 *
 * The ACTION_INTEGRAL_PART action is used on a floating point to remove the
 * fractional part.
 *
 * This action does not round the input. It only removes the fractional part.
 * To get a rounding effect, add 0.5 to the float first.
 *
 * This is the equivalent of the floor() function in the C/C++ math library.
 *
 * One can use the modulo action with 1.0 to extract the fractional part.
 *
 * \sa sswf::Action::ACTION_MODULO
 * \sa <a href="../SWFalexref.html#action_integral_part">SWF Alexis' Reference&mdash;Integral Part</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_GET_VARIABLE
 *
 * \brief Read a variable.
 *
 * The ACTION_GET_VARIABLE action reads the content of a variable and puts it
 * on the stack. The name of the variable is taken from the stack.
 *
 * The name can be a full path.
 *
 * \sa sswf::Action::ACTION_SET_VARIABLE
 * \sa sswf::Action::ACTION_SET_LOCAL_VARIABLE
 * \sa sswf::Action::ACTION_GET_PROPERTY
 * \sa sswf::Action::ACTION_SET_PROPERTY
 * \sa sswf::Action::ACTION_GET_MEMBER
 * \sa sswf::Action::ACTION_SET_MEMBER
 * \sa sswf::Action::ACTION_DELETE
 * \sa <a href="../SWFalexref.html#action_get_variable">SWF Alexis' Reference&mdash;Get Variable</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_SET_VARIABLE
 *
 * \brief Read a variable.
 *
 * The ACTION_SET_VARIABLE action reads the content of a variable and puts it
 * on the stack. The new value for the variable is pop first from the stack,
 * then the name of the variable.
 *
 * The name can be a full path.
 *
 * \sa sswf::Action::ACTION_GET_VARIABLE
 * \sa sswf::Action::ACTION_SET_LOCAL_VARIABLE
 * \sa sswf::Action::ACTION_GET_PROPERTY
 * \sa sswf::Action::ACTION_SET_PROPERTY
 * \sa sswf::Action::ACTION_GET_MEMBER
 * \sa sswf::Action::ACTION_SET_MEMBER
 * \sa sswf::Action::ACTION_DELETE
 * \sa <a href="../SWFalexref.html#action_set_variable">SWF Alexis' Reference&mdash;Set Variable</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_SET_TARGET2
 *
 * \brief Set an object as current.
 *
 * The ACTION_SET_TARGET2 action retreives one string from the stack. The string
 * must be either the empty string (to cancel a previous set target) or the name
 * of an existing object (sprite, movie).
 *
 * Actions such as ACTION_SET_PROPERTY and ACTION_GET_PROPERTY following a set
 * target apply to the current object. In other words, when an empty string is
 * specified, the actions apply to the main object, otherwise to the specified
 * object.
 *
 * \sa sswf::Action::ACTION_GET_TARGET
 * \sa sswf::Action::ACTION_SET_TARGET
 * \sa sswf::Action::ACTION_WITH
 * \sa <a href="../SWFalexref.html#action_set_target_dynamic">SWF Alexis' Reference&mdash;Set Target <i>(dynamic)</i></a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_CONCATENATE
 *
 * \brief Concatenate two strings together.
 *
 * The ACTION_CONCATENATE action retrieves two strings from the stack, concatenate
 * them together and push the result back on the stack.
 *
 * If one of the input is not a string, the \c toString() function is called on the
 * object. If not available, an empty string is used or the SWF throws (depending
 * on the version and setup.)
 *
 * Newer versions should make use of the ACTION_ADD_TYPED instead. The add will
 * concatenate strings properly as expected unless both operands are numbers in
 * which case the usual addition is applied.
 *
 * \sa sswf::Action::ACTION_STRING_ADD_TYPED
 * \sa sswf::Action::ACTION_STRING_EQUAL
 * \sa sswf::Action::ACTION_STRICT_EQUAL
 * \sa sswf::Action::ACTION_STRING_LENGTH
 * \sa <a href="../SWFalexref.html#action_concatenate">SWF Alexis' Reference&mdash;Concatenate</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_GET_PROPERTY
 *
 * \brief Read from an object property.
 *
 * The ACTION_GET_PROPERTY action reads the content of the specified property
 * of the specified object (sprite, movie) and puts it on the stack. The \e name
 * of the property is taken from the stack as a number.
 *
 * The \e name of a property is represented by a number. The number can be either
 * an integer or a floating point, though it has been a rule to use floating points.
 *
 * In general, this is used by a compiler as an optimization. Otherwise, it is
 * recommended to use the ACTION_GET_MEMBER with the name of the property in
 * a string. Some of these numeric properties may be removed in future versions
 * of SWF.
 *
 * \sa sswf::Action::ACTION_SET_PROPERTY
 * \sa sswf::Action::ACTION_GET_VARIABLE
 * \sa sswf::Action::ACTION_SET_VARIABLE
 * \sa sswf::Action::ACTION_GET_MEMBER
 * \sa sswf::Action::ACTION_SET_MEMBER
 * \sa sswf::Action::ACTION_DELETE
 * \sa <a href="../SWFalexref.html#action_get_property">SWF Alexis' Reference&mdash;Get Property</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_SET_PROPERTY
 *
 * \brief Write to an object property.
 *
 * The ACTION_SET_PROPERTY action gets the new property value, the \e name of
 * the property (as a number) and the name of the object (as a string) from
 * the stack and saves the new property value in that object property.
 *
 * The \e name of a property is represented by a number. The number can be either
 * an integer or a floating point, though it has been a rule to use floating points.
 *
 * In general, this is used by a compiler as an optimization. Otherwise, it is
 * recommended to use the ACTION_SET_MEMBER with the name of the property in
 * a string. Some of these numeric properties may be removed in future versions
 * of SWF.
 *
 * \sa sswf::Action::ACTION_GET_PROPERTY
 * \sa sswf::Action::ACTION_GET_VARIABLE
 * \sa sswf::Action::ACTION_SET_VARIABLE
 * \sa sswf::Action::ACTION_GET_MEMBER
 * \sa sswf::Action::ACTION_SET_MEMBER
 * \sa sswf::Action::ACTION_DELETE
 * \sa <a href="../SWFalexref.html#action_set_property">SWF Alexis' Reference&mdash;Set Property</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_DUPLICATE_SPRITE
 *
 * \brief Create a new sprite from an existing sprite.
 *
 * The ACTION_DUPLICATE_SPRITE action creates a duplicate of an existing
 * sprite. The new way to do so is to use the ACTION_NEW which represents
 * the ActionScript new operator.
 *
 * The new operator is somewhat different since it will also call the
 * constructor, though some people may still want to use this action instead.
 *
 * \sa sswf::Action::ACTION_REMOVE_SPRITE
 * \sa sswf::Action::ACTION_NEW
 * \sa <a href="../SWFalexref.html#action_duplicate_sprite">SWF Alexis' Reference&mdash;Duplicate Sprite</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_REMOVE_SPRITE
 *
 * \brief Remove an existing sprite from the display list.
 *
 * The ACTION_REMOVE_SPRITE action searches for the specified sprite and
 * remove it from the display list. Once removed, the sprite is also
 * deleted and cannot be reused.
 *
 * This action should be used whenever a sprite was created with the
 * ACTION_DUPLICATE_SPRITE.
 *
 * Objects created with the ACTION_NEW operator need to be deleted with
 * the ACTION_DELETE operator.
 *
 * \sa sswf::Action::ACTION_DUPLICATE_SPRITE
 * \sa sswf::Action::ACTION_NEW
 * \sa <a href="../SWFalexref.html#action_remove_sprite">SWF Alexis' Reference&mdash;Remove Sprite</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_TRACE
 *
 * \brief Turn on TRACE mode.
 *
 * This is a Macromedia Flash internal action caught by the debugger.
 *
 * Whenever encountered, it starts tracing the execution of your code.
 *
 * In the player, it has no effect.
 *
 * \sa <a href="../SWFalexref.html#action_trace">SWF Alexis' Reference&mdash;Trace</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_START_DRAG
 *
 * \brief Start dragging an object.
 *
 * This action has the effect of attaching an object to the user's mouse.
 *
 * The following movements of the mouse will move the object until the
 * ACTION_STOP_DRAG is used.
 *
 * This action is often executed after an sswf::Event::EVENT_POINTER_DOWN.
 *
 * \sa sswf::Event::EVENT_POINTER_DOWN
 * \sa sswf::Event::EVENT_POINTER_DRAG_ENTER
 * \sa sswf::Event::EVENT_POINTER_DRAG_LEAVE
 * \sa sswf::Action::ACTION_STOP_DRAG
 * \sa <a href="../SWFalexref.html#action_start_drag">SWF Alexis' Reference&mdash;Start Drag</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_STOP_DRAG
 *
 * \brief Stop dragging the dragged object.
 *
 * This action must be called once the drag action is over. This breaks
 * the effect of having an object follow the user's mouse all over the
 * place.
 *
 * This action is often executed after an sswf::Event::EVENT_POINTER_UP.
 *
 * \sa sswf::Event::EVENT_POINTER_UP
 * \sa sswf::Event::EVENT_POINTER_DRAG_ENTER
 * \sa sswf::Event::EVENT_POINTER_DRAG_LEAVE
 * \sa sswf::Action::ACTION_STOP_DRAG
 * \sa <a href="../SWFalexref.html#action_stop_drag">SWF Alexis' Reference&mdash;Stop Drag</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_STRING_LESS_THAN
 *
 * \brief Test whether two strings are ordered.
 *
 * The ACTION_STRING_LESS_THAN pops two strings from the stack, compare them for order
 * and pushes the result back on the stack.
 *
 * This action will ensure that two strings which represent numbers are still compared
 * as strings and not numbers.
 *
 * \note
 * This action should not be used anymore. It was deprecated. Instead, you should use
 * the ACTION_LESS_THAN_TYPED action which ensures proper casting (as expected in the
 * JavaScript reference&mdash;ECMA).
 *
 * \sa sswf::Action::ACTION_LESS_THAN_TYPED
 * \sa sswf::Action::ACTION_STRING_EQUAL
 * \sa sswf::Action::ACTION_STRICT_EQUAL
 * \sa sswf::Action::ACTION_STRING_GREATER_THAN
 * \sa <a href="../SWFalexref.html#action_string_less_than">SWF Alexis' Reference&mdash;String Less Than</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_THROW
 *
 * \brief Throw an exception.
 *
 * The ACTION_THROW pops one element from the stack and generates an
 * exception of that type.
 *
 * One can use a try/catch/finaly block to manage exceptions.
 *
 * \sa sswf::Action::ACTION_TRY
 * \sa <a href="../SWFalexref.html#action_throw">SWF Alexis' Reference&mdash;Throw</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_CAST_OBJECT
 *
 * \brief Cast from one type to another.
 *
 * The ACTION_CAST_OBJECT action transform an object reference
 * from one time to another. Really, in Javascript, this means
 * making sure that an object is of a specified type. If not,
 * you get NULL. Otherwise the action has no effect.
 *
 * This is similar to sswf::Action::ACTION_INSTANCE_OF except
 * that it returns a reference to the object instead of a
 * boolean value which often is more practical.
 *
 * \sa sswf::Action::ACTION_INSTANCE_OF
 * \sa sswf::Action::ACTION_TYPE_OF
 * \sa <a href="../SWFalexref.html#action_cast_object">SWF Alexis' Reference&mdash;Cast Object</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_IMPLEMENTS
 *
 * \brief Define a list of interfaces that an object implements.
 *
 * The ACTION_IMPLEMENTS is used to mark an object as a derivation
 * of one or more objects. These other objects are expected to be
 * interfaces. This means they should only define abstract functions.
 *
 * \sa sswf::Action::ACTION_EXTENDS
 * \sa <a href="../SWFalexref.html#action_implements">SWF Alexis' Reference&mdash;Implements</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_FSCOMMAND2
 *
 * \brief Dynamic "Foreign Script Command".
 *
 * The ACTION_FSCOMMAND2 action pops an integer which is the number of
 * strings to pop next. The first string popped is the name of the
 * command to execute and the following strings are its parameters.
 *
 * FS in this action name means Foreign Script. In other words, not
 * an ActionScript command, but a javascript command from within the
 * browser.
 *
 * In order to execute dynamic ActionScript code, use the eval()
 * function instead. Note that the SWF implementation of eval() is
 * quite limited. So don't expect too much out of it.
 *
 * \sa sswf::Action::ACTION_DECLARE_FUNCTION
 * \sa sswf::Action::ACTION_DECLARE_FUNCTION2
 * \sa <a href="../SWFalexref.html#action_fscommand2">SWF Alexis' Reference&mdash;FSCommand2</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_RANDOM
 *
 * \brief Generates a random value.
 *
 * The ACTION_RANDOM action pops one number from the stack and
 * generates a random value between 0 and that number (the number
 * not included.)
 *
 * The random value is not very good in older SWF players.
 *
 * It is suggested you use the Math.Random() function instead,
 * which returns a value between 0.0 and 1.0.
 *
 * \sa sswf::Action::ACTION_CALL_METHOD
 * \sa <a href="../SWFalexref.html#action_random">SWF Alexis' Reference&mdash;Random</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_MBSTRING_LENGTH
 *
 * \brief Compute the length of a UTF-8 string in characters.
 *
 * The ACTION_MBSTRING_LENGTH pops one string, counts the number of characters
 * and pushes the result back on the stack. The string is assumed to be defined
 * in UTF-8.
 *
 * \sa sswf::Action::ACTION_STRING_LENGTH
 * \sa <a href="../SWFalexref.html#action_string_length_mb">SWF Alexis' Reference&mdash;String Length</a> <i>(multi-bytes)</i>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_ORD
 *
 * \brief Transform a character in the corresponding integer.
 *
 * The ACTION_ORD action pops one string and transform the first
 * character in a number and push that number on the stack.
 *
 * This action can only deal with ASCII strings. Use the
 * sswf::Action::ACTION_MBORD for international strings.
 *
 * \sa sswf::Action::ACTION_MBORD
 * \sa sswf::Action::ACTION_CHR
 * \sa sswf::Action::ACTION_MBCHR
 * \sa <a href="../SWFalexref.html#action_ord">SWF Alexis' Reference&mdash;Ord</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_CHR
 *
 * \brief Transform a number in the corresponding character.
 *
 * The ACTION_CHR action pops one number and transform it in a
 * character, then it pushes a string composed of that character
 * on the stack.
 *
 * This action can only deal with ASCII characters. Use the
 * sswf::Action::ACTION_MBCHR for international characters.
 *
 * \sa sswf::Action::ACTION_MBCHR
 * \sa sswf::Action::ACTION_ORD
 * \sa sswf::Action::ACTION_MBORD
 * \sa <a href="../SWFalexref.html#action_chr">SWF Alexis' Reference&mdash;Chr</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_GET_TIMER
 *
 * \brief Push the current frame number on the stack.
 *
 * The ACTION_GET_TIMER action gets the frame counter and push it on the stack.
 * This is the main frame counter for the main SWF movie.
 *
 * In the newer versions of SWF you have access to a similar function on each
 * movie (I think it is called GetFrame(), but I'd have to verify...)
 *
 * \sa <a href="../SWFalexref.html#action_get_timer">SWF Alexis' Reference&mdash;Get Timer</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_SUB_MBSTRING
 *
 * \brief Retrieve part of a string.
 *
 * The ACTION_SUB_MBSTRING pops one string and two numbers: one position
 * and one length; then it generates a new string from the sub-string
 * starting at that position and for that many characters; this is the
 * result which is pushed backed on the stack. This action views the
 * input string as a UTF-8 encoded string.
 *
 * \sa sswf::Action::ACTION_SUB_STRING
 * \sa <a href="../SWFalexref.html#action_substring">SWF Alexis' Reference&mdash;SubString</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_MBORD
 *
 * \brief Transform a character in the corresponding integer.
 *
 * The ACTION_MBORD action pops one string and transform the first
 * character in a number and push that number on the stack.
 *
 * This action deals with any character (yet SWF is limited to
 * 16 bits characters or UCS-2).
 *
 * \sa sswf::Action::ACTION_ORD
 * \sa sswf::Action::ACTION_CHR
 * \sa sswf::Action::ACTION_MBCHR
 * \sa <a href="../SWFalexref.html#action_ord_mb">SWF Alexis' Reference&mdash;Ord <i>(multibyte)</i></a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_MBCHR
 *
 * \brief Transform a number in the corresponding character.
 *
 * The ACTION_MBCHR action pops one number and transform it in a
 * character, then it pushes a string composed of that character
 * on the stack.
 *
 * This action can deal with any international characters
 * (yet SWF is limited to 16 bits characters or UCS-2.)
 *
 * \sa sswf::Action::ACTION_CHR
 * \sa sswf::Action::ACTION_ORD
 * \sa sswf::Action::ACTION_MBORD
 * \sa <a href="../SWFalexref.html#action_chr_mb">SWF Alexis' Reference&mdash;Chr <i>(multibyte)</i></a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_DELETE
 *
 * \brief Delete an object.
 *
 * The ACTION_DELETE action pops an object and a string to delete
 * a property in an object. Note that an object does not need to
 * be deleted. If all references to that object disappear, then
 * the object is automatically deleted.
 *
 * It is possible to delete a global variable by pushing <b>undefined</b>
 * on the stack instead of an object.
 *
 * \sa sswf::Action::ACTION_NEW
 * \sa sswf::Action::ACTION_GET_VARIABLE
 * \sa sswf::Action::ACTION_SET_VARIABLE
 * \sa sswf::Action::ACTION_GET_MEMBER
 * \sa sswf::Action::ACTION_SET_MEMBER
 * \sa sswf::Action::ACTION_GET_PROPERTY
 * \sa sswf::Action::ACTION_SET_PROPERTY
 * \sa <a href="../SWFalexref.html#action_delete">SWF Alexis' Reference&mdash;Delete</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_SET_LOCAL_VAR
 *
 * \brief Same as sswf::Action::ACTION_SET_LOCAL_VARIABLE.
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_SET_LOCAL_VARIABLE
 *
 * \brief Set a variable local to the function being executed.
 *
 * When running within a function, it is possible to create
 * a variable within this function. This is very useful to
 * avoid clashes between variable names between the different
 * functions you write.
 *
 * To get a local variable, use the sswf::Action::ACTION_GET_VARIABLE
 * action.
 *
 * See also the sswf::Action::ACTION_DECLARE_LOCAL_VARIABLE.
 *
 * \sa sswf::Action::ACTION_DECLARE_LOCAL_VARIABLE
 * \sa sswf::Action::ACTION_GET_VARIABLE
 * \sa sswf::Action::ACTION_SET_VARIABLE
 * \sa sswf::Action::ACTION_GET_PROPERTY
 * \sa sswf::Action::ACTION_SET_PROPERTY
 * \sa sswf::Action::ACTION_GET_MEMBER
 * \sa sswf::Action::ACTION_SET_MEMBER
 * \sa sswf::Action::ACTION_DELETE
 * \sa <a href="../SWFalexref.html#action_set_local_variable">SWF Alexis' Reference&mdash;Set Local Variable</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_CALL_FUNCTION
 *
 * \brief Call a global function.
 *
 * This action is used to call a global or internal function.
 *
 * This action cannot be used to call a function on an object.
 * Use the sswf::Action::ACTION_CALL_METHOD instead.
 *
 * When a function returns, something will be on the stack.
 * A function declared as void in ActionScript usually
 * return an <b>undefined</b> entry. Just use
 * sswf::Action::ACTION_POP to get rid of it.
 * See the sswf::Action::ACTION_RETURN to see how you can
 * return right away from a function.
 *
 * The older versions (at least up to version 6) would return
 * as many things as you were pushing on the stack. I suggest
 * you make sure only one object is returned from your functions!
 *
 * \sa sswf::Action::ACTION_DECLARE_FUNCTION
 * \sa sswf::Action::ACTION_DECLARE_FUNCTION2
 * \sa sswf::Action::ACTION_RETURN
 * \sa sswf::Action::ACTION_CALL_METHOD
 * \sa sswf::Action::ACTION_NEW_METHOD
 * \sa sswf::Action::ACTION_NEW
 * \sa sswf::Action::ACTION_CALL_FRAME
 * \sa <a href="../SWFalexref.html#action_call_function">SWF Alexis' Reference&mdash;Call Function</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_RETURN
 *
 * \brief End a function execution and return.
 *
 * The ACTION_RETURN ends a function execution.
 *
 * Whatever was last pushed on the stack is what the function
 * returns.
 *
 * In older versions (up to version 6 at least), the stack was not
 * purged meaning that you could return multiple objects on the
 * stack. This is supposedly fixed, but I did not test to confirm
 * whether this is really the case. So be careful and make sure
 * that you have only one object on the stack or expect the
 * unexpected!
 *
 * \sa sswf::Action::ACTION_CALL_FUNCTION
 * \sa sswf::Action::ACTION_CALL_METHOD
 * \sa sswf::Action::ACTION_NEW_METHOD
 * \sa sswf::Action::ACTION_NEW
 * \sa <a href="../SWFalexref.html#action_return">SWF Alexis' Reference&mdash;Return</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_MODULO
 *
 * \brief Modulo of two values on the stack.
 *
 * The ACTION_MODULO pops two values from the stack, divide one by the
 * other and pushes the rest back onto the stack.
 *
 * Use this action with 1.0 to retrieve the fractional part of a floating
 * point value.
 *
 * \sa sswf::Action::ACTION_MULTIPLY
 * \sa sswf::Action::ACTION_DIVIDE
 * \sa sswf::Action::ACTION_INTEGRAL_PART
 * \sa <a href="../SWFalexref.html#action_modulo">SWF Alexis' Reference&mdash;Modulo</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_NEW
 *
 * \brief Create a new instance of an object.
 *
 * The ACTION_NEW creates a new instance of an object. The name of the class
 * and the parameters used to call the constructor are taken from the stack.
 *
 * The constructor result will be discarded. The result of the ACTION_NEW
 * is the newly created object which in general will be saved in a variable
 * or a variable member (also called property.)
 *
 * To delete the object, remove all instances by deleting or reassigning
 * the variables holding the object.
 *
 * To call an overloaded new constructor, you need to use the
 * sswf::Action::ACTION_NEW_METHOD action instead.
 *
 * \sa sswf::Action::ACTION_DELETE
 * \sa sswf::Action::ACTION_SET_MEMBER
 * \sa sswf::Action::ACTION_SET_VARIABLE
 * \sa sswf::Action::ACTION_SET_LOCAL_VARIABLE
 * \sa sswf::Action::ACTION_CALL_FUNCTION
 * \sa sswf::Action::ACTION_CALL_METHOD
 * \sa sswf::Action::ACTION_NEW_METHOD
 * \sa <a href="../SWFalexref.html#action_new">SWF Alexis' Reference&mdash;New</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_DECLARE_LOCAL_VAR
 *
 * \brief Same as sswf::Action::ACTION_DECLARE_LOCAL_VARIABLE.
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_DECLARE_LOCAL_VARIABLE
 *
 * \brief Declare names to be used for local variables.
 *
 * The ACTION_DECLARE_LOCAL_VARIABLE action takes an array of
 * strings naming all the variables that will be created in
 * this function and need to be created locally (i.e. not
 * visible outside of this function.)
 *
 * After this function, a regular sswf::Action::ACTION_SET_VARIABLE
 * will set a local variable if its name was specified
 * in the list of this ACTION_DECLARE_LOCAL_VARIABLE
 * array.
 *
 * This action has the side effect of setting the corresponding
 * variable to <b>undefined</b>. This hides any corresponding
 * global variables in case you try to get the variable before
 * setting it.
 *
 * \sa sswf::Action::ACTION_SET_LOCAL_VARIABLE
 * \sa sswf::Action::ACTION_GET_VARIABLE
 * \sa sswf::Action::ACTION_SET_VARIABLE
 * \sa <a href="../SWFalexref.html#action_declare_local_variable">SWF Alexis' Reference&mdash;Declare Local Variable</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_DECLARE_ARRAY
 *
 * \brief Declare an array.
 *
 * The ACTION_DECLARE_ARRAY action creates an array object and
 * save the result on the stack.
 *
 * This action pops one number from the stack which is the number
 * of values pushed on the stack which will be used to initialize
 * the array. These values are then assigned to the array starting
 * at index 0. A counter of 0 means only one value is to be assigned.
 * A counter of 1 means 2 values are to be assigned. Etc.
 *
 * To initialize an array sporadically, use the
 * sswf::Action::ACTION_DECLARE_OBJECT instead.
 *
 * \sa sswf::Action::ACTION_DECLARE_OBJECT
 * \sa sswf::Action::ACTION_ENUMERATE
 * \sa <a href="../SWFalexref.html#action_declare_array">SWF Alexis' Reference&mdash;Declare Array</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_DECLARE_OBJECT
 *
 * \brief Declare an object and its properties.
 *
 * The ACTION_DECLARE_OBJECT action creates an object and
 * save the result on the stack.
 *
 * This action pops the name of the new object and the number
 * of members defined on the stack. The stack holds the name
 * and the value of each pre-defined member. The value of a
 * member can be a function (when a function is declared
 * without a name, it is stacked!) Thus, in effect, you can
 * declare methods!
 *
 * It is possible to create an array with the ACTION_DECLARE_OBJECT
 * by specifying the indices as the variable member names. In this
 * case, you can initializes an array sporadically.
 *
 * \sa sswf::Action::ACTION_DECLARE_ARRAY
 * \sa sswf::Action::ACTION_ENUMERATE
 * \sa <a href="../SWFalexref.html#action_declare_object">SWF Alexis' Reference&mdash;Declare Object</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_TYPE_OF
 *
 * \brief Determine the type of the data on the stack.
 *
 * The ACTION_TYPE_OF action pops one object from the stack,
 * determines its type, and push the name of the type back
 * on the stack as a string.
 *
 * It is suggested to use one of sswf::Action::ACTION_CAST_OBJECT
 * or sswf::Action::ACTION_INSTANCE_OF isntead.
 *
 * If you need to keep the data also, use the
 * sswf::Action::ACTION_DUPLICATE first.
 *
 * The possible types are:
 *
 * \code
 *  number
 *  boolean
 *  string
 *  object
 *  movieclip
 *  null
 *  undefined
 *  function
 * \endcode
 *
 * \sa sswf::Action::ACTION_CAST_OBJECT
 * \sa sswf::Action::ACTION_INSTANCE_OF
 * \sa <a href="../SWFalexref.html#action_type_of">SWF Alexis' Reference&mdash;Type Of</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_GET_TARGET
 *
 * \brief Make this object the target.
 *
 * Get the path to the specified sprite and make it the
 * target (as with sswf::Action::ACTION_SET_TARGET2.)
 *
 * This function lets you specify a sprite instead of a
 * path which may be difficult to determine in some circumstances.
 *
 * \sa sswf::Action::ACTION_SET_TARGET
 * \sa sswf::Action::ACTION_SET_TARGET2
 * \sa sswf::Action::ACTION_WITH
 * \sa <a href="../SWFalexref.html#action_get_target">SWF Alexis' Reference&mdash;Get Target</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_ENUMERATE
 *
 * \brief Enumerate an object or an array.
 *
 * The ACTION_ENUMERATE action pops an object, stack a NULL and
 * then stacks the object member names and corresponding values.
 *
 * This can be used with either an object or an array. In case
 * of an array, the indices replace the member names.
 *
 * Unfortunately, what is being enumerated cannot as is be used
 * to create a new object since there is no way to know how
 * many entries have been enumerated without first going through
 * the entire stack! Otherwise, the stack looks like what the
 * sswf::Action::ACTION_DECLARE_OBJECT accepts as parameters.
 *
 * \sa sswf::Action::ACTION_DECLARE_ARRAY
 * \sa sswf::Action::ACTION_DECLARE_OBJECT
 * \sa sswf::Action::ACTION_ENUMERATE_OBJECT
 * \sa <a href="../SWFalexref.html#action_enumerate">SWF Alexis' Reference&mdash;Enumerate</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_ADD_TYPED
 *
 * \brief Add according to the operand types.
 *
 * The ACTION_ADD_TYPED action pops two objects and add them according
 * to their type. If both variables are strings, concatenate them.
 * If one of the variables is a floating point, convert the other
 * to a floating point if not already a floating point, then add them
 * and put the addition result back on the stack. If both are integers,
 * add them and put the result back on the stack.
 *
 * This is the prefered way to convert the + operator of ActionScript
 * since it follows the ECMA specification.
 *
 * \sa sswf::Action::ACTION_ADD
 * \sa sswf::Action::ACTION_SUBTRACT
 * \sa <a href="../SWFalexref.html#action_add_typed">SWF Alexis' Reference&mdash;Add <i>(Typed)</i></a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_LESS_THAN_TYPED
 *
 * \brief Compare according to the operand types.
 *
 * The ACTION_LESS_THAN_TYPED action pops two objects and compare
 * them according to their type.
 *
 * This is the prefered way to convert the &lt; operator of ActionScript
 * since it follows the ECMA specification.
 *
 * \sa sswf::Action::ACTION_EQUAL
 * \sa sswf::Action::ACTION_EQUAL_TYPED
 * \sa sswf::Action::ACTION_STRICT_EQUAL
 * \sa sswf::Action::ACTION_LESS_THAN
 * \sa sswf::Action::ACTION_GREATER_THAN_TYPED
 * \sa sswf::Action::ACTION_LOGICAL_NOT
 * \sa sswf::Action::ACTION_LOGICAL_AND
 * \sa sswf::Action::ACTION_LOGICAL_OR
 * \sa <a href="../SWFalexref.html#action_less_than_typed">SWF Alexis' Reference&mdash;Less Than <i>(Typed)</i></a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_EQUAL_TYPED
 *
 * \brief Compare according to the operand types.
 *
 * The ACTION_EQUAL_TYPED action pops two objects and compare
 * them according to their type.
 *
 * This is the prefered way to convert the == operator of ActionScript
 * since it follows the ECMA specification.
 *
 * \sa sswf::Action::ACTION_EQUAL
 * \sa sswf::Action::ACTION_STRICT_EQUAL
 * \sa sswf::Action::ACTION_LESS_THAN
 * \sa sswf::Action::ACTION_LESS_THAN_TYPED
 * \sa sswf::Action::ACTION_GREATER_THAN_TYPED
 * \sa sswf::Action::ACTION_LOGICAL_NOT
 * \sa sswf::Action::ACTION_LOGICAL_AND
 * \sa sswf::Action::ACTION_LOGICAL_OR
 * \sa <a href="../SWFalexref.html#action_equal_typed">SWF Alexis' Reference&mdash;Equal <i>(Typed)</i></a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_NUMBER
 *
 * \brief Converts an object to a number.
 *
 * The ACTION_NUMBER action calls the method valueOf() of the object
 * on the stack and replaces that object with a number.
 *
 * If the operation fails, <b>undefined</b> is pushed on the stack.
 *
 * This is a good way to optimize a call to the valueOf() method of
 * any object. Also, it works on internal types.
 *
 * \sa sswf::Action::ACTION_STRING
 * \sa sswf::Action::ACTION_CALL_METHOD
 * \sa <a href="../SWFalexref.html#action_number">SWF Alexis' Reference&mdash;Number</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_STRING
 *
 * \brief Converts an object to a string.
 *
 * The ACTION_STRING action calls the method toString() of the object
 * on the stack and replaces that object with a string representing
 * the object.
 *
 * If the operation fails, <b>undefined</b> is pushed on the stack.
 *
 * This is a good way to optimize a call to the toString() method of
 * any object. Also, it works on internal types.
 *
 * \sa sswf::Action::ACTION_STRING
 * \sa sswf::Action::ACTION_CALL_METHOD
 * \sa <a href="../SWFalexref.html#action_string">SWF Alexis' Reference&mdash;String</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_DUPLICATE
 *
 * \brief Duplicate one element on the stack.
 *
 * The ACTION_DUPLICATE action pops one element from the stack and
 * pushes it back twice.
 *
 * \sa sswf::Action::ACTION_POP
 * \sa sswf::Action::ACTION_SWAP
 * \sa <a href="../SWFalexref.html#action_duplicate">SWF Alexis' Reference&mdash;Duplicate</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_SWAP
 *
 * \brief Swap the two last elements on the stack.
 *
 * The ACTION_SWAP action pops two elements from the stack and push them
 * back the other way around.
 *
 * \sa sswf::Action::ACTION_POP
 * \sa sswf::Action::ACTION_SWAP
 * \sa <a href="../SWFalexref.html#action_swap">SWF Alexis' Reference&mdash;Swap</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_GET_MEMBER
 *
 * \brief Read the value of an object member.
 *
 * The ACTION_GET_MEMBER action is similar to the sswf::Action::ACTION_GET_VARIABLE
 * but looks within an object for the variable definition and content.
 *
 * The value of a member can be a function as well as a value.
 *
 * The member name can be an index when accessing an array.
 *
 * This action replaces the sswf::Action::ACTION_GET_PROPERTY which used a number to
 * access a set of predefined member names.
 *
 * \sa sswf::Action::ACTION_SET_MEMBER
 * \sa sswf::Action::ACTION_GET_PROPERTY
 * \sa sswf::Action::ACTION_SET_PROPERTY
 * \sa sswf::Action::ACTION_GET_VARIABLE
 * \sa sswf::Action::ACTION_SET_VARIABLE
 * \sa sswf::Action::ACTION_SET_LOCAL_VARIABLE
 * \sa sswf::Action::ACTION_DELETE
 * \sa <a href="../SWFalexref.html#action_get_member">SWF Alexis' Reference&mdash;Get Member</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_SET_MEMBER
 *
 * \brief Write the value of an object member.
 *
 * The ACTION_SET_MEMBER action is similar to the sswf::Action::ACTION_SET_VARIABLE
 * but creates the variable inside an object and that is called a member.
 *
 * The value of a member can be a function as well as a value. In case it is a
 * function, it can then be called with the sswf::Action::ACTION_CALL_METHOD
 * action.
 *
 * The member name can be an index when accessing an array.
 *
 * To get rid of a member, use the sswf::Action::ACTION_DELETE action.
 *
 * This action replaces the sswf::Action::ACTION_SET_PROPERTY which used a number to
 * access a set of predefined member names.
 *
 * \sa sswf::Action::ACTION_GET_MEMBER
 * \sa sswf::Action::ACTION_GET_PROPERTY
 * \sa sswf::Action::ACTION_SET_PROPERTY
 * \sa sswf::Action::ACTION_GET_VARIABLE
 * \sa sswf::Action::ACTION_SET_VARIABLE
 * \sa sswf::Action::ACTION_SET_LOCAL_VARIABLE
 * \sa sswf::Action::ACTION_DELETE
 * \sa <a href="../SWFalexref.html#action_set_member">SWF Alexis' Reference&mdash;Set Member</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_INCREMENT
 *
 * \brief Add 1 to the value at the top of the stack.
 *
 * The ACTION_INCREMENT action adds one to the value on the stack. The
 * stack is expected to be an integer or a floating point value. Another
 * object will be converted to a number if possible.
 *
 * \sa sswf::Action::ACTION_DECREMENT
 * \sa <a href="../SWFalexref.html#action_increment">SWF Alexis' Reference&mdash;Increment</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_DECREMENT
 *
 * \brief Subtract 1 from the value at the top of the stack.
 *
 * The ACTION_DECREMENT action subtracts one to the value on the stack. The
 * stack is expected to be an integer or a floating point value. Another
 * object will be converted to a number if possible.
 *
 * \sa sswf::Action::ACTION_DECREMENT
 * \sa <a href="../SWFalexref.html#action_decrement">SWF Alexis' Reference&mdash;Decrement</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_CALL_METHOD
 *
 * \brief Call a method on an object.
 *
 * The ACTION_CALL_METHOD action calls the named method of an object
 * with the specified parameters.
 *
 * This is similar to the sswf::Action::ACTION_CALL_FUNCTION but
 * it calls the function defined within an object instead. This means
 * that the 'this' parameter will be defined in that function and it
 * can be used to access the members of the object.
 *
 * A call always returns a value. If the method is declared as a
 * function returning void (a procedure in effect), the function
 * returns <b>undefined</b>.
 *
 * \sa sswf::Action::ACTION_CALL_FUNCTION
 * \sa sswf::Action::ACTION_NEW_METHOD
 * \sa sswf::Action::ACTION_NEW
 * \sa sswf::Action::ACTION_RETURN
 * \sa <a href="../SWFalexref.html#action_call_method">SWF Alexis' Reference&mdash;Call Method</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_NEW_METHOD
 *
 * \brief Create an object and call a constructor.
 *
 * The ACTION_NEW_METHOD action creates a new instance of an object
 * and then initializes it by calling a constructor depending on
 * its parameters (constructors can be overloaded in this case.)
 *
 * This is similar to the ACTION_NEW except that the proper overloaded
 * constructor is called automatically.
 *
 * \sa sswf::Action::ACTION_CALL_FUNCTION
 * \sa sswf::Action::ACTION_NEW_METHOD
 * \sa sswf::Action::ACTION_NEW
 * \sa sswf::Action::ACTION_RETURN
 * \sa <a href="../SWFalexref.html#action_new_method">SWF Alexis' Reference&mdash;New Method</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_INSTANCE_OF
 *
 * \brief Check wether an object of an instance of a specified class.
 *
 * The ACTION_INSTANCE_OF action checks whether a given object was created
 * from a given class. Since everything in SWF is an object (including a
 * classes, interfaces, etc.), I'm not too sure how this works. I suppose
 * they can keep a link to the original object used to create another and
 * each object has a set of inheritance in case of multiple inheritance
 * (which should only happen with interfaces.)
 *
 * \sa sswf::Action::ACTION_CAST_OBJECT
 * \sa sswf::Action::ACTION_TYPE_OF
 * \sa <a href="../SWFalexref.html#action_instance_of">SWF Alexis' Reference&mdash;Instance Of</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_ENUMERATE_OBJECT
 *
 * \brief Enumerate an object or an array.
 *
 * The ACTION_ENUMERATE_OBJECT action pops an object, stacks a NULL
 * and then stacks the object member names on the stack.
 *
 * This can be used with either an object or an array. In case
 * of an array, the indices replace the member names.
 *
 * \sa sswf::Action::ACTION_DECLARE_ARRAY
 * \sa sswf::Action::ACTION_DECLARE_OBJECT
 * \sa sswf::Action::ACTION_ENUMERATE
 * \sa <a href="../SWFalexref.html#action_enumerate_object">SWF Alexis' Reference&mdash;Enumerate Object</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_AND
 *
 * \brief Apply a bitwise AND between two numbers.
 *
 * The ACTION_AND action applies a bitwise AND between two integer numbers.
 *
 * The SWF player does not support bitwise AND between floating points.
 *
 * This is the & operator in ActionScript.
 *
 * \sa sswf::Action::ACTION_LOGICAL_AND
 * \sa sswf::Action::ACTION_LOGICAL_OR
 * \sa sswf::Action::ACTION_LOGICAL_NOT
 * \sa sswf::Action::ACTION_OR
 * \sa sswf::Action::ACTION_XOR
 * \sa <a href="../SWFalexref.html#action_and">SWF Alexis' Reference&mdash;And</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_OR
 *
 * \brief Apply a bitwise OR between two numbers.
 *
 * The ACTION_OR action applies a bitwise OR between two integer numbers.
 *
 * The SWF player does not support bitwise OR between floating points.
 *
 * This is the | operator in ActionScript.
 *
 * \sa sswf::Action::ACTION_LOGICAL_AND
 * \sa sswf::Action::ACTION_LOGICAL_OR
 * \sa sswf::Action::ACTION_LOGICAL_NOT
 * \sa sswf::Action::ACTION_AND
 * \sa sswf::Action::ACTION_XOR
 * \sa <a href="../SWFalexref.html#action_or">SWF Alexis' Reference&mdash;Or</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_XOR
 *
 * \brief Apply a bitwise XOR between two numbers.
 *
 * The ACTION_XOR action applies a bitwise XOR between two integer numbers.
 *
 * The SWF player does not support bitwise XOR between floating points.
 *
 * This is the ^ operator in ActionScript.
 *
 * \sa sswf::Action::ACTION_LOGICAL_AND
 * \sa sswf::Action::ACTION_LOGICAL_OR
 * \sa sswf::Action::ACTION_LOGICAL_NOT
 * \sa sswf::Action::ACTION_AND
 * \sa sswf::Action::ACTION_OR
 * \sa <a href="../SWFalexref.html#action_xor">SWF Alexis' Reference&mdash;XOr</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_SHIFT_LEFT
 *
 * \brief Shift bits to the left.
 *
 * The ACTION_SHIFT_LEFT action shifts the bits of an integer to the left.
 *
 * The SWF player does not support shifting floating points.
 *
 * This is the &lt;&lt; operator in ActionScript.
 *
 * \sa sswf::Action::ACTION_SHIFT_RIGHT
 * \sa <a href="../SWFalexref.html#action_shift_left">SWF Alexis' Reference&mdash;Shift Left</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_SHIFT_RIGHT
 *
 * \brief Shift bits to the right.
 *
 * The ACTION_SHIFT_RIGHT action shifts the bits of an integer to the right.
 *
 * The integer is taken as a signed integer. This means that a negative integer
 * remains negative and a positive integer remains positive.
 *
 * The SWF player does not support shifting floating points.
 *
 * This is the &gt;&gt; operator in ActionScript.
 *
 * \sa sswf::Action::ACTION_SHIFT_RIGHT
 * \sa <a href="../SWFalexref.html#action_shift_right">SWF Alexis' Reference&mdash;Shift Right</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_SHIFT_RIGHT_UNSIGNED
 *
 * \brief Shift bits to the right.
 *
 * The ACTION_SHIFT_RIGHT_UNSIGNED action shifts the bits of an integer to the right.
 *
 * The integer is taken as an unsigned integer. This means that the most significant
 * bits are cleared as the value is being shifted.
 *
 * The SWF player does not support shifting floating points.
 *
 * This is the &gt;&gt;&gt; operator in ActionScript.
 *
 * \sa sswf::Action::ACTION_SHIFT_RIGHT
 * \sa <a href="../SWFalexref.html#action_shift_right_unsigned">SWF Alexis' Reference&mdash;Shift Right Unsigned</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_STRICT_EQUAL
 *
 * \brief Compare two objects without conversions.
 *
 * The ACTION_STRICT_EQUAL compare two objects without trying to convert one or the
 * other so they match. For instance, 0 == "0" is considered true, but 0 === "0"
 * is not. This action represents the === operation of ActionScript.
 *
 * \sa sswf::Action::ACTION_EQUAL
 * \sa sswf::Action::ACTION_EQUAL_TYPED
 * \sa sswf::Action::ACTION_LESS_THAN
 * \sa sswf::Action::ACTION_LESS_THAN_TYPED
 * \sa sswf::Action::ACTION_GREATER_THAN_TYPED
 * \sa sswf::Action::ACTION_LOGICAL_NOT
 * \sa sswf::Action::ACTION_LOGICAL_AND
 * \sa sswf::Action::ACTION_LOGICAL_OR
 * \sa <a href="../SWFalexref.html#action_strict_equal">SWF Alexis' Reference&mdash;Strict Equal</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_GREATER_THAN_TYPED
 *
 * \brief Compare according to the operand types.
 *
 * The ACTION_GREATER_THAN_TYPED action pops two objects and compare
 * them according to their type.
 *
 * This is the prefered way to convert the &gt; operator of ActionScript
 * since it follows the ECMA specification.
 *
 * \sa sswf::Action::ACTION_EQUAL
 * \sa sswf::Action::ACTION_EQUAL_TYPED
 * \sa sswf::Action::ACTION_STRICT_EQUAL
 * \sa sswf::Action::ACTION_LESS_THAN
 * \sa sswf::Action::ACTION_LESS_THAN_TYPED
 * \sa sswf::Action::ACTION_LOGICAL_NOT
 * \sa sswf::Action::ACTION_LOGICAL_AND
 * \sa sswf::Action::ACTION_LOGICAL_OR
 * \sa <a href="../SWFalexref.html#action_greater_than_typed">SWF Alexis' Reference&mdash;Greater Than <i>(Typed)</i></a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_STRING_GREATER_THAN
 *
 * \brief Test whether two strings are ordered.
 *
 * The ACTION_STRING_GREATER_THAN pops two strings from the stack, compare them for order
 * and pushes the result back on the stack.
 *
 * This action will ensure that two strings which represent numbers are still compared
 * as strings and not numbers.
 *
 * \note
 * This action should not be used anymore. It was deprecated. Instead, you should use
 * the ACTION_GREATER_THAN_TYPED action which ensures proper casting (as expected in the
 * JavaScript reference&mdash;ECMA).
 *
 * \sa sswf::Action::ACTION_GREATER_THAN_TYPED
 * \sa sswf::Action::ACTION_STRING_EQUAL
 * \sa sswf::Action::ACTION_STRICT_EQUAL
 * \sa sswf::Action::ACTION_STRING_LESS_THAN
 * \sa <a href="../SWFalexref.html#action_string_greater_than">SWF Alexis' Reference&mdash;String Greater Than</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_EXTENDS
 *
 * \brief Mark a class as the extension of another.
 *
 * The ACTION_EXTENDS action is used to define the inheritance of a
 * class. It is used to implement the ActionScript:
 *
 * \code
 *  class A { ...};
 *  class B extends A { ... };
 * \endcode
 *
 * \sa sswf::Action::ACTION_IMPLEMENTS
 * \sa <a href="../SWFalexref.html#action_extends">SWF Alexis' Reference&mdash;Extends</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_GOTO_FRAME
 *
 * \brief Change the frame number of the playback.
 *
 * The ACTION_GOTO_FRAME action changes the frame number of the playback.
 * This means the playback of the movie continues at the frame specified
 * by the ACTION_GOTO_FRAME. The frame is hard coded in the action so this
 * action is not usually very useful unless your frame number is a constant
 * number.
 *
 * Use the sswf::Action::ACTION_GOTO_EXPRESSION instead to be able to use
 * a variable frame number.
 *
 * \sa sswf::Action::ACTION_GOTO_LABEL
 * \sa sswf::Action::ACTION_GOTO_EXPRESSION
 * \sa <a href="../SWFalexref.html#action_goto_frame">SWF Alexis' Reference&mdash;Goto Frame</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_URL
 *
 * \brief Load the specified URL.
 *
 * The ACTION_URL action loads the specified URL.
 *
 * The target specifies how the new URL should be loaded. "_level1"
 * means that the SWF movie is replaced. "_top" replaces the entire
 * window. "_blank" opens a new window. A frame name will reload that
 * frame.
 *
 * It is also possible to execute some Javascript code using the
 * javascript: protocol instead of http or https.
 *
 * \sa sswf::Action::ACTION_URL2
 * \sa <a href="../SWFalexref.html#action_get_url">SWF Alexis' Reference&mdash;Get URL</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_STORE_REGISTER
 *
 * \brief Store the value currently at the top of the stack in a register.
 *
 * The ACTION_STORE_REGISTER action saves the value currently at the
 * top of the stack in the specified register. The value on the stack
 * is not popped. The maximum register number varies depending on the
 * version of the player and whether you are in a function or the
 * global space.
 *
 * A register can later be read with an sswf::Action::ACTION_PUSH_DATA.
 *
 * \sa sswf::Action::ACTION_PUSH_DATA
 * \sa <a href="../SWFalexref.html#action_store_register">SWF Alexis' Reference&mdash;Store Register</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_DECLARE_DICTIONARY
 *
 * \brief Declare a special array of strings which can later be pushed on the stack.
 *
 * The ACTION_DECLARE_DICTIONARY action is a list of null terminated strings.
 * These strings are numbered from 0 to 65534 and can later be pushed on the
 * stack with an sswf::Action::ACTIO_PUSH_DATA.
 *
 * This is used to compress your movies. If the same rather long string needs to
 * be pushed onto the stack many times, repeating it in each Push Data would
 * generate a larger action script than putting it once in a dictionary and
 * pushing it using the special "push a dictionary entry" feature.
 *
 * The gain can be very small. You need to measure the length of the string,
 * the overhead of declaring a dictionary and the number of times a string is
 * used. If used once, no dictionary is necessary. If the string is one character,
 * using the dictionary will actually make you lose 1 byte per Push Data...
 *
 * \sa sswf::Action::ACTION_PUSH_DATA
 * \sa <a href="../SWFalexref.html#action_declare_dictionary">SWF Alexis' Reference&mdash;Declare Dictionary</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_STRICT_MODE
 *
 * \brief Whether the ActionScript engine is strict or not.
 *
 * The ACTION_STRICT_MODE action sets the strict mode flag to true or false.
 *
 * When the strict mode is true, more checks are done to ensure that the
 * ActionScript running is more compliant to the ECMA specification.
 *
 * \sa sswf::Action::ACTION_PUSH_DATA
 * \sa <a href="../SWFalexref.html#action_strict_mode">SWF Alexis' Reference&mdash;Strict Mode</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_WAIT_FOR_FRAME
 *
 * \brief Wait for the specified frame.
 *
 * The ACTION_WAIT_FOR_FRAME action is an old action used to wait for
 * a frame while loading on a slow modem and such. Thus you could know
 * what was loaded to know whether you could display such and such
 * sprite.
 *
 * Often, the actions to execute when the frame was finaly loaded is
 * an sswf::Action::ACTION_BRANCH_ALWAYS which skips the actions to
 * be executed when the frame was not yet loaded.
 *
 * There is now ways to check for the frame number and use a regular
 * sswf::Action::ACTION_BRANCH_IF_TRUE action instead.
 *
 * \sa sswf::Action::ACTION_PUSH_DATA
 * \sa <a href="../SWFalexref.html#action_wait_for_frame">SWF Alexis' Reference&mdash;Wait for Frame</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_SET_TARGET
 *
 * \brief Apply actions to the specified sprite (or movie).
 *
 * The ACTION_SET_TARGET action is used to optimize the code or call
 * a sub-function which apply functions on what is considered the
 * current movie.
 *
 * This current movie is defined by name with this action. An empty
 * name refer to the main movie (the root). When the name of a
 * specific sprite is used, then that specific sprite functions
 * are called.
 *
 * \sa sswf::Action::ACTION_GET_TARGET
 * \sa sswf::Action::ACTION_SET_TARGET2
 * \sa sswf::Action::ACTION_WITH
 * \sa <a href="../SWFalexref.html#action_set_target">SWF Alexis' Reference&mdash;Set Target</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_GOTO_LABEL
 *
 * \brief Change the current frame in the playback system.
 *
 * The ACTION_GOTO_LABEL action requests the current sprite to
 * now play starting at the named frame. A frame is named using
 * the <a href="../SWFalexref.html#tag_framelabel">FrameLabel</a> tag.
 *
 * \sa sswf::Action::ACTION_GOTO_EXPRESSION
 * \sa sswf::Action::ACTION_GOTO_FRAME
 * \sa <a href="../SWFalexref.html#action_goto_label">SWF Alexis' Reference&mdash;Goto Label</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_WAIT_FOR_FRAME2
 *
 * \brief Wait for the specified frame.
 *
 * The ACTION_WAIT_FOR_FRAME2 action pops one value from the stack.
 * This value represents the frame it has to wait for.
 *
 * The action otherwise has a new of action it has to skip in case
 * the frame was not reached yet.
 *
 * \sa sswf::Action::ACTION_WAIT_FOR_FRAME
 * \sa <a href="../SWFalexref.html#action_wait_for_frame_dynamic">SWF Alexis' Reference&mdash;Wait for Frame <i>(dynamic)</i></a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_DECLARE_FUNCTION2
 *
 * \brief Declare a function.
 *
 * The ACTION_DECLARE_FUNCTION2 action creates a user function with
 * capabilities as defined in SWF version 7 (i.e. up to 255 registers
 * to use instead of local variables and for temporary computations.)
 *
 * These functions can also pre-define a set of registers to the
 * internal variables such as _root, _global and this.
 *
 * A function declared as void is not expected to return anything
 * on the stack. Yet the caller will get an <b>undefined</b> value.
 * A function not declared as void is expected to return a valid
 * value with the use of the sswf::Action::ACTION_RETURN action.
 *
 * \sa sswf::Action::ACTION_DECLARE_FUNCTION
 * \sa sswf::Action::ACTION_CALL_FUNCTION
 * \sa sswf::Action::ACTION_RETURN
 * \sa sswf::Action::ACTION_CALL_METHOD
 * \sa sswf::Action::ACTION_NEW_METHOD
 * \sa sswf::Action::ACTION_NEW
 * \sa <a href="../SWFalexref.html#action_declare_function2">SWF Alexis' Reference&mdash;Declare Function (V7)</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_TRY
 *
 * \brief Create a try/catch/finaly block.
 *
 * The ACTION_TRY action is used to create a block of actions to execute safely.
 * This means, if an exception occurs, it is possible to catch it. The entire
 * block is composed of one try block, zero or more catch blocks and zero or one
 * finaly block. There must be one catch or one finaly block. The finaly block is
 * always executed. A catch block is executed only if the corresponding exception
 * is caught.
 *
 * Note that internally, there is only one catch. Your compiler may decided to
 * offer you a way to catch a specific type of exception by checking the type of
 * the exception (see sswf::Action::ACTION_INSTANCE_OF).
 *
 * \sa sswf::Action::ACTION_THROW
 * \sa sswf::Action::ACTION_INSTANCE_OF
 * \sa <a href="../SWFalexref.html#action_try">SWF Alexis' Reference&mdash;Try</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_WITH
 *
 * \brief Create a \e With block.
 *
 * The ACTION_WITH action is a block of actions which react to object names by
 * first searching the name specified by the With block.
 *
 * For instance, if you have an object named MyObject and you want to access
 * the field NiceField in that object, you need to use the name:
 *
 * \code
 *  v = MyObject.NiceField
 * \endcode
 *
 * In general this is not a problem, but when many fields need to be accessed,
 * it is possible to optimize using a \e With block:
 *
 * \code
 *  With MyObject
 *    v = NiceField
 * \endcode
 *
 * In this last case, the variable NiceField is first searched as a variable
 * member in the MyObject object.
 *
 * Note that this technic works to read variable members and modify existing
 * variable members. If you need to create a new member, you will need to
 * specify the object name.
 *
 * \note
 * A \e With blocks can include another \e With block. Total there can be
 * 20 levels of objects defined in this way. Extraneous levels will be
 * ignored in V7 and earlier. It should be throwing an exception in V8
 * (not tested--according to Macromedia, it already throws in V7...)
 *
 * \bug
 * Note that can also create bugs since you may be accessing the member of
 * an object when you wanted to access a global variable instead.
 *
 * \sa sswf::Action::ACTION_GET_MEMBER
 * \sa sswf::Action::ACTION_SET_MEMBER
 * \sa sswf::Action::ACTION_GET_PROPERTY
 * \sa sswf::Action::ACTION_SET_PROPERTY
 * \sa sswf::Action::ACTION_GET_VARIABLE
 * \sa sswf::Action::ACTION_SET_VARIABLE
 * \sa sswf::Action::ACTION_SET_LOCAL_VARIABLE
 * \sa sswf::Action::ACTION_DELETE
 * \sa sswf::Action::ACTION_SET_TARGET
 * \sa sswf::Action::ACTION_SET_TARGET2
 * \sa <a href="../SWFalexref.html#action_with">SWF Alexis' Reference&mdash;With</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_PUSH_DATA
 *
 * \brief Push constants and register data on the stack.
 *
 * The ACTION_PUSH_DATA action defines a block of data to push on the
 * stack.
 *
 * It is possible to push a constant string, boolean, integer,
 * floating point, null and the undefined value.
 *
 * Also, it is possible to specify a register number to load. This is
 * the only way you can load a register set with
 * sswf::Action::ACTION_STORE_REGISTER.
 *
 * To read a variable, you first push its name on the stack using
 * this action, then you use the sswf::Action::ACTION_GET_VARIABLE.
 *
 * \sa sswf::Action::ACTION_STORE_REGISTER
 * \sa sswf::Action::ACTION_GET_VARIABLE
 * \sa <a href="../SWFalexref.html#action_push_data">SWF Alexis' Reference&mdash;Push Data</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_BRANCH_ALWAYS
 *
 * \brief Change the current execution pointer.
 *
 * The ACTION_BRANCH_ALWAYS action changes the execution pointer
 * by the specified number of bytes. The offset is a signed 16
 * bits value. This means the jump is limited to a 64Kb span.
 * Note that most ActionScripts should anyway be limited to about
 * 32Kb.
 *
 * \sa sswf::Action::ACTION_STORE_REGISTER
 * \sa sswf::Action::ACTION_GET_VARIABLE
 * \sa <a href="../SWFalexref.html#action_branch_always">SWF Alexis' Reference&mdash;Branch Always</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_URL2
 *
 * \brief Load the specified URL.
 *
 * The ACTION_URL2 action loads the specified URL. This is
 * similar to ACTION_URL except that the URL itself is taken
 * from the stack and thus can dynamically be defined (i.e.
 * read from a variable, created using an expression, etc.)
 *
 * \sa sswf::Action::ACTION_URL
 * \sa <a href="../SWFalexref.html#action_get_url2">SWF Alexis' Reference&mdash;Get Url2</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_DECLARE_FUNCTION
 *
 * \brief Declare a function.
 *
 * The ACTION_DECLARE_FUNCTION action creates a user function with
 * capabilities as defined in SWF version 5.
 *
 * These functions do not support pre-set registers or more than 4
 * registers.
 *
 * A function declared as void is not expected to return anything
 * on the stack. Yet the caller will get an <b>undefined</b> value.
 * A function not declared as void is expected to return a valid
 * value with the use of the sswf::Action::ACTION_RETURN action.
 *
 * \sa sswf::Action::ACTION_DECLARE_FUNCTION2
 * \sa sswf::Action::ACTION_CALL_FUNCTION
 * \sa sswf::Action::ACTION_RETURN
 * \sa sswf::Action::ACTION_CALL_METHOD
 * \sa sswf::Action::ACTION_NEW_METHOD
 * \sa sswf::Action::ACTION_NEW
 * \sa <a href="../SWFalexref.html#action_declare_function">SWF Alexis' Reference&mdash;Declare Function</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_BRANCH_IF_TRUE
 *
 * \brief Change the current execution pointer if true.
 *
 * The ACTION_BRANCH_IF_TRUE action branches if the value it pops
 * from the stack represents true. A true number is a non-zero
 * number. A true string is a non-empty string. Other objects
 * may have a toBoolean() function which returns true or false
 * according to their type.
 *
 * The same limitations apply to this branch as for the
 * sswf::Action::ACTION_BRANCH_ALWAYS action.
 *
 * To branch when false, use the sswf::Action::ACTION_LOGICAL_NOT
 * right before this branch.
 *
 * \sa sswf::Action::ACTION_LOGICAL_NOT
 * \sa sswf::Action::ACTION_BRANCH_ALWAYS
 * \sa sswf::Action::ACTION_CALL_FUNCTION
 * \sa sswf::Action::ACTION_RETURN
 * \sa sswf::Action::ACTION_CALL_METHOD
 * \sa sswf::Action::ACTION_NEW_METHOD
 * \sa sswf::Action::ACTION_NEW
 * \sa <a href="../SWFalexref.html#action_branch_if_true">SWF Alexis' Reference&mdash;Branch If True</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_CALL_FRAME
 *
 * \brief Call the actions defined in a frame.
 *
 * The ACTION_CALL_FRAME action is an early bird function definition.
 * You should use the sswf::Action::ACTION_DECLARE_FUNCTION and then
 * an sswf::Action::ACTION_CALL_FUNCTION instead. This frame calling
 * is nothing more than a function call, really. The name or number
 * if the frame to call is popped from the stack.
 *
 * \bug
 * This tag takes a size of 0 since it does not need any data and yet
 * it has a value over 127.
 *
 * \sa sswf::Action::ACTION_CALL_FUNCTION
 * \sa sswf::Action::ACTION_DECLARE_FUNCTION
 * \sa sswf::Action::ACTION_DECLARE_FUNCTION2
 * \sa sswf::Action::ACTION_RETURN
 * \sa <a href="../SWFalexref.html#action_call_frame">SWF Alexis' Reference&mdash;Call Frame</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_GOTO_EXPRESSION
 *
 * \brief Move the display pointer to the specified frame.
 *
 * The ACTION_GOTO_EXPRESSION action pops a string or integer from
 * the stack and go to the frame.
 *
 * The action also specifies whether the movie should stop or play.
 *
 * \sa sswf::Action::ACTION_GOTO_FRAME
 * \sa sswf::Action::ACTION_GOTO_LABEL
 * \sa <a href="../SWFalexref.html#action_goto_expression">SWF Alexis' Reference&mdash;Goto Expression</a>
 *
 * <hr>
 */


/** \var sswf::Action::ACTION_max
 *
 * \brief The very last valid action.
 *
 * The ACTION_max definition is used to clamp action numbers valid in an SWF movie.
 * Note that this is not the largest action number but instead the maximum action
 * number which can possibly be accepted at all time (until the action scheme changes!)
 * At this time this value is 255 which is inclusive.
 *
 * \sa sswf::Action::ACTION_min
 *
 * <hr>
 */










/** \brief Initialize an action.
 *
 * The Action constructor is used to initialize an action object.
 *
 * Once an action was created, you cannot change its type. You cannot
 * copy an action with the copy constructor or the assignment operator.
 * You can however sswf::Action::Duplicate() an action.
 *
 * The constructor will determine the version of the action. This is
 * important to determine the minimum version necessary for that
 * action to function in the output SWF animation.
 *
 * At this time, you can add actions to any tags (but this may change!)
 * However, only a few set of tags really support actions:
 *
 *	\li Button
 *	\li DoAction
 *	\li DoInitAction
 */
Action::Action(TagBase *tag, action_t action)
	: f_action(action), f_tag(tag)
{
	//
	// TODO: should we put FSCOMMAND2 in version 7 or 8?
	//	 (it appeared in Flash Lite 1.1)
	//
	static int		action_to_version[256] = {
		/* 0x00-0x0F */
		 1,  0,  0,  0,  1,  1,  1,  1,  1,  1, -4,  4,  4,  4, -4, -4,
		/* 0x10-0x1F */
		 4,  4,  4, -4,  4,  4,  0,  4,  4,  0,  0,  0,  4,  4,  0,  0,
		/* 0x20-0x2F */
		 4,  4,  4,  4,  4,  4,  4,  4,  4, -4,  7,  7,  7,  8,  0,  0,
		/* 0x30-0x3F */
		 4,  4,  4,  4,  4,  4,  4,  0,  0,  0,  5,  5,  5,  5,  5,  5,
		/* 0x40-0x4F */
		 5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
		/* 0x50-0x5F */
		 5,  5,  5,  5,  6,  6,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		/* 0x60-0x6F */
		 5,  5,  5,  5,  5,  5,  6,  6,  6,  7,  0,  0,  0,  0,  0,  0,
		/* 0x70-0x7F */
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		/* 0x80-0x8F */
		/*   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F */
		 0,  1,  0,  1,  0,  0,  0,  5,  5,  6,  1,  1,  3,  4,  7,  7,
		/* 0x90-0x9F */
		 0,  0,  0,  0,  5,  0,  4,  0,  0,  4,  4,  5,  0,  4,  4,  4,
		/* 0xA0-0xAF */
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		/* 0xB0-0xBF */
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		/* 0xC0-0xCF */
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		/* 0xD0-0xDF */
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		/* 0xE0-0xEF */
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		/* 0xF0-0xFF */
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
	};

	assert(f_tag != 0, "all actions need to have a tag attached to them");
	if(f_tag == 0) {
		throw ErrorManager::InternalErrorException();
	}

	if(action == ACTION_LABEL) {
		f_min_version = 1;
	}
	else {
		assert(action >= ACTION_min && action <= ACTION_max, "trying to save an invalid action number");

		/* I'm not too sure why I wanted the -4, I think that's because these
		 * instructions are supposedly different in V4.x and V5.x plugins but
		 * that doesn't seem to really be the case. Anyway, we ignore it with
		 * the use of the labs() call below.
		 */
		f_min_version = (unsigned char) labs(action_to_version[action]);

		assert(f_min_version != 0, "unknown action #%d or undefined version -- please define the version in Action::Action()", action);
	}
}



/** \fn sswf::Action::~Action(void)
 *
 * \brief Clean up the action.
 *
 * This function exists because the Action class defines virtual function. It
 * has otherwise nothing to do here.
 */


#if DEBUG
Action::Action(const Action& action)
	 : f_action(action.f_action)	// required by Visual C++ because f_action is constant
{
}
Action& Action::operator = (const Action& action)
{
	return *this;
}
#endif


/** \brief Retrieve the largest register number used.
 *
 * This function goes through the list of actions defined
 * in the Vectors array and determines what the largest
 * register used by any of the instructions is in that
 * array.
 *
 * This is necessary to determine the largest used register
 * in a version 7 function (See
 * <a href="../SWFalexref.html#action_declare_function2">Declare Function (V7)</a>.)
 * Before version 7, there could only be 4 registers and you
 * never had to determine which ones were used.
 *
 * \param[in] list A Vectors of actions
 *
 * \return The largest register number or -1 if the list of
 * actions does not use any register.
 *
 * \sa sswf::Action::GetMaxRegister
 */
int Action::GetMaximumRegister(const Vectors& list)
{
	Action		*a;
	int		idx, max, r, register_number;
	Vectors		*sub_list;

	register_number = -1;
	max = list.Count();
	for(idx = 0; idx < max; idx++) {
		a = dynamic_cast<Action *>(list.Get(idx));
		if(a->f_action >= 128) {
			sub_list = a->SubList();
			if(sub_list != 0) {
				// Function, With and others are nested type
				// of entries and they may include higher
				// action versions
				r = GetMaximumRegister(*sub_list);
				if(r > register_number) {
					register_number = r;
				}
			}
		}
		r = a->GetMaxRegister();
		if(r > register_number) {
			register_number = r;
		}
	}

	return register_number;
}


/** \brief Retrive the minimum version required to use this list of actions.
 *
 * This function sweeps through all the actions found in an
 * array and determines the minimum SWF version required for the
 * script to run.
 *
 * For instance, the 'New Method' action requires at least a version 5
 * Flash Player to work.
 */
int Action::MinimumListVersion(const Vectors& list)
{
	Action		*a;
	int		idx, max, v, version;
	Vectors		*sub_list;

	version = 1;
	max = list.Count();
	for(idx = 0; idx < max; idx++) {
		a = dynamic_cast<Action *>(list.Get(idx));
		if(a->f_action >= 128) {
			sub_list = a->SubList();
			if(sub_list != 0) {
				// Function, With and others are nested type
				// of entries and they may include higher
				// action versions
				v = MinimumListVersion(*sub_list);
				if(v > version) {
					version = v;
				}
			}
		}
		// Now Version() is a virtual function since
		// ActionTry has to check three sub-lists
		v = a->Version();
		if(v > version) {
			version = v;
		}
	}

	return version;
}


/** \brief Save a list of actions in a Data buffer.
 *
 * This function is used to save a list of actions in a Data buffer
 * for output in a Flash animation.
 *
 * \param[in] list	The list of actions to be saved, it can be NULL
 * \param[in] data	The Data buffer where the result is saved
 * \param[in] extra	Another list of actions saved after the 'list' of actions, usually is NULL
 *
 * \return 0 when no error occured, non-zero otherwise
 */
ErrorManager::error_code_t Action::SaveList(const Vectors *list, Data& data, const Vectors *extra)
{
	Action				*a;
	int				idx, max;
	const Vectors			*saved, *lst;
	bool				has_end;
	ErrorManager::error_code_t	ec;

	saved = extra;
	ec = ErrorManager::ERROR_CODE_NONE;

	has_end = false;
	lst = list;
	while(lst != 0) {
		max = lst->Count();
		for(idx = 0; idx < max; idx++) {
			if(has_end) {
				ec = ErrorManager::KeepFirst(ec, OnError(ErrorManager::ERROR_CODE_ENDED_ACTION_SCRIPT, "action END found before the end of your action script."));
			}

			a = dynamic_cast<Action *>(lst->Get(idx));

//printf("Action[%d] %p: id %d, tag = %p\n", idx, a, a->f_action, a->f_tag);

			// the offset is necessary to compute offsets of branch instructions
			// and also the With operator
			a->f_offset = data.ByteSize();

			if(a->f_action != ACTION_LABEL) {
				// there is nothing to save in a label
				ec = ErrorManager::KeepFirst(ec, a->Save(data));
				if(a->f_action == ACTION_END) {
					has_end = true;
				}
			}
		}
		lst = extra;
		extra = 0;
	}
	if(!has_end) {
		data.PutByte(Action::ACTION_END);		// end the list of actions
	}


	/* now we do the 2nd pass! */
	lst = list;
	while(lst != 0) {
		max = lst->Count();
		for(idx = 0; idx < max; idx++) {
			a = dynamic_cast<Action *>(lst->Get(idx));
			ec = ErrorManager::KeepFirst(ec, a->Save2ndPass(*lst, data));
		}
		lst = saved;
		saved = 0;
	}

	return ec;
}


/** \brief Save the action in a Data buffer.
 *
 * This function saves 'this' Action in the specified Data buffer.
 *
 * Simple actions have their byte code saved and the function returns.
 *
 * Composed actions have their SaveData() virtual function called.
 *
 * Also, actions which can include sub-ations (such as a Function or
 * a With action) get their SubList() saved as well.
 *
 * The result in an SWF animation just looks like a long list of
 * byte codes. The reality is that this technique generates blocks
 * of actions.
 *
 * \param[in] data The data buffer where the actions need to be saved
 */
ErrorManager::error_code_t Action::Save(Data& data)
{
	Data				sub_data, nested_data;
	Vectors				*sub_list;
	ErrorManager::error_code_t	ec;

	ec = ErrorManager::ERROR_CODE_NONE;

	data.PutByte(f_action);

	if(f_action >= 128) {
		sub_list = SubList();
		if(sub_list != 0) {	// Function & With are nested type of entries
			ec = SaveList(sub_list, nested_data);

			// get rid of the ACTION_END
			nested_data.SetSize(nested_data.GetSize() - CHAR_BIT);

			if(nested_data.ByteSize() >= USHRT_MAX) {
				ec = ErrorManager::KeepFirst(ec, OnError(ErrorManager::ERROR_CODE_ACTION_OVERFLOW, "too many nested instructions; length overflow."));
			}
		}

		ec = ErrorManager::KeepFirst(ec, SaveData(sub_data, nested_data));
		data.PutShort((short) sub_data.ByteSize());
		data.Append(sub_data);

		if(nested_data.ByteSize() > 0) {
			data.Append(nested_data);
		}
	}

	return ec;
}


/** \brief Query for the Vectors of sub-actions.
 *
 * By default, this function returns a NULL pointer. Actions which support
 * sub-actions (such as a ActionFunction or ActionWith) will return their
 * array of sub-actions.
 *
 * return A pointer to a list of actions or NULL
 */
Vectors *Action::SubList(void)
{
	return 0;
}


/** \brief Save a string in a way compatible to the actions.
 *
 * This functions saves a string in the Data buffer in a way that
 * the SWF actions can read it.
 *
 * The function simply calls the SaveString() of the corresponding tag
 * thus converting the string as required for a version 5 or earlier
 * movie. Strings are otherwise expected to be in UTF-8.
 *
 * \param[in] data The Data buffer where the string is to be saved
 * \param[in] string The string to save in the Data buffer
 *
 * \return The size of the string not including the null terminator,
 * 		or -1 if the function failed
 */
ErrorManager::error_code_t Action::SaveString(Data& data, const char *string)
{
	return f_tag->SaveString(data, string);
}


/** \brief Save extraneous data.
 *
 * All the actions having a byte code larger than 127 include extra-data.
 *
 * These actions need to overload this function and save these extraneous data
 * when requested to do so.
 *
 * The default function asserts.
 *
 * \note
 * This function is not a pure virtual because actions with a byte code of 0 to
 * 127 do not need to be derived.
 *
 * \param[in] data The Data buffer where the extraneous information is to be saved
 * \param[in] nested_data When the action supports sub-actions, the Data buffer
 * 		where these sub-actions have been saved
 */
ErrorManager::error_code_t Action::SaveData(Data& data, Data& nested_data)
{
	assert(0, "the action 0x%02X which has an action number of 128 or more needs to overload the SaveData() function", f_action);
	OnError(ErrorManager::ERROR_CODE_INTERNAL_ERROR, "the action 0x%02X which has an action number of 128 or more needs to overload the SaveData() function", f_action);
	return ErrorManager::ERROR_CODE_INTERNAL_ERROR;
}


/** \brief Last chance for an action to save itself right.
 *
 * This function is called after all the actions have been
 * saved in a list of actions (i.e. sswf::Action::SaveList()
 * calls sswf::Action::Save() on all the actions of a list
 * and then sswf::Action::Save2ndPass().)
 *
 * At this time, the only action which requires this second
 * pass is the sswf::ActionBranch. It will search for a
 * label and save the proper offset from itself to the
 * label.
 *
 * \bug
 * The Data buffer should not be grown by the Save2ndPass().
 * Instead it should be tweaked (i.e. some bytes overwritten
 * as required.)
 *
 * \param[in] list The list of all the actions being saved
 * \param[in] data The Data buffer where the actions were saved
 */
ErrorManager::error_code_t Action::Save2ndPass(const Vectors& list, Data& data)
{
	/* most actions don't require a 2nd pass */
	return ErrorManager::ERROR_CODE_NONE;
}


/** \brief Create a clone of 'this' Action.
 *
 * This function creates a clone of 'this' Action.
 *
 * The function knows how to create a new Action which is a clone of this
 * Action.
 *
 * Actions with extraneous data will overwrite this function and
 * duplicate their extraneous data as required.
 *
 * \note
 * This function needs to be used instead of the copy operator
 * since depending on the type of action, the result will be
 * different.
 *
 * For example, if the action to duplicate is an ActionBranch
 * you would need to do a new ActionBranch and not a new Action.
 * The Duplicate function takes care of that for you.
 *
 * \return A new action pointer
 */
Action *Action::Duplicate(void) const
{
	// errors are checked in the object which attach this action to its
	// memory manager
	return new Action(f_tag, f_action);
}


/** \fn unsigned long sswf::Action::Offset(void) const
 *
 * \brief Retrieve the offset position of this action.
 *
 * The position of an action can be used to compute different
 * offsets such as the ActionBranch offset to get the current
 * ActionScript pointer to a specific position in the
 * script.
 *
 * \return The offset in bytes of this action
 */


/** \fn virtual unsigned char sswf::Action::Version(void) const
 *
 * \brief Retrieve the minimum version required for this action.
 *
 * The minimum version required for any action is defined on
 * creation of the action. The sswf::Action::Action(TagBase *tag, action_t action)
 * function has a table which tells it the minimum SWF version
 * required for such and such action to work thus you can query
 * this value at any time.
 *
 * \return The minimum version required for this action to work
 */




/** \brief Send an error to the error manager.
 *
 * This function calls the
 * sswf::ErrorManager::OnError(error_code_t errcode, const char *message, va_list ap)
 * function whenever possible.
 *
 * The function will not be called if the action was not given a valid
 * tag object pointer on creation.
 *
 * \param[in] errcode	The error code that this call represents
 * \param[in] message	The message of this error
 * \param[in] ...	The parameters to the message
 *
 * \return Usually the input errcode parameter
 */
ErrorManager::error_code_t Action::OnError(ErrorManager::error_code_t errcode, const char *message, ...) const
{
	va_list ap;
	va_start(ap, message);
	ErrorManager::error_code_t ec = f_tag->OnError(errcode, message, ap);
	va_end(ap);

	return ec;
}



/** \brief Search for a label within a list of actions.
 *
 * A special SSWF Action is the Label Action. The label action
 * is NOT saved in the output SWF animation files. However, it is
 * required to allow branches to jump from one place to another
 * without the burden of using just offsets to know where the
 * label would otherwise be.
 *
 * The ActionBranch will search for labels.
 *
 * \note
 * The SSWF implementation never allowed a branch to jump to a
 * label defined outside of the block of actions where it (the
 * branch) is defined. This conforms to version 6 of SWF.
 *
 * \param[in] list The list of actions to be searched
 * \param[in] label The label to be searched
 *
 * \return A pointer to an ActionLabel or NULL when not found
 */
ActionLabel *Action::FindLabel(const Vectors& list, const char *label)
{
	Action		*a;
	ActionLabel	*l;
	int		idx;

	if(label == 0) {
		return 0;
	}

	idx = list.Count();
	while(idx > 0) {
		idx--;
		a = dynamic_cast<Action *>(list.Get(idx));
		if(a->f_action == ACTION_LABEL) {
			l = dynamic_cast<ActionLabel *>(a);
			if(l->GetLabel() != 0) if(strcasecmp(l->GetLabel(), label) == 0) {
				return l;
			}
		}
	}

	return 0;
}



////////////////////////////// Action BRANCH

/** \class sswf::ActionBranch
 *
 * \brief An action to change the execution pointer.
 *
 * The ActionBranch class is used to create a branch or jump from one
 * place to another in your ActionScript. Depending on the type of
 * Branch that you define, it will always be taken, or it will be
 * taken only when the current value on the stack is true.
 *
 * By default, if you do not specify the type of branch, it will
 * always branch.
 *
 * \sa <a href="../SWFalexref.html#action_branch_always">SWF Alexis' Reference&mdash;Branch Always</a>
 * \sa <a href="../SWFalexref.html#action_branch_if_true">SWF Alexis' Reference&mdash;Branch If True</a>
 */

/** \brief Initialize an branch action.
 *
 * This function initializes an ActionBranch object. You can specify which
 * action whether you want the branch to be conditional or not.
 *
 * \param[in] tag The tag in which this action is being created
 * \param[in] action The branch to be created, one of: ACTION_BRANCH_ALWAYS
 *		or ACTION_BRANCH_IF_TRUE
 */
ActionBranch::ActionBranch(TagBase *tag, action_t action)
	: Action(tag, action)
{
	assert(action == ACTION_BRANCH_ALWAYS || action == ACTION_BRANCH_IF_TRUE, "The ActionBranch expects ACTION_BRANCH_ALWAYS or ACTION_BRANCH_IF_TRUE.");

	if(action != ACTION_BRANCH_ALWAYS && action != ACTION_BRANCH_IF_TRUE) {
		throw ErrorManager::InternalErrorException();
	}

	f_label = 0;
}


/** \brief Set the label this branch needs to branch to.
 *
 * This function defines the label this branch needs to branch to. This
 * label will be searched in the same block the ActionBranch is inserted
 * in. (note that their is no 'if' block in byte code ActionScript.)
 *
 * There should be an ActionLabel for each different label defined in
 * ActionBranch objects.
 *
 * \param[in] label The label to branch to
 */
void ActionBranch::SetLabel(const char *label)
{
	MemFree(f_label);
	f_label = StrDup(label);
}



/** \brief Duplicate an ActionBranch object.
 *
 * This function creates a new ActionBranch and copies the label from this
 * ActionBranch to the new one.
 *
 * \return The ActionBranch copy
 */
Action *ActionBranch::Duplicate(void) const
{
	ActionBranch		*a;

	a = new ActionBranch(Tag(), f_action);
	if(f_label != 0) {
		a->SetLabel(f_label);
	}

	return a;
}


/** \brief Save a branch offset placeholder.
 *
 * This function saves 2 bytes which represent the offset
 * where the branch needs to go.
 *
 * Since at this time we cannot be sure of the exact offset
 * (forward offset are not yet known), we just save an offset
 * of zero. The Save2ndPass() will save the real offset.
 *
 * \param[in] data The Data buffer where the offset is saved
 * \param[in] nested_data Branches have no nested data
 */
ErrorManager::error_code_t ActionBranch::SaveData(Data& data, Data& nested_data)
{
	data.PutShort(0);		// unknown offset yet (we do it on the 2nd pass)
	return ErrorManager::ERROR_CODE_NONE;
}


/** \brief Save the real branch offset.
 *
 * This function searches the whole list of actions for the label
 * specified in the branch. If the label cannot be found, this is an
 * error and the function fails.
 *
 * When the label is found, the offset to that label is read and
 * used to compute the offset we need to save in the branch byte codes.
 *
 * If the branch cannot be generated because the offset is out of bounds
 * (i.e. smaller than 0x8000 or larger than 0x7FFF) then an error is
 * generated and the function fails.
 *
 * \param[in] list The list of actions where the label is searched
 * \param[in] data The Data buffer where the resulting offset is saved
 */
ErrorManager::error_code_t ActionBranch::Save2ndPass(const Vectors& list, Data& data)
{
	ActionLabel	*l;
	long		offset;

	// look for that label...
	l = FindLabel(list, f_label);
	if(l == 0) {
		return OnError(ErrorManager::ERROR_CODE_LABEL_NOT_FOUND, "could not find label \"%s\" in the list of actions.", f_label);
	}

	// NOTE: the result is a signed value!
	offset = l->Offset() - f_offset - 1 - 2 - 2;
	data.OverwriteShort(f_offset + 1 + 2, (short) offset);

	if(offset < (short) 0x8000 || offset > (short) 0x7FFF) {
		return OnError(ErrorManager::ERROR_CODE_LABEL_OVERFLOW, "label \"%s\" is out of bounds.", f_label);
	}

	return ErrorManager::ERROR_CODE_NONE;
}


/** \fn virtual int sswf::Action::GetMaxRegister(void) const
 *
 * \brief Retrieve the largest register used by this action.
 *
 * This function goes through all the list and sub-lists of
 * actions and retrieve the largest register currently in use.
 *
 * \note
 * Objects with sub-lists accessible with the sswf::Action::SubList(void)
 * function do not need to implement this GetMaxRegister() function.
 *
 * \sa sswf::Action::GetMaximumRegister(const Vectors& list)
 */


/** \fn TagBase *sswf::Action::Tag(void) const
 *
 * \brief Get the tag in which this action resides.
 *
 * This function returns the pointer to the tag this action
 * was created in (see the constructor!).
 *
 * \return The pointer of the tag this action was created in
 *
 * \sa sswf::Action::Action(TagBase *tag, action_t action);
 */


/** \var const action_t sswf::Action::f_action;
 *
 * \brief This action code (ACTION_...).
 *
 * This variable member holds the action code of this action.
 * It is currently read-only since changing it would require
 * changes to the minimum version and size information.
 */

/** \var unsigned long sswf::Action::f_offset;
 *
 * \brief The byte position of this action in its list.
 *
 * This offset defines the position at which the action was
 * inserted in the Data buffer while in the sswf::Action::Save() function.
 *
 * \bug
 * This offset is not defined until the sswf::Action::Save() function reaches
 * this specific action in its list of actions.
 * This is why there is a sswf::Action::Save2ndPass() so the ActionBranch
 * action can properly calculate forward references.
 */







////////////////////////////// Action CALL FRAME

/** \class sswf::ActionCallFrame
 *
 * \brief Change the SWF pointer to the specified frame.
 *
 * This tag was improperly given a number larger than 127. It actually
 * uses no immediate data, instead it uses the current number on the
 * stack.
 *
 * None-the-less, I had to create a specific Action for this tag
 * in order to overload the SaveData() function which would otherwise
 * generate an assert.
 *
 * \sa <a href="../SWFalexref.html#action_call_frame">SWF Alexis' Reference&mdash;Call Frame</a>
 */
ActionCallFrame::ActionCallFrame(TagBase *tag)
	: Action(tag, ACTION_CALL_FRAME)
{
}


/** \brief A do nothing function.
 *
 * This function is used to prevent the default SaveData() from generating
 * an assert. This is an error from Macromedia which should have created
 * a code byte smaller than 128 for this action and did not.
 *
 * This function just returns right away.
 *
 * \param[in] data The Data buffer to save extraneous data (i.e. ignored)
 * \param[in] nested_data The pre-saved sub-actions (i.e. ignored)
 */
ErrorManager::error_code_t ActionCallFrame::SaveData(Data& data, Data& nested_data)
{
	// it is necessary to have a SaveData() function
	// but there isn't any need for us to have anything
	// there since the call frame data is always empty
	return ErrorManager::ERROR_CODE_NONE;
}


////////////////////////////// Action DICTIONARY

/** \class sswf::ActionDictionary
 *
 * \brief Create a dictionary action.
 *
 * This action holds pre-defined string constants. These can later be retrieved
 * using a query in a ActionPushData action.
 *
 * Note that too small a string will not benefit from being saved in a dictionary.
 * Similarly, if the dictionary is used for only one string, it usually won't help.
 *
 * Note that there should be only one single dictionary per Action list. The
 * dictionary is visible through all the different blocks/level that an Action
 * list represents. The consequences of saving more than one ActionDictionary
 * in the same list are undefined.
 *
 * \sa <a href="../SWFalexref.html#action_declare_dictionary">SWF Alexis' Reference&mdash;Declare Dictionary</a>
 */

/** \brief Initializes the dictionary.
 *
 * Create an empty tag of type ACTION_DECLARE_DICTIONARY.
 */
ActionDictionary::ActionDictionary(TagBase *tag)
	: Action(tag, ACTION_DECLARE_DICTIONARY)
{
}


/** \brief Add a string to a dictionary.
 *
 * This function adds the specified string to the dictionary.
 *
 * There is no limit to the string or the number of string one
 * can add to a dictionary, except for the total size of an
 * action block.
 *
 * \param[in] string The string to append
 */
void ActionDictionary::AddString(const char *string)
{
	string_t	*str;

	str = new string_t;
	MemAttach(str, sizeof(string_t), "ActionDictionary::AddString() -- adding a string to the dictionary");
	str->f_string = StrDup(string);
	f_strings.Set(-1, str);
}



/** \brief Duplicate a dictionary.
 *
 * This function creates a new ActionDictionary and then copy all the
 * strings from 'this' dictionary to the new dictionary.
 *
 * \return A pointer to the new dictionary.
 */
Action *ActionDictionary::Duplicate(void) const
{
	string_t		*str;
	ActionDictionary	*d;
	int			max, idx;

	d = new ActionDictionary(Tag());
	max = f_strings.Count();
	for(idx = 0; idx < max; idx++) {
		str = dynamic_cast<string_t *>(f_strings.Get(idx));
		d->AddString(str->f_string);
	}

	return d;
}



/** \brief Save the dictionary strings.
 *
 * This function is used to save the dictionary strings
 * in the specified Data buffer.
 *
 * \param[in] data The Data buffer where the strings are to be saved
 * \param[in] nested_data The sub-actions of the dictionary (i.e. none)
 */
ErrorManager::error_code_t ActionDictionary::SaveData(Data& data, Data& nested_data)
{
	string_t			*str;
	int				max, idx;
	ErrorManager::error_code_t	ec;

	max = f_strings.Count();
	if(max > 256) {
		// we can't save more than 256 strings -- we should
		// warn the user somehow that there is something wrong
		// here!
		max = 256;
	}
	data.PutShort(max);
	for(idx = 0; idx < max; idx++) {
		str = dynamic_cast<string_t *>(f_strings.Get(idx));
		ec = SaveString(data, str->f_string);
		if(ec != ErrorManager::ERROR_CODE_NONE) {
			return ec;
		}
	}

	return ErrorManager::ERROR_CODE_NONE;
}




////////////////////////////// Action FUNCTION

/** \class sswf::ActionFunction
 *
 * \brief The action to hold an ActionScript function.
 *
 * This class is used to create an ActionFunction, meaning a
 * function to be called from within an ActionScript.
 *
 * \sa <a href="../SWFalexref.html#action_declare_function">SWF Alexis' Reference&mdash;Declare Function</a>
 * \sa <a href="../SWFalexref.html#action_declare_function2">SWF Alexis' Reference&mdash;Declare Function (V7)</a>
 */


/** \enum sswf::ActionFunction::action_function_t
 *
 * \brief List the flags supported by the DeclareFunction2 tag
 *
 * These flags can be used to very much optimize ActionScripts.
 *
 * Each special variable and arguments to functions can be saved
 * in registers for fast retrieval.
 *
 * \sa <a href="../SWFalexref.html#action_declare_function2">SWF Alexis' Reference&mdash;Declare Function (V7)</a>
 *
 * <hr>
 */


/** \var sswf::ActionFunction::ACTION_FUNCTION_LOAD_THIS
 *
 * \brief Make 'this' variable ready
 *
 * The ACTION_FUNCTION_LOAD_THIS loads a register with the value of
 * 'this'. The register depends on what is loaded before.
 *
 * \sa sswf::ActionFunction::ACTION_FUNCTION_SUPPRESS_THIS
 * \sa <a href="../SWFalexref.html#action_declare_function2">SWF Alexis' Reference&mdash;Declare Function (V7)</a>
 *
 * <hr>
 */


/** \var sswf::ActionFunction::ACTION_FUNCTION_SUPPRESS_THIS
 *
 * \brief Don't create the 'this' variable
 *
 * The ACTION_FUNCTION_SUPPRESS_THIS can be used so 'this' variable
 * is not even created. This can speed things up.
 *
 * \sa sswf::ActionFunction::ACTION_FUNCTION_LOAD_THIS
 * \sa <a href="../SWFalexref.html#action_declare_function2">SWF Alexis' Reference&mdash;Declare Function (V7)</a>
 *
 * <hr>
 */


/** \var sswf::ActionFunction::ACTION_FUNCTION_LOAD_ARGUMENTS
 *
 * \brief Load arguments in registers
 *
 * The ACTION_FUNCTION_LOAD_ARGUMENTS loads a register with the value of
 * each of the arguments specified when calling this function. The
 * registers depend on what is loaded before.
 *
 * \sa sswf::ActionFunction::ACTION_FUNCTION_SUPPRESS_ARGUMENTS
 * \sa <a href="../SWFalexref.html#action_declare_function2">SWF Alexis' Reference&mdash;Declare Function (V7)</a>
 *
 * <hr>
 */


/** \var sswf::ActionFunction::ACTION_FUNCTION_SUPPRESS_ARGUMENTS
 *
 * \brief Ignore all arguments
 *
 * The ACTION_FUNCTION_SUPPRESS_ARGUMENTS ensures that the ActionScript
 * interpreter does not spend any time saving the arguments. This useful
 * for virtual functions support.
 *
 * \sa sswf::ActionFunction::ACTION_FUNCTION_LOAD_ARGUMENTS
 * \sa <a href="../SWFalexref.html#action_declare_function2">SWF Alexis' Reference&mdash;Declare Function (V7)</a>
 *
 * <hr>
 */


/** \var sswf::ActionFunction::ACTION_FUNCTION_LOAD_SUPER
 *
 * \brief Make the 'super' variable ready
 *
 * The ACTION_FUNCTION_LOAD_SUPER loads a register with the value of
 * 'super'. The register depends on what is loaded before.
 *
 * \sa sswf::ActionFunction::ACTION_FUNCTION_SUPPRESS_SUPER
 * \sa <a href="../SWFalexref.html#action_declare_function2">SWF Alexis' Reference&mdash;Declare Function (V7)</a>
 *
 * <hr>
 */


/** \var sswf::ActionFunction::ACTION_FUNCTION_SUPPRESS_SUPER
 *
 * \brief Don't bother creating the 'super' variable
 *
 * The ACTION_FUNCTION_SUPPRESS_SUPER asks the ActionScript interpreter
 * to not bother creating the super variable. This can speed things
 * up.
 *
 * \sa sswf::ActionFunction::ACTION_FUNCTION_LOAD_SUPER
 * \sa <a href="../SWFalexref.html#action_declare_function2">SWF Alexis' Reference&mdash;Declare Function (V7)</a>
 *
 * <hr>
 */


/** \var sswf::ActionFunction::ACTION_FUNCTION_LOAD_ROOT
 *
 * \brief Make the 'root' variable ready
 *
 * The ACTION_FUNCTION_LOAD_ROOT loads a register with the value of
 * 'root'. The register depends on what is loaded before.
 *
 * \sa sswf::ActionFunction::ACTION_FUNCTION_LOAD_THIS
 * \sa sswf::ActionFunction::ACTION_FUNCTION_LOAD_PARENT
 * \sa sswf::ActionFunction::ACTION_FUNCTION_LOAD_GLOBAL
 * \sa <a href="../SWFalexref.html#action_declare_function2">SWF Alexis' Reference&mdash;Declare Function (V7)</a>
 *
 * <hr>
 */


/** \var sswf::ActionFunction::ACTION_FUNCTION_LOAD_PARENT
		ACTION_FUNCTION_LOAD_PARENT        = 0x0080,
		ACTION_FUNCTION_LOAD_GLOBAL        = 0x0100
 *
 * \brief Make the 'parent' variable ready
 *
 * The ACTION_FUNCTION_LOAD_PARENT loads a register with the value of
 * 'parent'. The register depends on what is loaded before.
 *
 * \sa sswf::ActionFunction::ACTION_FUNCTION_LOAD_THIS
 * \sa sswf::ActionFunction::ACTION_FUNCTION_LOAD_ROOT
 * \sa sswf::ActionFunction::ACTION_FUNCTION_LOAD_GLOBAL
 * \sa <a href="../SWFalexref.html#action_declare_function2">SWF Alexis' Reference&mdash;Declare Function (V7)</a>
 *
 * <hr>
 */


/** \var sswf::ActionFunction::ACTION_FUNCTION_LOAD_GLOBAL
 *
 * \brief Make the 'global' variable ready
 *
 * The ACTION_FUNCTION_LOAD_THIS loads a register with the value of
 * 'global'. The register depends on what is loaded before.
 *
 * \sa sswf::ActionFunction::ACTION_FUNCTION_SUPPRESS_THIS
 * \sa sswf::ActionFunction::ACTION_FUNCTION_LOAD_ROOT
 * \sa sswf::ActionFunction::ACTION_FUNCTION_LOAD_PARENT
 * \sa <a href="../SWFalexref.html#action_declare_function2">SWF Alexis' Reference&mdash;Declare Function (V7)</a>
 */


/** \enum sswf::ActionFunction::as_set_prop_flags_t
 *
 * \brief List of flags available to call the ASSetPropFlags() function
 *
 * This undocumented function is used to change the properties of an
 * object variable member or function member. The properties are defined
 * by three flags:
 *
 * \li Is hidden&mdash;whether the member can be seen by an enumeration action
 * \li Can delete&mdash;whether the member can be removed
 * \li Can overwrite&mdash;whether the member can be modified (this does not
 * prevent the content of a variable member from being modified)
 *
 * \sa sswf::ActionFunction::PROP_FLAG_IS_HIDDEN
 * \sa sswf::ActionFunction::PROP_FLAG_CAN_DELETE
 * \sa sswf::ActionFunction::PROP_FLAG_CAN_OVERWRITE
 *
 * <hr>
 */


/** \var sswf::ActionFunction::PROP_FLAG_IS_HIDDEN
 *
 * \brief Prevent the enumeration actions from showing this member
 *
 * The PROP_FLAG_IS_HIDDEN flag, if set, prevents the enumeration functions
 * from listing to corresponding member.
 *
 * \sa sswf::ActionFunction::PROP_FLAG_CAN_DELETE
 * \sa sswf::ActionFunction::PROP_FLAG_CAN_OVERWRITE
 *
 * <hr>
 */


/** \var sswf::ActionFunction::PROP_FLAG_CAN_DELETE
 *
 * \brief Whether a member can be removed from an object
 *
 * The PROP_FLAG_CAN_DELETE flag, if set, lets the user delete requests
 * function. Once deleted, a member loses its property flag setup. If
 * the member is re-created later, it may be required to set this flag
 * again to delete it again.
 *
 * \sa sswf::ActionFunction::PROP_FLAG_IS_HIDDEN
 * \sa sswf::ActionFunction::PROP_FLAG_CAN_OVERWRITE
 *
 * <hr>
 */


/** \var sswf::ActionFunction::PROP_FLAG_CAN_OVERWRITE
 *
 * \brief Whether a member can be overwritten in an object
 *
 * The PROP_FLAG_CAN_OVERWRITE flag, if set, means that the
 * corresponding member can be replaced (i.e. set with a
 * different type, or in case of a function, by a different
 * function.)
 *
 * This flag does not prevent a variable member from being
 * modified.
 *
 * \sa sswf::ActionFunction::PROP_FLAG_IS_HIDDEN
 * \sa sswf::ActionFunction::PROP_FLAG_CAN_DELETE
 */




/** \brief Initializes ActionFunction objects.
 *
 * This function is used to initialize ActionFunction objects.
 *
 * In debug mode it will test that the action is valid. It has
 * to be set to either:
 *
 * ACTION_DECLARE_FUNCTION or ACTION_DECLARE_FUNCTION2
 *
 * The former can be used for movies version 5 or 6, the
 * latter for movies version 7 or more.
 *
 * \param[in] tag The tag holding this action
 * \param[in] action The type of function to create
 */
ActionFunction::ActionFunction(TagBase *tag, action_t action)
	: Action(tag, action)
{
	assert(action == ACTION_DECLARE_FUNCTION || action == ACTION_DECLARE_FUNCTION2, "The ActionFunction expects ACTION_DECLARE_FUNCTION or ACTION_DECLARE_FUNCTION2.");
	if(action != ACTION_DECLARE_FUNCTION && action != ACTION_DECLARE_FUNCTION2) {
		throw ErrorManager::InternalErrorException();
	}

	f_name = 0;
	f_registers_count = 0;
	f_flags = 0;
}


/** \brief Define the name of the function.
 *
 * This function saves the specified name as the name of the function.
 *
 * This is the name you need to use to call the function later.
 *
 * Note that an object function member has no name.
 *
 * \param[in] name The new function name
 */
void ActionFunction::SetName(const char *name)
{
	MemFree(f_name);
	f_name = StrDup(name);
}


/** \brief Set the maximum number of registers to use with this function.
 *
 * With an ACTION_DECLARE_FUNCTION2, you can use as many as 255 registers
 * in your function, otherwise you are limited to 4 as before version 7.
 * Also, before version 7, the parameters cannot automatically be assigned
 * to registers and thus this function is not necessary.
 *
 * \param[in] count The number of registers you want to use
 */
void ActionFunction::SetRegistersCount(unsigned int count)
{
	if(count > 255) {
		f_registers_count = 255;
	}
	else {
		f_registers_count = count;
	}
}


/** \brief Add a function parameter.
 *
 * This function adds a parameter to the ActionFunction.
 *
 * The name is mandatory for an
 * ACTION_DECLARE_FUNCTION and optional for an ACTION_DECLARE_FUNCTION2.
 * There are some special parameter names for an ACTION_DECLARE_FUNCTION2
 * to create or not system registers. The special names are as follow:
 *
 * 	\li this &mdash; put 'this' in a register
 * 	\li /this &mdash; do not create 'this' even when available
 * 	\li arguments &mdash; put 'arguments' in a register
 * 	\li /arguments &mdash; do not create the 'arguments' array
 * 	\li super &mdash; put 'super' in a register
 * 	\li /super &mdash; do not create 'super'
 * 	\li _root &mdash; put '_root' in a register
 * 	\li /_root &mdash; cancel the action of '_root'
 * 	\li _parent &mdash; put '_parent' in a register
 * 	\li /_parent &mdash; cancel the action of '_parent'
 * 	\li _global &mdash; put '_global' in a register
 * 	\li /_global &mdash; cancel the action of '_global'
 *
 * The register number is used only by an ACTION_DECLARE_FUNCTION2.
 * By default the register number is set to -1 which means that no register
 * is assigned to that parameter. You can use 0 to have the system automatically
 * assign a register number to your parameter.
 *
 * According to my testings, the register 255 cannot be used. So you are limited
 * to a register number from 1 to 254. However, don't forget that system parameters
 * must use the first few registers! If the register number you specify is larger
 * than the one defined by the sswf::ActionFunction::SetRegistersCount(unsigned int count)
 * then it is increased as required.
 *
 * \param[in] name The name of the parameter
 * \param[in] register_number The assigned register for that parameter
 */
void ActionFunction::AddParameter(const char *name, int register_number)
{
	parameter_t	*param;

	if(name != 0 && f_action == ACTION_DECLARE_FUNCTION2) {
		if(strcmp(name, "this") == 0) {
			f_flags |= ACTION_FUNCTION_LOAD_THIS;
			f_flags &= ~ACTION_FUNCTION_SUPPRESS_THIS;
			return;
		}
		if(strcmp(name, "/this") == 0) {
			f_flags |= ACTION_FUNCTION_SUPPRESS_THIS;
			f_flags &= ~ACTION_FUNCTION_LOAD_THIS;
			return;
		}
		if(strcmp(name, "arguments") == 0) {
			f_flags |= ACTION_FUNCTION_LOAD_ARGUMENTS;
			f_flags &= ~ACTION_FUNCTION_SUPPRESS_ARGUMENTS;
			return;
		}
		if(strcmp(name, "/arguments") == 0) {
			f_flags |= ACTION_FUNCTION_SUPPRESS_ARGUMENTS;
			f_flags &= ~ACTION_FUNCTION_LOAD_ARGUMENTS;
			return;
		}
		if(strcmp(name, "super") == 0) {
			f_flags |= ACTION_FUNCTION_LOAD_SUPER;
			f_flags &= ~ACTION_FUNCTION_SUPPRESS_SUPER;
			return;
		}
		if(strcmp(name, "/super") == 0) {
			f_flags |= ACTION_FUNCTION_SUPPRESS_SUPER;
			f_flags &= ~ACTION_FUNCTION_LOAD_SUPER;
			return;
		}
		if(strcmp(name, "_root") == 0) {
			f_flags |= ACTION_FUNCTION_LOAD_ROOT;
			return;
		}
		if(strcmp(name, "/_root") == 0) {
			f_flags &= ~ACTION_FUNCTION_LOAD_ROOT;
			return;
		}
		if(strcmp(name, "_parent") == 0) {
			f_flags |= ACTION_FUNCTION_LOAD_PARENT;
			return;
		}
		if(strcmp(name, "/_parent") == 0) {
			f_flags &= ~ACTION_FUNCTION_LOAD_PARENT;
			return;
		}
		if(strcmp(name, "_global") == 0) {
			f_flags |= ACTION_FUNCTION_LOAD_GLOBAL;
			return;
		}
		if(strcmp(name, "/_global") == 0) {
			f_flags &= ~ACTION_FUNCTION_LOAD_GLOBAL;
			return;
		}
	}

	assert(register_number > -2 && register_number < 255, "ActionFunction::AddParameter() -- invalid register number specification for a function parameter");

	param = new parameter_t;
	MemAttach(param, sizeof(parameter_t), "ActionFunction::AddParameter() -- parameter_t structure");
	param->f_name = StrDup(name);
	param->f_register_number = register_number;
	if((int) f_registers_count <= register_number) {
		f_registers_count = register_number + 1;
	}
	f_parameters.Set(-1, param);
}


/** \brief Add an action in the function.
 *
 * Most functions include a set of actions to be executed when
 * called. These actions are added using this functions. It is
 * also possible to get a pointer to the sub-actions Vectors
 * and directly add the actions in the Vectors object.
 *
 * These actions are seen as the function block.
 *
 * \param[in] action The action to add to this function
 *
 * \sa sswf::ActionFunction::SubList(void)
 */
void ActionFunction::AddAction(Action *action)
{
	f_actions.Set(-1, action);
}


/** \brief Duplicate the function action.
 *
 * This function duplicates a function. This includes all the
 * parameters and actions as well as the name and number of
 * registers used in the list of parameters.
 *
 * \return A pointer to a new ActionFunction object
 */
Action *ActionFunction::Duplicate(void) const
{
	parameter_t	*param;
	ActionFunction	*f;
	Action		*a;
	int		max, idx;

	f = new ActionFunction(Tag(), f_action);
	f->SetName(f_name);
	f->SetRegistersCount(f_registers_count);
	f->f_flags = f_flags;	// this wouldn't be set just by duplicating the parameters

	max = f_parameters.Count();
	for(idx = 0; idx < max; idx++) {
		param = dynamic_cast<parameter_t *>(f_parameters.Get(idx));
		f->AddParameter(param->f_name, param->f_register_number);
	}

	max = f_actions.Count();
	for(idx = 0; idx < max; idx++) {
		a = dynamic_cast<Action *>(f_actions.Get(idx));
		f->AddAction(a->Duplicate());
	}

	return f;
}


/** \brief Get a pointer to the Vectors of sub-actions.
 *
 * This function can be used to retrieve a pointer to the
 * sub-actions Vectors object. This can be used to add
 * actions to the function in a way similar to the main
 * block.
 *
 * \return A pointer to a Vectors object expecting actions
 */
Vectors *ActionFunction::SubList(void)
{
	return &f_actions;
}


/** \brief Save the function header and nested data.
 *
 * This function creates the function header which includes
 * its name, all the parameters, whether to create or suppress
 * system registers and the size of the function block.
 *
 * Note that the function block cannot be larger than about
 * 64Kb.
 *
 * \param[in] data The Data buffer where the function is saved
 * \param[in] nested_data The Data buffer holding the function
 * 		block
 */
ErrorManager::error_code_t ActionFunction::SaveData(Data& data, Data& nested_data)
{
	parameter_t			*param;
	int				max, idx, reg;
	char				regs[256];
	ErrorManager::error_code_t	ec;

	ec = SaveString(data, f_name);

	max = f_parameters.Count();
	data.PutShort(max);

	if(f_action == ACTION_DECLARE_FUNCTION2) {

		GetMaxRegister();

		data.PutByte(f_registers_count);
		data.PutShort(f_flags);

		// mark the used registers
		memset(regs, 0, sizeof(regs));

		idx = 0;

		if((f_flags & ACTION_FUNCTION_LOAD_THIS) != 0) {
			idx++;
			regs[idx] = 1;
		}
		if((f_flags & ACTION_FUNCTION_LOAD_SUPER) != 0) {
			idx++;
			regs[idx] = 1;
		}
		if((f_flags & ACTION_FUNCTION_LOAD_ROOT) != 0) {
			idx++;
			regs[idx] = 1;
		}
		if((f_flags & ACTION_FUNCTION_LOAD_PARENT) != 0) {
			idx++;
			regs[idx] = 1;
		}
		if((f_flags & ACTION_FUNCTION_LOAD_GLOBAL) != 0) {
			idx++;
			regs[idx] = 1;
		}

		// TODO: we need to make sure that user registers don't
		//	 overlap with system registers
		for(idx = 0; idx < max; idx++) {
			param = dynamic_cast<parameter_t *>(f_parameters.Get(idx));
			if(param->f_register_number > 0 && param->f_register_number < 256) {
				regs[param->f_register_number] = 1;
			}
		}

		reg = 1;
		for(idx = 0; idx < max; idx++) {
			param = dynamic_cast<parameter_t *>(f_parameters.Get(idx));
			if(param->f_register_number == 0) {	// auto-assign register?
				while(reg < 255 && regs[reg] != 0) {
					reg++;
				}
				// TODO: should the max. by 255 instead? (TBD)
				if(reg >= 256) {
					ec = ErrorManager::KeepFirst(ec, OnError(ErrorManager::ERROR_CODE_REGISTER_OVERFLOW, "too many registers used in this function."));
					data.PutByte(0);
					data.PutByte(0);
				}
				else {
					regs[reg] = 1;
					data.PutByte(reg);
					reg++;
					data.PutByte(0);	// no variable name
				}
			}
			else if(param->f_register_number > 0) {	// user defined register?
				// TODO: we need error handling to tell whether the
				//	 same register is used multiple times
				data.PutByte(param->f_register_number);
				regs[param->f_register_number] = 1;
				if(*param->f_name != '\0') {
					ec = ErrorManager::KeepFirst(ec, SaveString(data, param->f_name));
				}
				else {
					data.PutByte(0);	// no variable name
				}
			}
			else {
				data.PutByte(0);	// no register; use variable name
				ec = ErrorManager::KeepFirst(ec, SaveString(data, param->f_name));
			}
		}
	}
	else {
		for(idx = 0; idx < max; idx++) {
			param = dynamic_cast<parameter_t *>(f_parameters.Get(idx));
			ec = ErrorManager::KeepFirst(ec, SaveString(data, param->f_name));
		}
	}

	// the actions were already saved by the Action::Save() function!
	data.PutShort((unsigned short) nested_data.ByteSize());

	return ec;
}




////////////////////////////// Action GOTO

/** \class sswf::ActionGoto
 *
 * \brief A goto action to change the current frame.
 *
 * This action is used in ActionScripts to change the current frame
 * to display.
 *
 * \sa <a href="../SWFalexref.html#action_goto_expression">SWF Alexis' Reference&mdash;Goto Expression</a>
 * \sa <a href="../SWFalexref.html#action_goto_frame">SWF Alexis' Reference&mdash;Goto Frame</a>
 * \sa <a href="../SWFalexref.html#action_goto_label">SWF Alexis' Reference&mdash;Goto Label</a>
 */

/** \brief Initializes the ActionGoto action.
 *
 * This function initializes the ActionGoto. This means the frame
 * name is set to NULL and the playback flag is set to false
 * (i.e. go to that frame and stop playing.)
 *
 * The valid actions are:
 *
 *	\li ACTION_GOTO_FRAME
 *	\li ACTION_GOTO_LABEL
 *	\li ACTION_GOTO_EXPRESSION
 */
ActionGoto::ActionGoto(TagBase *tag, action_t action)
	: Action(tag, action)
{
	assert(action == ACTION_GOTO_FRAME || action == ACTION_GOTO_LABEL || action == ACTION_GOTO_EXPRESSION,
			"The ActionGoto expects ACTION_GOTO_FRAME, ACTION_GOTO_LABEL or ACTION_GOTO_EXPRESSION.");
	if(action != ACTION_GOTO_FRAME && action != ACTION_GOTO_LABEL && action != ACTION_GOTO_EXPRESSION) {
		throw ErrorManager::InternalErrorException();
	}
	f_frame_name = 0;
	f_play = false;
}


/** \brief Set the name of the frame to go to.
 *
 * It is possible to give a name to a frame. This action can then be used
 * to go to that frame. You need to use an ACTION_GOTO_FRAME or ACTION_GOTO_LABEL
 * for this purpose. The ACTION_GOTO_EXPRESSION uses the last string on the stack
 * instead.
 *
 * In case of an ACTION_GOTO_FRAME, the name can actually be a frame number
 * in ASCII (i.e. "15"), otherwise it is the SSWF label name of a frame.
 *
 * In case of an ACTION_GOTO_LABEL, whether the label exists in the movie is not
 * being tested by the library.
 *
 * \param[in] frame_name The name of the frame you want to go to
 */
void ActionGoto::SetFrameName(const char *frame_name)
{
	MemFree(f_frame_name);
	f_frame_name = StrDup(frame_name);
}


/** \fn void sswf::ActionGoto::SetPlay(bool play)
 *
 * \brief Set whether the animation continues to play after the goto.
 *
 * This function is used to define whether the animation should continue
 * to play after it jumped to the specified frame.
 *
 * By default, the action says that the animation should stop playing.
 *
 * \param[in] play The flag to tell whether it should play (true) or not (false)
 */


/** \brief Create a duplicate of this action goto.
 *
 * Create a new ActionGoto object copy the frame name and whether to continue
 * or stop playback.
 *
 * \return The new ActionGoto object
 */
Action *ActionGoto::Duplicate(void) const
{
	ActionGoto	*a;

	a = new ActionGoto(Tag(), f_action);
	a->SetFrameName(f_frame_name);
	a->SetPlay(f_play);

	return a;
}


/** \brief Save the extraneous information of the ActionGoto.
 *
 * Save the label information of the ActionGoto object.
 *
 * \param[in] data The Data buffer where the ActionGoto is to be saved
 * \param[in] nested_data There is no nested data in an ActionGoto
 */
ErrorManager::error_code_t ActionGoto::SaveData(Data& data, Data& nested_data)
{
	TagBase				*tag;
	const char			*s;
	long				no;
	ErrorManager::error_code_t	ec;

	ec = ErrorManager::ERROR_CODE_NONE;

	switch(f_action) {
	case ACTION_GOTO_LABEL:
		/* in this case the user wants to use a label */
		ec = SaveString(data, f_frame_name);
		break;

	case ACTION_GOTO_FRAME:
		/* here we have to find what ShowFrame is linked to this entry */
		no = 0;
		s = f_frame_name;
		while(*s >= '0' && *s <= '9') {
			no = no * 10 + *s - '0';
			++s;
		}
		if(*s == '\0' && s != f_frame_name) {
			data.PutShort(no);
		}
		else {
			tag = Tag()->FindLabelledTag(f_frame_name);
			if(tag == 0) {
				/* ha! couldn't find this object... */
				ec = OnError(ErrorManager::ERROR_CODE_OBJECT_NOT_FOUND, "cannot find any tag labelled '%s'.", f_frame_name);
				data.PutShort(0);	// a default, just so the file is not boggus.
			}
			else {
				data.PutShort(tag->WhichFrame());
			}
		}
		break;

	case ACTION_GOTO_EXPRESSION:
		// TODO: my doc. says this is a char not a short...
		//	 we need to test to know who's right!
		data.PutShort(f_play);
		break;

	default:
		assert(0, "invalid f_action for an ActionGoto() object");
		ec = OnError(ErrorManager::ERROR_CODE_INTERNAL_ERROR, "invalid f_action for an ActionGoto() object");
		break;

	}

	return ec;
}


////////////////////////////// Action LABEL

/** \class sswf::ActionLabel
 *
 * \brief Create a label in an action script.
 *
 * An ActionLabel is an SSWF addition which is not saved in the SWF
 * movie. It is used to indicate where a BranchAction can branch.
 */


/** \brief Initialize an ActionLabel.
 *
 * An action label is set to "no name" by default. You are expected
 * to call SetLabel() once initialized.
 *
 * \param[in] tag The tag including this action
 */
ActionLabel::ActionLabel(TagBase *tag)
	: Action(tag, ACTION_LABEL)
{
	f_label = 0;
}


/** \brief Set the name of an ActionLabel.
 *
 * This function defines the name of an ActionLabel. The name
 * can be any valid string. It should not be empty.
 *
 * \param[in] label The new label name
 */
void ActionLabel::SetLabel(const char *label)
{
	MemFree(f_label);
	f_label = StrDup(label);
}


/** \fn ActionLabel::GetLabel(void) const
 *
 * \brief Get the name of this label.
 *
 * This function retrieves the name of this label. It is used to search
 * all the labels in an array of actions.
 *
 * \return The name of this label
 */


/** \brief Create a duplicate of the label.
 *
 * This function creates a new label action and copies the
 * label of 'this' action.
 *
 * \return The pointer to the new ActionLabel
 */
Action *ActionLabel::Duplicate(void) const
{
	ActionLabel		*a;

	a = new ActionLabel(Tag());
	if(f_label != 0) {
		a->SetLabel(f_label);
	}

	return a;
}


////////////////////////////// Action PUSH DATA

/** \class sswf::ActionPushData
 *
 * \brief The PushData action adds data on the ActionScript stack.
 *
 * Create a PushData action each time you need some constant data
 * or the content of a register on the ActionScript stack.
 *
 * \sa <a href="../SWFalexref.html#action_push_data">SWF Alexis' Reference&mdash;Push Data</a>
 */


/** \brief The PushData constructor initialize an ActionPushData object
 *
 * The ActionPushData constructor expects a valid parent tag (a TagHeader
 * or a TagSprite.) Call the Add functions to add the different values
 * necessary on the stack.
 *
 * \param[in] tag The tag in which this action is inserted
 */
ActionPushData::ActionPushData(TagBase *tag)
	: Action(tag, ACTION_PUSH_DATA)
{
}

/** \fn sswf::ActionPushData::AddEmptyString(void)
 *
 * \brief Add an empty string on the stack
 *
 * This function is the same as AddString(NULL).
 *
 * \sa sswf::ActionPushData::AddString()
 */



/** \fn sswf::ActionPushData::AddTrue(void)
 *
 * \brief Add the boolean value True
 *
 * This function is the same as AddBoolean(true).
 *
 * \sa sswf::ActionPushData::AddBoolean()
 */



/** \fn sswf::ActionPushData::AddFalse(void)
 *
 * \brief Add the boolean value False
 *
 * This function is the same as AddBoolean(false).
 *
 * \sa sswf::ActionPushData::AddBoolean()
 */



/** \brief Add a string to the ActionPushData.
 *
 * This function adds a string to the action.
 *
 * \sa sswf::ActionPushData::AddEmptyString()
 * \param[in] string The string to add to the action
 */
void ActionPushData::AddString(const char *string)
{
	action_immediate_t	*imm;

	imm = new action_immediate_t(ACTION_IMMEDIATE_TYPE_STRING);
	MemAttach(imm, sizeof(action_immediate_t), "ActionPushData::AddString() -- immediate data structure");
	if(string != 0) {
		imm->f_data.f_string = StrDup(string);
	}
	f_data.Set(-1, imm);
}


/** \brief Add a boolean value to the ActionPushData.
 *
 * This function adds a boolean value (true or false) to the ActionPushData.
 * Note that it is a good idea to use a boolean value for an ACTION_BRANCH_IF_TRUE
 * byte code. However, this is very similar to an integer or even a float.
 *
 * \param[in] value The boolean value (true or false)
 */
void ActionPushData::AddBoolean(bool value)
{
	action_immediate_t	*imm;

	imm = new action_immediate_t(ACTION_IMMEDIATE_TYPE_BOOLEAN);
	MemAttach(imm, sizeof(action_immediate_t), "ActionPushData::AddBoolean() -- immediate data structure");
	imm->f_data.f_boolean = value;
	f_data.Set(-1, imm);
}


/** \brief Add an integer to the ActionPushData.
 *
 * This function adds a 32 bits integer to the ActionPushData
 *
 * \param[in] value A 32 bits integer
 */
void ActionPushData::AddInteger(long value)
{
	action_immediate_t	*imm;

	imm = new action_immediate_t(ACTION_IMMEDIATE_TYPE_INTEGER);
	MemAttach(imm, sizeof(action_immediate_t), "ActionPushData::AddInteger() -- immediate data structure");
	imm->f_data.f_integer32 = value;
	f_data.Set(-1, imm);
}


/** \brief Add a floating point value to the ActionPushData.
 *
 * This function adds a 32 bits floating point to the ActionPushData object.
 *
 * \param[in] value A 32 bits floating point value
 */
void ActionPushData::AddFloat(float value)
{
	action_immediate_t	*imm;

	imm = new action_immediate_t(ACTION_IMMEDIATE_TYPE_FLOAT);
	MemAttach(imm, sizeof(action_immediate_t), "ActionPushData::AddDouble() -- immediate data structure");
	imm->f_data.f_float32 = value;
	f_data.Set(-1, imm);
}


/** \brief Add a floating point to the ActionPushData.
 *
 * This function adds a 64 bits floating point value to the ActionPushData object
 *
 * \param[in] value The 64 bits floating point value
 */
void ActionPushData::AddDouble(double value)
{
	action_immediate_t	*imm;

	imm = new action_immediate_t(ACTION_IMMEDIATE_TYPE_DOUBLE);
	MemAttach(imm, sizeof(action_immediate_t), "ActionPushData::AddDouble() -- immediate data structure");
	imm->f_data.f_float64 = value;
	f_data.Set(-1, imm);
}


/** \brief Add the special value NULL to the ActionPushData.
 *
 * This function is used to add the special value NULL to an
 * ActionPushData. This value is also called Nil in some
 * ActionScripts. It represents a "no object reference".
 */
void ActionPushData::AddNull(void)
{
	action_immediate_t	*imm;

	imm = new action_immediate_t(ACTION_IMMEDIATE_TYPE_NULL);
	MemAttach(imm, sizeof(action_immediate_t), "ActionPushData::AddNull() -- immediate data structure");
	f_data.Set(-1, imm);
}


/** \brief Add the undefined value to the ActionPushData.
 *
 * This function is used to add the special value Undefined to
 * an ActionPushData. This is value is used to test whether
 * some object, function, variable is defined or not.
 *
 * It can also be used to pass as a parameter to a function
 * which requires a parameter you cannot define.
 */
void ActionPushData::AddUndefined(void)
{
	action_immediate_t	*imm;

	imm = new action_immediate_t(ACTION_IMMEDIATE_TYPE_UNDEFINED);
	MemAttach(imm, sizeof(action_immediate_t), "ActionPushData::AddUndefined() -- immediate data structure");
	f_data.Set(-1, imm);
}


/** \brief Add a string from the dictionary.
 *
 * This function adds a string to the ActionPushData object. The index
 * is the string index in this ActionScript dictionary.
 *
 * Don't forget that you can have only one dictionary within one tag.
 *
 * \param[in] index The index of the string to be added on the stack
 */
void ActionPushData::AddLookup(unsigned short index)
{
	action_immediate_t	*imm;

	imm = new action_immediate_t(index >= 256 ? ACTION_IMMEDIATE_TYPE_LOOKUP_LARGE : ACTION_IMMEDIATE_TYPE_LOOKUP);
	MemAttach(imm, sizeof(action_immediate_t), "ActionPushData::AddLookup() -- immediate data structure");
	imm->f_data.f_lookup = index;
	f_data.Set(-1, imm);
}


/** \brief Add the content of a register.
 *
 * This function adds the content of the specified register. This is particularly
 * useful for version 7+ functions which can save all their parameters in registers.
 * Then you avoid an ActionGetVariable.
 *
 * The register index is limited to 0, 1, 2 and 3 for the main script and any scripts
 * before version 7. Since version 7, registers can be set from 0 to 254 within a
 * function 2 declaration.
 *
 * \param[in] reg_index The index of the register to read
 */
void ActionPushData::AddRegister(unsigned char reg_index)
{
	action_immediate_t	*imm;

	// we would need to know whether we're in a function
	// (limit outside a function is 0..3 and in a function 0..255 or 254)
	//assert(reg_index < 256, "invalid register index, limited to the range 0..3 inclusive");

	imm = new action_immediate_t(ACTION_IMMEDIATE_TYPE_REGISTER);
	MemAttach(imm, sizeof(action_immediate_t), "ActionPushData::AddRegister() -- immediate data structure");
	imm->f_data.f_register = reg_index;
	f_data.Set(-1, imm);
}




/** \brief Duplicate an ActionPushData.
 *
 * This function creates a new ActionPushData object and copies
 * 'this' ActionPushData in it.
 *
 * The function copies all the data which was added to the
 * ActionPushData.
 *
 * \return The new ActionPushData pointer
 */
Action *ActionPushData::Duplicate(void) const
{
	ActionPushData		*a;
	action_immediate_t	*imm;
	int			i, max;

	a = new ActionPushData(Tag());

	max = f_data.Count();
	for(i = 0; i < max; i++) {
		imm = dynamic_cast<action_immediate_t *>(f_data.Get(i));
		switch(imm->f_type) {
		case ACTION_IMMEDIATE_TYPE_STRING:
			a->AddString(imm->f_data.f_string);
			break;

		case ACTION_IMMEDIATE_TYPE_FLOAT:
			a->AddFloat(imm->f_data.f_float32);
			break;

		case ACTION_IMMEDIATE_TYPE_BOOLEAN:
			a->AddBoolean(imm->f_data.f_boolean);
			break;

		case ACTION_IMMEDIATE_TYPE_DOUBLE:
			a->AddDouble(imm->f_data.f_float64);
			break;

		case ACTION_IMMEDIATE_TYPE_INTEGER:
			a->AddInteger(imm->f_data.f_integer32);
			break;

		case ACTION_IMMEDIATE_TYPE_LOOKUP:
		case ACTION_IMMEDIATE_TYPE_LOOKUP_LARGE:
			a->AddLookup(imm->f_data.f_lookup);
			break;

		case ACTION_IMMEDIATE_TYPE_REGISTER:
			a->AddRegister(imm->f_data.f_register);
			break;

		case ACTION_IMMEDIATE_TYPE_NULL:
			a->AddNull();
			break;

		case ACTION_IMMEDIATE_TYPE_UNDEFINED:
			a->AddUndefined();
			break;

		default:
			assert(0, "unknown immediate data type");
			/*NOTREACHED*/

		}
	}

	return a;
}


/** \brief Search the action for registers and return the largest number.
 *
 * This function defines what the largest register is in this
 * ActionPushData.
 *
 * \return The largest register used in this ActionPushData
 */
int ActionPushData::GetMaxRegister(void) const
{
	action_immediate_t	*imm;
	int			register_number;
	int			i;

	register_number = -1;

	i = f_data.Count();
	while(i > 0) {
		i--;
		imm = dynamic_cast<action_immediate_t *>(f_data.Get(i));
		switch(imm->f_type) {
		case ACTION_IMMEDIATE_TYPE_STRING:
		case ACTION_IMMEDIATE_TYPE_FLOAT:
		case ACTION_IMMEDIATE_TYPE_BOOLEAN:
		case ACTION_IMMEDIATE_TYPE_DOUBLE:
		case ACTION_IMMEDIATE_TYPE_INTEGER:
		case ACTION_IMMEDIATE_TYPE_NULL:
		case ACTION_IMMEDIATE_TYPE_UNDEFINED:
			break;

		case ACTION_IMMEDIATE_TYPE_LOOKUP:
		case ACTION_IMMEDIATE_TYPE_LOOKUP_LARGE:
			// here we would need to check in the dictionary
			// to know whether the dictionary is itself defining
			// a register...
			break;

		case ACTION_IMMEDIATE_TYPE_REGISTER:
			if((int) imm->f_data.f_register > register_number) {
				register_number = imm->f_data.f_register;
			}
			break;

		default:
			assert(0, "unknown immediate data type");
			/*NOTREACHED*/

		}
	}

	return register_number;
}


/** \brief Save the ActionPushData data.
 *
 * This function is used to save the actual data of the ActionPushData
 * in the Data buffer.
 *
 * \param[in] data The Data buffer where the ActionPushData is saved
 * \param[in] nested_data There is no nested data in an ActionPushData
 */
ErrorManager::error_code_t ActionPushData::SaveData(Data& data, Data& nested_data)
{
	action_immediate_t		*imm;
	int32_t				*ptr;
	int				i, max;
	ErrorManager::error_code_t	ec;

	ec = ErrorManager::ERROR_CODE_NONE;

	max = f_data.Count();
	i = 0;
	while(i < max) {
		imm = dynamic_cast<action_immediate_t *>(f_data.Get(i));
		data.PutByte(imm->f_type);
		switch(imm->f_type) {
		case ACTION_IMMEDIATE_TYPE_STRING:
			ec = ErrorManager::KeepFirst(ec, SaveString(data, imm->f_data.f_string));
			break;

		case ACTION_IMMEDIATE_TYPE_FLOAT:
			ptr = (int32_t *) &imm->f_data;	// .f_float32
			data.PutLong(*ptr);
			break;

		case ACTION_IMMEDIATE_TYPE_BOOLEAN:
			data.PutByte(imm->f_data.f_boolean);
			break;

		case ACTION_IMMEDIATE_TYPE_DOUBLE:
			ptr = (int32_t *) &imm->f_data;	// .f_float64
#if BYTE_ORDER == LITTLE_ENDIAN
			// AMD/Intel like
			data.PutLong(ptr[1]);
			data.PutLong(ptr[0]);
#else
			// RISC like
			data.PutLong(ptr[0]);
			data.PutLong(ptr[1]);
#endif
			break;

		case ACTION_IMMEDIATE_TYPE_INTEGER:
			data.PutLong(imm->f_data.f_integer32);
			break;

		case ACTION_IMMEDIATE_TYPE_REGISTER:
			data.PutByte(imm->f_data.f_register);
			break;

		case ACTION_IMMEDIATE_TYPE_LOOKUP:
			// in this case we know that f_lookup < 256
			data.PutByte((unsigned char) imm->f_data.f_lookup);
			break;

		case ACTION_IMMEDIATE_TYPE_LOOKUP_LARGE:
			data.PutShort(imm->f_data.f_lookup);
			break;

		case ACTION_IMMEDIATE_TYPE_NULL:
		case ACTION_IMMEDIATE_TYPE_UNDEFINED:
			break;

		default:
			assert(0, "unknown immediate data type");
			ec = ErrorManager::KeepFirst(ec, OnError(ErrorManager::ERROR_CODE_INTERNAL_ERROR, "unknown immediate data type"));
			break;

		}
		i++;
	}

	return ec;
}



////////////////////////////// Action SET TARGET

/** \class sswf::ActionSetTarget
 *
 * \brief This class is used to define the sprite on which the actions apply.
 *
 * Before becoming fully object oriented, ActionScript used this
 * action to define the name of the Sprite on which the actions
 * had an effect.
 *
 * Using an empty name would reset the ActionScript to its default
 * behavior.
 *
 * \sa <a href="../SWFalexref.html#action_set_target">SWF Alexis' Reference&mdash;Set Target</a>
 * \sa <a href="../SWFalexref.html#action_set_target_dynamic">SWF Alexis' Reference&mdash;Set Target <i>(dynamic)</i></a>
 */

/** \brief Initializes the ActionSetTarget.
 *
 * By default, the constructor creates an action target with no
 * name (i.e. reset to normal default behavior).
 *
 * Use the sswf::ActionSetTarget::SetTarget() function to define
 * which sprite should be affected.
 *
 * \param[in] tag The tag in which this action is saved.
 */
ActionSetTarget::ActionSetTarget(TagBase *tag)
	: Action(tag, ACTION_SET_TARGET)
{
	f_target = 0;
}


/** \brief Set the name of the Sprite to affect.
 *
 * This function should be called with the name of the Sprite
 * which needs to be affected by the following actions.
 *
 * Set the name to NULL or an empty string to cancel a
 * previous ActionSetTarget (this is the default so you
 * do not have to do so.)
 */
void ActionSetTarget::SetTarget(const char *target)
{
	MemFree(f_target);
	f_target = StrDup(target);
}


/** \brief Create a duplicate of this action.
 *
 * This function creates a new ActionSetTarget and copy the
 * target name of 'this' SetTarget and return the result.
 *
 * \return The pointer to the new ActionSetTarget
 */
Action *ActionSetTarget::Duplicate(void) const
{
	ActionSetTarget	*a;

	a = new ActionSetTarget(Tag());
	a->SetTarget(f_target);

	return a;
}


/** \brief Save the extra data of the ActionSetTarget.
 *
 * This function saves the name of the target as expected
 * by this function.
 *
 * \param[in] data The Data buffer where the target name is saved
 * \param[in] nested_data The ActionSetTarget has no nested data
 */
ErrorManager::error_code_t ActionSetTarget::SaveData(Data& data, Data& nested_data)
{
	return SaveString(data, f_target);
}





////////////////////////////// Action STORE REGISTER

/** \class sswf::ActionStoreRegister
 *
 * \brief Store the top stack value in a register.
 *
 * This action is used to save the current content of the stack
 * in a register. Later, you can read the register with an
 * sswf::ActionPushData action.
 *
 * \sa <a href="../SWFalexref.html#action_store_register">SWF Alexis' Reference&mdash;Store Register</a>
 */

/** \brief Initialize the ActionStoreRegister.
 *
 * Initialize the ActionStoreRegister by setting the register
 * number to zero. Use the SetRegister() function to change
 * the default.
 *
 * \param[in] tag The tag in which this action is being added
 */
ActionStoreRegister::ActionStoreRegister(TagBase *tag)
	: Action(tag, ACTION_STORE_REGISTER)
{
	f_reg = 0;
}


/** \brief Defines which register will hold the stack content.
 *
 * This function can be used to define the register number
 * to hold the current stack content.
 *
 * Outside a function, only registers 0 to 3 are acceptable.
 *
 * Inside a function (DeclareFunction2--Version 7 of SWF),
 * all registers from 0 to 254 are acceptable. (from my
 * testing it seems that register 255 does not work.)
 *
 * \param[in] reg The new register to assign to this action
 */
void ActionStoreRegister::SetRegister(unsigned char reg)
{
	f_reg = reg;
}


/** \brief Create a clone of this action.
 *
 * This function allocates a new ActionStoreRegister object,
 * it copies the register number and returns the pointer of
 * the new action.
 *
 * \return The action clone pointer
 */
Action *ActionStoreRegister::Duplicate(void) const
{
	ActionStoreRegister	*a;

	a = new ActionStoreRegister(Tag());
	a->SetRegister(f_reg);

	return a;
}


/** \brief Get the maximum register number in use.
 *
 * This function gets the larger register number in
 * use by this action. This is actually equal to the
 * register you defined with SetRegister() or zero.
 *
 * \return The largest register number in use by this action
 */
int ActionStoreRegister::GetMaxRegister(void) const
{
	return f_reg;
}


/** \brief Save the extraneous data for this action.
 *
 * This means saving one byte with the register number.
 *
 * \param[in] data The Data buffer where the register number is to be saved
 * \param[in] nested_data The ActionStoreRegister does not support nested data
 */
ErrorManager::error_code_t ActionStoreRegister::SaveData(Data& data, Data& nested_data)
{
	data.PutByte(f_reg);

	return ErrorManager::ERROR_CODE_NONE;
}





////////////////////////////// Action STRICT MODE

/** \class sswf::ActionStrictMode
 *
 * \brief This action is used to define the current scripting mode.
 *
 * It can be strict (i.e. follows JavaScript specification
 * to the letter) or lazy (i.e. accepts old ActionScript
 * commands).
 *
 * \sa <a href="../SWFalexref.html#action_strict_mode">SWF Alexis' Reference&mdash;Strict Mode</a>
 */

/** \brief Initialize the ActionStrictMode object.
 *
 * This constructor marks the mode as <i>not strict</i>.
 *
 * Use the SetStrict() function to change the mode.
 *
 * \param[in] tag The tag in which this action is being created
 */
ActionStrictMode::ActionStrictMode(TagBase *tag)
	: Action(tag, ACTION_STRICT_MODE)
{
	f_strict = false;
}


/** \brief Change the mode as required.
 *
 * This function lets you change the mode from strict (true)
 * to lazy (false).
 *
 * \param[in] strict Set to 'true' to enter strict mode
 */
void ActionStrictMode::SetStrict(bool strict)
{
	f_strict = strict;
}


/** \brief Create a clone of this ActionStrictMode object.
 *
 * This function creates a new ActionStringMode object; it
 * copies 'this' strict mode in the new action and then
 * it returns the pointer of the new action.
 *
 * \return The pointer to the new action
 */
Action *ActionStrictMode::Duplicate(void) const
{
	ActionStrictMode	*a;

	a = new ActionStrictMode(Tag());
	a->SetStrict(f_strict);

	return a;
}


/** \brief Save the mode in the Data buffer.
 *
 * This function saves the strict mode in the Data buffer passed in.
 *
 * \param[in] data The Data buffer where the strict mode is saved
 * \param[in] nested_data The ActionStrictMode has no nested_data
 */
ErrorManager::error_code_t ActionStrictMode::SaveData(Data& data, Data& nested_data)
{
	data.PutByte(f_strict);

	return ErrorManager::ERROR_CODE_NONE;
}





////////////////////////////// Action TRY

/** \class sswf::ActionTry
 *
 * \brief This action encompasses the Try, Catch and Finally actions.
 *
 * This action creates two or three blocks of sub-actions. The first
 * block (the 'try' block) is protected, meaning that if an error occurs
 * within that block code, it will not break execution. Instead it will
 * continue with the 'catch' block if present and terminate the 'finally'
 * block if it exists.
 *
 * It is necessary to at least have one of the 'catch' or 'finally' blocks.
 * The 'try' block is mandatory.
 *
 * \sa <a href="../SWFalexref.html#action_try">SWF Alexis' Reference&mdash;Try</a>
 */

/** \brief Initialize the ActionTry action.
 *
 * This constructor marks the Try action as not having any catch or
 * finally blocks, no name and no register.
 *
 * Use the AddTryAction() or SubListTry() to add actions to the try block.
 *
 * Use the AddCatchAction() or SubListCatch() to add actions to the
 * catch block.
 *
 * Use the AddFinallyAction() or SubListFinally() to add actions to
 * the finally block.
 *
 * Use the SetIdentifier(int register_number) function with an integer
 * to define a register number for the catch variable.
 *
 * Use the SetIdentifier(const char *name) function with a string to
 * define the name of a variable to use as the catch variable.
 *
 * \param[in] tag The tag in which this action is inserted
 */
ActionTry::ActionTry(TagBase *tag)
	: Action(tag, ACTION_TRY)
{
	f_register = -1;
	f_variable_name = 0;
	f_has_catch = false;
	f_has_finally = false;
}


/** \brief Add an action to the try block.
 *
 * This function adds the specified action to the try block. There should
 * be at least one action in the try block.
 *
 * The action is not duplicated.
 *
 * \param[in] action The pointer to the action to add to the try block or NULL
 */
void ActionTry::AddTryAction(Action *action)
{
	if(action != 0) {
		f_actions_try.Set(-1, action);
	}
}


/** \brief Add an action to the catch block.
 *
 * This function adds the specified action to the catch block. The catch
 * block can be empty, in which case you must have a non-empty finally block.
 *
 * The action passed is not duplicated.
 *
 * This function has the side effect of marking the action as having
 * a catch block, unless the pointer is null.
 *
 * \param[in] action The pointer to the action to add to the catch block or NULL
 */
void ActionTry::AddCatchAction(Action *action)
{
	if(action != 0) {
		f_has_catch = true;
		f_actions_catch.Set(-1, action);
	}
}


/** \brief Add an action to the finally block.
 *
 * This function adds the specified action to the finally block. The finally
 * block can be empty, in which case you must have a non-empty catch block.
 *
 * The action passed is not duplicated.
 *
 * This function has the side effect of marking the action as having
 * a finally block, unless the pointer is null.
 *
 * \param[in] action The pointer to the action to add to the finally block or NULL
 */
void ActionTry::AddFinallyAction(Action *action)
{
	if(action != 0) {
		f_has_finally = true;
		f_actions_finally.Set(-1, action);
	}
}


/** \brief Request the error to be saved in a register.
 *
 * The catch block, when called, receives an error variable.
 * This variable can be saved in a register. To archive this,
 * set the register number that you want to use for this catch
 * block.
 *
 * This function has priority over the SetIdentifier(const char *name)
 * function. This means the register number will be used instead of
 * the register name if defined.
 *
 * The register number can be any number between 0 and 254.
 *
 * If the register number is set to -1, then it is ignored.
 *
 * \param[in] register_number The register to use in the catch block to access the error
 */
void ActionTry::SetIdentifier(int register_number)
{
	f_register = register_number;
}


/** \brief Request the error to be saved in a named variable.
 *
 * This function defines the name to use as the catch variable.
 * When a register number from 0 to 254 was defined with SetIdentifier(),
 * this variable name is ignored.
 *
 * \param[in] name The name of the variable to use within the catch block to access the error
 */
void ActionTry::SetIdentifier(const char *name)
{
	MemFree(f_variable_name);
	f_variable_name = StrDup(name);
}


/** \brief Create a clone of this action.
 *
 * This function creates a new ActionTry object, it copies the register
 * number, variable name, has catch & finally flags and then copy the
 * lists of actions (try, catch and finally blocks.)
 *
 * \return The pointer to the new action
 */
Action *ActionTry::Duplicate(void) const
{
	ActionTry	*t;
	Action		*a;
	int		max, idx;

	t = new ActionTry(Tag());
	t->SetIdentifier(f_register);
	t->SetIdentifier(f_variable_name);
	t->f_has_catch = f_has_catch;
	t->f_has_finally = f_has_finally;

	max = f_actions_try.Count();
	for(idx = 0; idx < max; idx++) {
		a = dynamic_cast<Action *>(f_actions_try.Get(idx));
		t->AddTryAction(a->Duplicate());
	}

	max = f_actions_catch.Count();
	for(idx = 0; idx < max; idx++) {
		a = dynamic_cast<Action *>(f_actions_catch.Get(idx));
		t->AddCatchAction(a->Duplicate());
	}

	max = f_actions_finally.Count();
	for(idx = 0; idx < max; idx++) {
		a = dynamic_cast<Action *>(f_actions_finally.Get(idx));
		t->AddFinallyAction(a->Duplicate());
	}

	return t;
}


/** \brief The version required to save this action.
 *
 * This function goes through all the sub-action lists to determine
 * the minimum version necessary to save it.
 *
 * The ActionTry itself requires version 7, but actions in the
 * sub-lists may require a higher version.
 *
 * \return The minimum version required to have the request work
 */
unsigned char ActionTry::Version(void) const
{
	int		v, version;

	// Until version 8, this Version() function is
	// useless... But that's here for forward compatibility
	// since when version 8 comes out I'd probably forget
	// to come back to it!
	version = 7;		// the ActionTry is version 7 by itself

	v = MinimumListVersion(f_actions_try);
	if(v > version) {
		version = v;
	}

	v = MinimumListVersion(f_actions_catch);
	if(v > version) {
		version = v;
	}

	v = MinimumListVersion(f_actions_finally);
	if(v > version) {
		version = v;
	}

	return version;
}


/** \brief Defines the maximum register number in use.
 *
 * This function overwrites the default sswf::Action::GetMaxRegister()
 * function in order to retrieve the largest register in use in any
 * of the sub-action blocks (try, catch, finally).
 *
 * \return The largest register in use within this ActionTry object
 */
int ActionTry::GetMaxRegister(void) const
{
	int		result, r;

	result = GetMaximumRegister(f_actions_try);

	r = GetMaximumRegister(f_actions_catch);
	if(r > result) {
		result = r;
	}

	r = GetMaximumRegister(f_actions_finally);
	if(r > result) {
		result = r;
	}

	return result;
}




/** \brief Retrieve the Vectors to the try action block.
 *
 * This function can be used to retrieve a direct pointer to the Vectors
 * holding the action block for the 'try' block.
 *
 * \return A pointer to the action list for the 'try' block
 */
Vectors *ActionTry::SubListTry(void)
{
	return &f_actions_try;
}


/** \brief Retrieve the Vectors to the catch action block.
 *
 * This function can be used to retrieve a direct pointer to the Vectors
 * holding the action block for the 'catch' block.
 *
 * \warning
 * This function has the side effect of setting the catch block flag
 * to true, meaning that the catch block exists. You should always add
 * at least one item in the Vectors to validate this properly.
 *
 * \return A pointer to the action list for the 'catch' block
 */
Vectors *ActionTry::SubListCatch(void)
{
	f_has_catch = true;
	return &f_actions_catch;
}


/** \brief Retrieve the Vectors to the finally action block.
 *
 * This function can be used to retrieve a direct pointer to the Vectors
 * holding the action block for the 'finally' block.
 *
 * \warning
 * This function has the side effect of setting the finally block flag
 * to true, meaning that the finally block exists. You should always add
 * at least one item in the Vectors to validate this properly.
 *
 * \return A pointer to the action list for the 'finally' block
 */
Vectors *ActionTry::SubListFinally(void)
{
	f_has_finally = true;
	return &f_actions_finally;
}


/** \brief Save the ActionTry extraneous data.
 *
 * The SaveData() function saves the try, catch and finally blocks in
 * the nested_data and the try header in the Data buffers.
 *
 * Note that the maximum size for any one sub-block is 65535 bytes.
 * A larger sub-block will generate an error and the save will fail.
 *
 * This function should not be called until at least one of the
 * catch or finally block has been created.
 *
 * \param[in] data The Data buffer where the ActionTry header is saved
 * \param[in] nested_data This buffer is used to save the try, catch and finally blocks
 */
ErrorManager::error_code_t ActionTry::SaveData(Data& data, Data& nested_data)
{
	Data				try_data, catch_data, finally_data;
	unsigned long			try_size, catch_size, finally_size;
	bool				bad;
	ErrorManager::error_code_t	ec;

	assert(f_has_finally || f_has_catch, "an ActionTry needs at least one of CATCH or FINALLY");
	if(!f_has_finally && !f_has_catch) {
		ec = OnError(ErrorManager::ERROR_CODE_INTERNAL_ERROR, "an ActionTry needs at least one of CATCH or FINALLY");
	}
	else {
		ec = ErrorManager::ERROR_CODE_NONE;
	}

	ec = ErrorManager::KeepFirst(ec, SaveList(&f_actions_try, try_data));
	ec = ErrorManager::KeepFirst(ec, SaveList(&f_actions_catch, catch_data));
	ec = ErrorManager::KeepFirst(ec, SaveList(&f_actions_finally, finally_data));

	// get rid of the ACTION_END
	try_data.SetSize(try_data.GetSize() - CHAR_BIT);
	catch_data.SetSize(catch_data.GetSize() - CHAR_BIT);
	finally_data.SetSize(finally_data.GetSize() - CHAR_BIT);

	try_size = try_data.ByteSize();
	catch_size = catch_data.ByteSize();
	finally_size = finally_data.ByteSize();

	if((bad = try_size >= USHRT_MAX)) {
		ec = ErrorManager::KeepFirst(ec, OnError(ErrorManager::ERROR_CODE_ACTION_OVERFLOW, "too many nested instructions in a TRY; length overflow."));
		bad = true;
	}
	if(catch_size >= USHRT_MAX) {
		ec = ErrorManager::KeepFirst(ec, OnError(ErrorManager::ERROR_CODE_ACTION_OVERFLOW, "too many nested instructions in a CATCH; length overflow."));
		bad = true;
	}
	if(finally_size >= USHRT_MAX) {
		ec = ErrorManager::KeepFirst(ec, OnError(ErrorManager::ERROR_CODE_ACTION_OVERFLOW, "too many nested instructions in a FINALLY; length overflow."));
		bad = true;
	}
	if(bad) {
		try_size = 0;
		catch_size = 0;
		finally_size = 0;
	}

	data.WriteBits(0, 5);
	data.WriteBits(f_register < 0 ? 0 : 1, 1);
	data.WriteBits(f_has_finally, 1);
	data.WriteBits(f_has_catch, 1);
	data.PutShort((short) finally_size);
	data.PutShort((short) catch_size);
	data.PutShort((short) try_size);
	if(f_register < 0) {
		ec = ErrorManager::KeepFirst(ec, SaveString(data, f_variable_name));
	}
	else {
		data.PutByte(f_register);
	}
	if(bad) {
		return ec;
	}

	nested_data.Append(try_data);
	nested_data.Append(catch_data);
	nested_data.Append(finally_data);

	return ec;
}





////////////////////////////// Action URL

/** \class sswf::ActionURL
 *
 * \brief Go to a static or dynamic URL.
 *
 * The ActionURL class is used to define a URL to load in the
 * user browser.
 *
 * Use the SetURL() or SetMethod() functions to setup this
 * action appropriately.
 *
 * \note
 * The ACTION_URL expects a SetURL() call.
 *
 * The ACTION_URL2 expects a SetMethod() call.
 *
 * If the ActionURL does not automatically choose which of the
 * ACTION_URL or ACTION_URL2 to save it is because the former
 * does not use the stack whereas the latter does. Thus this
 * action by itself cannot know which action to save.
 *
 * \sa <a href="../SWFalexref.html#action_get_url">SWF Alexis' Reference&mdash;Get URL</a>
 * \sa <a href="../SWFalexref.html#action_get_url2">SWF Alexis' Reference&mdash;Get URL 2</a>
 */


/** \enum sswf::ActionURL::url_method_t
 *
 * \brief The different methods which can be used with the ActionURL
 *
 * The ActionURL can pass the data to the server with a GET, a POST
 * or with no variable.
 *
 * \sa sswf::ActionURL::URL_METHOD_UNDEFINED
 * \sa sswf::ActionURL::URL_METHOD_NOVARIABLE
 * \sa sswf::ActionURL::URL_METHOD_NOVARIABLES
 * \sa sswf::ActionURL::URL_METHOD_GET
 * \sa sswf::ActionURL::URL_METHOD_POST
 *
 * <hr>
 */


/** \var sswf::ActionURL::URL_METHOD_UNDEFINED
 *
 * \brief The method is still undefined
 *
 * This is the default method value. It is required to be defined before
 * the action is saved in a Flash animation.
 *
 * <hr>
 */


/** \var sswf::ActionURL::URL_METHOD_NOVARIABLE
 *
 * \brief Send the request without any variable
 *
 * Send the URL with no variable.
 *
 * <hr>
 */


/** \var sswf::ActionURL::URL_METHOD_NOVARIABLES
 *
 * \brief Send the request without any variable
 *
 * Send the URL with no variable.
 *
 * <hr>
 */


/** \var sswf::ActionURL::URL_METHOD_GET
 *
 * \brief Send the request using an HTTP GET
 *
 * Send the request as an HTTP GET with the variables
 * appended at the end of the URL.
 *
 * <hr>
 */


/** \var sswf::ActionURL::URL_METHOD_POST
 *
 * \brief Send the request using an HTTP POST
 *
 * Send the request as an HTTP POST with the variables
 * sent one per line, starting on the line after the URL.
 */




/** \brief Initialize the ActionURL action.
 *
 * The constructor defines default values to the different variable
 * members. It sets the URL to none, the target to none and the
 * method to URL_METHOD_NOVARIABLES.
 *
 * This function can be called with either ACTION_URL or
 * ACTION_URL2.
 *
 * \param[in] tag The tag in which this action is being added
 * \param[in] action The SWF action to save this action
 */
ActionURL::ActionURL(TagBase *tag, action_t action)
	: Action(tag, action)
{
	assert(action == ACTION_URL || action == ACTION_URL2, "only ACTION_URL or ACTION_URL2 can be specified to the ActionURL object.");
	if(action != ACTION_URL && action != ACTION_URL2) {
		throw ErrorManager::InternalErrorException();
	}
	f_url = 0;
	f_target = 0;
	f_method = URL_METHOD_NOVARIABLES;
}


/** \brief Set the URL and target names.
 *
 * This function is used to define a valid URL and target.
 *
 * The target can be the name of a window or set to '_top'
 * to replace the content of the current window.
 *
 * This function assumes that you defined the action as
 * ACTION_URL.
 *
 * \param[in] url A standard URL (i.e. http://sswf.m2osw.com)
 * \param[in] target A window name or a standard HTML target
 */
void ActionURL::SetURL(const char *url, const char *target)
{
	MemFree(f_url);
	MemFree(f_target);
	f_url = StrDup(url);
	f_target = StrDup(target);
}


/** \brief Set the method used to pass the URL to the browser.
 *
 * Set the method to use execute the URL, this assumes that you
 * defined this action as an ACTION_URL2. This is one of the
 * following values:
 *
 *	URL_METHOD_NOVARIABLE or URL_METHOD_NOVARIABLES
 *	URL_METHOD_GET
 *	URL_METHOD_POST
 *
 * \param[in] method One of the available methods
 */
void ActionURL::SetMethod(url_method_t method)
{
	f_method = method;
}


/** \brief Create a clone of this action.
 *
 * This function creates a new ActionURL object and copy the
 * URL, target and method in it. Finally, it returns the pointer
 * to the new action.
 *
 * \return The pointer to the clone action
 */
Action *ActionURL::Duplicate(void) const
{
	ActionURL	*a;

	a = new ActionURL(Tag(), f_action);
	a->SetURL(f_url, f_target);
	a->SetMethod(f_method);

	return a;
}


/** \brief Save the action extraneous data in the Data buffer.
 *
 * This function saves the URL/target information (ACTION_URL) or
 * the method (ACTION_URL2) in the the Data buffer.
 *
 * \param[in] data The Data buffer where the URL information is saved
 * \param[in] nested_data There is no nested data in an ActionURL
 */
ErrorManager::error_code_t ActionURL::SaveData(Data& data, Data& nested_data)
{
	if(f_action == ACTION_URL) {
		ErrorManager::error_code_t ec = SaveString(data, f_url);
		return ErrorManager::KeepFirst(ec, SaveString(data, f_target));
	}

	data.PutByte(f_method);

	return ErrorManager::ERROR_CODE_NONE;
}






////////////////////////////// Action WAIT FOR FRAME

/** \class sswf::ActionWaitForFrame
 *
 * \brief Create an action used to wait for a frame to be loaded.
 *
 * This class creates an action one can use to wait for a certain
 * frame to be saved. As long as that frame is not loaded, the
 * sub-actions are skipped. Once the frame was loaded, the actions
 * are executed. These actions can result in the execution of the
 * rest of the movie.
 *
 * \warning
 * The WaitForFrame action uses a byte to define the number of the
 * sub-actions to skip. That means a maximum of 255 actions, which is
 * relatively small for an ActionScript. In general, you can bypass
 * the problem by calling a function.
 *
 * \note
 * This is 255 actions. Thus in bytes it can be much larger. However,
 * do NOT try to define a function or an object within this block.
 * It is likely to fail.
 *
 * \bug
 * It could be that the ACTION_WAIT_FOR_FRAME and ACTION_WAIT_FOR_FRAME2
 * should each have its own class since the dynamic version should
 * not be given a frame name (it is taken dynamically!). On the other
 * hand it could be that I could change the code and if you define a
 * frame name then I force the ACTION_WAIT_FOR_FRAME and by default
 * I would use ACTION_WAIT_FOR_FRAME2. In this latter case, I would
 * need a PreSave() to determine the action before to save the result.
 *
 * \sa <a href="../SWFalexref.html#action_wait_for_frame">SWF Alexis' Reference&mdash;Wait For Frame</a>
 * \sa <a href="../SWFalexref.html#action_wait_for_frame_dynamic">SWF Alexis' Reference&mdash;Wait For Frame <i>(dynamic)</i></a>
 */

/** \brief Initialize the ActionWaitForFrame object.
 *
 * This constructor initializes the ActionWaitForFrame object with
 * a frame with no name and no actions.
 *
 * The action parameter can be set to:
 *
 *	ACTION_WAIT_FOR_FRAME
 *	ACTION_WAIT_FOR_FRAME2
 *
 * \param[in] tag The tag in which this action is being added
 * \param[in] action One of the wait for action codes
 */
ActionWaitForFrame::ActionWaitForFrame(TagBase *tag, action_t action)
	: Action(tag, action)
{
	assert(action == ACTION_WAIT_FOR_FRAME || action == ACTION_WAIT_FOR_FRAME2, "the action of an ActionWaitForFrame needs to be ACTION_WAIT_FOR_FRAME or ACTION_WAIT_FOR_FRAME2");
	if(action != ACTION_WAIT_FOR_FRAME && action != ACTION_WAIT_FOR_FRAME2) {
		throw ErrorManager::InternalErrorException();
	}
	// f_actions = ... -- auto-init with Vectors constructor
	f_frame_name = 0;
}


/** \brief Set the name of the frame to wait for.
 *
 * In case you used ACTION_WAIT_FOR_FRAME, this is the name of
 * the frame to wait for.
 *
 * \param[in] frame_name The name of the frame to wait for
 */
void ActionWaitForFrame::SetFrameName(const char *frame_name)
{
	MemFree(f_frame_name);
	f_frame_name = StrDup(frame_name);
}


/** \brief Add a sub-action to the wait frame action.
 *
 * This function adds a sub-action to execute once the movie loaded the
 * specified frame.
 *
 * You can also access the list of sub-actions using the
 * sswf::ActioWaitForFrame::SubList() function.
 *
 * Note that the total number of these actions is 255 (and not
 * 255 bytes!) This makes it difficult to read this action.
 *
 * \param[in] action The action to append to this wait for frame
 */
void ActionWaitForFrame::AddAction(Action *action)
{
	f_actions.Set(-1, action);
}


/** \brief Create a clone of this action.
 *
 * This function creates a new ActionWaitForFrame and copies the
 * frame name and all the sub-actions in it. Finally, it returns
 * the pointer of the new action.
 *
 * \return The pointer of the clone action
 */
Action *ActionWaitForFrame::Duplicate(void) const
{
	ActionWaitForFrame	*w;
	Action			*a;
	int			idx, max;

	w = new ActionWaitForFrame(Tag(), f_action);
	w->SetFrameName(f_frame_name);
	max = f_actions.Count();
	for(idx = 0; idx < max; idx++) {
		a = dynamic_cast<Action *>(f_actions.Get(idx));
		w->AddAction(a->Duplicate());
	}

	return w;
}


/** \brief Return the Vectors holding the sub-actions.
 *
 * This function is used to retrieve the pointer of the Vectors
 * used to register all the sub-actions of this ActionWaitForFrame
 * object.
 *
 * \return The Vectors pointers of the sub-actions
 */
Vectors *ActionWaitForFrame::SubList(void)
{
	return &f_actions;
}


/** \brief Save the extraneous data of the ActionWaitForFrame object.
 *
 * This function saves the frame number (ACTION_WAIT_FOR_FRAME) and
 * the number of nested actions.
 *
 * If the specified frame is not found or no frame name is specified
 * for an ACTION_WAIT_FOR_FRAME, then an error results.
 *
 * \param[in] data The Data buffer where the information is saved
 * \param[in] nested_data The Action::Save() function defines this buffer,
 * 		this function does not need it since the size is not
 * 		what is saved in these actions
 */
ErrorManager::error_code_t ActionWaitForFrame::SaveData(Data& data, Data& nested_data)
{
	TagBase				*tag;
	ErrorManager::error_code_t	ec;

	ec = ErrorManager::ERROR_CODE_NONE;

	if(f_actions.Count() > 255) {
		ec = OnError(ErrorManager::ERROR_CODE_ACTION_OVERFLOW, "too many actions within a WaitForFrame; please, use branches as may be required.");
	}

	if(f_action == ACTION_WAIT_FOR_FRAME) {
		if(f_frame_name == 0 || *f_frame_name == '\0') {
			// we save the frame name within the tag in this case
			// so we actually need it!
			ec = ErrorManager::KeepFirst(ec, OnError(ErrorManager::ERROR_CODE_MISSING_FRAME_NAME, "a frame name was expected for action WaitForFrame."));
			data.PutShort(0);	// a default, just so the file is not boggus.
		}
		else {
			tag = Tag()->FindLabelledTag(f_frame_name);
			if(tag == 0) {
				/* ha! couldn't find this object... */
				ec = ErrorManager::KeepFirst(ec, OnError(ErrorManager::ERROR_CODE_OBJECT_NOT_FOUND, "cannot find any tag labelled '%s'.", f_frame_name));
				data.PutShort(0);	// a default, just so the file is not boggus.
			}
			else {
				data.PutShort(tag->WhichFrame());
			}
		}
	}

	data.PutByte(f_actions.Count());

	return ec;
}


////////////////////////////// Action WITH

/** \class sswf::ActionWith
 *
 * \brief Block including variable member names refering to the With object.
 *
 * This action is supposed to be useful to optimize JavaScript code by
 * not having to fully qualify variables by their respective object name.
 *
 * For instance, the following code:
 *
 *	\code
 *	obj.a = 1;
 *	obj.b = 2;
 *	obj.c = 3;
 *	obj.d = 4;
 *	obj.e = 5;
 *	\endcode
 *
 * can be simplified using a 'with' instruction as follow:
 *
 *	\code
 *	with obj {
 *		a = 1;
 *		b = 2;
 *		c = 3;
 *		d = 4;
 *		e = 5;
 *	}
 *	\endcode
 *
 * \sa <a href="../SWFalexref.html#action_with">SWF Alexis' Reference&mdash;With</a>
 */

/** \brief Initialize the ActionWith object.
 *
 * This function initialize the 'with' object by making the 'with' block
 * empty.
 *
 * \param[in] tag The tag where the With is inserted
 */
ActionWith::ActionWith(TagBase *tag)
	: Action(tag, ACTION_WITH)
{
}


/** \brief Add an action to the 'with' block.
 *
 * The 'with' block is a list of actions which can be grown using this
 * function. Note that you can have several levels of 'with' (i.e. within
 * a 'with' block you can have another 'with' block to a depth of 7 up to
 * version 5 of SWF, and 15 in version 6 of SWF.)
 *
 * Of course, it can be quite tedious to know what variable reference
 * which object when all the objects have variable and function members
 * of the same name (it should be the inner most object which has a match.)
 *
 * Note that the action being added is not duplicated.
 *
 * \param[in] action The pointer to the action to add to this ActionWith
 */
void ActionWith::AddAction(Action *action)
{
	f_actions.Set(-1, action);
}


/** \brief Create a clone of this ActionWith object.
 *
 * This function creates a new ActionWith object and copies all the
 * actions of 'this' ActionWith in it. Finally, it returns a pointer
 * to the newly allocated object.
 *
 * \return The newly allocated action pointer
 */
Action *ActionWith::Duplicate(void) const
{
	ActionWith	*w;
	Action		*a;
	int		max, idx;

	w = new ActionWith(Tag());
	max = f_actions.Count();
	for(idx = 0; idx < max; idx++) {
		a = dynamic_cast<Action *>(f_actions.Get(idx));
		w->AddAction(a->Duplicate());
	}

	return w;
}


/** \brief The sub-list of actions of this ActionWith.
 *
 * This function returns a direct pointer to the Vectors of this
 * ActioWith object. This Vectors array holds all the actions to
 * execute once the specified frame was loaded.
 *
 * Do not forget that the actions are limited to a byte size of
 * 65535 in the outer most ActionWith object.
 *
 * \return A Vectors pointer to fill with actions
 */
Vectors *ActionWith::SubList(void)
{
	return &f_actions;
}


/** \brief Save the byte size of the nested data.
 *
 * This function saves the extraneous data for an ActionWith object
 * which is the size of the nested data buffer in bytes.
 *
 * \param[in] data The Data buffer where the size is to be saved
 * \param[in] nested_data The Data buffer which holds the sub-actions
 */
ErrorManager::error_code_t ActionWith::SaveData(Data& data, Data& nested_data)
{
	// the actions were already saved by the Action::Save() function!
	data.PutShort((unsigned short) nested_data.ByteSize());

	return ErrorManager::ERROR_CODE_NONE;
}



/* The following options fold the documentation; use 'zi' to turn on and off
 *
 * vim: foldexpr=getline(v\:lnum)!~'^/\\*\\*'&&getline(v\:lnum)!~'^\ \\*'?0\:1 foldcolumn=2 foldmethod=expr
 */
