| Animation Adobe Flash: le format SWF 
	
		
			|  |  |  |  
 
  Alexis' SWF Reference
  (started in June 2002)
 
    
	
 
 
 
 
 
 
 
 
 
 (sorted by number and version)
 
 
 
 
 
 
 
 
 
 
 
 
 The entire SSWF project licenseThe following license covers the entire SSWF project. 
  Copyright (c) 2002-2007 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. Authors
  
  This document was written by Alexis Wilke. Different people have helped
  in fixing mistakes in the different structures defined here. Their names
  appear in the Appendix B — History of this reference.
   
  SWF Format
  Please, note that there is no restriction in using this document.
  However, the SWF format copyright holders are Macromedia and Adobe.
  There may be limits in what you can do using this format.
  If you are not sure, I suggest you contact a knowledgeable copyright
  and Software attorney who can help you decide what you can do with the
  SWF format.
   MP3 Format
  Please, note that MP3 audio encoders and decoders can freely be
  used as long as you don't generate any revenue from them. If you
  intend to sell or buy a product which uses an MP3 audio encoder
  or encoder or both, you most certainly want to know more about
  licensing issues in regard to that concept. You can find all
  the necessary information on the following site:
  http://www.mp3-tech.org/
   
 About SWF
  Brief History
  At the very beginning, a company created the SWF format to generate
  small vector animations on the Internet. It also included images.
  This company was bought by Macromedia around 1997 (if I recall properly).
  This is when Flash v3 was created. Since then, Macromedia created a new
  version about once a year up to version 8. At that time (in 2005/2006),
  Macromedia sealed a deal with Adobe which wanted to use the SWF format
  in their PDF files.
   What is SWF?
  SWF (pronounced like swiff by some, but really is is S, W, F)
  is a file format used to describe movies built of mainly two graphical elements:
  vector based objects and images.
  The newest versions also accept external modules, sound, video and interaction with the
  end user using ActionScript.
   
  The file format was first created by a small company that Macromedia
  purchased early on.
  The main goal of the format was and still is to create small files of
  highly intertaining animations.
  The idea was to have a format which could be reused by a player running
  on any system and which would work with slower network (such as
  a browser connected to the Internet with a slow modem).
  The format is fairly simple also.
   
  This document presents the SWF format and includes code examples
  for really difficult points (like bit fields) and it explains with words
  what is really not clear otherwise.
  I hope this document will help you in developing your own
  players and/or generators of SWF file formats.
   The geometry in SWF
  The SWF file formats uses several types of objects.
  The ones used the most are called shapes. These are vector
  based objects which can be rendered really fast in 2D.
  The other type of graphical objects are images, fonts,
  colors and matrices. More information about the SWF
  geometry is given in the Appendix A below.
   
  In different versions of SWF they also added different
  graphical enhancements.
  In version 6, they added support (somewhat flaky, fixed
  in version 7) for internationalization.
  In version 7 they added much better support for small fonts.
  In version 8 they added support for transparent videos.
  You can see the evolution by looking at the different tags
  and the tag structures (many times, a tag was enhanced in
  a version without the need to create a new tag.)
   Multimedia content in SWF
  The SWF file format has evolved to support more and more multimedia
  formats. It started with 2 audio formats (raw uncompressed and ADPCM)
  and it now supports many audio and video formats.
   
  Because multimedia files tend to be large, the SWF format was also
  enhanced to allow you to load separate multimedia files as required.
  This is done using the FLV files. These files can also include
  scripts.
   Interactivity support in SWF
  At the very beginning, SWF was only for animations. You started it,
  it played a loop forever until you'd move on to another web page.
   
  In version 3, better support for keyboard and mouse clicks was added.
  This was rough and didn't offer much possibilities beyond a simple switch
  (i.e. if you click start playing B instead of A). Since version 4,
  Macromedia added support for a scripting language. This is very
  similar to what Sun has done with Java. This is an interpreted language
  which runs within the Flash player in its own environment.
   
  Real interactivity came with version 4, but real scripting came only
  in version 5. That is, since version 5 you got real objects. At that time
  Macromedia decided to be more compliant with what ECMAScript described
  in their specification. Yet, they used the free Netscape interpreter
  available (if I'm correct) in Netscape 4. This was pretty bogus. They
  kept trying to enhance that interpretor until version 7. In version 8
  they finally did a full rewrite (or did they get a new free interpreter
  from somewhere?) to really support ECMAScript properly.
  This means there are some inconsistencies between older versions and
  version 8 in the scripting language, even though the encoding is the
  same, running your older scripts may fail in version 8. So don't be too
  surprised!
   
  With version 8, they also very much improved their library coming with
  their Flash builder product.
   
 Table of the SWF tags
In the table below, the tags are sorted by version and numbers.
To find a tag by name, use the list under Descriptions of each tag
in the TABLE OF CONTENT.
 | 
  
    | Name | Number | Type | Comments |  
    | SWF Version 1.0 |  
    | File Header | None | Format | We can consider the file header as being a tag though
      it isn't a tag per say. |  
    | End | 0 | Format | Mark the end of the file. It can't appear anywhere else
      but the end of the file. |  
    | ShowFrame | 1 | Define | Display the current display list and pauses for 1 frame
      as defined in the file header. |  
    | DefineShape | 2 | Define | Define a simple geometric shape. |  
    | FreeCharacter Unknown encoding
 | 3 | Define | Release a character which won't be used anymore. |  
    | PlaceObject | 4 | Display | Place the specified object in the current display list. |  
    | RemoveObject | 5 | Display | Remove the specified object at the specified depth. |  
    | DefineBitsJPEG | 6 | Define | Define a JPEG bit stream. |  
    | DefineButton | 7 | Define | Define an action button. |  
    | JPEGTables | 8 | Define | Define the tables used to compress/decompress all the SWF 1.0
      JPEG images (See also DefineBitsJPEG). |  
    | SetBackgroundColor | 9 | Display | Change the background color. |  
    | DefineFont | 10 | Define | List shapes corresponding to glyphs. |  
    | DefineText | 11 | Define | Defines a text of characters displayed using
      a font. This definition doesn't support any
      transparency. |  
    | DoAction | 12 | Action | Actions to perform at the time the next show frame
      is reached and before the result is being displayed.
      It can duplicate sprites, start/stop movie clips,
      etc. 
      All the actions within a frame are executed
      sequencially in the order they are defined.
       
      Note: some actions are specific to other versions
      than SWF V1.0. Please, see the reference
      of actions below in order to know which actions
      can be used with which version.
       |  
    | DefineFontInfo | 13 | Define | Information about a previously defined font. Includes the font style,
      a map and the font name. |  
    | SWF Version 2.0 |  
    | DefineSound | 14 | Define | Declare a sound effect. This includes sound samples which can later
      be played back using either a
      StartSound or a
      DefineButtonSound.
      Note that the same DefineSound block can actually include
      multiple sound files and only part of the entire sound can
      be played back as required. |  
    | StartSound | 15 | Display | Start the referenced sound on the next
      DisplayFrame. |  
    | StopSound Unknown encoding
 | 16 | Display | Stop the referenced sound on the next
      DisplayFrame. |  
    | DefineButtonSound | 17 | Define | Defines how to play a sound effect for when an event occurs for
      the given button. |  
    | SoundStreamHead | 18 | Define | Declare a sound effect which will be interleaved with a
      movie data so as to be loaded over a network connection
      while being played. |  
    | SoundStreamBlock | 19 | Define | A block of sound data. The size of this block of data will
      be defined in the previous
      SoundStreamHead tag.
      It can be used so sound is downloaded on a per frame
      basis instead of being loaded all at once. |  
    | DefineBitsLossless | 20 | Define | A bitmap compressed using ZLIB (similar to the PNG format). |  
    | DefineBitsJPEG2 | 21 | Define | Declare a complete JPEG image (includes the bit stream and
      the tables all in one thus enabling multiple table to be
      used within the same SWF file). |  
    | DefineShape2 | 22 | Define | Declaration of complex 2D shapes. |  
    | DefineButtonCxform | 23 | Define | Setup a color transformation for a button. |  
    | Protect | 24 | Format | Disable edition capabilities of the given SWF file. Though
      this doesn't need to be enforced by an SWF editor, it marks
      the file as being copyrighted in a way. |  
    | SWF Version 3.0 |  
    | PathsArePostscript Unknown encoding
 | 25 | Display | The shape paths are defined as in postscript? |  
    | PlaceObject2 | 26 | Display | Place an object in the current display list. |  
    | RemoveObject2 | 28 | Display | Remove the object at the specified level. This tag should be
      used in SWF 3.0+ since it compressed better than the standard
      RemoveObject tag. |  
    | SyncFrame Unknown encoding
 | 29 | Display | ? |  
    | FreeAll Unknown encoding
 | 31 | Display | ? |  
    | DefineShape3 | 32 | Define | Declare a simple geometric shape. |  
    | DefineText2 | 33 | Define | Defines a text of characters displayed using
      a font. Transparency is supported with this
      tag. |  
    | DefineButton2 | 34 | Define | Define an action button. Includes a color transformation. |  
    | DefineBitsJPEG3 | 35 | Define | Defines a complete JPEG (includes the tables and data bit stream)
      twice. Once with the RGB data and once with the alpha channel.
      Note that the alpha channel uses the Z-lib compression instead
      of the JPEG one. |  
    | DefineBitsLossless2 | 36 | Define | Defines an RGBA bitmap compressed using ZLIB (similar to the PNG format). |  
    | DefineSprite | 39 | Define | Declares an animated character. This is similar to a shape
      with a display list so the character can be changing on
      its own over time. |  
    | NameCharacter Unknown encoding
 | 40 | Define | Define the name of an object (for buttons, bitmaps, sprites and sounds) |  
    | ProductInfo | 41 | Define | This tag defines information about the product used to generate the
	animation. The product identifier should be unique among all the
	products. The info includes a product identifier, a product edition,
	a major and minor version, a build number and the date of compilation.
	All of this information is all about the generator, not the output
	movie. |  
    | DefineTextFormat Unknown encoding
 | 42 | Define | ? |  
    | FrameLabel | 43 | Define | Names a frame or anchor. This frame can later be referenced
      using this name. |  
    | SoundStreamHead2 | 45 | Define | Declare a sound effect which will be interleaved with a
      movie data so as to be loaded over a network connection
      while being played. |  
    | DefineMorphShape | 46 | Define | This is similar to a sprite with a simple morphing between
      two shapes. |  
    | GenerateFrame Unknown encoding
 | 47 | Define | ? |  
    | DefineFont2 | 48 | Define | Define a list of glyphs using shapes and other font metric
      information. |  
    | GeneratorCommand | 49 | Define | Gives some information about the tool which generated
      this SWF file and its version. |  
    | SWF Version 4.0 |  
    | DefineEditText | 37 | Define | An edit text enables the end users to enter text in a Flash window. |  
    | DefineVideo Unknown encoding
 | 38 | Define | ? |  
    | SWF Version 5.0 |  
    | DefineCommandObject Unknown encoding
 | 50 | Define | ? |  
    | CharacterSet Unknown encoding
 | 51 | Define | ? |  
    | ExternalFont Unknown encoding
 | 52 | Define | ? |  
    | Export | 56 | Define | Exports a list of definitions to other movies. You can in
      this way create one or more movies to hold a colection of
      objects to be reused by other movies without having to
      insert these info in each movie. A single export is
      enough for an entire movie (and you should have just
      one). |  
    | Import | 57 | Define | Imports a list of definitions from another movie. You
      can retrieve objects which were exported in the
      specified movie. You can have as many import as you
      like, though you should have only one per referenced
      movie. |  
    | ProtectDebug | 58 | Format | The data of this tag is an MD5 password like the
      Protect tag. When it exists and
      you know the password, you will be given the right to debug
      the movie with Flash V5.x. 
      WARNING: this tag is only valid in Flash V5.x,
      use the ProtectDebug2 instead in V6.x movies.
       |  
    | SWF Version 6.0 |  
    | DoInitAction | 59 | Action | Actions to perform the first time the following show frame
      is reached. All the initialization actions are executed
      before any other actions. You have to specify a sprite to
      which the actions are applied. Thus you don't need a
      set target action. When multiple initialization action
      blocks are within the same frame, they are executed one
      after another. |  
    | DefineVideoStream | 60 | Define | Defines the necessary information for the player to display a
      video stream (i.e. size, codec, how to decode the data, etc.).
      Play the frames with VideoFrame
      tags. |  
    | VideoFrame | 61 | Define | Show the specified video frame of a movie. |  
    | DefineFontInfo2 | 62 | Define | Defines information about a font, like the DefineFontInfo
      tag plus a language reference. To force the use of a given
      language, this tag should be used in v6.x+ movies instead of
      the DefineFontInfo. |  
    | DebugID | 63 | Define | This tag is used when debugging an SWF movie. It gives information
      about what debug file to load to match the SWF movie with the source.
      The identifier is a UUID. |  
    | ProtectDebug2 | 64 | Format | The data of this tag is a 16 bits word followed by an MD5 password
      like the Protect tag. When it exists and
      you know the password, you will be given the right to debug
      the movie with Flash V6.x and over. |  
    | SWF Version 7.0 |  
    | ScriptLimits | 65 | Define | Change limits used to ensure scripts don't use more resources than
      you choose. In version 7, it supports a maximum recursive depth
      and a maximum amount of time scripts can be run for in seconds. |  
    | SetTabIndex | 66 | Define | Define the order index so the player knows where to go next when
      the Tab key is pressed by the user. |  
    | SWF Version 8.0 |  
    | FileAttributes | 69 | Format | Since version 8, this tag is required and needs to be the very
      first tag in the movie. It is used as a way to better handle
      security with the Flash Player. |  
    | PlaceObject3 | 70 | Define | Place an object in the display list. The object can include bitmap
      caching information, a blend mode and a set of filters. |  
    | Import2 | 71 | Define | Imports a list of definitions from another movie.
      In version 8+, this tag replaces the original
      Import tag.
      You can retrieve objects which were exported in the
      specified movie. You can have as many import as you
      like, though you should have only one per referenced
      movie. |  
    | DefineFontAlignZones | 73 | Define | Define advanced hints about a font glyphs to place them on a pixel boundary. |  
    | CSMTextSettings | 74 | Define | Define whether CSM text should be used in a previous
      DefineText,
      DefineText2
      or DefineEditText. |  
    | DefineFont3 | 75 | Define | Define a list of glyphs using shapes and other font metric
      information. |  
    | Metadata | 77 | Format | This tag includes XML code which describes the movie. The format is
      RDF compliant to the XMP as defined on W3C. |  
    | DefineScalingGrid | 78 | Format | Define scale factors for a window, a button, or other similar objects. |  
    | DefineShape4 | 83 | Define | Declare a shape which supports new line caps, scaling and fill options. |  
    | DefineMorphShape2 | 84 | Define | Declare a morphing shape with attributes supported by version 8+. |  
    | SWF Version 9.0 |  
    | DoABC | 72 | Action | New container tag for ActionScripts under SWF 9. Includes only
      actions. |  
    | SymbolClass | 76 | Action | Instantiate objects from a set of classes. |  
    | DoABCDefine | 82 | Action | New container tag for ActionScripts under SWF 9. Includes
      an identifier, a name and actions. |  
    | DefineSceneAndFrameData | 86 | Define | Define raw data for scenes and frames. |  
    | DefineBinaryData | 87 | Define | Defines a buffer of any size with any binary user data. |  
    | DefineFontName | 88 | Define | Define the legal font name and copyright. |  | 
 
 Structures definitions
  
  This documents makes use of structure definitions which look like C structures.
  It is important to note that this is not all that true since the data saved in
  a SWF file are very specific and they don't follow the default C definitions.
   
  The following table lists the types used in this document. The comment will
  explain in more details how each type is used. The notes below also include
  example where it applies.
   | 
    | Type | Comment | Version | 
|---|
 | [un]signed char(1,2) | a signed or unsigned 8 bits value | 1 |  | [un]signed short(1,2) | a signed or unsigned 16 bits value | 1 |  | [un]signed long(1,2) | a signed or unsigned 32 bits value | 1 |  | [un]signed long long(1,2) | a signed or unsigned 64 bits value | 8 |  | [un]signed(3,4) | a signed or unsigned bit field which width
	doesn't correspond to any C type; the width of the field is specified after the field name and it can
	be dynamic; signed bit fields have an implied sign extend | 1 |  | [un]signed twips(3,4) | a
	variable defined as twips represents a floating point defined
	in twips; load the value as a signed or unsigned integer and
	then divide it by 20; the result is a dimension in pixel; | 1(5) |  | [un]signed short fixed(1,2) | a short fixed value is a 16 bits (or less) number which
	represents a value with 8 bits on the left of the decimal
	point (and 8 on the right); when less bits are specified, we
	will assume that only the least significant bits were defined
	(often only those after the decimal point) | 1(5) |  | [un]signed long fixed(1,2) | a long fixed value is a 32 bits (or less) number which
	represents a value with 16 bits on the left of the decimal
	point (and 16 on the right); when less bits are specified, we
	will assume that only the least significant bits were defined
	(often only those after the decimal point) | 1 |  | [un]signed short float(1,2,6) | a
    	standard IEEE 754 floating point value of 16 bits; the value is defined like a 32 bits floating
	points with: 
	  The easiest to deal with these floats is to convert them to 32 bits floats.1 bit for the sign5 bits for the exponent10 bits for the mantissa | 8 |  | [un]signed long float(1,2,6) | a
	long float is a standard IEEE 754 floating point value of 32 bits; the value is defined
	as follow: 
	  1 bit for the sign8 bits for the exponent23 bits for the mantissa | 8 |  | [un]signed double float(1,2,6) | a
	double float is a standard IEEE 754 floating point value of 64 bits; the value is defined
	as follow: 
	  1 bit for the sign11 bits for the exponent52 bits for the mantissa | 8 |  | string | a null terminated string of 8 bits characters;
    	you have to scan the string in order to skip it to the next element | 1 |  | if(<cond>) ... else ... | some fields are defined only if some conditions
	are met. These are defined in this way. These if() can be viewed as being dynamic in regard
	to the structure declaration. Though, once a set of data is created, this isn't true anymore
	since you can't easilly change a parameter part of the condition without having to regenerate
	the whole tag. (That is, it's easier to parse a tag putting it in standard structure, make the
	necessary changes, then save it back in the file). | 1 |  | char align; | used to mark that the following bit field is always
	aligned on a byte boundary | 1 |  | struct <name> { ... } | declares a structure
	with the different C types; fields are never aligned but on a char if one of char,
	short, long or fixed is used; the size of structures depends on their content; | 1 |  | union <name> { ... } | declares a group of
	structures; the size of a union depends on its content; it is not the largest possible size as usually
	defined in C | 1 |  | 
 
    BROWSER NOTE: this table will look broken in older versions of I.E. which interprets the ']' character
    as a space character.
   | 1 | short, long, fixed and float values are saved in little
  endian in the file; the following is a sample of C code on how you can
  compute a short value by reading two bytes for an unsigned short whatever the endian
  of your computer: | 
 	short read_short(FILE *f)
	{
		unsigned char	input[2];
		fread(input, 2, 1, f);
		return input[0] + input[1] * 256;
	}
| 2 | char, short, long, fixed and float values which
  are not part of a bit field are always aligned on a byte. | 
 | 3 | a bit field which specifies one of char, short or
  long is aligned on a byte | 
 | 4 | all bit fields are always declared from the MSB to the LSB of the
  bytes read from the input file; the first bit read in the file correspond
  to the MSB of the value being read; as a side effect, the bytes in the
  file appear as if they were defined in big endian order (which is the
  opposite of the char, short, long, fixed and float
  declared outside a bit field); the following is a slow but working
  algorithm to read bit fields: | 
 	/* global variables (could be in a structure or an object) */
	long	mask, count, last_byte;
	/* call once before to read a bit field to reset the parameters */
	void start_read_bits(void)
	{
		mask = 0x80;
		count = 0;
	}
	/* call for each bit field */
	long read_bits(long bit_size)
	{
		/* NOTE: any value is at most 32 bits */
		/* the result of this function could also be an unsigned long */
		long		result;
		unsigned long	bit;
		bit = 1 << (bit_size - 1);
		while(bit != 0) {
			if(mask == 0x80) {
				last_byte = read_input();
			}
			if(last_byte & mask) {
				result |= bit;
			}
			mask /= 2;
			if(mask == 0) {
				mask = 0x80;
			}
			bit /= 2;
		}
	}
| 5 | note that many fields were defined as unsigned short fixed since version 1.0; however,
  the type was only officially introduced in version 8 of the SWF reference | 
 
 The File Header
  
  The file header is found at the very beginning of the file.
  It should be used to determine whether a file is an SWF
  file or not. Also, it contains information about the frame
  size, the speed at which is should be played and the version
  (which determines which tags and actions are possibly used
  in the file).
   	struct swf_header {
		unsigned char		f_magic[3];	'FWS' or 'CWS'
		unsigned char		f_version;
		unsigned long		f_file_length;
	}
	struct swf_header_movie {
		swf_rect		f_frame_size;
		unsigned short fixed	f_frame_rate;
		unsigned short		f_frame_count;
	};
  The f_magic[3] array is defined as the characters: 'FWS' (it is going backward
  probably because it was supposed to be read in a little endian as a long word).
  A movie can be compressed when the version is set to 6. In this case, the
  magic characters are: 'CWS'.
 
  The f_version is a value from 1 to 6 (the maximum at time of writing,
  the maximum will continue to increase).
 
  The f_file_length is exactly what it says. That's useful for all these
  network connections which don't give you the size of the file. In case of a
  compressed movie, this is the total length of the uncompressed movie
  (useful to allocate the destination buffer for zlib).
 
  The f_frame_size is a rectangle definition in TWIPS used to set the
  size of the frame on the screen. The minx and miny are usually not necessary
  in this rectangle definition.
 
  The parameter in the swf_header_movie structure are part of the
  buffer which gets compressed in a V6.x movie (in other words, only the very
  first 8 bytes of the resulting file aren't compressed).
 
  The f_frame_rate is a fixed value of 8.8 bits. It represents the number
  of frames per second the movie should be played at. Since version 8 of SWF, it
  is defined as an unsigned short fixed point value instead of an
  unsigned short. This value should never be set to zero.
 
  The f_frame_count is a counter of the number of SHOW FRAME within that
  movie. Most of the tools will compute this number automatically and it can
  usually be wrong and the movie will still play just fine.
 
 Description of the SWF tags
  
    
    CSMTextSettings (V8.0)
     
    The CSMTextSettings are used to change the
    rendering mode of glyphs in a
    DefineText,
    DefineText2 and
    DefineEditText
     	struct swf_csmtextsettings {
		swf_tag			f_tag;		/* 74 */
		unsigned short		f_text_id_ref;
		unsigned		f_use_flag_type : 2;
		unsigned		f_grid_fit : 3;
		unsigned		f_reserved : 3;
		long float		f_thickness;
		long float		f_sharpness;
		unsigned char		f_reserved;
	};
    The f_text_id_ref is a reference to a tag holding some
    texts which glyphs need to be tweaked with these settings.
     
    The f_use_flag_type defines which of the system (0) or Flash (1)
    font renderer should be used.
     | 
        
          | Value | Renderer | Version |  
          | 0 | System | 8 |  
          | 1 | Internal Flash Type | 8 |  | 
 
    The f_grid_fit defines whether the glyphs should be moved
    to fit on a grid (i.e. to look less blurry.)
     | 
        
          | Value | Mode | Version |  
          | 0 | No alignment | 8 |  
          | 1 | Pixel alignment (for left aligned text only — go figure!) | 8 |  
          | 2 | 1/3rd pixel for LCD displays | 8 |  | 
 
    The f_thickness and f_sharpness are used to compute
    the external and internal cutoff. According to Macromedia they
    compute these values as follow:
     	External Cutoff = ( 0.5 × f_sharpness - f_thickness) × f_font_height
	Internal Cutoff = (-0.5 × f_sharpness - f_thickness) × f_font_height
 
    
    DebugID (V9.0?)
     
    The DebugID tag is used to match a debug file
    (.swd) with a Flash animation (.swf). This is used by the Flash
    environment and is not required to create movies otherwise.
     	struct swf_debugid {
		swf_tag			f_tag;		/* 63 */
		unsigned char		f_uuid[<variable size>];
	};
    The f_uuid is a universally unique identifier. The size should be 128 bytes.
    It is otherwise defined by the size of the tag.
     
    
    DefineBinaryData (V9.0)
     
    The DefineBinaryData tag is used to save any arbitrary user
    defined binary data in an SWF movie. The Flash player itself ignores that data.
    The size of the data is not specifically limited.
     	struct swf_definebinarydata {
		swf_tag			f_tag;		/* 87 */
		unsigned short		f_data_id;
		unsigned long		f_reserved;	/* must be zero */
		unsigned char		f_data[<variable size>];
	};
    The f_data_id is this object identifier. The identifier is the same type
    as any identifier (like a sprite identifier.) It is used in ActionScripts to
    reference the data.
     
    The f_reversed area is 32 bits and it must be set to zero in version 9.
     
    The size of the f_data buffer is defined as the size of the tag minus the
    f_data_id and f_reserved fields. This is where the raw binary data goes.
     
    
    DefineBitsJPEG (V1.0)
    DefineBitsJPEG2 (V2.0)
 DefineBitsJPEG3 (V3.0)
 
  These tags define an image saved using the JPEG compression scheme.
   
  DefineBitsJPEG (V1.0) does not include the encoding
  tables which are defined in the unique
  JPEGTables tag
  instead. All the DefineBitsJPEG of an SWF file use
  the only JPEGTables tag.
   
  The other tags incorporate their own version of the JPEG encoding tables.
   
  The DefineBitsJPEG3 also supports an alpha channel
  bitplane (8 bits). This alpha channel is compressed using the ZLIB
  scheme as with the
  DefineBitsLossless
  image formats.
   
  WARNING: These tags require you to save
  the swf_tag in long format (i.e. f_tag_and_size & 0x3F == 0x3F even
  if the size is smaller.)
   	struct swf_definebitsjpeg {
		swf_tag			f_tag;		/* 6, 21 or 35 */
		unsigned short		f_image_id;
		if(f_tag == DefineBitsJPEG3) {
			/* sizeof(f_encoding) + sizeof(f_image_data) */
			unsigned long	f_offset_to_alpha;
		}
		if(f_tag != DefineBitsJPEG) {
			/* when DefineBitsJPEG, use JPEGTables instead */
			unsigned char	f_encoding_tables[<variable size>];
		}
		unsigned char		f_image_data[<variable size>];
		if(f_tag == DefineBitsJPEG3) {
			unsigned char	f_alpha[<variable size>];
		}
	};
  The f_encoding should include 0xFF 0xDB and 0xFF 0xC4 entries.
   
  The f_image_data buffer should include the 0xFF 0xE0, 0xFF 0xC0
  and 0xFF 0xDA.
   
  WARNING: Both buffers (f_encoding and f_image_data)
  need to start with a 0xFF 0xD8 (SOI) and end with 0xFF 0xD9 (EOI).
   
  The f_alpha buffer is compressed with ZLIB as defined in the
  DefineBitsLossless
  tag (this is similar to the PNG format).
   
  Also, the DefineBitsJPEG tag may fail if it includes
  any encoding tables. These tables shall be defined within the
  JPEGTables
  instead.
   
  Note that the player of SWF better enforces the correctness of these tags
  since version 8.
   
    
    DefineBitsLossless (V2.0)
    DefineBitsLossless2 (V3.0)
 
    These tags declares a loss-less image bitmap. It has a small header
    followed by an optional colormap and the bitmap data. When we have
    a colormap, the bitmap data is an array of indices in the colormap
    which is aligned to 32 bits on a per row basis.
     
    There are three supported formats:
 
    
      
	| Format No.
 (bits)
 | Color Format | Comments |  
	| Without Alpha
 | With Alpha
 |  
	| 3 (8 bits(1))
 | RGB | RGBA | Uses a colormap with up to 256 entries of 24 or 32 bits colors |  
	| 4 (16 bits(1))
 | RGB555 | RGB555 | There is no alpha available in this format. The data is saved in
	    big endian (it is NOT a U16 like some doc. mention). The colors looks like
	    this (most significant bit first): 0RRRRRGGGGGBBBBB. You should certainly
	    always use the DefineBitsLossless tag for this format. |  
	| 5 (32 bits)
 | XRGB | ARGB | Uses a strange scheme for colors. Most probably because the alpha was
	    added later and thus inserted in place of the X to keep some backward
	    compatibility with older versions. |  (1) the data must be 32 bits aligned (4 bytes) on a per row basis. In 8 bits,
    you may have to add up to three bytes at the end of each row (
 4 - width & 3whenwidth & 3is not zero.).
    In 16 bits, you need to add two bytes at the end of each row
    when the width of the image is odd. 
  The f_colormap, f_indices and f_bitmap are all compressed with the
  ZLIB scheme.
   
  WATCH OUT: the f_colormap and f_indices are
  compressed as one large block.
   
  WARNING: These tags require you to save
  the swf_tag in long format (i.e. f_tag_and_size & 0x3F == 0x3F even
  if the size is smaller.)
   
  WARNING: An image cannot always be scaled
  more than 64×. Trying to enlarge it more may result in a
  rectangle of one color. The 64× is cumulative. So a sprite
  of an image × 3 inside another sprite × 10 inside
  another sprite × 4 results in scaling of 120 and this is
  likely to break the image. This seems to be true mainly
  when there is a rotation or skew.
   	struct swf_definebitslossless {
		swf_tag			f_tag;		/* 20 or 36 */
		unsigned short		f_image_id;
		unsigned char		f_format;	/* 3, 4 or 5 */
		unsigned short		f_width;
		unsigned short		f_height;
		if(f_format == 3) {
			unsigned char	f_colormap_count;
			if(f_tag == DefineBitsLossless) {
				swf_rgb		f_colormap[f_colormap_count];
			}
			else {
				swf_rgba	f_colormap[f_colormap_count];
			}
			unsigned char	f_indices[((f_width + 3) & -4) * f_height];
		}
		else {
			if(f_tag == DefineBitsLossless) {
				swf_xrgb	f_bitmap[f_width * f_height];
			}
			else {
				swf_argb	f_bitmap[f_width * f_height];
			}
		}
	};
 
    
    DefineButton (V1.0)
     
  The interactivity of the SWF format comes from the buttons. All
  the buttons have an ID and can be placed in the display list like
  any other shape.
   
  A buttons has different states. Some states can be entered only
  when the button was in a specific state before (like a button
  being pushed).
   
  Buttons can be represented graphically in any manner you want.
  Each state can use a different edit text, shape, sprite or text
  to render the button.
   	struct swf_definebutton {
		swf_tag			f_tag;		/* 7 */
		unsigned short		f_button_id;
		swf_button		f_buttons;
		swf_action		f_actions;
	};
  The f_buttons and f_actions are null terminated arrays
  (the end marker in either case is a byte set to zero).
   
  There will always be at least one f_buttons since the object
  require at least one shape to be drawn (though the shape can very well be
  transparent and empty).
   
  There is no need for any action. The action(s) are executed whenever the
  button is pushed. Note that it is possible to execute actions also when
  the mouse moves over a button (in, out, over) with the use of a sprite
  in V5.0+. However, in this case it is certainly preferable to use a
  DefineButton2 instead.
   
    
    DefineButton2 (V3.0)
     
  The DefineButton2 is very similar to the DefineButton tag.
  The list of actions was however changed in a list of actions to execute
  on a condition. Whenever an event occur, the plugin checks for that
  condition within all the buttons which can possibly catch that event at
  the time. For all the matches it finds, the corresponding actions are
  executed.
   	struct swf_definebutton2 {
		swf_tag			f_tag;		/* 34 */
		unsigned short		f_button_id;
		unsigned		f_reserved : 7;
		unsigned		f_menu : 1;
		unsigned short		f_buttons_size;
		swf_button		f_buttons;
		swf_condition		f_conditions;
	};
  The f_buttons_size is equal to the size of the f_buttons buffer
  plus 2 (the size of the f_buttons_size field itself). Note
  however that if you don't have any conditions, the f_buttons_size
  field will be zero (0). This is similar to the list of conditions which
  also ends with a condition having a size of zero (0). You can still
  deduce the size of the f_buttons when the f_button_size
  is zero by using the total tag size minus the offset where the
  f_buttons declarations start.
   
    
    DefineButtonCxform (V2.0)
     
  The DefineButton doesn't include any means to transform the
  colors of the shapes it includes. This tag was thus added just so
  one can transform a button colors. It is wise to use the new
  DefineButton2 instead so the transformation can be applied
  on a per state basis.
   	struct swf_definebuttoncxform {
		swf_tag			f_tag;		/* 23 */
		unsigned short		f_button_id_ref;
		swf_color_transform	f_color_transform;
	};
  The f_button_id_ref is a reference to the button which is to be
  transformed with the specified color matrix.
   
    
    DefineButtonSound (V2.0)
     
  The DefineButtonSound can be used to emit a sound when an event
  occur on the specified button. It is likely better to use sprites that
  you display using actions than to use this tag. You will have access
  to more events and conditions and also can avoid sound effects on the
  conditions included in this tag.
   	enum {
		DEFINE_BUTTON_SOUND_CONDITION_POINTER_LEAVE = 0,
		DEFINE_BUTTON_SOUND_CONDITION_POINTER_ENTER = 1,
		DEFINE_BUTTON_SOUND_CONDITION_POINTER_PUSH = 2,
		DEFINE_BUTTON_SOUND_CONDITION_POINTER_RELEASE_INSIDE = 3,
		DEFINE_BUTTON_SOUND_CONDITION_MAX = 4
	};
	struct swf_definebuttonsound {
		swf_tag			f_tag;		/* 17 */
		unsigned short		f_button_id_ref;
		swf_soundinfo		f_button_sound_condition[DEFINE_BUTTON_SOUND_CONDITION_MAX];
	};
  The f_button_id_ref is a reference to the button which will get the
  given sound effects.
   
  There are four f_button_sound_condition. Each have a reference to
  a sound and some information on how to play it. The four conditions
  are given in the enumeration preceeding the DefineButtonSound
  structure.
   
    
    DefineEditText (V4.0)
     
    Additional interactivity has been added in V4.0 of the SWF format.
    This is given by the use of edit boxes which offer the end users
    a way to enter new text as if the SWF movie was in fact an
    interactive form.
     
    The text is defined in a variable (accessible in action scripts).
    It can be dynamically assigned and retreived. It is legal to have
    an empty string as the variable name (not dynamically accessible).
     
    Since version 8, the text drawn by a DefineEditText
    tag can be tweaked by adding a
    CSMTextSettings tag.
     	struct swf_defineedittext {
		swf_tag			f_tag;		/* 37 */
		unsigned short		f_edit_id;
		swf_rect		f_rect;
		unsigned		f_edit_has_text : 1;
		unsigned		f_edit_word_wrap : 1;
		unsigned		f_edit_multiline : 1;
		unsigned		f_edit_password : 1;
		unsigned		f_edit_readonly : 1;
		unsigned		f_edit_has_color : 1;
		unsigned		f_edit_has_max_length : 1;
		unsigned		f_edit_has_font : 1;
		if(version >= 6) {
			unsigned		f_edit_reserved : 1;
			unsigned		f_edit_auto_size : 1;
		}
		else {
			unsigned		f_edit_reserved : 2;
		}
		unsigned		f_edit_has_layout : 1;
		unsigned		f_edit_no_select : 1;
		unsigned		f_edit_border : 1;
		unsigned		f_edit_reserved : 1;
		unsigned		f_edit_html : 1;
		unsigned		f_edit_use_outlines : 1;
		if(f_edit_has_font) {
			unsigned short		f_edit_font_id_ref;
			unsigned short		f_edit_font_height;
		}
		if(f_edit_has_color) {
			swf_rgba		f_edit_color;
		}
		if(f_edit_has_max_length) {
			unsigned short		f_edit_max_length;
		}
		if(f_edit_has_layout) {
			unsigned char		f_edit_align;
			unsigned short		f_edit_left_margin;
			unsigned short		f_edit_right_margin;
			signed short		f_edit_indent;
			signed short		f_edit_leading;
		}
		string			f_edit_variable_name;
		if(f_edit_has_text) {
			string			f_edit_initial_text;
		}
	};
  The f_edit_word_wrap flag will be set to true (1) in order to
  have words which go beyond the right side of the box to appear
  on the next line instead. This only works if you have the
  f_edit_multiline flag also set to true.
   
  The f_edit_multiline flag can be used to create an edit text field
  which accepts new lines and can wrap words.
   
  The f_edit_readonly flag ensure that the end user can't modify
  the text in the edit area.
   
  The f_edit_has_color & f_edit_color will be used to
  indicate the color of the text. Note that it is possible to ask for a
  border and a background to be drawn (see the f_edit_border flag
  below) but these items colors can't be defined.
   
  The f_edit_has_max_length & f_edit_max_length can
  be used to ensure the user can't type more than a certain number
  of letters and digits.
   
  The f_edit_password flag is used to visually transform the
  typed characters to asterisks. The edit text field variable has the
  proper typed characters.
   
  The f_edit_border will be used to not only draw a border, but also have
  a white background. Make sure you don't select a white color for your
  font or you won't see any text in this case. The color of the border
  is likely to be black. If you want to have better control of these
  colors you will have to draw your own background and borders.
   
  The f_edit_auto_size flag requests the player to automatically
  resize the object to the text. Thus, you don't need to know the size
  of the text at the time you create an edit text, plus different fonts
  from different platforms will always fit the edit text (but maybe not
  the screen...).
   
  The f_edit_use_outlines flag will be used to tell
  whether the specified SWF internal font should be used.
  When not set, a default font is choosen by the plugin.
  The font should include a mapping so it can be drawn
  properly.
   
  The f_edit_align can be set to the following values:
   
  | 
      
	| Alignment | Value |  
	| Left | 0x00 |  
	| Right | 0x01 |  
	| Center | 0x02 |  
	| Justify(1) | 0x03 |  | 
 (1) justification doesn't seem to work yet. 
  The f_edit_indent is the first line indentation in a multiline box of
  text. This is added to the left margin.
  The f_edit_leading is the number of extra pixels to skip
  to reach the following line. It should be put to zero to have the default
  font leading value.
   
  The f_edit_left/right_margin indicate how many TWIPS to not use on
  the sides. If you don't use a border, these are rather useless.
   
  The f_edit_html flag, when set, means the contents of this edit
  text is a basic HTML text. The following table shows you the tags
  which the Macromedia plugin understands.
   | 
      
        | Tag | Accepted Attributes | Comments |  
        | Open | Close |  
        | <A> | </A> | HREF=url
[ TARGET=name ] | Defines an hyperlink |  
        | <B> | </B> | none | Write in bold |  
        | <BR> | n.a. | none | Inserts a line break |  
        | <FONT> | </FONT> | [ FACE=name ]
[ SIZE=[+|-][0-9]+ ]
[ COLOR=#RRGGBB ] | Change the font face. The face name must
		match a DefineFont2 name. The size is in TWIPS.
		The color only supports #RRGGBB triplets. |  
        | <I> | </I> | none | Write in italic |  
        | <LI> | </LI> | none | Defines a list item |  
        | <P> | </P> | [ ALIGN=left|right|center ] | Defines a paragraph |  
        | <TAB> | n.a. | none | Inserts a tab character (see TEXTFORMATalso) |  
        | <TEXTFORMAT> | </TEXTFORMAT> | [ BLOCKINDENT=[0-9]+ ]
[ INDENT=[0-9]+ ]
[ LEADING=[0-9]+ ]
[ LEFTMARGIN=[0-9]+ ]
[ RIGHTMARGIN=[0-9]+ ]
[ TABSTOPS=[0-9]+{,[0-9]+} ] | Change the different parameters as indicated.
		The sizes are all in TWIPs. There can be multiple positions
		for the tab stops. These are seperated by commas. |  
        | <U> | </U> | none | Write with an underline |  | 
 
  For more information about HTML, please, refer to a full HTML
  documentation. You can find the complete specification 
  at http://www.w3.org/. It
  was written by the MIT, INRIA and Keio and that's very well
  written!
   
      
    	
          | WARNING: | There seems to be a problem with the use of a system font when
            that font doesn't exist on your system. At this time I do not
            know if it only happens with this object or whether others
            would also be affected. Anyway, when it happens you get
            nothing in the text area. |  
    
    DefineFont (V1.0)
     
  It is common to use the DefineFont tag in order to create an array of
  shapes later re-used to draw strings of text on the screen. Note that the
  definition of the shape within a font is limited since it can't include any
  specific fill and/or line style. Also, each shape is assumed to be defined
  within a 1024x1024 square. This square is called the EM Square.
  Fig 1. below shows you the EM Square and how it is used. The
  characters baseline can be placed anywhere within the EM Square (it certainly
  can be outside too if you wish?!?). The baseline is the position where the
  Y coordinate of the font is set to 0. The characters have to
  be drawn over that line to be properly defined. Only letters such as g, j, p
  and q will have a part drawn below. This means all the main characters will
  use negative Y coordinates. The Y coordinates increase
  from top to bottom (opposite the TrueType fonts and possibly others too).
  The width gives the number of TWIPs between this character and the next to
  be drawn on the right. The drawing should not go outside the EM Square
  (what happens in this case is not specified, it is likely that what
  is drawn outside will be lost but it can have some side effects too).
   
  Though it is possible to define a font which draws from right to left (such
  as an Arabic or Farsi font), it may cause problems (I didn't try yet...)
   
    
 Fig 1. Font EM Square
 
  With SSWF, you can see the EM Square of a character adding
  this code in your glyph definition (where <descent>
  is the descent value as saved in the layout of the font):
   	glyph "test" {
		...
		move: 0, -<descent>;
		points { 0, 1024; 1024, 1024; 1024, 0; 0, 0; };
		...
	};
  The font structure defines the font ID (which is common with a corresponding
  DefineFontInfo) an array of offsets and an
  array of glyphs. Note that if a DefineFontInfo tag is to be saved,
  you need to have the glyphs ordered in ascending order ('a' before 'b',
  etc.) This is important for the definition of the map present in the
  DefineFontInfo.
   
  You must use a DefineFont2 if a
  DefineEditText references a font.
  It will either fail or crash a plugin if you use this font definition
  instead.
   
  Note that an embedded font can be rotated. A system font (also called a device font)
  cannot be rotated. Also, the scaling and translation of a system font does not
  always respect the exact position. It is likely that the font will be moved to
  the next pixel left or right to avoid bluriness. That means it will look quite
  jaggy if you try to have a quite smooth move.
   	struct swf_definefont {
		swf_tag			f_tag;		/* 10 */
		unsigned short		f_font_id;
		/* there is always at least one glyph */
		f_font_glyphs_count = f_font_offsets[0] / 2;
		unsigned short		f_font_offsets[f_font_glyphs_count];
		swf_shape		f_font_shapes[f_font_glyphs_count];
	};
  The f_offsets array is a list of byte offsets given from the beginning of
  the f_offsets array itself to the beginning of the corresponding shape.
  (If it were possible to write such structure in C, then ...) In C one
  would write the following to find the shape in the font tag:
   	struct swf_definefont	*df;
	df = ...
	character67 = (struct swf_shape *) ((char *) df->f_offsets + df->f_offsets[67]);
 
    
    DefineFont2 (V3.0)
    DefineFont3 (V8.0)
 
  It is common to use the DefineFont2 tag in order to create an array of
  shapes later re-used to draw strings of text on the screen. This tag must
  be used whenever a DefineEditText
  references a font; and in that case it is suggested you include a full description
  of the font with layouts.
   
  The array of glyphs must be ordered in ascending order (the smaller glyph number
  saved first; thus 'a' must be saved before 'b', etc.).
   
  All the characters should be defined in a 1024x1024 square (in pixels) to be
  drawn with the best possible quality. This square is called the EM square.
   
  The DefineFont3 tag has the exact same definition as
  the DefineFont2 tag. The difference lies in the shapes
  being referenced. These have a precision 20 times higher. This gives you a
  font with that much higher precision (each pixel can be divided in a 400
  sub-pixels.) The other difference is that a DefineFont3
  can be referenced by a
  DefineFontAlignZones
  tag. That one can be used to properly align characters on a pixel boundary.
   
  Note that an embedded font can be rotated. A system font (also called a device font)
  cannot be rotated. Also, the scaling and translation of a system font does not
  always respect the exact position. It is likely that the font will be moved to
  the next pixel left or right to avoid bluriness. That means it will look quite
  jaggy if you try to have a quite smooth move.
   	struct swf_definefont2 {
		swf_tag			f_tag;		/* 48 or 75 */
		unsigned short		f_font2_id;
		unsigned		f_font2_has_layout : 1;
		if(version >= 6) {
			unsigned	f_font2_reserved : 1;
			if(version >= 7) {
				unsigned	f_font2_small_text : 1;
			}
			unsigned	f_font2_reserved : 1;
		}
		else {
			unsigned	f_font2_shiftjis : 1;
			unsigned	f_font2_unicode : 1;
			unsigned	f_font2_ansii : 1;
		}
		unsigned		f_font2_wide_offsets : 1;
		unsigned		f_font2_wide : 1;	/* always 1 in v6.x+ */
		unsigned		f_font2_italic : 1;
		unsigned		f_font2_bold : 1;
		if(version >= 6) {
			unsigned char	f_font2_language;
		}
		else {
			unsigned char	f_font2_reserved;
		}
		unsigned char		f_font2_name_length;
		unsigned char		f_font2_name[f_font2_name_length];
		unsigned short		f_font2_glyphs_count;
		if(f_font2_wide_offsets) {
			unsigned long		f_font2_offsets[f_font2_glyphs_count];
			unsigned long		f_font2_map_offset;
		}
		else {
			unsigned short		f_font2_offsets[f_font2_glyphs_count];
			unsigned short		f_font2_map_offset;
		}
		swf_shape		f_font2_shapes[f_font2_glyphs_count];
		if(f_font_info_wide) {
			unsigned short		f_font2_map[f_font2_glyphs_count];
		}
		else {
			unsigned char		f_font2_map[f_font2_glyphs_count];
		}
		if(f_font2_has_layout) {
			signed short		f_font2_ascent;
			signed short		f_font2_descent;
			signed short		f_font2_leading_height;
			signed short		f_font2_advance[f_font2_glyphs_count];
			swf_rect		f_font2_bounds[f_font2_glyphs_count];
			signed short		f_font2_kerning_count;
			swf_kerning		f_font2_kerning[f_font2_kerning_count];
		}
	};
	/* DefineFont3 is the same as DefineFont2 */
	typedef struct swf_definefont2 swf_definefont3;
  Since V6.x the f_font2_wide must always be set to 1.
   
  The f_font2_shiftjis, f_font2_unicode and f_font2_ansii flags
  are for older movies (SWF 5 or older). Note that these are still defined as is in
  the Macromedia documentation (except for the Unicode flag which is implied and
  was replaced by another flag in version 7.) I strongly suggest that you follow
  my structure and totally ignore these flags (set them to 0) in newer movies.
   
  The f_offsets array is a list of byte offsets given from the beginning of
  the f_offsets array itself (and not the beginning of the tag) to the
  beginning of the corresponding shape.
   
  f_font2_map_offset is the offset to the f_font2_map table.
  This offset is relative to the position of the f_offsets array. It
  very much looks like it is part of that table.
  This offset should always be present, though if the font is not used in
  a DefineEditText tag, older
  version of the Flash player would still work just fine.
   
  The f_font2_kerning_count and f_font2_kerning are used since
  version 8. Before that, just put the kerning count to zero and do not save
  any kerning.
   
  (If it were possible to write such a structure as is in C, then ...) In C one
  would write the following to find the shape in the font tag:
   	struct swf_definefont2	*df;
	df = ...
	character67 = (struct swf_shape *) ((char *) df->f_offsets + df->f_offsets[67]);
 
    
    DefineFontAlignZones (V8.0)
     
    Since SWF8, this tag was added to allow a clear definition of where
    a glyph starts. This is a hint to ensure that glyphs are properly
    drawn on pixel boundaries. Note that it is only partially useful
    for italic fonts since only vertical hints really make a difference.
     	struct swf_definefontalignzones {
		swf_tag			f_tag;		/* 73 */
		unsigned short		f_font2_id_ref;
		unsigned		f_csm_table_hint : 2;
		unsigned		f_reserved : 6;
		swf_zone_array		f_zones[corresponding define font3.f_font2_glyphs_count];
	}
    The f_font2_id_ref needs to reference the font identifier of a
    DefineFont3.
    Each DefineFontAlignZones shall have a
    different f_font2_id_ref.
     
    The f_csm_table_hint field can be set to one of the values
    as defined in the following table. It refers to the thickness of
    the stroke. This is only a hint meaning that the Flash Player may
    not use this information if it thinks it knows better about the
    font you are trying to render.
     | 
        
          | Value | Name | Version |  
          | 0 | Thin | 8 |  
          | 1 | Medium | 8 |  
          | 2 | Thick | 8 |  | 
 
    
    DefineFontInfo (V1.0)
    DefineFontInfo2 (V6.0)
 
  A DefineFontInfo tag will be used to complete the definition
  of a DefineFont tag. It uses the exact
  same id (f_font_info_id_ref = f_font_id). You must have the corresponding
  font definition appearing before the DefineFontInfo since it
  will use the number of glyphs defined in the DefineFont to know
  the size of the map definition in the DefineFontInfo tag.
   
  When it looks like it perfectly matches an existing system font, the
  plugin is likely to use that system font. It is also possible to force
  the use of the system font by declaring an empty DefineFont tag
  (i.e. no glyph declaration at all).
   
  The use of system fonts usually ensures a much better quality of
  smaller prints.
   
  Note, however, that a system font (also called a device font)
  cannot be rotated. Also, the scaling and translation of a system font does not
  always respect the exact position. It is likely that the font will be moved to
  the next pixel left or right to avoid bluriness. That means it will look quite
  jaggy if you try to have a quite smooth move of a system font.
   	struct swf_definefontinfo {
		swf_tag			f_tag;		/* 13 or 62 */
		unsigned short		f_font_info_id_ref;
		unsigned char		f_font_info_name_length;
		unsigned char		f_font_info_name[f_name_length];
		if(version >= 7 && f_tag.f_tag == DefineFontInfo2) {
			unsigned		f_font_info_reserved : 2;
			unsigned		f_font_info_small_text : 1;
			unsigned		f_font_info_reserved : 2;
		}
		else if(version >= 6 && f_tag.f_tag == DefineFontInfo2) {
			unsigned		f_font_info_reserved : 5;
		}
		else {
			unsigned		f_font_info_reserved : 2;
			unsigned		f_font_info_unicode : 1;
			unsigned		f_font_info_shiftjis : 1;
			unsigned		f_font_info_ansii : 1;
		}
		unsigned		f_font_info_italic : 1;
		unsigned		f_font_info_bold : 1;
		unsigned		f_font_info_wide : 1;	/* always 1 in v6.x+ */
		if(version >= 6 && f_tag.f_tag == DefineFontInfo2) {
			unsigned char		f_font_info_language;
		}
		if(f_font_info_wide) {
			unsigned short		f_font_info_map[f_font_glyphs_count];
		}
		else {
			unsigned char		f_font_info_map[f_font_glyphs_count];
		}
	};
  The f_font_info_wide flag must be set to 1 in v6.x movies.
   
  Note that the flag f_font_info_small_text is the same bit as
  the flag f_font_info_unicode in SWF version 5 or less.
   
  Since version 6, the font name has to be encoded in UTF-8 instead of
  whatever encoding you want.
   
    
    DefineFontName (V9.0)
     
  A DefineFontName tag is used to complement the definition
  of a DefineFont tag.
  It uses the exact same id (f_font_name_id_ref = f_font_id). You
  must have the corresponding font definition appearing before the
  DefineFontName since it needs to be attached to the
  DefineFont tag.
   	struct swf_definefontname {
		swf_tag			f_tag;		/* 88 */
		unsigned short		f_font_name_id_ref;
		string			f_font_name_display_name;
		string			f_font_name_copyright;
	};
  The f_font_name_display_name is the legal name of a font. This name cannot
  be used to load a corresponding system font.
   
  The f_font_name_copyright string represents the font license.
   
    
    GeneratorCommand (V3.0 or V4.0 — to be confirmed)
     
  Define some information about the tool which generated this SWF
  movie file.
   	struct swf_defineinfo {
		swf_tag			f_tag;		/* 31 */
		unsigned long		f_version;
		string			f_info;
	};
  The information seems to be formatted with names written between
  periods (.). The two I found are "com" (comment?) and
  "commands" (used when you edit the movie?).
   
    
    DefineScalingGrid (V8.0)
     
    This definition is used so the scaling factors applied on an object affects only
    the center of the object fully. The borders are only affected in one direction
    and the corners are not scaled (note, restrictions apply, see below.) This is
    quite useful to draw a scalable button or window.
     
      Fig 1 — Sample button being scaled with a scaling grid
 
    As we can see in the example, the corners are not being scaled. The vertical
    borders are scaled vertically only. The horizontal borders are scaled
    horizontally only. The inner area is scaled both ways.
     
    For your grid to work, there are many restrictions as follow:
     
      The referenced object must be a Sprite
          or a Button. Note that any button
	  tag is affected.The referenced object cannot be rotated or skewed. However, it is possible to
          include the resulting object in a sprite and then use a rotation or
	  skew in the Place matrix
	  when placing that sprite.Shapes directly defined in the referenced object are affected. If you create a
          button or sprite made up of sub-sprites, these sub-sprites are not affected.Text is not affected by the grid. It is always scaled as expected.Fills are likely to not work as expected (i.e. bitmaps, images); that is, this
          tag is likely to have no effect on themWhen scaling down so much that the inner area represents less than 1 pixel
          will then affect the borders and corners as if there wasn't a scaling grid.Somehow the Stop action can prevent the grid from working (i.e. insert Shapes,
          Button, Grid, Action Stop, Resize, Show Frame; the edges are resized as if no
	  grid was there.)[would need more testing] It may be that to work you need to place the
          resulting button or sprite in another parent sprite. This is how I could make my
	  grid work properly without having to mess around. 	struct swf_definescalinggrid {
		swf_tag				f_tag;		/* 78 */
		unsigned short			f_button_id_ref;
		swf_rect			f_rect;
	};
    The f_button_id_ref needs to specify a button or a sprite.
     
    The f_rect defines the inner area.
     
    
    DefineSceneAndFrameData (V9.0)
     
    This tag is used to define some raw data for a scene and frame.
     	struct swf_definesceneandframedata {
		swf_tag				f_tag;		/* 86 */
		unsigned char			f_data[tag size];
	};
    f_data is an array of bytes.
     
    
    DefineShape (V1.0)
    DefineShape2 (V2.0)
 DefineShape3 (V3.0)
 DefineShape4 (V8.0)
 DefineMorphShape (V3.0)
 DefineMorphShape2 (V8.0)
 
  These are probably the most important tags in this reference. They
  are used to define a shape using Bezier curves and lines with
  different styles. The DefineShape of V1.0 is usually
  enough unless you need a large number of styles or you want to
  specify colors with an alpha channel (RGBA).
   
  The DefineMorphShape and DefineMorphShape2 can be used
  to render an intermediate shape between two defined shapes.
  All the points and control points of both shapes must match.
  This is because the rendering of the morphing shapes is just an
  interpolation between both shapes points and control points positions.
  The interpolation is a very simple linear function (note however that
  you still can use a non-linear transformation effect in the end.)
  Most of the parameters in a shape definition are doubled when this tag
  is used. It otherwise looks very similar.
   	struct swf_defineshape {
		swf_tag				f_tag;		/* 2, 22, 32, 83, 46 or 84 */
		unsigned short			f_shape_id;
		swf_rect			f_rect;
		is_morph = f_tag == DefineMorphShape || f_tag == DefineMorphShape2;
		has_strokes = f_tag == DefineShape4 || f_tag == DefineMorphShape2;
		if(is_morph) {
			swf_rect			f_rect_morph;
		}
		if(has_strokes) {
			swf_rect			f_stroke_rect;
			if(is_morph) {
				swf_rect			f_stroke_rect_morph;
			}
			unsigned			f_define_shape_reserved : 6;
			unsigned			f_define_shape_non_scaling_strokes : 1;
			unsigned			f_define_shape_scaling_strokes : 1;
		}
		if(is_morph) {
			unsigned long			f_offset_morph;
			swf_morph_shape_with_style	f_morph_shape_with_style;
		}
		else {
			swf_shape_with_style		f_shape_with_style;
		}
	};
  The f_stroke_rect and f_stroke_rect_morph rectangles define the
  boundaries around their respective shapes without the line strokes (excluding
  the thickness of the line.)
   
  The f_define_shape_non_scaling_strokes flag should be set to 1 if at
  least one of the line strokes always stays the same while morphing.
   
  The f_define_shape_scaling_strokes flag should be set to 1 if at least
  one of the line strokes is changing while morphing.
   
  The f_offset_morph 32 bits value gives the offset from after that
  value to the start of the second shape (the shape to morph to.) In other words,
  this value can be used to skip the styles and the first shape at once.
   
    
    DefineSound (V2.0)
     
  A DefineSound tag declares a set of samples of a sound effect
  or a music.
   
  The sound samples can be compressed or not, stereo or not and 8 or
  16 bits. The different modes are not all available in V2.0.
   	struct swf_definesound {
		swf_tag			f_tag;		/* 14 */
		unsigned short		f_sound_id;
		unsigned		f_sound_format : 4;
		unsigned		f_sound_rate : 2;
		unsigned		f_sound_is_16bits : 1;
		unsigned		f_sound_is_stereo : 1;
		unsigned long		f_sound_samples_count;
		unsigned char		f_sound_data[<variable size>];
	};
  The f_sound_is_16bits is always set to 1 (16bits samples) if the
  samples are compressed (neither RawnorUncompressed). 
  The f_sound_rate represents the rate at which the samples are
  defined. The rate at which it will be played on the target computers
  may differ. The following equation can be used to determine the rate:
   	rate = 5512.5 * 2 ** f_sound_rate 
  It yields the following values (the rate of 5512.5 is rounded down to 5512):
   | 
      
	| f_sound_rate | Rate in bytes per seconds
 |  
	| 0 | 5512 |  
	| 1 | 11025 |  
	| 2 | 22050 |  
	| 3 | 44100 |  | 
 
  The f_sound_samples_count value is the exact number of samples
  not the size of the data in byte. Thus, in stereo, it represents the
  number of pairs. To know the byte size, use the total size of the tag
  minus the header (11 or 13 depending on whether the size of the tag
  is larger than 64 - it is more than likely that it will be 13).
   
  The f_sound_format can be one of the following values:
   | 
      
	| Value | Name | Comment | Version |  
	| 0 | Raw | 16 bits uncompressed samples are not specified as
		being saved in little or big endian. The endianess of the
		processor on which the movie is being played will be used.
		Thus you should never use this format with 16 bits samples. | 2 |  
	| 1 | ADPCM | Audio differential pulse code modulation
		compression scheme. | 2 |  
	| 2 | MP3 | High ratio of compression with very good
		quality sound. Use MP3 if you can save a V4.x or
		better movie. | 4 |  
	| 3 | Uncompressed | Uncompressed samples which are always saved in
		little endian. This is similar to the format 0 except you
		can be sure the data will be properly played on any
		system. | 4 |  
	| 6 | Nellymoser | Good quality sound compression for voices.
	        Use Nellymoser if you can save a V6.x or better movie
		and the sound is actually a voice or animal roar, squeek,
		etc. This is a single channel compression. | 6 |  | 
 
  The f_sound_data depends on the sound format. The following
  describes the different formats as used in the DefineSound
  and the SoundStreamBlock tags.
  8 bits 
  8 bits data is saved in an array of 16 bitssigned char.
  The value 0 represents silence. The samples can otherwise have
  values between -128 and +127. 
  16 bits data is saved in an array of Monosigned short.
  The value 0 represents silence. The samples can otherwise have values
  between -32768 and +32767.
  By default, the data will be encoded in little endian. However, theRAWformat doesn't specify the endianess of the data
  saved in that case. You should avoid usingRAW16 bits
  data. UseUncompresseddata instead, compress it in
  some of the available compression formats (includingRAW8 bits data). A player may wish to avoid playing any sound saved inRAW16 bits to avoid any problem. 
  Mono sound saves only one channel of sound. It will be played back
  on both output (left and right) channels. This is often enough for
  most sound effects and voice.
  Stereo 
  For better quality music and sound effects, you can save the data
  in stereo. In this case, the samples for each channel (left and right)
  are interleaved, with the data for the left channel first. Thus, you
  will have: LRLRLRLRLR... In 8 bits, you get one byte for the left channel,
  then one byte for the right, one for the left, one for the right, etc.
  In 16 bits, you get two bytes for the left then two for the right channel,
  etc.
  Raw 
  The ADPCMRAWencoding is an uncompressed endian unspecified
  encoding. You can use this format to save small 8 bits samples sound
  effects. 
  Audio differential pulse code modulation compression scheme. This is
  pretty good compression for sound effects.
   
  The ADPCM tables used by the SWF players are as follow:
   int swf_adpcm_2bits[ 2] = { -1,  2 };
int swf_adpcm_3bits[ 4] = { -1, -1,  2,  4 };
int swf_adpcm_4bits[ 8] = { -1, -1, -1, -1,  2,  4,  6,  8 };
int swf_adpcm_5bits[16] = { -1, -1, -1, -1, -1, -1, -1, -1,
                             1,  2,  4,  6,  8, 10, 13, 16 };
  The ADPCM data is composed of a 2 bits encoding size (2 to 5 bits)
  and an array of 4096 left (mono) or left and right (stereo) samples.
   	struct swf_adpcm_header {
		unsigned		f_encoding : 2;
	};
  The number of bits for the compression is f_encoding + 2. 	struct swf_adpcm_mono {
		unsigned short		f_first_sample;
		unsigned		f_first_index : 6;
		unsigned		f_data[4096] : f_encoding + 2;
	};
	struct swf_adpcm_stereo {
		unsigned short		f_first_sample_left;
		unsigned		f_first_index_left : 6;
		unsigned short		f_first_sample_right;
		unsigned		f_first_index_right : 6;
		unsigned		f_data[8192] : f_encoding + 2;
	};
MP3
  IMPORTANT LICENSING NOTES: please, see
  The entire SSWF license above for information
  about the Audio MPEG licensing rights.
   
  The SWF players which support movie v4.x and better will also support
  MPEG1 audio compression. This is a good quality high compression
  scheme. The players need to support constant and variable bit rates,
  and MPEG1 Layer 3, v2 and v2.5. For more information about MPEG
  you probably want to check out this web site:
  http://www.mp3-tech.org/.
   
  In SWF movies, you need to save a seeking point (position of the
  data to play in a given frame) before the MP3 frames themselves.
  It is also called the initial latency. I will make this clearer
  once I understand better what it means.
   
  An MP3 frame is described below. This is exactly what you will
  find in any music file.
   	struct swf_mp3_header {
		unsigned		f_sync_word : 11;
		unsigned		f_version : 2;
		unsigned		f_layer : 2;
		unsigned		f_no_protection : 1;
		unsigned		f_bit_rate : 4;
		unsigned		f_sample_rate : 2;
		unsigned		f_padding : 1;
		unsigned		f_reserved : 1;
		unsigned		f_channel_mode : 2;
		unsigned		f_mode_extension : 2;
		unsigned		f_copyright : 1;
		unsigned		f_original : 1;
		unsigned		f_emphasis : 2;
		if(f_no_protection == 0) {
			unsigned short	f_check_sum;
		}
		unsigned char		f_data[variable size];
	};
  The f_sync_word are 11 bits set to 1's only. This can be
  used to synchronize to the next frame without knowing the exact
  size of the previous frame.
   
  The f_version can be one of the following:
   
    0 - MPEG version 2.5 (extension to MPEG 2)1 - reserved2 - MPEG version 2 (ISO/IEC 13818-3)3 - MPEG version 1 (ISO/IEC 11172-3) 
  Note: if the MPEG version 2.5 isn't use, then the f_sync_word
  can be viewed as 12 bits and the f_version as 1 bit.
   
  In SWF movies, the f_layer must be set to III (which is 1).
  The valid MPEG layers are as follow:
   
    0 - reserved1 - Layer III2 - Layer II3 - Layer I 
  The f_no_protection determines whether a checksum is
  defined right after the 32 bits header. If there is a checksum,
  it is a 16 bit value which represents the total of all the words
  in the frame data.
   
  The f_bit_rate determines the rate at which the following
  data shall be taken as. The version and layer have also an
  effect on determining what the rate is from this f_bit_rate
  value. Since SWF only accepts Layer III data, we can only accepts
  a few set of rates as follow. MP3 players (and thus SWF players)
  must support variable bit rates. Thus, each frame may use a different
  value for the f_bit_rate field.
   | 
      | f_bit_rate | MPEG version 1 | MPEG version 2 | 
|---|
 | 0 | free(1) | free(1) |  | 1 | 32 kbps | 8 kbps |  | 2 | 40 kbps | 16 kbps |  | 3 | 48 kbps | 24 kbps |  | 4 | 56 kbps | 32 kbps |  | 5 | 64 kbps | 40 kbps |  | 6 | 80 kbps | 48 kbps |  | 7 | 96 kbps | 56 kbps |  | 8 | 112 kbps | 64 kbps |  | 9 | 128 kbps | 80 kbps |  | 10 | 160 kbps | 96 kbps |  | 11 | 192 kbps | 112 kbps |  | 12 | 224 kbps | 128 kbps |  | 13 | 256 kbps | 144 kbps |  | 14 | 320 kbps | 160 kbps |  | 15 | bad(2) | bad(2) |  | 
 
    (1) free — means any (variable) bit rate
    (2) bad — means you can't properly use this value
 
  The f_sample_rate defines the rate at which the encoded
  samples will be played at. This rate may vary and be equal or
  smaller than the rate indicated in the DefineSound header.
  The rate definition depends on the MPEG version as follow:
   | 
      | f_sample_rate | MPEG version 1 | MPEG version 2 | MPEG version 2.5 | 
|---|
 | 0 | 44100 Hz | 22050 Hz | 11025 Hz |  | 1 | 48000 Hz | 24000 Hz | 12000 Hz |  | 2 | 32000 Hz | 15000 Hz | 8000 Hz |  | 3 | reserved |  | 
 
  The f_padding will be set to 1 if the stream includes
  pads (one extra slot - 8 bits of data). This is used to ensure
  that the sound is exactly the right size. Useful only if your
  sound is very long and synchronized with the images.
   
  The f_reserved isn't used and must be set to zero in
  SWF files.
   
  The f_channel_mode determines the mode used to
  compress stereophonic audio. Note that the Dual Channel
  mode is viewed as a stereo stream by SWF.
  It can be one of the following:
   
    0 - stereo (standard LRLRLR...)1 - joint stereo (L+R and L-R)2 - dual channels (LLLLL... and then RRRRR...)3 - single channel (monophonic audio) 
  The f_mode_extension determines whether the intensity
  stereo (L+R — bit 5) and middle side stereo (L-R — bit 4)
  are used (set bit to 1) or not (set bit to 0) in joint stereo.
  f_mode_extension is usually always set to 3.
   
  The f_copyright field is a boolean value which specify
  whether the corresponding audio is copyrighted or not. The
  default is to set it to 1 (copyrighted).
   
  The f_original field is a boolean value which specify
  whether the corresponding audio is a copy or the actual original
  sound track. It's usually set to 0 (a copy) in SWF movies.
   
  The f_emphasis field can be one of the following values.
  It is rarely used. It tells the decoder to re-equalize the
  sounds.
   
    Nellymoser0 - no emphasis1 - 50/15 ms2 - reserved3 - CCIT J.17 
  This is a newly supported scheme to encode speech (and audio) of
  either better quality or smaller bit rate. Thus you can either
  put more sound in your files resulting in a similar file size
  or make the entire file smaller so it downloads faster.
   
  The Nellymoser encoding and decoding scheme have not yet been
  released in the public domain and it is likely that won't ever
  be. Thus, you won't find any info here about this compression
  scheme.
   
  Feel free to check out the
  http://www.nellymoser.com
  web site for more info about this compression scheme.
   
    
    DefineSprite (V1.0)
     
  A sprite is a set of SWF tags defining an animated object which can then be
  used as a simple object. A sprite can't contain another sprite.
   
  The following are the tags which are accepted within the list of tags present
  in the Sprite:
   
  The data array of tags should always be terminted by an
  End tag though this can be infered
  some players may not support a non-terminated list.
   	struct swf_definesprite {
		swf_tag			f_tag;		/* 39 */
		unsigned short		f_sprite_id;
		unsigned short		f_frame_count;
		...			<data>;
		swf_tag			f_end;
	};
    In order to initialize a sprite once, you can use the
    DoInitAction.
    This tag comes along a sprite and not inside it.
     
    
    DefineText (V1.0)
    DefineText2 (V3.0)
 
  Define an object of text so the SWF player can draw a string.
  The only difference between the DefineText and
  DefineText2 tags is that the latter supports RGBA colors.
  This can be seen in one of the swf_text_record
  structures.
   
  Since version 8 it is possible to define extraneous parameters when
  defining a CSMTextSettings
  tag referencing a DefineText or
   DefineText2.
   	struct swf_definetext {
		swf_tag			f_tag;		/* 11 or 33 */
		unsigned short		f_text_id;
		swf_rect		f_rect;
		swf_matrix		f_matrix;
		unsigned char		f_glyph_bits;
		unsigned char		f_advance_bits;
		swf_text_record		f_text_record;
	};
 
    
    DefineVideoStream (V6.0)
     
  This tag defines a video stream. To playback the video stream, one needs
  to add a list of VideoFrame tags.
   	struct swf_definevideostream {
		swf_tag			f_tag;		/* 60 */
		unsigned short		f_video_id;
		unsigned short		f_frame_count;
		unsigned short		f_width;	/* WARNING: this is in pixels */
		unsigned short		f_height;
		unsigned char		f_reserved : 5;
		unsigned char		f_deblocking : 2;
		unsigned char		f_smoothing : 1;
		unsigned char		f_codec;
	};
  The f_width and f_height are defined in pixels. This is
  rather uncommon in SWF so it is to be noted multiple times.
   
  The f_deblocking parameter can be set to one of the
  values defined in the following table.
  All videos are saved in small blocks of about 32x32 pixels
  (there are different sizes.) Turning this feature on lets
  the player mix colors between blocks for better output
  quality.
   | 
      
        | Number | Comments | SWF Version |  
        | 0 | Use video packet information | 6 |  
        | 1 | Always Off | 6 |  
        | 2 | Fast deblocking (in version 6 it meant: always on) | 6 |  
        | 3 | High Quality Deblocking | 8 |  
        | 4 | High Quality Deblocking and Fast Deringing | 8 |  
        | 5 | High Quality Deblocking and Deringing | 8 |  | 
 
  The f_smoothing flag can be set to 1 to have the player
  smooth the video before to render it on the output screen.
   
  The f_codec number specifies which codec was used to
  compress the video. At this time, the following are defined:
   | 
      
        | Number | Name | Comments | SWF Version |  
        | 2 | Sorenson H.263 |  | 6 |  
        | 3 | Screen Video |  | 7 |  
        | 4 | VP6 |  | 8 |  
        | 5 | VP6 with Alpha |  | 8 |  | 
 
    
    DoAction (V1.0*)
    DoInitAction (V6.0*)
 
  *the version specified here is the version in
  which the tags appeared—however, actions of higher versions can be used with
  older version tags and thus this version doesn't indicate the version of all the
  actions used in this tag
   
  The DoAction tag will be used to execute an action in place. Usually, actions
  are used on buttons to add interactivity to the SWF movies. In V1.0 you had only
  one dynamic branch (WaitForFrame).
  In V4.0 you can test many different things such as a position, angle or sound
  track cursor position. Since V5.0 SWF has a complete scripting language
  supporting string and arithmetic operations.
   
  The DoInitAction tag is used when some initialization of a sprite is
  necessary. These actions are carried on the sprite only once. These are
  outside of the given sprite and will reference the sprite so all the actions
  are automatically applied to the sprite without you having to do a
  SetTarget.
   
  The following describes the data in the DoAction and DoInitAction tags:
   	struct swf_doaction {
		swf_tag			f_tag;		/* 12 and 59 */
		if(f_tag == DoInitAction) {
			unsigned short	f_action_sprite;
		}
		swf_action		f_action_record[variable];
	};
  The f_sprite  is a reference to the sprite which will be initialized.
   
  The f_action_record is an array of actions terminated by an
  End action.
   
  The following is a list of all the actions available in SWF movies. The Version
  column will be used to know what version of Flash player you need in order to use the
  given action (otherwise it is likely to be ignored or worse, make the player crash).
  Note that Macromedia defines all the actions as being part of V3.0+. Thus, any action
  mark as being available in earlier versions (V1.0 or V2.0) may in fact not be (though
  the DoAction and
  DefineButton tags were part of V1.0!!!)
   
  The Length (Stacked) column specifies the length of the data following the
  property (only with the property ID is 0x80 to 0xFF) and what will be pushed onto
  the stack. All the expressions work as in polish notation. The actions which don't
  push anything on the stack have nothing written between parenthesis.
   
  The Data & Operation column specifies what data follows the action
  and what the operation is. If there is no data and no operation, then n.a.
  is used. The data will be described as a list of fields as in the other
  structures described in this document. The operations will be written as
  closely as possible to a C like operation (though strings are managed in a
  much different way than C!) Anything which is poped from the stack will
  be given a letter and a digit. The digit represents the count and the letter
  the type of the data (a count of 1 represents the first pop, a count of 2
  represents the second pop, etc.) The following column (Comments) will
  explain how the operation uses the data when appropriate.
   
  The data types used are as follow:
   
    | 
        | Short | Type | 
|---|
 | a | any type |  | b | boolean |  | f | foat |  | i | integer |  | n(1) | numeric (integer or float) |  | o(2) | object (as in C++) |  | s | string |  | t | array or table of values |  | v | variable - pushes multiple values on the stack |  | 
 
    (1) when I don't know whether an integer or a float
    should be specified I will use 'n' as well. This should
    be correct most of the time anyway.
    (2) an object reference can be obtained by evaluating
    the name of that object; thus GetVariable("carrot") will return a
    reference to the carrot object.
 
  The following lists all the actions by type. Thoses which have the comment (typed)
  operates taking the type of its arguments in account as defined in ECMA-262 Section 11.6.1
  (arithmetic), 11.8.5 (comparison), 11.9.3 (equality)
  which you can certainly find somewhere on the Internet. Version 3 is available here:
  ECMA-262 V3.0. The functions which aren't typed
  will behave by (1) trying to transform parameters in values, then perform the operation
  with numbers only or (2) when strings can't be transformed in values, perform a string
  operation.
   
    Actions in alphabetical order
    
      
     Actions by Type
 
      Action Script Control
      
	Branch Always [0x99]Branch If True [0x9D]
 Call Function [0x3D]
 Call Method [0x52]
 Declare Function [0x9B]
 Declare Function (V7) [0x8E]
 End [0x00]
 Return [0x3E]
 Throw [0x2A]
 Try [0x8F]
 
      Stack Control
      
	Duplicate [0x4C]Push Data [0x96]
 Swap [0x4D]
 
      Action Script Context
      
	Set Target [0x8B]Set Target (dynamic) [0x20]
 With [0x94]
 
      Movie Control
      
	Call Frame [0x9E]Get URL [0x83]
 Get URL2 [0x9A]
 Goto Expression [0x9F]
 Goto Frame [0x81]
 Goto Label [0x8C]
 Next Frame [0x04]
 Play [0x06]
 Previous Frame [0x05]
 Stop [0x07]
 Toggle Quality [0x08]
 Wait For Frame [0x8A]
 Wait For Frame (dynamic) [0x8D]
 
      Sound
      
	Stop Sound [0x09]
       
      Arithmetic
      
	Add [0x0A]Add (typed) [0x47]
 Decrement [0x51]
 Divide [0x0D]
 Increment [0x50]
 Integral Part [0x18]
 Modulo [0x3F]
 Multiply [0x0C]
 Number [0x4A]
 Subtract [0x0B]
 
      Comparisons
      
	Equal [0x0E]Equal (typed) [0x49]
 Strict Equal [0x66]
 Greater Than (typed) [0x67]
 Less Than [0x0F]
 Less Than (typed) [0x48]
 String Equal [0x13]
 String Greater Than [0x68]
 String Less Than [0x29]
 
      Logical and Bit Wise
      
	And [0x60]Logical And [0x10]
 Logical Not [0x12]
 Logical Or [0x11]
 Or [0x61]
 Shift Left [0x63]
 Shift Right [0x64]
 Shift Right Unsigned [0x65]
 XOr [0x62]
 
      Strings & Characters
      (See the String Object also)
      
	Chr [0x33]Chr (multi-bytes) [0x37]
 Concatenate Strings [0x21]
 Ord [0x32]
 Ord (multi-bytes) [0x36]
 String [0x4B]
 String Length [0x14]
 String Length (multi-bytes) [0x31]
 SubString [0x15]
 SubString (multi-bytes) [0x35]
 
      Properties
      
	Get Property [0x22]Set Property [0x23]
 
      Objects
      
	Cast Object [0x2B]Declare Array [0x42]
 Declare Dictionary [0x88]
 Declare Object [0x43]
 Delete [0x3A]
 Delete All [0x3B]
 Duplicate Sprite [0x24]
 Enumerate [0x46]
 Enumerate Object [0x55]
 Extends [0x69]
 Get Member [0x4E]
 Get Target [0x45]
 Implements [0x2C]
 Instance Of [0x54]
 New [0x40]
 New Method [0x53]
 Remove Sprite [0x25]
 Set Member [0x4F]
 Type Of [0x44]
 
      Variables
      
	Declare Local Variable [0x41]Get Variable [0x1C]
 Set Local Variable [0x3C]
 Set Variable [0x1D]
 
      Miscellaneous
      
	FSCommand2 [0x2D]Get Timer [0x34]
 Random [0x30]
 Start Drag [0x27]
 Stop Drag [0x28]
 Store Register [0x87]
 Strict Mode [0x89]
 Trace [0x26]
 
      Internal Functions & Constants
      
	Color ObjectMath Object
 String Object
 
  WARNING: the order of unstacking values in regard to some operators
  is to be confirmed
   | 
      
	| Name | ID | Length (Stacked) | Data & Operation | Comments | Version |  
	| End | 0x00 | 0 | <n.a.> | End a record of actions | 1 |  
	| Next Frame | 0x04 | 0 | <n.a.> | Go to the next frame | 1 |  
	| Previous Frame | 0x05 | 0 | <n.a.> | Go to the previous frame | 1 |  
	| Play | 0x06 | 0 | <n.a.> | Enter the standard (default) auto-loop playback | 1 |  
	| Stop | 0x07 | 0 | <n.a.> | Stop playing. Only a button (or the plugin menu) can be used to restart the movie | 1 |  
	| Toggle Quality | 0x08 | 0 | <n.a.> | Change the quality level from low to high and vice versa. At this time, not sure what
	happens if you use medium! | 1 |  
	| Stop Sound | 0x09 | 0 | <n.a.> | Stop playing any sound effect. | 2 |  
	| Add | 0x0A | 0 (n) | operation: n2 + n1 | Pops two values, add them and put the result back on the stack. | 4 only |  
	| Subtract | 0x0B | 0 (n) | operation: n2 - n1 | Pops two values, subtract them and put the result back on the stack. | 4 |  
	| Multiply | 0x0C | 0 (n) | operation: n2 * n1 | Pops two values, multiply them and put the result back on the stack. | 4 |  
	| Divide | 0x0D | 0 (f) | operation: n2 / n1 | Pops two values, divide them and put the result back on the stack. | 4 |  
	| Equal | 0x0E | 0 (b) | operation: n2 == n1 | Pops two values, compare them for equality and put the boolean result back on the stack. The !=is created by adding a Logical Not
		after the Equal | 4 only |  
	| Less Than | 0x0F | 0 (b) | operation: n2 < n1 | Pops two values, compare them for inequality and put the boolean result back on the stack. Other comparison operators: 
		  Less Than or Equal (n2 <= n1) Swap + Less Than + Logical Not 
		  Greater Than or Equal (n2 >= n1) Less Than + Logical Not Swap + Less Than | 4 only |  
	| Logical And | 0x10 | 0 (b) | operation: b2 && b1 | Pops two values, compute the Logical AND and put the boolean result back on the stack. 
	Note: if b2 is a function call and b1 is false, then b2 is not called. | 4 |  
	| Logical Or | 0x11 | 0 (b) | operation: b2 || b1 | Pops two values, compute the Logical OR and put the boolean result back on the stack. 
	Note: if b2 is a function call and b1 is true, then b2 is not called. | 4 |  
	| Logical Not | 0x12 | 0 (b) | operation: ! b1 | Pops one value, compute the Logical NOT and put the result back on the stack. | 4 |  
	| String Equal | 0x13 | 0 (b) | operation: s2 == s1 | Pops two strings, compute the equality and put the boolean result back on the stack. | 4 only? |  
	| String Length | 0x14 | 0 (n) | operation: strlen(s1) | Pops two strings, compute the equality and put the boolean result back on the stack. | 4 |  
	| SubString | 0x15 | 0 (s) | operation: s3[i2 .. i2 + i1 - 1] | Pops two values and one string, the first value is the new
			string size (at most that many characters) and the second
			value is the index (1 based) of the first character to start
			the copy from. The resulting string is pushed back on the
			stack. | 4 |  
	| Pop (0x17) | 0x17 | 0 (i) | operation: a1 | Pops one value from the stack and forget it. | 4 |  
	| Integral Part | 0x18 | 0 (i) | operation: floor(n1) | Pops one value, transform in an integer, and push the result back on the stack. | 4 |  
	| Get Variable | 0x1C | 0 (a) | operation: GetVariable(s1) | Pops one string, search for a variable of that name, and push its value on the stack.
	The variable name can include sprite names separated by slashes and finished by a colon as in: /Sprite1/Sprite2:MyVarThis gets the variable named MyVarfrom the sprite namedSprite2which resides inSprite1. Note that in a browser you can add variables
	at the end of the movie URL (as defined in the W3C docs) and these will automatically
	be accessible via the GetVariable instruction.my_movie?language=jp 
	Since Flash V5.x, there are
	internal variables available to you. These can
	be read with the Get Variableinstruction. | 4 |  
	| Set Variable | 0x1D | 0 | operation: s2 = v1 | Pops one value and one string, set the variable of that name with that value.
	Nothing is pushed back on the stack. The names can be full paths as defined in the
	GetVariable action. | 4 |  
	| Set Target (dynamic)
 | 0x20 | 0 | operation: SetTarget(s1) | Pops one string from the stack. If the string is the empty string, then
			the next actions apply to the main movie. Otherwise it is the name of a
			sprite and the followings actions apply to that sprite only. | 3 |  
	| Concatenate Strings | 0x21 | 0 (s) | operation: s2 & s1 | Pops two strings, concatenate them, push the result on the stack. | 4 |  
	| Get Property | 0x22 | 0 (a) | operation: s2.n1 | Query the property 'n1' of the object named 's2' (a field in a structure
	if you wish), and push the result on the stack. See the table below for a list of possible
	properties (or fields) values. | 4 |  
	| Set Property | 0x23 | 0 | operation: s3.n2 = a1 | Pop a value from the stack and use it to set the specified
	named object at the specified field property. See the table below for a list
	of possible properties (or fields) values. | 4 |  
	| Duplicate Sprite | 0x24 | 0 | operation: s3 s2 i1 Duplicate | 's3' is the name of a sprite which is copied. The new sprite
	has the name 's2' and is placed at depth 'i1'. The depth
	isn't used the same way in Flash 4 and Flash 5. The depth isn't clearly
	documented anywhere, but it looks like you need to have a depth of
	16384 or more for a duplicated sprite to work properly. | 4 |  
	| Remove Sprite | 0x25 | 0 | operation: s1 Remove | Pop the string 's1' with the name of the sprite to be removed from view. | 4 |  
	| Trace | 0x26 | 0 | operation: s1 Trace | Print out string s1 in debugger output window. Ignored otherwise. | 4 |  
	| Start Drag | 0x27 | 0 | operation: [n7 n6 n5 n4] b3 b2 s1 StartDrag | Pop a target name (s1), a first boolean (b2) — (un)lock the center of the object
	to the mouse pointer, a second boolean (b3) — constrained the mouse in the following rectangle
	(n4 to n7, representing y2, x2, y1, x1 — NOTE: the rectangle is not defined if (b3) is False).
	The object will follow the mouse until a Stop Drag is
	applied or another object is defined as the object to be dragged. | 4 |  
	| Stop Drag | 0x28 | 0 | operation: StopDrag | Stop a drag operation. | 4 |  
	| String Less Than | 0x29 | 0 (b) | operation: s2 < s1 | Pops two strings, compare them, push the result back on the stack. | 4 only? |  
	| Throw | 0x2A | 0 (a) | operation: throw a1 | This action pops one item and returns it as an exceptional result.
			You can catch exceptions using the Try
			action. | 7 |  
	| Cast Object | 0x2B | 0 (o) | operation: (s2) o1 | The Cast Object action makes sure that the
			object o1 is an instance of the class s2.
			If it is the case, then o1 is pushed back onto
			the stack. Otherwise Null is pushed back onto
			the stack. The comparison is identical to the one
			applied by the Instance Of
			action. | 7 |  
	| Implements | 0x2C | 0 (o) | operation: o1 implements i2, o3, o4 ... on
(where n is i2) | This action declares an object as a sub-class of one or
			more interfaces. The syntax here is simple, the real
			implementation is quite unbelivibly difficult to fathom. 
 The following shows you how you can add an implements
			of interfaces "A" and "B" to the class "C". Notice that
			class "C" needs to already exist. Here we assume that all
			classes are defined in the global scope.
 
 
 	push data "_global"
	get variable
	push data "A"
	get member
	push data "_global"
	get variable
	push data "B"
	get member
	push data 2
	push data "_global"
	get variable
	push data "C"
	get member
	implements | 7 |  
	| FSCommand2 | 0x2D | 0 (a) | operation: fscommand2 i1, s2, s3, s4 ... sn
(where n is i1) | NOTE: Ammar Mardawi sent a correction for this action
			and it looks like it works the way it is described now. 
 Execute the named command (s2) passing on parameters
			(s3, s4 ... sn.)
 | 7 |  
	| Random | 0x30 | 0 (i) | operation: random(n1) | Pops one number which is the maximum value (not included) that the
	random() function will return, push the generated value on the stack. 'n1'
	should not be zero. | 4 |  
	| String Length (multibyte)
 | 0x31 | 0 (i) | operation: mbslen(s1) | Pops one multi-byte string, push it's length in actual character on the stack. | 4 |  
	| Ord | 0x32 | 0 (i) | operation: s1[0] | Pops one string, compute the ASCII value of its first character and put it back on the stack. | 4 |  
	| Chr | 0x33 | 0 (s) | operation: i1 | Pops one integer, use it as a ASCII character and push the newly created string on the stack. | 4 |  
	| Get Timer | 0x34 | 0 (i) | operation: movie_time() | Get the current movie timer in milliseconds and push it on the stack.
	This is equivalent to the number of frames which have been played so far. | 4 |  
	| SubString (multibyte)
 | 0x35 | 0 (s) | operation: s3[i2 .. i2 + i1 - 1] | Pops a multi-byte string, get i1 characters from the position i2 (1 based) and push the result back on the stack. | 4 |  
	| Ord (multibyte)
 | 0x36 | 0 (i) | operation: s1[0] | Pops one string, compute the multi-byte value of its first character and put it back on the stack. | 4 |  
	| Chr (multibyte)
 | 0x37 | 0 (s) | operation: i1 | Pops one integer, use it as a multi-byte string
	character and push the newly created string on the stack. | 4 |  
	| Delete | 0x3A | 0 (undefined) | operation: delete(s1, o2) | Pops one string which is the name of the property
	to be deleted. Then pop the object from which the property is to
	be deleted. 
	It is necessary to Push Data
	type undefined (0x03) before the string as in:
	 96 04 00 03 00 'a' 00 3A
delete("a");
	to delete a global variable. According to some movies I have
	looked at, the delete instruction returns some undefined value. | 5 |  
	| Delete All | 0x3B | 0 | operation: delete(s1, o2) | Pops one string which is the name of the thread
	which will get all of its variables deleted. | 5 |  
	| Set Local Variable | 0x3C | 0 | operation: s2 = a1 | Pops a value and a variable name. Create or set a local
	variable of that name with the (initial) value as specified. The same
	local variable can safely be set in this way multiple times. To only declare a
	local variable, use the
	Declare Local Variable
	instead. | 5 |  
	| Call Function | 0x3D | 0 (a) | operation: s1(i2, [a3, a4, a5...]) | Pops one string which is the name of the function to call, pop
	one integer which indicates the number of arguments following, pop each argument,
	call the named function, push the result of the function on the stack. There is
	always a result. The idea of the concept is that the function being called will
	use its own stack, however, that was not really the case until version 7. In other
	words, if a function stacks multiple results, they all were returned in older
	versions of SWF. 
	Flash V5.x offers a set of internal functions available to the end user via
	this Call Functioninstruction. Please, see the table below
	for a complete list of these
	internal functions. | 5 |  
	| Return | 0x3E | 0 (a) | operation: return a1 | Pops one object and return it to the caller. The result is stacked on the caller
	stack, not the stack of the function being executed. | 5 |  
	| Modulo | 0x3F | 0 (i) | operation: i2 % i1
           or
	   f2 % f1 | Pops two numbers, computes the modulo and push the result back on the stack. | 5 |  
	| New | 0x40 | 0 (o) | operation: o = new s1
           o.s1(i2, [a3, a4, a5 ...]) | Pop the class name for the new object to create.
			Pop the number of arguments. Pop each argument.
			Create an object of class s1. Call the
			constructor function (which has the same name
			as the object class: s1).
			The result of the constructor is discarded.
			Push the created object on the stack.
			The object should then be saved in a variable
			or object method. | 5 |  
	| Declare Local Variable | 0x41 | 0 | operation: s1 | Pops a variable name and marks it as a local variable. If the
	variable doesn't exist yet, then its value is undefined. To declare and set a
	local variable, use the Set Local Variable
	instead. | 5 |  
	| Declare Array | 0x42 | 0 (t) | operation: new array[i1]
array[0] = a2
array[1] = a3
...
array[i1 - 1] = an
(where n = i1 + 1) | Pops the number of elements in the array. Pop one value per
			element and set the corresponding entry in the array. The array is pushed
			on the stack. It can later be sent to a function or set in a variable. | 5 |  
	| Declare Object | 0x43 | 0 (o) | operation: new Object
count = i1
object.a3 = a2
object.a5 = a4
...
object.an = am
(where n = i1 * 2 + 1 and m = i1 * 2) | Pops the number of members in the object. Pop one value and one name per
			member and set the corresponding member in the object. The resulting object
			is pushed on the stack. It can later be sent to a function or set in a
			variable. 
			Note: the member names are converted to strings; they certainly should
			be strings though anything is supported. | 5 |  
	| Type Of | 0x44 | 0 (s) | operation: typeof(a1) | Pops some data, define its type and push the name of its type back on the stack.
	The currently supported types are as follow: number
boolean
string
object
movieclip
null
undefined
function | 5 |  
	| Get Target | 0x45 | 0 (s) | operation: target_of(o1) | Pops an object, if it is a valid sprite, push it's path on the stack.
			A sprite path can be used by different other actions such as the
			Goto Expression. | 5 |  
	| Enumerate | 0x46 | 0 (v) | operation: s1 | Pop the name of an object and push all of its children (methods
			& variables) back on the stack. The list is null terminated. | 5 |  
	| Add (typed)
 | 0x47 | 0 (a)
 | operation: i2 + i1
	   or
	   f2 + f1
	   or
	   s2 + s1 | Pops two numbers or two strings, computes the sum or concatenation
			and push the result back on the stack. | 5 |  
	| Less Than (typed)
 | 0x48 | 0 (b) | operation: i2 < i1
	   or
	   f2 < f1
	   or
	   s2 < s1 | Pops two integers or two strings, computes whether they are ordered
			from smaller to larger and push the result back on the stack. | 5 |  
	| Equal (typed)
 | 0x49 | 0 (b) | operation: i2 == i1
        or f2 == f1
        or s2 == s1 | Pops two integers, floats or strings, computes whether they are equal
			and push the result back on the stack. If a mix of types is found, then
			convertions occur. Strings may be transformed in numbers and numbers in
			strings as with the untyped Equal operator. | 5 |  
	| Number | 0x4A | 0 (n) | operation: a1.valueOf() | Pops one item and transform it into a number. For strings it works as
			expected (see the strtof(3C) manual pages). For a user defined object,
			the method named valueOf()is called. | 5 |  
	| String | 0x4B | 0 (n) | operation: a1.toString() | Pops one item and transform it into a string. For numbers it works as
			expected (see the sprintf(3C) manual pages). For a user defined object,
			the method named toString()is called. | 5 |  
	| Duplicate | 0x4C | 0 (a1 a1) | operation: a1 | Pops one item and push it back twice. | 5 |  
	| Swap | 0x4D | 0 (a1 a2)
 | operation: a2 <-> a1 | Pops two items and push them back the other way around. | 5 |  
	| Get Member | 0x4E | 0 (a) | operation: o2[a1] | Pops one string or an integer (member name), pop an object reference,
			defines the value of that object member and push the result back on the stack. | 5 |  
	| Set Member | 0x4F | 0 | operation: o3[a2] = a1 | Pops a value 'a1' which will be the new member value, then one string
			or integer 'a2' (the name of the member to modified or create),
			and finally pop an object reference 'o3'. If the member doesn't
			exists yet, create it. Finally, sets the object member to the
			value 'a1'. | 5 |  
	| Increment | 0x50 | 0 (n) | operation: n1 + 1 | Pops one number, add 1 to it and push it back on the stack. | 5 |  
	| Decrement | 0x51 | 0 (n) | operation: n1 - 1 | Pops one number, substract 1 to it and push it back on the stack. | 5 |  
	| Call Method | 0x52 | 0 (a) | operation: o2.s1(i3, [a4, a5, a6...])
or
o2(i3, [a4, a5, a6...]) | Pops the name of a method (can be the empty string), pop an object, pop the number
			of arguments, pop each argument, call the method (function) of the object, push
			the returned value on the stack. | 5 |  
	| New Method | 0x53 | 0 (o) | operation: o = new s2
           o.s1(i3, [a4, a5, a6...])
           or
           o.s2(i3, [a4, a5, a6...]) | Pops the name of a method (can be the empty string), pop an object (created with
			the Declare Object,)
			pop the number of arguments, pop each argument, create a new object, then call
			the specified method (function) as the constructor function of the object, push
			the returned value on the stack. This allows for overloaded constructors as in C++. | 5 |  
	| Instance Of | 0x54 | 0 (b) | operation: o2 is_instance_of s1 | Pops the name of a constructor (s1 - ie. "Color") then
			the name of an object (s2). Checks whether the named object is
			part of the class defined by the constructor. If so, then true
			is push on the stack, otherwise false. 
			Since SWF version 7, it is possible to cast an object to
			another using the Cast Object
			action. This action returns a copy of the object or Null,
			which in many cases can be much more practical. | 6 |  
	| Enumerate Object | 0x55 | 0 (v) | operation: o1 | Pops an object from the stack, push a null, then push the
			name of each member on the stack. | 6 |  
	| And | 0x60 | 0 (i) | operation: i2 & i1 | Pops two integers, computes the bitwise AND and push the result back on the stack. | 5 |  
	| Or | 0x61 | 0 (i) | operation: i2 | i1 | Pops two integers, computes the bitwise OR and push the result back on the stack. | 5 |  
	| XOr | 0x62 | 0 (i) | operation: i2 ^ i1 | Pops two integers, computes the bitwise XOR and push the result back on the stack. 
			This operator is also used to generate a bitwise NOT with an immediate value of -1. | 5 |  
	| Shift Left | 0x63 | 0 (i) | operation: i2 << i1 | Pops two integers, shift the 2nd one by the number of bits specified by the first integer
			and push the result back on the stack. | 5 |  
	| Shift Right | 0x64 | 0 (i) | operation: i2 >> i1 | Pops two integers, shift the 2nd signed integer by the number of bits specified by
			the first integer and push the result back on the stack. | 5 |  
	| Shift Right Unsigned | 0x65 | 0 (i) | operation: i2 >>> i1 | Pops two integers, shift the 2nd unsigned integer by the number of bits specified by
			the first integer and push the result back on the stack. | 5 |  
	| Strict Equal | 0x66 | 0 (b) | operation: a1 === a2 | Pops two parameters and return whether they are strictly
			equal. No cast is applied to either s1 or s2. Thus two
			items of different type are not equal ( 0 == "0"is true, but0 === "0"is false.) | 6 |  
	| Greater Than (typed)
 | 0x67 | 0 (b) | operation: a2 > a1 | Similar to Swap + Less Than. It checks whether the second
			parameter is greater than the first and return the boolean
			result on the stack. | 6 |  
	| String Greater Than (typed)
 | 0x68 | 0 (b) | operation: s2 > s1 | Similar to Swap + String Less Than. It checks whether the second
			string is greater than the first and return the boolean
			result on the stack. | 6 |  
	| Extends | 0x69 | 0 (o) | operation: super_class = s1
sub_class = s2
sub_class.prototype = new object
sub_class.prototype.__proto__
		= super_class.prototype;
sub_class.prototype.__constructor__
		= super_class; | The Extends action will be used to define a new object
			which extends another object. The declaration in ActionScript
			is: class A extends B;In an SWF action script, you don't exactly declare objects,
			you actually instantiate them and define their functions.
			This action creates a new object named s2 which is
			an extension of the object s1. 
			Use this action whenever you need to inherit an object
			without calling its constructor. | 7 |  
	| Goto Frame | 0x81 | 2 | unsigned short	f_frame_no; | The playback continues at the specified frame | 1 |  
	| Get URL | 0x83 | variable | string	f_url;
string	f_target; | Load the specified URL in the specified target window. 
	When the target is set as "_level0", the current SWF file is replaced
	by the file specified in the f_urlfield. The name in thef_urlfield should be a proper SWF file or the area will
	simply become black. 
	When the target is set as "_level1", something
	special is supposed to happen. I still don't know what it is...
	Also the effect of _level1 + an empty URL is ... (to remove
	level1?)
 The URL can be a javascript command when the protocol
	is set to "javascript:". For instance, you can call your function
	as follow: "javascript:MyFunction(5)". If you want to use dynamic
	values, you will need to concatenate strings and use
	Get URL2 instead.
	 
	The target can also be set to the regular HTML names such as
	"_top" or a frame name.
	 | 1 |  
	| Store Register | 0x87 | 1 (a) | unsigned char	f_register;
operation: regs[f_register] = a1 | 
	  Pop one value from the stack, push it back on the stack
	  and also store it in one of four or 256 registers which
	  number is specified in the tag (0, 1, 2 or 3 only if
	  not in a
	  Declare Function (V7).
	  I tried other numbers and they don't work in SWF version 6 or older.)
	  Until set a register has the value undefined. The value
	  of a register can be retrieved with a
	  Push Data action
	  and the register type with the matching register
	  number.
	   
	  (To be tested) It is likely that trying to read a register
	  which is not legal in a Declare Function (V7)
	  will generate an exception (Yes! A Throw!)
	  but I wouldn't be surprised if you just get undefined.
	   | 5 |  
	| Declare Dictionary | 0x88 | variable (s)
 | unsigned short	f_count;
string		f_dictionary[f_count]; | Declare an array of strings which can later be retrieved
	using the Push Data action with a
	dictionary lookup. There can be a maximum of 65534 strings. The visibility of
	a dictionary is within its DoAction or other
	similar block of actions. | 5 |  
	| Strict Mode | 0x89 | 1 | unsigned char	f_strict; | Set the strict mode (f_strict != 0) or reset the
	strict mode (f_strict == 0). | 5 |  
	| Wait For Frame | 0x8A | 3 | unsigned short	f_frame;
unsigned char	f_skip; | Wait until the frame specified in f_frame is
	fully loaded to execute actions right after this one. Otherwise skip
	the specified number of actions. This is usually used with a
	Goto Frame like in: Next Frame
Wait for Frame #10
  (otherwise skip 1 action)
Goto Frame #5
Play
End
This will usually be used to display some Loading... info
before the complete movie is loaded. | 1 |  
	| Set Target | 0x8B | variable | string	f_target; | If the string f_target is the empty string, then
			the next actions apply to the main movie. Otherwise it is the name of a
			sprite and the followings actions apply to that sprite only. | 1 |  
	| Goto Label | 0x8C | variable | string	f_label; | Go to a named frame. Frames are given names with the use of the
	FrameLabel tag. | 3 |  
	| Wait For Frame (dynamic)
 | 0x8D | 1 | unsigned char	f_skip;
operation: a1 WaitForFrame | Pop a value or a string used as the frame
	number to wait for. The frame can be specified as with the
	Goto Expression. If the
	frame was not reached yet, skip the following f_skip actions | 4 |  
	| Declare Function (V7) (with 256 registers)
 | 0x8E | variable | string		f_name;
unsigned short	f_arg_count;
unsigned char	f_reg_count;
unsigned short	f_declare_function2_reserved : 7;
unsigned short	f_preload_global : 1;
unsigned short	f_preload_parent : 1;
unsigned short	f_preload_root : 1;
unsigned short	f_suppress_super : 1;
unsigned short	f_preload_super : 1;
unsigned short	f_suppress_arguments : 1;
unsigned short	f_preload_arguments : 1;
unsigned short	f_suppress_this : 1;
unsigned short	f_preload_this : 1;
swf_params	f_params[f_arg_count];
unsigned short	f_function_length; WARNING: the preload/suppress flags are defined
	on a short and thus the bytes in a Flash file will look swapped. | Declare a function which can later be called with the
	Call Function
	action or
	Call Method action
	(when defined as a function member.) The
	f_function_length defines the number of bytes that the function
	declaration uses after the header (i.e. the size of the actions defined
	in the function). All the actions included in this block are part of
	the function body. Do not terminate a function with an End action 
	A function should terminate with a Return
	action. The value used by the return statement will be the only value
	left on the caller stack.
	 
	Functions declared with this action code byte also support the use
	of up to 255 local registers (registers 0 to 254 since the
	f_reg_count byte specifies the last register which can be
	used plus one). To access the local registers, use the
	Push Data action with a load register
	and to change a register value use the
	Store Register action.
	 
	Also, it is possible to control the preloading or suppressing of
	the different internal variables: this, arguments,
	super, _root, _parent and _global.
	All the function arguments can also be ignored. If you write a
	compiler, you should preload only the variables which are used
	in the function body. And you should suppress all the variables
	which are never being accessed in the function body [WARNING: note
	that it is possible to concatenate two strings such as "th" and
	"is" to generate the name "this" and then do a 'get that variable'.
	This means a function can't really know whether any of the internal
	variables are really never going to be used... but who writes code
	like that, really?!]. If you are writing a smart player, then you
	may want to avoid creating the variables until they are actually
	being used (thus when an if() statement ends the function prematurly,
	you may end up not creating many of these variables!).
	 
	The preloading bits indicate in which register to load the given
	internal variable. The suppressing bits indicate which internal
	variable not to create at all. That is, if the preloading bit is
	not set and the suppressing is not set, then the internal variable
	are supposed to be created by name (i.e. you can access a variable
	named "this" from within the function when bits 0 and 1 are zero).
	 
	The f_reg_count parameter needs to be specified and it tells
	the player the largest register number in use in this function.
	This way it can allocate up to 255 registers on entry. By default,
	these registers are initialized as undefined. The variables
	automatically loaded in registers are loaded starting at register 1.
	The internal variables are loaded in this order: this,
	arguments, super, _root, _parent and
	_global. Thus, if you call a function which
	accepts three user parameters and wants this and _parent,
	it will load this in register 1, _parent in register
	2 and the user parameters can be loaded in registers 3, 4 and 5.
	User parameters are loaded in registers only if their corresponding
	f_param_register field is not zero (see
	swf_params). Also, they don't need to be
	defined in order.
	 
	Note that system variables are loaded AFTER arguments. This means
	if you put an argument in register 3 and this register is also used
	for _root, then within the function the register 3 will be
	equal to the content of _root. Compilers should never do that
	though.
	 | 7 |  
	| Try | 0x8F | variable | unsigned char	f_try_reserved : 5;
unsigned char	f_catch_in_register : 1;
unsigned char	f_finally : 1;
unsigned char	f_catch : 1;
unsigned short	f_try_size;
unsigned short	f_catch_size;
unsigned short	f_finally_size;
if(f_catch_in_register == 0) {
	string		f_catch_name;
}
else {
	unsigned char	f_catch_register;
} | Declare a try/catch/finally block. 
	This has the behavior of the action script:
	 	try { ... }
	catch(name) { ... }
	finally { ... }
	At this time, there is no definition of exception in the action
	scripts. But you can write a function which
	Throws.
	 
	The sementic of the try/catch/finally block is very well defined
	in ECMA 262 version 3 (see pages 87/88).
	 
	The f_finally and f_catch may not both be null or
	the sementic of the try block would be wrong. The f_try_size,
	f_catch_size and f_finally_size are defined in bytes
	and give the size of each of the block of instructions just like
	a function definition.
	 Do not terminate these blocks with an End action 
	If the f_catch_in_register is set to 1, then a register
	number is specified instead of a variable name. This will usually
	be faster.
	 | 7 |  
	| With | 0x94 | 0 | unsigned short	f_size;
operation: with o1 | The variable references within the following f_size bytes
	are taken as names of members of the specified object 'o1'. When no member is
	available in that object, the previous With, or the corresponding global
	variable is queried.
	This is similar to the Pascal language with instruction or a
	Set Target (dynamic).
	Note that the number of With within other With is limited to 7 in version 5
	and 15 since version 6 (note that the official documentation says 8 and 16, but it seems that
	is wrong.) Additional With blocks are ignored.
	The size defines up to where the With has an effect (the f_size is taken
	as a branchment offset except that it is always positive). Note that it is to the
	creator of the action scripts to ensure the proper nesting of each With. | 5 |  
	| Push Data | 0x96 | variable | struct {
	unsigned char	f_type;
	...		f_data;
} f_push_data[<variable>];
 | Push some immediate data on the stack.
	This action was introduced in V4.0. The supported data types
	vary depending on the version of player that you have. As many
	values as necessary can be pushed at once. The f_push_data
	structure will be repeated multiple times as required. For
	instance, to push two strings on the stack at once, you would
	use the following code: 96
0C 00
00 't' 'e' 's' 't' 00
00 'm' 'o' 'r' 'e' 00 
	Please, see the
	table of data types
	below for more information. | variable |  
	| Branch Always | 0x99 | 2 | signed short	f_offset;* | Jump to the specified instruction. | 4 |  
	| Get URL2 | 0x9A | 1 | unsigned char	f_method;
operation: s1 s2 | Pop two strings, the URL (s2) and the target name (s1). All the usual HTML target names seem to be supported (_top,
	_blank, <frame name>, etc.) You can also use
	the special internal names _level0 to _level10. _level0 is
	the current movie. Other levels, I'm still not too sure how
	these can be used. Use
	f_method to tell Flash how to handle the variables (see
	table below).
	The variables of the current SWF context can be forwarded
	to the destination page using GET or POST (this means you can
	create dynamic forms with full HTML conformance).
	 It seems that in V4.x (or would it be in V6.x?!? —
	it doesn't seem
	to work in V5.x) you could use URL2 to read a text file (with
	a .txt extension) with a list of variables using something like this: Push URL "myvars.txt", Target "_level0"; Get URL2; The syntax of the file myvars.txt is lines which are defined
	as a variable name followed by an equal sign and the contents
	for that variable. If contents of a single variable is more than
	one line, start the following line(s) with an ampersand to
	continue that one variable. The URL can also start with "javascript:" in which case
	the given browser javascript language receives a call. 
	  | f_method | Action | 
|---|
 | 0 | <don't send variables> |  | 1 | GET |  | 2 | POST |  | 4 |  
	| Declare Function | 0x9B | variable | string		f_name;
unsigned short	f_arg_count;
string		f_arg_name[f_arg_count];
unsigned short	f_function_length; | Declare a function which can later be called with the
	Call Function action. The
	f_function_length defines the number of bytes that the function
	declaration takes. All the actions included in this block are part of the function.
	A function should terminate with a Return
	action. The value used by the return statement should be the only value
	left on the caller stack. Do not terminate a function with an End action Prior version 6, the Macromedia player
	would keep all the data pushed in a function as is when the function
	returned whether there is a return statement or not. Since version 7, it is preferable to use the new type of functions:
	Declare Function (V7). | 5 |  
	| Branch If True | 0x9D | 2 | signed short	f_offset;*
operation: b1 | Pop a boolean value; if true then jump to the specified instruction; otherwise
	continue with the following instructions. | 4 |  
	| Call Frame | 0x9E | 0 | nothing
(this is a bug known by Macromedia)
operation: s1 | Pop a string or integer and call the corresponding frame.
		This means: (1) search the corresponding frame, (2) execute its
		actions and (3) continue with the action defined after this one.
		The frame can be identified with a name or a number. It is also
		possible to specify a target movie ("<sprite name>.<frame name>?
		- to be tested...) | 4 |  
	| Goto Expression | 0x9F | 2 | unsigned char	f_play;
operation: a1 | Pop a value or a string and jump to the specified frame.
	 Numerical frame numbers start at 0 and go up to the number of frames - 1.
	 When a string is specified, it can include a path to a sprite as in: /Test:55When f_play is ON (1), the action is to play as soon as that frame is
	 reached. Otherwise, the frame is shown in stop mode. | 4 |  | 
 
	
	* f_offset is a relative offset to the
	instruction to execute next; the current program counter is taken as being AFTER the
	branch instruction.
	 | 
	    
	      | ID | Name | Data | Comments | Version |  
	      | 0x00 | String | string	f_string | Push a string on the stack | 4 |  
	      | 0x01 | Float (32 bits)
 | float	f_float; | Push a 32 bits IEEE floating point value on the stack.
	      This type can be used to specify a Property reference. Note that
	      the property reference will be saved as a floating point value though
	      only the integral part will be used. | 4 |  
	      | 0x02 | NULL | <none> | Push a NULL on the stack (0?). | 5 |  
	      | 0x03 | Undefined | <none> | Push an undefined object on the stack. This
	      is not a string, integer, float or boolean. It simply is an undefined
	      element. Any operation on an undefined element yields undefined
	      except an equal comparison (and some operations such as a
	      Pop). | 5 |  
	      | 0x04 | Register | unsigned char	f_register; | Push the content of the given register on the stack.
	      You have only 4 registers available in SWF (number 0, 1, 2 and 3).
	      Since version 7 of SWF, it is possible to use up to 256 registers
	      in a Declare Function (V7).
	      However, outside such a function, the limit is the same.
	      To set a register, use the Store Register
	      action. | 5 |  
	      | 0x05 | Boolean | unsigned char	f_boolean; | Push a boolean value on the stack (f_boolean
	      needs to be 0 or 1). | 5 |  
	      | 0x06 | Double (64 bits)
 | unsigned char	f_value[8]; | An IEEE double value saved in a strange way. The
	      following gives you the C code used to read these
	      double values. double	result;
char	value[8];
value[4] = ReadByte(input_stream);
value[5] = ReadByte(input_stream);
value[6] = ReadByte(input_stream);
value[7] = ReadByte(input_stream);
value[0] = ReadByte(input_stream);
value[1] = ReadByte(input_stream);
value[2] = ReadByte(input_stream);
value[3] = ReadByte(input_stream);
result = * (double *) value;
 | 5 |  
	      | 0x07 | Integer | unsigned long	f_integer; | Push an integer on the stack. | 5 |  
	      | 0x08 | Dictionary Lookup | unsigned char	f_reference; | Push a string as declared with a
	      Declare Dictionary.
	      The very first string in a dictionary has reference 0.
	      There can only be up to 256 strings push with this instruction. | 5 |  
	      | 0x09 | Large Dictionary Lookup | unsigned short	f_reference; | Push a string as declared with a
	      Declare Dictionary
	      action.
	      The very first string in a dictionary has reference 0.
	      There can be up to 65534 strings pushed this way. Note that
	      the strings 0 to 255 should use the type 0x08 instead. | 5 |  | 
 
    Properties
    
    The following is the list of currently accepted properties or fields
    for the Get Property and
    the Set Property. Note that the
    properties can be specified with either an integer (type 7,
    requires V5.0+) or a single precision floating point (type 1, V4.0 compatible).
    And since strings are automatically transformed in a value when
    required, one can use a string to represent the property number (type 0).
    It works with a double value, I even tested a boolean and null and it
    works. Obviously it isn't a good idea to use these. The default should
    be a single precision float.
    Please, see the Push Data action for
    more information about the types.
     | 
	    
	      | Float | Decimal | Name | Comments | Version |  
	      | 0x00000000 | 0 | x | the x coordinate in pixels (not TWIPs!) | 4 |  
	      | 0x3F800000 | 1 | y | the y coordinate in pixels (not TWIPs!) | 4 |  
	      | 0x40000000 | 2 | x scale | the horizontal scaling factor in percent (50 — NOT 0.5 — represents half the normal size!!!) | 4 |  
	      | 0x40400000 | 3 | y scale | the vertical scaling factor in percent (50 — NOT 0.5 — represents half the normal size!!!) | 4 |  
	      | 0x40800000 | 4 | current frame | the frame being played; one can query the root current frame using
	          an empty string ("") as the name of the object; note that the first
		  current frame is number 1 and the last is equal to the number of
		  frames; however, the goto
		  instruction expects a frame number from 0 to the number of
		  frames - 1 | 4 |  
	      | 0x40A00000 | 5 | number of frames | total number of frames in movie/sprite | 4 |  
	      | 0x40C00000 | 6 | alpha | the alpha value in percent (50 — NOT 0.5 — means half transparent) | 4 |  
	      | 0x40E00000 | 7 | visibility | whether the object is visible | 4 |  
	      | 0x41000000 | 8 | width | maximum width of the object (scales the object to that width) | 4 |  
	      | 0x41100000 | 9 | height | maximum height of the object (scales the object to that height) | 4 |  
	      | 0x41200000 | 10 | rotation | the rotation angle in degrees | 4 |  
	      | 0x41300000 | 11 | target | returns the name (full path) to an object; this can be viewed as a reference to that object | 4 |  
	      | 0x41400000 | 12 | frames loaded | the number of frames already loaded | 4 |  
	      | 0x41500000 | 13 | name | the name of an object | 4 |  
	      | 0x41600000 | 14 | drop target | object over which this object was last dropped | 4 |  
	      | 0x41700000 | 15 | url | a URL linked to that object | 4 |  
	      | 0x41800000 | 16 | high quality | whether we are in high quality mode | 4 |  
	      | 0x41880000 | 17 | show focus rectangle | whether the focus rectangle is visible | 4 |  
	      | 0x41900000 | 18 | sound buffer time | what is currently being played sound wise | 4 |  
	      | 0x41980000 | 19 | quality | what the quality is (0, 1 or 2) | 5 |  
	      | 0x41A00000 | 20 | x mouse | the current horizontal position of the mouse pointer | 5 |  
	      | 0x41A80000 | 21 | y mouse | the current vertical position of the mouse pointer | 5 |  
	      | 0x46800000 | 16384 | WTHIT | unnamed at this time; used in one case or another... well
	          it seems this is a flick and has to do with the depth of
		  sprites being duplicated | 4 |  | 
 
    Internal Functions & Constants 
    Since Flash V5.x, you can use internal functions which
    are available at all times. These are called Methods.
    These methods are called using the
    Call Function
    action with the name of the object and function separated
    by a period. A few of these internal functions are duplicates
    of some direct action script instructions.
     
    Similarly, you can acces internal constants which are also
    available at all times. These are called Properties.
    These properties are read using the
    Get Variable
    action with the name of the object and constnat separated
    by a period. This can increase the precision of some values
    such a PI and E and give you information about the system
    on which the plugin is running. These properties are usually
    read-only.
     
    The name of the objects and their functions are case insensitive.
    Thus "Math.SIN"is equivalent to"math.sin". 
    The internal functions were defined in different objects.
    The following is a list of these objects followed by a table
    for each of the function of each object. Note that a complete
    declaration is given below. Only the function or constant name
    can be used. The rest of the prototype is only here to help
    you know how to call the function or what type is the constant.
     
    Sample to compute the sine of an angle given in degree:
     	// expect the angle on the top of the stack here
	Push Data (string) "math.pi"
	Get Variable
	Multiply
	Push Data (float) 180.0
	Swap
	Divide
	Push Data (integer) 1
		  (string) "math.sin"
	Call Function
	// the result is on the top of the stack
	// i.e.:  math.sin(<input> * math.pi / 180.0);
 
    Since Version 8, Macromedia created a new website called livedocs
    which includes a complete and up to date documentation of the scripting
    language (ActionScript) and the default objects coming with
    Flash.
     
    Flash 8 LiveDocs
    
 | 
	    
	      | Color Object |  
	      | Function Prototype | Comments | Version |  
	      | Color(sprite target) | When you create a color object you need to specify the
	          target to which the color changes (or retrieval) will
		  be applied. | 5 |  
	      | integer getRGB() | Retrieve the RGB color from the color object. The color
	          format is 0xRRGGBB. | 5 |  
	      | colorTransformObject
	getTransform() | Returns a transform object representing the current color
	          transformation applied to the object. This object is
		  composed of eitght members (ra, rb, ga, gb, ba, bb,
		  aa, ab). One for each component (rgba) divided in
		  two sets: scaling factor ra, ga, etc. — a value from
		  -100 to +100; and an offset rb, gb, etc. — a value
		  from -255 to +255. | 5 |  
	      | void setRGB(integer new_color) | Changes the color of the object attached to this
	          color object. The color format is 0xRRGGBB. | 5 |  
	      | void setTransform(
	colorTransformObject
		color_transform) | Changes the colors in the transformation matrix of the
	          attached object. Please see the getTransform()for more information about the colorTransformObject. | 5 |  | 
 | 
	    
	      | Math Object |  
	      | Function Prototype | Comments | Version |  
	      | double abs(double x); | Returns the absolute value of x | 5 |  
	      | double acos(double x); | Returns the arc cosine of x | 5 |  
	      | double asin(double x); | Returns the arc sine of x | 5 |  
	      | double atan(double x); | Returns the arc tangent of x | 5 |  
	      | double atan2(double y, double x); | Returns the arc tangent of y / x | 5 |  
	      | double ceil(double x); | Returns the ceiling value of x, that is, find a value y which
	      is an integer greater than or equal to x | 5 |  
	      | double cos(double x); | Returns the cosine of x which should be a radian angle | 5 |  
	      | double exp(double x); | Returns the neperian exponential of x (e power x) | 5 |  
	      | double floor(double x); | Returns the floor value of x, that is, find a value y which
	      is an integer smaller than or equal to x | 5 |  
	      | double log(double x); | Returns the neperian logarithm of x (the value of
	      y in x = e power y) | 5 |  
	      | double max(double x, double y); | Returns x or y, whichever is the largest value | 5 |  
	      | double min(double x, double y); | Returns x or y, whichever is the smallest value | 5 |  
	      | double pow(double x, double y); | Returns x power y | 5 |  
	      | double random(); | Returns a random value which lies between 0.0 and 1.0
	      (1.0 included? — to be confirmed) | 5 |  
	      | double round(double x); | Returns the integer closest to x | 5 |  
	      | double sin(double x); | Returns the sine of x which should be a radian angle | 5 |  
	      | double sqrt(double x); | Returns the square root of x | 5 |  
	      | double tan(double x); | Returns the tangent of x which shuold be a radian angle | 5 |  
	      | Constant Definitions | Comments | Version |  
	      | double e; | Returns the value of e(about 2.7182818284590452354) | 5 |  
	      | double ln2; | Returns the value of log(2)(about 0.69314718055994530942) | 5 |  
	      | double log2e; | Returns the value of log2(e)(about 1.4426950408889634074) | 5 |  
	      | double ln10; | Returns the value of log(10)(about 2.30258509299404568402) | 5 |  
	      | double log10e; | Returns the value of log10(e)(about 0.43429448190325182765) | 5 |  
	      | double pi; | Returns the value of pi(about 3.14159265358979323846) | 5 |  
	      | double sqrt1_2; | Returns the value of sqrt(0.5)(about 0.7071067811865475244) | 5 |  
	      | double sqrt2; | Returns the value of sqrt(2)(about 1.4142135623730950488) | 5 |  | 
 
	
	NOTE: you can use a String object
	like any other string; for instance,
	to put the contents of the String object in a
	DefineEditText variable,
	you simply do:
	 	push "myTextFieldVariable", "myStringObject";
	get variable;
	set variable; 
	(assuming you saved your string in a variable named
	"myStringObject"and the name of the variable
	in the text field is"myTextFieldVariable"). 
	Most of the time, positions can be given out of bounds and the
	functions will still perform as expected as if that position was 0 or
	string.length.
	
 | 
	    
	      | String Object |  
	      | Function Prototype | Comments | Version |  
	      | string charAt(int index); | Returns a string composed of the character at the position
	      defined by the index. The first character is at position
	      0. The last character is at position string.length - 1. | 5 |  
	      | integer charCodeAt(int index); | Returns the code of the character at the position defined
	      by index. The first character is at position 0. The last character
	      is at position string.length - 1. | 5 |  
	      | string concat
  (string s1 [, string s2 [, ...]]); | Concatenate each string (this, s1, s2, etc.) in one and return the result.
	      The parameters will automatically be converted to strings if necessary. Note
	      that floating point values will usually be written with great precision
	      (i.e. 0.33will appear as0.33000001311302) | 5 |  
	      | string fromCharCode
  (int c1 [, int c2 [, ...]]); | WARNING: I tried to make this function work, it only
	      returns an empty string. If you can make sense of it, please let me know
	      how you're using it! (this is with a V5.x plug in) 
	      Create a string composed of each of the specified characters (c1, c2, etc.).
	      Each value must represent a valid 16-bit character code (1 to 65535). | 5 |  
	      | int indexOf(string s [, int start]); | Returns the first index at which s is found within the string
	      object. When start is specified, the search begins at that
	      position (inclusive) instead of the first character (by default start
	      is assumed to be zero). If s isn't found,
	      -1 is returned instead of a valid position. The first character is
	      at position 0 and the last at string.length - 1. | 5 |  
	      | int lastIndexOf
  (string s [, int start]); | Returns the last index at which s is found within the
	      string object. When start is specified, the search begins
	      at that position (inclusive) instead of the last character. Watch
	      out, the search goes backward thus the start is actually the
	      last character of this string which is tested.
	      If s isn't found, -1 is returned instead of a position. | 5 |  
	      | string slice(int start [, int end]); | Returns a string composed of the characters of this string
	      starting at the position start and ending at position end - 1
	      inclusive. When the end parameter isn't specified, it
	      is automatically given the position of the last character.
	      It is possible to use negative values for both parameters.
	      Negative values give a position from the last character of
	      the string rather than the first. -1 represents the last character
	      of the string, -2 the one before the last, etc. 
	      When the resulting start position is larger or equal to the
	      end position, then an empty string is returned. The following
	      gives you the equation to test whether the start and
	      end parameter are valid or if an empty string should be
	      returned.
	       if((start < 0 ? start + string.length
              : start)
>= (end   < 0 ? end + string.length
              : end)) {
    return "";
}
/* else compute the result */(See thesubstrfor a function used with a position
	      and length instead of two positions) | 5 |  
	      | array split([string delimiter]); | Returns the string split in an array of strings. The delimiter
	      determines where the string will be cut (the delimiters are removed
	      from the source string). When no or an empty delimiter is specified,
	      the string as a whole is saved in the array as the 1st item.
	      Otherwise, the delimiter is searched and each instance represents
	      a string separation. 
	      NOTE:
	      An empty string delimiter supposedly means that each character of the
	      input string is saved in the array as strings (See the Macromedia website
	      fromCharCode).
	      I tried and it looks like the empty string or no delimiter cases are
	      both working alike as described above. | 5 |  
	      | string substr
  (int start [, int length]); | Returns a string composed of the characters of this string
	      starting at the position start and ending at position start
	      + length - 1 inclusive. When the length parameter isn't
	      specified, it is automatically given the necessary value so the end
	      of the string is fully included. It is possible to use negative
	      values for the start parameter in which case it references
	      a position starting at the end of the string. The position -1
	      represents the last character of the string. If length is
	      small or equal to zero ( length <= 0) then
	      an empty string is returned. (See theslicefor a function used with two positions instead of a position and
	      length and thesubstringmethod for out of order
	      indices). | 5 |  
	      | string substring
  (int p1 [, int p2]); | Returns a string composed of the characters of this string
	      starting at the position start and ending at position end - 1
	      inclusive. This function doesn't support negative positions. The start
	      and end positions are defined as: cp1 = p1 < 0 ? 0 : p1;
cp2 = p2 < 0 ? 0 : p2;
start = cp1 < cp2 ? cp1 : cp2
end = cp2 > cp1 ? cp2 : cp1(See also the sliceandsubstrmethods). | 5 |  
	      | string toLowerCase(); | Returns a string which is like the input string except for all
	      uppercase characters are first swapped for their corresponding
	      lowercase characters. | 5 |  
	      | string toUpperCase(); | Returns a string which is like the input string except for all
	      lowercase characters are first swapped for their corresponding
	      uppercase characters. | 5 |  
	      | Constant Definitions | Comments | Version |  
	      | int length; | Returns the length of the string in characters. | 5 |  | 
 
   
    
    DoABC (V9.0*)
    DoABCDefine (V9.0*)
 
  *the version specified here is the version in
  which the tags appeared—however, actions of higher versions can be used with
  older version tags and thus this version doesn't indicate the version of all the
  actions used in this tag
   
  The DoABC and DoABCDefine are
  available since version 9. These are similar to the old DoAction and
  DoInitAction, yet the actions use a different declarations and they
  can include an identifier and a name. This new scheme help greatly in simplifying
  the definitions of ECMAScript classes.
   
  Note that the f_allow_abc bit of the
  FileAttributes flags must be set
  for the ABC actions to work at all.
   
  The following describes the data in the DoABC and DoABCDefine tags:
   	struct swf_doaction3 {
		swf_tag			f_tag;		/* 72 or 82 */
		if(f_tag == DoAction3Define) {
			unsigned long	f_action_flags;
			string		f_action_name;
		}
		swf_action3		f_action_record[variable];
	};
  The f_action_flags must be set to 1 for now (maybe 0 is also valid?
  For sure 1 is the default.)
   
  The f_action_name represents the name of this action script in
  case of a DoAction3Define. It represents the name of a class when the
  DoAction3Instantiate tag is used.
   
  The f_action_record is a buffer of action script version 3. It is
  different from the DoAction action script and is called the ABC script.
   
  At this time, the swf_action3 is
  documented in the abcFormat.html file.
   
    
    End (V1.0)
     
  The End tag marks the end of a sequence of tags. It is
  used to end the whole movie and to end the sequence of tags in
  a DefineSprite.
  The tag is composed just of the tag id.
   	struct swf_export {
		swf_tag			f_tag;		/* 0 */
	};
 
    
    Export (V5.0)
     
  The Export tag works in conjunction with the
  Import
  and Import2
  tags. The Export tag gives a list of definitions
  made visible to the external world. Thus these definitions are in
  effect available to be imported by other movies.
   
  The Export tag is a list of identifiers which are the
  identifiers of the objects defined within this movie and gives an external
  name to that object. The name is the external reference and that's what the
  Player will use to know how to retrieve the data from another movie. Each
  name need to be different, however there is no other restriction.
   
  There should be only one Export per SWF movie. It
  is not clearly defined anywhere, but it is likely that the player will stop
  at the first export they find and not try to see if other
  Exports are defined in your SWF movies. It is not
  clear whether a movie using Export can itself
  Import other movies yet it is likely.
   	struct swf_export {
		swf_tag			f_tag;		/* 56 */
		unsigned short		f_count;
		swf_external		f_symbol[<count>];
	};
  You should at least have one external reference (i.e. f_count > 0).
   
  The identifiers defined in this list must match an object in the movie which
  includes this tag.
   
    
    FileAttributes (V8.0)
     
    The FileAttributes tag is new to version 8. It must be
    present in all version 8 movies. It must be the very first tag in the SWF movie.
    It should be unique.
     	struct swf_fileattributes {
		swf_tag			f_tag;		/* 69 */
		unsigned		f_reserved : 3;
		unsigned		f_has_metadata : 1;
		unsigned		f_allow_abc : 1;	/* since V9.0 */
		unsigned		f_suppress_cross_domain_caching : 1;	/* since V9.0 */
		unsigned		f_swf_relative_urls : 1;	/* since V9.0 */
		unsigned		f_use_network : 1;
		unsigned		f_reserved : 24;
	};
  The f_has_metadata flag shall be set to 1 whenever the movie
  includes a Metadata tag.
   
  The f_allow_abc flag shall be set to 1 to give the
  player the right to execute
  DoABC scripts
  (this is a version 9 flag, in version 8, keep it set to 0.)
   
  The f_suppress_cross_domain_caching must have some effect
  over the chaching of some things... (version 9+)
   
  The f_swf_relative_urls means that URLs specified in the
  movie are relative to the URL where the movie was loaded from.
  (version 9+)
   
  The f_use_network flag needs to be set to 1 in order for the
  movie to be given the right to access the network. By default, a
  local movie will be allowed to load other local movies but nothing
  from the network.
   
    
    FrameLabel (V3.0)
     
  The FrameLabel tag gives a textual name to a frame. This name can also
  be used as an anchor in V6.x+ and whenever specified in this way.
   	struct swf_framelabel {
		swf_tag			f_tag;		/* 43 */
		string			f_label;
		if(version >= 6) {
			/* optional field */
			unsigned short	f_flags;
		}
	};
  At this time, the optional field f_flags must be set to 1 if present. This
  means it has to be used as an anchor when the URL to the SWF movie includes a
  #<frame label>at the end. 
  The f_label is a null terminated string.
   
    
    JPEGTables (V1.0)
     
  The JPEGTables tag is used to define the encoding
  tables of the JPEG images defined using the
  DefineBitsJPEG tag.
   
  There can be only one JPEGTables tag in a valid SWF file.
  And it should be defined before the DefineBitsJPEG tag.
   
  The content of this tag is the JPEG encoding tables defined by the 0xFF 0xDB
  and 0xFF 0xC4 tags.
  The f_encoding_tables buffed must start with 0xFF 0xD8 (SOI) and end
  with 0xFF 0xD9 (EOI).
   
  Note that the player of SWF better enforces the correctness of this tag
  since version 8.
   	struct swf_jpegtables {
		swf_tag			f_tag;		/* 8 */
		unsigned char		f_encoding_tables[<variable size>];
	};
 
    
    Import (V5.0)
    Import2 (V8.0)
 
    WARNING: in a Version 8 movie you MUST use an Import2 tag instead of Import
    or it just will not work (Import tags are ignored
    in version 8 movies).
     
    The Import tag works in conjunction with the Export
    tag. The Import tag gives the name of another movie and a list of
    external names as defined for export in that other movie. There is also a
    list of identifiers which represent the identifier the object(s) will have
    in this movie (the movie with the Import tag) and they don't need
    to match the source movie identifiers.
     
    The list of identifiers given in the list of the Import tag must be unique
    within the entire movie. The names are only used to match the names present in
    the Export tag of the other movie. Thus, these can be duplicates of
    named sprite in this movie.
     
    There should be only one Import per referenced movie (it would be a waste
    to have more). It is not clear whether a movie can Export definitions
    when it itself Import definitions. Also, it isn't clear what happens if
    such an external reference fails (I assume the corresponding objects are defined
    as being empty shapes).
     	struct swf_import {
		swf_tag			f_tag;		/* 57 or 71  */
		string			f_url;
		if(version >= 8) {
			unsigned char		f_version;	/* must be set to 1 */
			unsigned char		f_reserved;
		}
		unsigned short		f_count;
		swf_external		f_symbol[f_count];
	};
    You should at least have one external reference (i.e. f_count > 0).
     
    The f_url parameter is a standard URL which names the object to be loaded
    and searched for an Export tag.
     
    The identifiers defined in this tag must be unique within the entire movie.
     
    Since SWF version 8, we are forced to use TagImport2
    (since TagImport is ignored since that version.)
    It includes two extra bytes: the first one must be set to 1 and the second
    to 0. Macromedia termed both bytes Reserved. I put f_version
    in the first one so that way it makes more sense to set a 1 in there. We
    certainly will learn later what that bit is for.
     
    
    Metadata (V8.0)
     
    The Metadata tag is used to describe the SWF movie
    in a robot readable form. It will be used by search engines to index
    your Flash movies.
     	struct swf_metadata {
		swf_tag			f_tag;		/* 77 */
		string			f_metadata;
	};
    The f_metadata string is an XML buffer defined using the
    RDF definition compliant with the XMP specification. You can find
    more information on the W3C and
    other websites:
     
    RDF Primer
    RDF Specification
 XMP home page
 Dublin Core
 
    Note that this description can describe everything, from
    the entire movie to each single line of code in your action
    scripts.
     
    The string must be UTF-8 encoded.
     
    
    ProductInfo (V3.0)
     
    The ProductInfo tag stores information about the
    tool used to generate the Flash animation. This is ignored by flash
    players (unless it knows of problems in the generators...)
     	struct swf_metadata {
		swf_tag			f_tag;		/* 41 */
		long			f_product_id;
		long			f_edition;
		unsigned char		f_major_version;
		unsigned char		f_minor_version;
		long long		f_build_number;
		long long		f_compilation_date;
	};
    The f_product_id is expected to be a unique identifier for all
    the products which can possibly generate an SWF output file.
     
    The f_edition represents an edition of the generator. For instance,
    you may have a free version, and three commercial versions (Standard, Pro
    and Deluxe) which all should have a different edition number. Yet, the
    product is the same.
     
    The f_major_version and f_minor_version are used to define
    the generator version used to create the SWF animation. Note that these
    numbers are limited to a value between 0 and 255.
     
    The f_build_number is usually a MS-Windows build number. This does
    not really apply to Unix versions. Under Unix, one can use this number to
    extend the version to additional digits (i.e. SSWF saves 1.8.1 in the
    build number.)
     
    The f_compilation_date represents the date and time when the
    generator was compiled (not the time when the output movie is generated!)
     
    
    Protect (V2.0)
    ProtectDebug (V5.0 only)
 ProtectDebug2 (V6.0)
 
  The protection tag is totally useless. The SWF format is an open
  format, otherwise how would you have so many players and tools to
  work with SWF movies? Thus, you can pretend to protect your movies,
  but anyone with a simple binary editor can transform the tag and
  make it another which has no such effect. Also, swf_dump and
  some other tools (such as flasm)
  can read your movie anyway.
   
  For the sake of defining what you have in each tag, there are the
  protection tags fully described.
   	struct swf_protect {
		swf_tag			f_tag;		/* 24, 58 or 64  */
		if(version >= 5) {
			if(tag == ProtectDebug2) {
				unsigned short	f_reserved;(1)
			}
			/* the password is optional when tag == Protect */
			string		f_md5_password;
		}
	};
  | (1) | The f_reserved must be set to zero. |  
  According to Macromedia, you can find some free implementation of the MD5
  algorithm by Poul-Henning Kamp in FreeBSD in the file
  src/lib/libcrypt/crypt-md5.c. 
    
    PlaceObject (V1.0)
     
  This tag will be used to specify where and how to place an object
  in the next frame. The PlaceObject2
  and PlaceObject3 tags
  are much different and is presented below.
   
  The f_depth field is used to indicate at which depth the character is
  inserted in the current frame. There can be any number of object per depth value,
  however, the players may or may not properly redraw them. Usually the last added
  item in a given depth is drawn behind the previously added objects. Placing one
  object per depth is safer so you can be sure of the drawing order.
   
  The f_objec_id_ref is a reference to an object previously defined with one
  of the Define... tags.
   	struct swf_placeobject {
		swf_tag			f_tag;		/* 4 */
		unsigned short		f_objec_id_ref;
		unsigned short		f_depth;
		swf_matrix		f_matrix;
		if(f_tag_data_real_size is large enough) {(1)
			swf_color_transform	f_color_transform;
		}
	};
  | (1) | The f_color_transform is an optional field. The size of the tag data
  determines whether it was saved or not. |  
    
    PlaceObject2 (V3.0)
    PlaceObject3 (V8.0)
 
  This tag will be used to specify where and how to place an object
  in the next frame. The PlaceObject
  is much different and is presented separately.
   	struct swf_placeobject2 {	/* and swf_placeobject3 */
		swf_tag			f_tag;		/* 26 or 70 */
		/* NOTE: the following flags can be read as one or two bytes also */
		if(version >= 8) {
			unsigned	f_place_reserved : 5;
			unsigned	f_place_bitmap_caching : 1;
			unsigned	f_place_blend_mode : 1;
			unsigned	f_place_filters : 1;
		}
		if(version >= 5) {
			unsigned	f_place_has_actions : 1;
		}
		else {
			unsigned	f_place_reserved : 1;
		}
		unsigned		f_place_has_clipping_depth : 1;
		unsigned		f_place_has_name : 1;
		unsigned		f_place_has_morph_position : 1;
		unsigned		f_place_has_color_transform : 1;
		unsigned		f_place_has_matrix : 1;
		unsigned		f_place_has_id_ref : 1;
		unsigned		f_place_has_move : 1;
		unsigned short		f_depth;
		if(f_place_has_id_ref) {
			unsigned short		f_object_id_ref;
		}
		if(f_place_has_matrix) {
			swf_matrix		f_matrix;
		}
		if(f_place_has_color_transform) {
			swf_color_transform	f_color_transform;
		}
		if(f_place_has_morph_position) {
			unsigned short		f_morph_position;
		}
		if(f_place_has_name) {
			string			f_name;
		}
		if(f_place_has_clipping_depth) {
			unsigned short		f_clipping_depth;
		}
		/* 3 next entries since v8.0 */
		if(f_place_filters) {
			unsigned char		f_filter_count;
			swf_any_filter		f_filter;
		}
		if(f_place_blend_mode) {
			unsigned char		f_blend_mode;
		}
		if(f_place_bitmap_caching) {
			/* WARNING: this is not defined in the Macromedia documentation
			 * it may be that it was part of the blend mode whenever the person
			 * who defined this byte was testing (I copied that from somewhere else!).
			 */
			unsigned char		f_bitmap_caching;
		}
		/* since v5.0 */
		if(f_place_has_actions) {
			unsigned short		f_reserved;
			if(version >= 6) {
				unsigned long	f_all_flags;
			}
			else {
				unsigned short	f_all_flags;
			}
			swf_event		f_event[<variable>];
			if(version >= 6) {
				unsigned long	f_end;	/* always zero */
			}
			else {
				unsigned short	f_end;	/* always zero */
			}
		}
	};
  The f_depth field is used to indicate at which depth the character is
  inserted in the current frame. There can be only one object per depth value
  (thus a maximum of 65536 objects can appear on a single frame).
   
  If both f_place_has_move and f_place_has_id_ref are zero, the character is
  removed from the screen (same as
  RemoveObject2).
   
  The f_morph_position will only be used when the place object references a
  DefineMorphShape object. It defines
  a linear position between the first and second shapes
  (0 - draws shape 1 and 65535 - draws shape 2).
   
  The f_clipping_depth parameter is used to tell the player to use
  the linked shape 
  (DefineShape)
  or text (DefineText)
  as a mask for all the objects inserted in the display list from
  f_depth to f_clipping_depth inclusive. The mask itself
  isn't draw in the screen.
  For instance, you could create a sprite which draws a burning fire. To
  place this fire in a text, insert the text with this clipping feature
  with a depth, say, of 7 and clipping depth of 8 and place the fire at
  a depth of 8 (note that to have an animation, the fire will certainly
  be a sprite). The fire will only appear in the text letters.
  Obviously this is somewhat limited since the f_clipping_depth
  is hard coded and not a range (Macromedia should have used depth + clip
  like in SSWF instead). Note that it doesn't seem to work with
  duplicated sprites even if these are placed at the right depth.
   
  
    
      | NOTE: |  
      | 
	At this time I checked and I can tell that the following objects
	will work for clipping purposes:
	 
	  DefineShapeDefineShape2DefineShape3DefineText(note that the alpha channel of a DefineShape3 is not taken in
		account.) 
	and the following will not work:
	 
	  DefineSpriteDefineEditTextDefineButton 
	The following need to be checked, I also added a comment telling
	whether I think it has a chance to work:
	 
	  DefineButton2 (very unlikely) |  
  The f_blend_mode parameter is one byte which is included only
  when f_place_blend_mode is set to 1. The possible values are
  as defined in the following table. The equations use R as Result, C
  as the object color component, B and the background color. All
  components are viewed as values from 0 to 255. The result is a
  temporary value which is later saved in the new background before
  processing the next object.
   
  Values not shown in the following table are reserved for future blending
  modes.
   
  
    
      | Name | Value | Comment | Version |  
      | Normal | 0 or 1 | Copy the object as is. 
 R = C
 | 8 |  
      | Layer | 2 | Uses multiple objects to render (?) | 8 |  
      | Multiply | 3 | Multiply the background with the object colors. 
 R = B × C / 255
 | 8 |  
      | Screen | 4 | Multiply the inverse colors of the background and the object. 
 R = (255 - B) × (255 - C) / 255
 | 8 |  
      | Lighten | 5 | Take the largest of each component of the background and object. 
 R = max(B, C)
 | 8 |  
      | Darken | 6 | Take the smallest of each component of the background and object. 
 R = min(B, C)
 | 8 |  
      | Difference | 7 | Defines the absolute value of the difference. 
 R = | B - C |
 | 8 |  
      | Add | 8 | Add the components and clamp at 255. 
 R = min(B + C, 255)
 | 8 |  
      | Subtract | 9 | Subtract the components and clamp at 0. 
 R = max(B - C, 0)
 | 8 |  
      | Invert | 10 | Inverse the background components 
 R = 255 - B
 | 8 |  
      | Alpha | 11 | Copy the alpha channel of the object in the background.
	This mode requires that the parent (background) be set to
	mode Layer. 
 Ra = Ca
 | 8 |  
      | Erase | 12 | Copy the inverse of the alpha channel of the object in the
	background alpha. This mode requires that the parent
	(background) be set to mode Layer. 
 Ra = 255 - Ca
 | 8 |  
      | Overlay | 13 | Apply the same effect as multiply or screen
	depending on the background color before the operation.
	(Note: the comparison with
	128 could be <= and the results would be same for C but
	not B. I current do not know which one is picked) 
 R = (B < 128 ? B × C : (255 - B) × (255 - C)) / 255
 | 8 |  
      | HardLight | 14 | Apply the same effect as multiply or screen
	depending on the object color. (Note: the comparison with
	128 could be <= and the results would be same for C but
	not B. I current do not know which one is picked) 
 R = (C < 128 ? B × C : (255 - B) × (255 - C)) / 255
 | 8 |  
  The f_bitmap_caching seems to be one byte. It is present only when the
  f_place_bitmap_caching is set to 1. At this time, I do not know
  the exact definition and it could be that it does not exist (the Macromedia
  reference does not include it.) I will need to test this byte to see whether
  it is a mistake in the Macromedia documentation or from the person who thought
  adding the Bitmap Caching flag was also a reason to add one byte in the structure.
   
    
    RemoveObject (V1.0)
    RemoveObject2 (V3.0)
 
  Remove the specified object from the display list. If the same object was
  placed multiple times at the specified depth, only the last copy is removed.
  When only a depth is specified, the last object placed at that depth is removed
  from the list. Note that in V3.0 it is possible to use the
  PlaceObject2 in order to replace an object at a
  given depth without having to remove it first.
   	struct swf_removeobject {
		swf_tag			f_tag;		/* 5 or 28 */
		if(f_tag == RemoveObject) {
			unsigned short		f_object_id_ref;
		}
		unsigned short		f_depth;
	};
 
    
    ScriptLimits (V7.0)
     
  This tag is used to change the default limits for script execution.
   	struct swf_scriptlimits {
		swf_tag			f_tag;		/* 65 */
		unsigned short		f_max_recursion_depth;
		unsigned short		f_timeout_seconds;
	};
  The maximum recursion depth is 256 by default. Any value, except zero (0)
  is valid.
   
  The f_timeout_seconds parameter specifies the number of seconds
  before the players opens a dialog box saying that the SWF animation is stuck.
   
  This can be very useful if you have some heavy initialization which takes
  more resources than a few seconds (~15 seconds by default), and/or has
  a lot of recusivity (or just calls? to be tested...). You can then set
  large limits for the initialization to run fine, and then put some much
  lower limits afterward so as to ensure that the other scripts don't use
  too much resources.
   
    
    SetBackgroundColor (V1.0)
     
  This tag is used to specify the background color. It should always
  be included at the start of every .swf file. Only an RGB color can
  be used (i.e. there is no way to have a transparent SWF animation
  with Flash at this time - it seems)
   	struct swf_setbackgroundcolor {
		swf_tag			f_tag;		/* 9 */
		swf_rgb			f_rgb;
	};
 
    
    SetTabIndex (V7.0)
     
  This tag defines the tab index of any text object (static and
  dynamic text objects.)
   	struct swf_settabindex {
		swf_tag			f_tag;		/* 66 */
		unsigned short		f_depth;
		unsigned short		f_tab_index;
	};
  The depth references the object which is assigned the tab index.
  The tab index defines the order in which objects are sorted to know
  where to go next when the tab key is pressed.
   
    
    ShowFrame (V1.0)
     
  This empty tag signals to the player to display the current frame. The
  player will then fall asleep until it is time to draw the next frame
  (well... actually, it should prepare the next frame and then sleep
  if necessary).
   	struct swf_showframe {
		swf_tag			f_tag;		/* 1 */
	};
 
    
    SoundStreamBlock (V2.0)
     
  The SoundStreamBlock tag defines the data of a sound effect
  previously defined with a SoundStreamHead
  or a SoundStreamHead2
  tag.
   
  WARNING: This tag requires you to save
  the swf_tag in long format (i.e. f_tag_and_size & 0x3F == 0x3F even
  if the size is smaller.)
   	struct swf_soundstreamblock {
		swf_tag			f_tag;		/* 19 */
		unsigned char		f_sound_data[variable size];
	};
  The data depends on the SoundStreamHead[2] definition and is
  variable in size. Please, see the DefineSound
  tag for more information about sound data.
   
    
    SoundStreamHead (V2.0)
    SoundStreamHead2 (V3.0)
 
  The SoundStreamHead[2] tag defines a sound effect which is to be
  loaded with a set of SoundStreamBlock
  tags. It defines the sound once and for all.
   
  Streaming sound has a strong side effect when playing a movie: it will
  force a synchronization between the images and the audio. Thus some images
  may be dropped if the drawing isn't fast enough.
   
  Streaming sound effects should be either used in the main movie or
  in a sprite which needs a sound track properly synchronized to the
  sprite animation. Otherwise, it is much better to use the
  DefineSound and
  StartSound tags.
   
  It seems (though it isn't documented) that using a SoundStreamHead
  tag by itself (without any sound blocks) is taken as a hint of how to
  play all the other sounds in an animation (see the f_playback_rate)
   
  Important note: there can be only one streaming sound per movie
  clip including the main movie. If you need multiple sound effects
  or music to be played back, these will have to be merged at the
  time you create the movie in a single sound which will then be
  played back as a simple sound effect.
   	struct swf_soundstreamhead {
		swf_tag			f_tag;		/* 18 or 45 */
		unsigned		f_compression : 4;
		unsigned		f_sound_rate : 2;
		unsigned		f_sound_size : 1;
		unsigned		f_sound_stereo : 1;
		unsigned		f_reserved : 4;
		unsigned		f_playback_rate : 2;
		unsigned		f_playback_size : 1;
		unsigned		f_playback_stereo : 1;
		unsigned short		f_sample_size;
		if(f_compression == 2) {
			signed short	f_latency_seek;
		}
	};
  Some of the fields in the SoundStreamHead tag can't have
  all the possible values when defined in an older version of SWF.
  What follows describes each field in more details.
   
  The f_playback_rate and f_sound_rate define the
  rate at which the data should be played and the exact rate of
  the data found in the SWF file.
   	rate = 5512.5 * 2 ** f_playback_rate
	rate = 5512.5 * 2 ** f_sound_rate 
  The f_playback_size and f_sound_size define the
  number of bits found in the data (0 for 8 bits and 1 for 16 bits.)
  Note that with a SoundStreamHead tag (18) only 16 bits
  data are allowed (both are always set to 1). If the compression
  mode isn't Raw or Uncompressed then the f_sound_size must
  be set to 1.
   
  The f_playback_stereo and f_sound_stereo define
  whether the sound should be played on both speakers and whether
  the data includes both channels.
   
  The f_compression entry defines the compression mode.
  The list of sound compression modes
  can be found with the DefineSound tag.
  Note that with a SoundStreamHead tag (18) only the ADPCM
  compression is accepted. All the compression modes are accepted in
  a SoundStreamHead2 tag (45).
   
  The f_sample_size represents the average number of samples
  per frame. It is used to ensure a proper synchronization. Note that
  there can be more (and even less in MP3) samples within a given
  frame.
   
  The f_latency_seek is usually zero. It exists only
  when the MP3 compression mode is used. It defines the number of
  samples to skip at the beginning of the very first frame (I'm not
  totally sure what this is to tell you the truth... I'll tell you
  more once I know more).
   
    
    SymbolClass (V9.0)
     
    The SymbolClass tag is used to instantiate objects from action script
    version 3 definitions (see DoABCDefine.
    You can instantiate each object only once with this technique.
     	struct swf_symbolclass {
		swf_tag			f_tag;		/* 76 */
		unsigned short		f_symbol_count;
		struct {
			unsigned short		f_symbol_id;
			string			f_symbol_name;
		} f_symbol_references[f_symbol_count];
	};
    The f_symbol_id references an ActionScript version 3 object and
    the f_symbol_name references the class to instantiate.
     
    When f_symbol_id is set to zero, this tag becomes a special case
    and uses the f_symbol_name as the name of the top level class
    (root?)
     
    
    VideoFrame (V6.0)
     
  The VideoFrame tag is used to render one frame. It includes the
  data of the video to be drawn.
   	struct swf_startsound {
		swf_tag			f_tag;		/* 61 */
		unsigned short		f_video_id_ref;
		unsigned short		f_frame;
		unsigned char		f_video_data[variable size];
	};
  The f_object_id_ref parameter is a reference to a
  DefineVideoStream.
   
  The f_frame parameter defines which frame needs to be rendered.
   
  The f_video_data content depends on the codec defined in
  the DefineVideoStream tag. Once I really know what that
  data is, I will update this documentation. Note that the
  Sorenson H.263 encoding is actually a subset of MPEG-2.
  
 
 Common Structures
  swf_tag
  
  The tag and size are saved in a 16 bits unsigned integer. The is
  always aligned to a byte. The size is defined in the lower 6 bits.
  And the short value is in a little endian format as expected by
  the declaration. If the size is 63 (0x3F), then another 4 bytes
  are read for the size. This is used for really large tags such
  as fonts with many characters.
   
  WARNING: Some tags require you to save
  them in long format (i.e. f_tag_and_size & 0x3F == 0x3F even
  if the size is smaller.) These are:
   	struct swf_tag {
		unsigned short		f_tag_and_size;
		f_tag = f_tag_and_size >> 6;
		f_tag_data_size = f_tag_and_size & 0x3F;
		if(f_tag_data_size == 63) {
			unsigned long	f_tag_data_real_size;
		}
		else {
			f_tag_data_real_size = f_tag_data_size;
		}
	};
swf_rgb	struct swf_rgb {
		unsigned char		f_red;
		unsigned char		f_green;
		unsigned char		f_blue;
	};
swf_xrgb	struct swf_xrgb {
		unsigned char		f_pad;
		unsigned char		f_red;
		unsigned char		f_green;
		unsigned char		f_blue;
	};
  Images without an alpha channel which are saved using 32 bits (format 5)
  use XRGB colors.
  swf_rgba 	struct swf_rgba {
		unsigned char		f_red;
		unsigned char		f_green;
		unsigned char		f_blue;
		unsigned char		f_alpha;
	};
swf_argb	struct swf_argb {
		unsigned char		f_alpha;
		unsigned char		f_red;
		unsigned char		f_green;
		unsigned char		f_blue;
	};
  Images using an alpha channel and 32 bits (format 5) will use ARGB
  instead of RGBA.
  swf_rect 
  The rectangles are very well compressed in an SWF file. These
  make use of a 5 bits size which specifies how many bits are
  present in the following four fields. Don't forget that the
  bits are read from the MSB to the LSB and in big endian like
  when multiple bytes are necessary.
   	struct swf_rect {
		char align;
		unsigned		f_size : 5;
		signed twips		f_x_min : f_size;
		signed twips		f_x_max : f_size;
		signed twips		f_y_min : f_size;
		signed twips		f_y_max : f_size;
	};
swf_kerning
  The following table defines the number of TWIPs to move left or right
  before to draw the 2nd character when the 1st one was drawn right
  before it. For instance, the letters AV may be drawn really close so
  the V is written over the A. To the contrary, WI may be seperated some
  more so the I doesn't get merged to the top of the W.
   
  The computation to move the drawing pen is done as follow:
     /* writing 'AV' */
  x += f_font2_advance['A'] + f_kerning['AV'].f_kerning_adjustment;
where 'x' is the position at which f_kerning_code1 was draw. 
    
 Fig 1. Kerning "AV" and "WI"
 	struct swf_kerning {
		if(f_font2_wide) {
			unsigned short		f_kerning_code1;
			unsigned short		f_kerning_code2;
		}
		else {
			unsigned char		f_kerning_code1;
			unsigned char		f_kerning_code2;
		}
		signed short		f_kerning_adjustment;
	};
swf_shape
  Fonts uses this declaration which doesn't include any style (fill or line)
  definitions. The drawing will use fill 0 when the inside of the shape shouldn't
  be drawn and 1 when it is to be filled. The line style shouldn't be used.
   	struct swf_shape {
		swf_styles_count	f_styles_count;
		swf_shape_record	f_shape_records[variable];
	};
swf_morph_shape_with_style
  The array of shape records starts with a set of styles definition and then
  is followed by shape records which is null terminated.
   	struct swf_morph_shape_with_style {
		swf_styles		f_styles;
		swf_shape_record	f_shape_records[variable];
		char align;
		swf_styles_count	f_styles_count;
		swf_shape_record	f_shape_records_morph[variable];
	};
  Note that f_shape_records_morph can't include any reference to styles and
  lines, nor include new styles. It is likely that the f_styles_count will
  always be 0x11. Also, it is always byte aligned.
  swf_shape_with_style 
  The array of shape records starts with a set of styles definition and then
  is followed by shape records which is null terminated.
   	struct swf_shape_with_style {
		swf_styles		f_styles;
		swf_shape_record	f_shape_records[variable];
	};
swf_shape_record
  The shape records are typed. Depending on that type, the contents vary. The
  following defines one structure for each type. The shape record is a union of
  these structures.
   
  It is important to note that the f_shape_move_x and f_shape_move_y are not
  deltas from the current point, but a position from the current shape origin.
  All the other positions are defined as deltas from the previous position,
  including the anchors which are deltas from the control point position!
   
  The control point defines how much the curve is curved. Please, see
  The geometry in SWF for more
  information.
   	/* if f_shape_record_type = 0 & f_end_of_shape = 0
	  then that's the end of the list of shape records */
	struct swf_shape_record_end {
		unsigned		f_shape_record_type : 1;
		unsigned		f_end_of_shape : 5;
	};
	/* f_shape_record_type = 0 & at least one of the following five bits is not zero
	  then change style, fill and position setup */
	struct swf_shape_record_setup {
		unsigned		f_shape_record_type : 1;
		if(f_tag == DefineShape) {(1)
			unsigned	f_shape_reserved : 1;		/* always zero */
		}
		else {
			unsigned	f_shape_has_new_styles : 1;
		}
		unsigned		f_shape_has_line_style : 1;
		unsigned		f_shape_has_fill_style1 : 1;
		unsigned		f_shape_has_fill_style0 : 1;
		unsigned		f_shape_has_move_to : 1;
		if(f_shape_has_move_to) {
			unsigned	f_shape_move_size : 5;
			signed twips	f_shape_move_x : f_shape_move_size;
			signed twips	f_shape_move_y : f_shape_move_size;
		}
		if(f_shape_has_fill_style0) {
			unsigned	f_shape_fill_style0 : f_fill_bits_count;
		}
		if(f_shape_has_fill_style1) {
			unsigned	f_shape_fill_style1 : f_fill_bits_count;
		}
		if(f_shape_has_line_style) {
			unsigned	f_shape_line_style : f_line_bits_count;
		}
		if(f_shape_has_new_styles) {
			swf_styles	f_styles;
		}
	};
	/* f_shape_record_type = 1 -- edge record */
	struct swf_shape_record_edge {
		unsigned		f_shape_record_type : 1;
		unsigned		f_shape_edge_type : 1;
		unsigned		f_shape_coord_size : 4;
		f_shape_coord_real_size = f_shape_coord_size + 2;
		if(f_shape_edge_type == 0) {
			signed twips	f_shape_control_delta_x : f_shape_coord_real_size;
			signed twips	f_shape_control_delta_y : f_shape_coord_real_size;
			signed twips	f_shape_anchor_delta_x : f_shape_coord_real_size;
			signed twips	f_shape_anchor_delta_y : f_shape_coord_real_size;
		}
		else {
			unsigned	f_shape_line_has_x_and_y : 1;
			if(f_shape_line_has_x_and_y == 1) {
				signed twips	f_shape_delta_x : f_shape_coord_real_size;
				signed twips	f_shape_delta_y : f_shape_coord_real_size;
			}
			else {
				unsigned	f_shape_line_has_x_or_y : 1;
				if(f_shape_line_has_x_or_y == 0) {
					signed twips	f_shape_delta_x : f_shape_coord_real_size;
				}
				else {
					signed twips	f_shape_delta_y : f_shape_coord_real_size;
				}
			}
		}
	};
	union swf_shape_record {
		swf_shape_record_end	f_shape_end;
		swf_shape_record_setup	f_shape_setup;
		swf_shape_record_edge	f_shape_edge;
	};
    | 1 | From my tests with the official Macromedia Flash plugin, it looks that
    there is always a bit at this position. It seems however that it cannot
    be set to 1 in v1.0 of the tag (i.e. when the DefineShape tag is used). |  swf_styles
 
  This structure is found in the shape with style and change style structures.
   	struct swf_styles {
		swf_fill_style_array	f_fill_styles;
		swf_line_style_array	f_line_styles;
		swf_styles_count	f_styles_count;
	};
swf_styles_count
  Note that the line & fill bits are declared as "unsigned char" because they
  will always be aligned. The proper definition would probably be a bit field though.
   	struct swf_styles {
		unsigned char		f_fill_bits_count : 4;
		unsigned char		f_line_bits_count : 4;
	};
swf_fill_style_array
  The array of fill styles starts with a counter. When DefineShape is used,
  the counter can be any value from 0 (no style) to 255. When DefineShape2
  or DefineShape3 are used, the value 255 is reserved so you can declare
  more than 255 styles.
   	struct swf_fill_style_array {
		unsigned char		f_count;
		if(f_tag != DefineShape && f_count == 255) {
			unsigned short	f_real_count;
		}
		else {
			f_real_count = f_count;
		}
		swf_fill_style		f_fill_style[f_real_count];
	};
swf_fill_style
  The fill style is defined in the first byte. The values are
  defined below. Depending on that value, the fill style structure
  changes as shown below. The swf_fill_style is a union of all
  these other structures.
   
  Notice that types 0x42 and 0x43 are only available since version 7
  and type 0x13 is only available since version 8.
   	/* f_type = 0x00 - solid fill */
	struct swf_fill_style_solid {
		unsigned char		f_type;
		if(f_tag == DefineMorphShape || f_tag == DefineMorphShape2) {
			swf_rgba	f_rgba;
			swf_rgba	f_rgba_morph;
		}
		else if(f_tag == DefineShape3) {
			swf_rgba	f_rgba;
		}
		else {
			swf_rgb		f_rgb;
		}
	};
	/* f_type = 0x10 - linear gradient fill,
		    0x12 - radial gradient fill
		    0x13 - focal gradient fill (V8.0) */
	struct swf_fill_style_gradient {
		unsigned char		f_type;
		swf_matrix		f_gradient_matrix;
		if(f_tag == DefineMorphShape || f_tag == DefineMorphShape2) {
			swf_matrix	f_gradient_matrix_morph;
		}
		swf_gradient		f_gradient;
	};
	/* f_type = 0x40 - tilled bitmap fill with smoothed edges,
		    0x41 - clipped bitmap fill with smoothed edges,
		    0x42 - tilled bitmap fill with hard edges (V7.0),
		    0x43 - clipped bitmap fill with hard edges (V7.0) */
	struct swf_fill_style_bitmap {
		unsigned char		f_type;
		unsigned short		f_bitmap_ref;
		swf_matrix		f_bitmap_matrix;
		if(f_tag == DefineMorphShape || f_tag == DefineMorphShape2) {
			swf_matrix	f_bitmap_matrix_morph;
		}
	};
	union swf_fill_style {
		unsigned char		f_type;
		swf_fill_style_solid	f_solid;
		swf_fill_style_gradient	f_gradient;
		swf_fill_style_bitmap	f_bitmap;
	};
swf_line_style_array
  The array of line styles starts with a counter. When DefineShape is used,
  the counter can be any value from 0 (no style) to 255. When DefineShape2
  or DefineShape3 are used, the value 255 is reserved so you can declare
  more than 255 styles.
   	struct swf_line_style_array {
		unsigned char		f_count;
		if(f_tag != DefineShape && f_count == 255) {
			unsigned short	f_real_count;
		}
		else {
			f_real_count = f_count;
		}
		swf_line_style		f_line_style[f_real_count];
	};
swf_line_style
  The width of the line is in TWIPS (1/20th of a pixel).
   	struct swf_line_style {
		if(f_tag == DefineMorphShape) {
			unsigned short twips	f_width;
			unsigned short twips	f_width_morph;
			swf_rgba		f_rgba;
			swf_rgba		f_rgba_morph;
		}
		else if(f_tag == DefineShape4 || f_tag == DefineMorphShape2) {
			unsigned short twips	f_width;
			if(f_tag == DefineMorphShape2) {
				unsigned short twips	f_width_morph;
			}
			unsigned		f_start_cap_style : 2;
			unsigned		f_join_style : 2;
			unsigned		f_has_fill : 1;
			unsigned		f_no_hscale : 1;
			unsigned		f_no_vscale : 1;
			unsigned		f_pixel_hinting : 1;
			unsigned		f_reserved : 5;
			unsigned		f_no_close : 1;
			unsigned		f_end_cap_style : 2;
			if(f_join_style == 2) {
				unsigned short fixed	f_miter_limit_factor;
			}
			if(f_has_fill) {
				swf_fill_style		f_fill_style;
			}
			else {
				swf_rgba		f_rgba;
				if(f_tag == DefineMorphShape2) {
					swf_rgba		f_rgba_morph;
				}
			}
		}
		else if(f_tag == DefineShape3) {
			unsigned short twips	f_width;
			swf_rgba		f_rgba;
		}
		else {
			unsigned short twips	f_width;
			swf_rgb			f_rgb;
		}
	};
  The f_start_cap_style and f_end_cap_style can be:
   
    0 - Round cap,1 - No cap,2 - Square cap. 
  Round is the default, the way line caps looked before version 8.
  No Cap means that nothing is added at the tip of the line. This
  means the line stops exactly where you say it should end. The
  Square Cap is like the No Cap, but it hads the cap which is
  about Width / 2.
   
  The f_join_style can be:
   
    0 - Round join,1 - Bevel join,2 - Miter join. 
  Each time a line is multiple segments, each segment join is
  rendered using this definition.
  A Round Join is what we had before.
  A Bevel Join is a straight line between the end edges of each
  line (rectangle representing a line.)
  The Miter Join is similar to a Bevel, except that you can control
  the length between the tips and the closure of the line. When
  the miter limit factor is large, it continues the edges of the
  lines and it looks like triangles or squares.
   
  The f_no_hscale and f_no_vscale flags, when set to 1,
  request that the stroke thickness not be scaled along with the
  object.
   
  When f_pixel_hinting is set to 1, the SWF Player forces all
  the anchors to be placed on a pixel (it ignores sub-pixels.) This
  can be useful to create small objects which you do not want blurry.
   
  The f_no_close can be set to 1 to request that the first
  and last points be rendered with caps rather than a join even if
  they are equal (and thus close the shape.)
   
  The f_miter_limit_factor field is defined whenever the join
  is set to Miter Join (2). The value is unsigned from 0.0 to about 255.0.
  Note that under 1.0, it has no effect.
  swf_matrix 
  The default scale is 1.0. The default rotate is 0.0. The default
  translate is (0, 0).
   
  The scale is a ratio. The rotate is an angle in radian.
  The translate is in TWIPs.
   	struct swf_matrix {
		char align;
		unsigned		f_has_scale : 1;
		if(f_has_scale) {
			unsigned	f_scale_bits : 5;
			signed fixed	f_scale_x : f_scale_bits;
			signed fixed	f_scale_y : f_scale_bits;
		}
		unsigned		f_has_rotate : 1;
		if(f_has_rotate) {
			unsigned	f_rotate_bits : 5;
			signed fixed	f_rotate_skew0 : f_rotate_bits;
			signed fixed	f_rotate_skew1 : f_rotate_bits;
		}
		unsigned		f_translate_bits : 5;
		signed			f_translate_x : f_rotate_bits;
		signed			f_translate_y : f_rotate_bits;
	};
swf_text_record
  The swf_text_record structure is a structure composed of
  a text style definition followed by characters. Multiple records
  can follow each others. The list is ended with one byte set to 0.
   
  WARNING: it seems that Macromedia didn't
  think about a file having two records of type glyph one after
  another (it makes their plugins crash); you will have to insert a
  setup record between each glyph record (the setup can be empty: i.e.
  add one byte equal to 0x80). The very first setup has to
  at least define the font. 
  NOTE: this has been corrected by Macromedia
  it now shows as one structure including the style and an array of
  glyphs. This fixes the problem at once. It however makes the structure
  look a bit more complicated.
   	struct swf_text_record_end {
		unsigned		f_end : 8;	/* all zeroes */
	};
	struct swf_text_record_setup {
		unsigned		f_type_setup : 1;	/* always one */
		unsigned		f_reserved : 3;
		unsigned		f_has_font : 1;
		unsigned		f_has_color : 1;
		unsigned		f_has_move_y : 1;
		unsigned		f_has_move_x : 1;
		if(f_has_font) {
			unsigned short		f_font_id_ref;
		}
		if(f_has_color) {
			if(tag == DefineText) {
				swf_rgb		f_color;
			}
			else {	/* if tag is DefineText2 */
				swf_rgba	f_color;
			}
		}
		if(f_has_move_x) {
			signed short		f_move_x;
		}
		if(f_has_move_y) {
			signed short		f_move_y;
		}
		if(f_has_font) {
			unsigned short		f_font_height;
		}
	};
	struct swf_text_record_glyphs {
		unsigned		f_type_glyph : 1;		/* always zero */
		unsigned		f_glyph_count : 7;		/* at least one */
		swf_text_entry		f_entry[f_glyph_count];
	};
	struct swf_text_record_string {
		unsigned		f_type_setup : 1;	/* always one */
		unsigned		f_reserved : 3;
		unsigned		f_has_font : 1;
		unsigned		f_has_color : 1;
		unsigned		f_has_move_y : 1;
		unsigned		f_has_move_x : 1;
		if(f_has_font) {
			unsigned short		f_font_id_ref;
		}
		if(f_has_color) {
			if(tag == DefineText) {
				swf_rgb		f_color;
			}
			else {	/* if tag is DefineText2 */
				swf_rgba	f_color;
			}
		}
		if(f_has_move_x) {
			signed short		f_move_x;
		}
		if(f_has_move_y) {
			signed short		f_move_y;
		}
		if(f_has_font) {
			unsigned short		f_font_height;
		}
		unsigned char		f_glyph_count;		/* at least one */
		swf_text_entry		f_entry[f_glyph_count];
	};
	union swf_text_record {
		unsigned		f_flags : 8;
		swf_text_record_end	f_end;
		if(version >= 7) {
			swf_text_record_string	f_string;
		}
		else {
			swf_text_record_setup	f_setup;
			swf_text_record_glyphs	f_glyphs;
		}
	};
  The very first byte of a record determines its type. When it is set
  to zero, it is the end of text records. In all versions (though it
  was not defined that way before), you need to alternate the setup
  and glyph records. It seems that even older versions would support
  more than 127 characters, however, if you plan to use 128 to 255
  characters in a text records, I recommand you create a version 7
  movie. So, in other words, go ahead and use the swf_text_record_string
  with f_glyph_count set to a value from 1 to 127 in a version 1 to 6
  movie.
   
  To make sure that none of the setup records are recognized as the
  end record, you should always set the bit 7 to 1 (f_type_setup).
  You don't otherwise have to have any font, color or displacement
  definition in setups (except the very first which needs to specify
  a font).
   
  The f_glyph_count must be at least 1. If you don't have any
  characters, just don't create a text entry.
   
  The f_move_x and f_move_y always specify a position from
  the origin where the text object is placed like in a shape.
  swf_text_entry 
  The swf_text_entry structure defines a list of characters and
  the number of TWIPs to skip to go to the next character. Note that
  the advance is a signed value. Thus you can write characters from
  right to left languages such as Arabic in a native way. The number
  of bits used to define each field of this structure is defined in
  the DefineText or
  DefineText2 tags.
   	struct swf_text_entry {
		unsigned		f_glyph_index : f_glyph_bits;
		signed			f_advance : f_advance_bits;
	};
swf_gradient
  This structure defines a gradient. This is a set of colors which are
  used to define an image with colors smoothly varying from one color to
  the next. The gradient can be radial (circular) or linear (rectangular).
   	struct swf_gradient {
		if(tag == DefineShape4) {
			unsigned		f_spread_mode : 2;
			unsigned		f_interpolation_mode : 2;
			unsigned		f_count : 4;
		}
		else {
			unsigned		f_pad : 4;
			unsigned		f_count : 4;
		}
		swf_gradient_record	f_gradient_record[f_count];
		/* f_type is defined in the swf_fill_style encompassing this gradient */
		if(f_type == 0x13) {
			signed short fixed	f_focal_point;
		}
	};
  The f_countfield is limited depending on the tag used and the
  version of SWF as defined below: 
  | 
      | Range | Tag | Version | 
|---|
 
	| 1 to 8 | DefineShape | 3 |  
	| 1 to 8 | DefineShape2 | 3 |  
	| 1 to 8 | DefineShape3 | 3 |  
	| 1 to 15 | DefineShape4 | 8 |  
	| 1 to 8 | DefineShapeMorph | 3 |  
	| 1 to 8(1) | DefineShapeMorph2 | 8 |  | 
 
    | (1) | To be determined. The Macromedia documentation says it is limited to 8,
      the player needs to be tested to verify that DefineShapeMorph2 cannot
      support 15 gradients |  
  The f_spread_modeis an enumeration and appeared in version 8 (undefined values are reserved.) 
  | 
      | Value | Comment | Version | 
|---|
 
	| 0 | Pad | 8 |  
	| 1 | Reflect | 8 |  
	| 2 | Repeat | 8 |  | 
 
  The f_interpolation_modeis an enumeration and appeared in version 8 (undefined values are reserved.) 
  | 
      | Value | Comment | Version | 
|---|
 
	| 0 | Normal RGB mode | 8 |  
	| 1 | Linear RGB mode | 8 |  | 
 
  The swf_gradient_recordf_focal_pointis a position from the left edge of the gradient
  square to the center and then to the right edge of the gradient. The left edge
  is at position -1.0, the center at 0.0 and the right edge at +1.0. This is
  particularly useful for radial gradients. 
  The first record position should be 0 and the last 255. The
  intermediate should use the corresponding value depending
  on their position in the gradient effect.
   	struct swf_gradient_record {
		if(f_tag == DefineMorphShape || f_tag == DefineMorphShape2) {
			unsigned char	f_position;
			swf_rgba	f_rgba;
			unsigned char	f_position_morph;
			swf_rgba	f_rgba_morph;
		}
		else if(f_tag == DefineShape3 || f_tag == DefineShape4) {
			unsigned char	f_position;
			swf_rgba	f_rgba;
		}
		else {
			unsigned char	f_position;
			swf_rgb		f_rgb;
		}
	};
  A linear gradient is defined from left to right. A radial from inside
  to outside. In order to see the full effect of the gradient, one needs
  to define its matrix properly. The gradients are always drawn in
  a square with coordinates -819.2, -819.2 to +819.2, +819.2 (in pixels,
  that's 16384 in TWIPs). The usual is to scale the gradient square down, translate
  to the proper position and rotate as necessary. There is no point in
  rotating a radial gradient.
   
  IMPORTANT NOTE: If you use positions (see f_position)
  which are too close to each others, you are likely to see a reverse effect
  of what you would expect
  (Well... at least in the Macromedia plugin V5.0 — the gradient goes the wrong
  way between each color change!!!).
   
    
 Fig 1. Red to green radial fill
 
  The image in Fig 1. shows you a radial fill using pure red as the color
  at position 0 and pure green at position 255. It is often used to draw
  a round corner of an object such as a button.
   
    
 Fig 2. Red to green linear fill
 
  The image in Fig 2. shows you a linear fill using pure red as the color
  at position 0 and pure green at position 255. It goes from left to
  right when no rotation is applied. Using a rotation provides means to
  have the colors going top to bottom or in diagonals.
  swf_color_transform 
  When the f_color_<component>_mult are not defined in the input
  file, use 1.0 by default. When the f_color_<component>_add
  are not defined in the input file, use 0.0 by default.
   
  The factors are saved as 8.8 fixed values (divide by 256 to obtain a proper
  floating point value). Note that the values are limited to a signed 16 bits
  value. This allows for any value between -128.0 and +127.98828.
   
  When the resulting color is defined, the multiplication is applied first
  as in:
   	result-component = source-component * component-mult + component-add;
 
  The result is then clamped between 0.0 and 1.0.
   	struct swf_color_transform {
		char align;
		unsigned		f_color_has_add : 1;
		unsigned		f_color_has_mult : 1;
		unsigned		f_color_bits : 4;
		if(f_color_has_mult) {
			signed short fixed	f_color_red_mult : f_color_bits;
			signed short fixed	f_color_green_mult : f_color_bits;
			signed short fixed	f_color_blue_mult : f_color_bits;
			if(f_tag == PlaceObject2) {
				signed short fixed	f_color_alpha_mult : f_color_bits;
			}
		}
		if(f_color_has_add) {
			signed short fixed	f_color_red_add : f_color_bits;
			signed short fixed	f_color_green_add : f_color_bits;
			signed short fixed	f_color_blue_add : f_color_bits;
			if(f_tag == PlaceObject2) {
				signed short fixed	f_color_alpha_add : f_color_bits;
			}
		}
	};
swf_any_filter
  A filter defines how to transform the objects it is attached to. The
  first byte is the filter type. The data following depends on the type.
  Because each filter is much different, they are defined in a separate
  structure below. You can attach a filter to an object using an
  ActionScript or the PlaceObject3 tag.
   	/* the filter type */
	struct swf_filter_type {
		unsigned char	f_type;
	};
  The following describes the different filters available since version 8.
   
  
   
 
 Glow, Drop Shadow, Bevel, Gradient Glow and Gradient Bevel 
  The following structure describes the Glow, Drop Shadow, Bevel, Gradient
  Glow and Gradient Bevel which all use the same algorithm. Those with less
  parameters can use a faster (optimized) version of the full version
  algorithm.
   	struct swf_filter_glow {
		swf_filter_type	f_type;		/* 0, 2, 3, 4 or 7 */
		if(f_type == GradientGlow || f_type == GradientBevel) {
			unsigned char		f_count;
		}
		else {
			f_count = 1;
		}
		swf_rgba		f_rgba[f_count];
		if(f_type == Bevel) {
			swf_rgba		f_highlight_rgba[f_count];
		}
		if(f_type == GradientGlow || f_type == GradientBevel) {
			unsigned char		f_position[f_count];
		}
		signed long fixed	f_blur_horizontal;
		signed long fixed	f_blur_vertical;
		if(f_type != Glow) {
			signed long fixed	f_radian_angle;
			signed long fixed	f_distance;
		}
		signed short fixed	f_strength;
		unsigned		f_inner_shadow : 1;
		unsigned		f_knock_out : 1;
		unsigned		f_composite_source : 1;
		if(f_type == Bevel) {
			unsigned		f_on_top : 1;
		}
		else {
			unsigned		f_reserved : 1;
		}
		if(f_type == GradientGlow || f_type == GradientBevel) {
			unsigned		f_passes : 4;
		}
		else {
			unsigned		f_reserved : 4;
		}
	};
  These filters are used to generate what looks like a glow or a shadow. It uses the
  alpha channel of the object being filtered. Only the alpha is used in the computation
  of the shape until the end when the color is applied. The result is then composited
  with the object (unless f_knock_out is set to 1 in which case it replaces the object)
  before being drawn in the display.
   
  The f_count is assumed to be 1 unless a gradient filter is used, in
  which case a byte will be defined here. Note: the maximum number of gradient
  is not specified in the Macromedia documentation. It can be assumed to be
  the same as for the other gradients and thus it either can be 1 to 8 or 1 to 15.
  I will need to test that too!
   
  The f_rgba color is used as the final step to color the resulting shape.
  A standard shadow uses a black or dark grey color and a standard glow has a
  color between the general color of the object being filtered and white.
   
  The f_hightlight_rgba color is used by the Bevel filter to color the
  second half of the final shape (f_rgba colors the first half). This is
  usually set to a glow color whereas the f_rgba is set to a shadow color.
   
  The f_position is used as the position of that specific gradient entry.
  THis is similar to the f_position parameter of the
  swf_gradient_record.
   
  The f_blur_horizontal and f_blur_vertical values are used
  to blur the edges horizontally and vertically. See the
  Blur filter for more information about
  the blur effect.
   
  The f_radian_angle and f_distance are used to move the shadow
  away from the object being placed. Notice that the angle is in radian.
  Increasing the angle turns the effect clockwise. An angle of 0.0 points
  to the right side of the object.
   
  The f_strengh value is used to multiply the resulting grey scale.
  Smaller values make the shadow darker. 1.0 keeps the alpha channel as it is
  (beside the blur).
   
  The f_inner_shadow flag means that the result is applied inside the
  parent object and not arround as you would expected for a shadow. If you
  need both: an inner and an outer shadow (necessary for semi-transparent
  objects) then you will need to setup two filters.
   
  The f_knock_out flag means that the source object is not rendered in
  the result, only the shadow. This can be used (in general) to draw the edges
  of the object. It can also be used to apply a different transformation on
  the shadow than on the object (in which case the object will be twice in the
  display list: once to draw its shadow and once to draw itself.)
   
  The f_composite_source must be set to 1 for the Drop Shadow.
   
  The f_on_top flag indicates whether the resulting shadow
  and highlight should be rendered below (0) or over (1) the
  source image. This is at times referenced as Overlay.
   
  The f_passes counter available with the gradient filters
  can be used to repeat the filter computations multiple times.
  This parameter should be set to 1, 2 or 3. A value of 0 is illegal
  and a larger value will not only slow down the computation time,
  it is likely to generate a bad result.
   
 
 Blur 	struct swf_filter_blur {
		swf_filter_type		f_type;		/* 1 */
		unsigned long fixed	f_blur_horizontal;
		unsigned long fixed	f_blur_vertical;
		unsigned		f_passes : 5;
		unsigned		f_reserved : 3;
	};
  The Blur filter applies a simingly complex mathematical equation to all
  the pixels in order to generate soft edges. To simplify: it adds the
  surrounding pixels to a center pixel and normalize the result. This
  generates the effect of a blurry image. Note that this blur is applied
  to squares (box filter).
   
  The math in a C++ function goes like this:
   	swf_rgba blur(const char *image, int x, int y, int blur_h, int blur_v)
	{
		/* we assume that blur_h/v are odd */
		int x1 = x - blur_h / 2;
		int x2 = x + blur_h / 2;
		int y1 = y - blur_v / 2;
		int y2 = y + blur_v / 2;
		swf_rgba blur;
		blur.reset();	/* set to all 0's */
		yp = y1;
		while(yp <= y2) {
			int xp = x1;
			while(xp <= x2) {
				blur += image(xp, yp);
				++xp;
			}
			++yp;
		}
		return blur / (blur_h * blur_v);
	}
    
      | Notes: | The Flash player implementation works on sub-pixels and this
      algorithm does not. |  
      | The fact that this algorithm uses a square means it will
      generate visible artifacts in your image if you use a large
      value for the blur (i.e. more than about 7.) |  
      | If you want this algorithm to work properly, make sure to
      save the results in a separate image so each pixel can be
      computed properly without the effect pre-applied. |  
      | This algorithm does not show any clipping; if you want to
      keep it fast, you need to keep it that way and enlarge the source
      image making the edges a repeat of the edge color and the corners
      the corresponding corner color. |  
  The f_blur_horizontal and f_blur_vertical are expected to be
  larger than 1.0 to have an effect (usually at least 3, and in most cases
  5 or more.)
   
  The f_passes is a counter which should be at least 1. The blur effect
  will be repeated that many times on the image. When using 3, the resulting
  blur is close to a Gaussian Blur. Note that it will make the
  image bigger each time and applying this filter can be slow.
   
 
 Convolution 	struct swf_filter_convolution {
		swf_filter_type	f_type;		/* 5 */
		unsigned char	f_columns;
		unsigned char	f_rows;
		long float	f_divisor;
		long float	f_bias;
		long float	f_weights[f_columns × f_rows];
		swf_rgba	f_default_color;
		unsigned	f_reserved : 6;
		unsigned	f_clamp : 1;
		unsigned	f_preserve_alpha : 1;
	};
  The convolution filter can be used to generate a really nice blur or
  avoid the vertical jitter of an animation on a CRT monitor. It is
  similar to the Blur filter, except that the computation of the destination
  pixels is fully controlled.
   
    Fig 1 — Convolution Filter Example
 
  The image above shows an example of a convolution filter. The red pixel is
  the one being tweaked. The different grey color represent the heavier (darker)
  weight and the lighter weights. The pixels drawn in white are ignored (i.e.
  their weights will be set to 0.)
   
  The convolution filter can be described with the following C function:
   	swf_rgba convolution(swf_rgba *source, int x, int y, swf_filter_convolution convolution)
	{
		swf_rgba	result;
		swf_rgba	pixel;
		int		i, j, p, q, pmax, qmax;
		result.reset();		/* black */
		pmax = convolution.f_rows / 2;
		qmax = convolution.f_columns / 2;
		for(j = 0, p = -pmax; p < pmax; ++p, ++j) {
			for(i = 0, q = -qmax; q < qmax; ++q, ++i) {
				pixel = source[x + p][y + q];
				pixel += convolution.f_bias;
				pixel *= convolution.f_weights[i][j];
				pixel /= convolution.f_divisor;
				result += pixel;
			}
		}
		return result;
	}
  We can clearly see that a weight of 0 cancels that very pixel effect.
  We can notice also that the divisor is not necessary here (however,
  it may be possible to tweak the divisor using an ActionScript and
  in that case it can be useful.)
   
  A blur algorithm can use a convolution filter with the following parameters:
   
    Set f_columns to 5Set f_rows to 5Set f_divisor to 1Set f_bias to 0Set f_weights to:{
  { 0.000, 0.050, 0.050, 0.050, 0.000 },
  { 0.050, 0.075, 0.075, 0.075, 0.050 },
  { 0.050, 0.075, 0.000, 0.075, 0.050 },
  { 0.050, 0.075, 0.075, 0.075, 0.050 },
  { 0.000, 0.050, 0.050, 0.050, 0.000 }
}
Set f_clamp to 1Set f_preserve_alpha to 1 
    Fig 2 — Convolution filter to create a radian blur
 
  When you want to remove most of the jitter on a television or any CRT monitor
  which use an interlace video mode, you can use the following setup:
   
    Set f_columns to 1Set f_rows to 3Set f_divisor to 1Set f_bias to 0Set f_weights to { 0.25, 0.5, 0.25 }Set f_default_color to black (0, 0, 0, 1)Set f_clamp to 0Set f_preserve_alpha to 1 
    Fig 3 — Convolution filter to limit interlace jitter
 
  The f_columns and f_rows determine the size of the
  convolution filter.
   
  The f_divisor divise the sum of the weighted pixel components.
  Note that you can incorporate the divisor in the weights. However, this
  is a mean to divide (or multiply) all the weights at once. Yet I suggest
  you put this parameter to 1 and change the weights instead.
   
  The f_bias is added to the component of each pixel before
  they are multiplied by their corresponding factor.
   
  The f_weights are used to determine how much of a given pixel
  color shall be used in the result.
   
  The f_default_color color is used only if f_clamp is set
  to 0. This is the color to be used whenever it is necessary to compute
  the color of a pixel which is outside of the source.
   
  f_clamp is used to determine the color to use whenever a pixel
  outside of the input image is necessary. When set to 1, the closest input
  pixel is used. When set to 0, the f_default_color is used.
   
  If f_preserve_alpha is set to 1, then the source alpha channel is
  copied as is in the destination.
   
 
 Color Matrix 	struct swf_filter_colormatrix {
		swf_filter_type	f_type;		/* 6 */
		long float	f_matrix[20];
	};
  The color matrix is a 5x5 matrix used to tweak or adjust the
  colors of your objects. A full matrix can be used to change
  the contrast, brightness and color (just like you do on your
  television.)
   
  The matrix is composed of 5 components of red, green,
  blue and alpha. The 5th row is not saved in
  the filter and is assume to always be [0 0 0 0 1].
   
    Fig 1 — Color Matrix Filter
 
  The resulting color Q is computed as M · C, where C is
  a column matrix composed of the source pixel colors: red,
  green, blue, alpha and 1. The result is also a column matrix
  in which component 5 can be dropped.
   
  Notice that f_matrix is composed of floats and not
  fixed point values.
   
  In order to compute a color matrix from simple values, you
  want to use the following matrices and equations
  (see Appendix A. for more matrix
  computations.) Most of these equations are based on a paper
  written by
  Paul Haeberli
  in 1993.
   
  Why is matrix computation on colors working so well? This is
  because the colors, when defined as (R, G, B) perfectly map
  to a 3 dimensional cube. The corner at (0, 0, 0) represents
  black, and the opposite corner at (1, 1, 1) represents white.
  The other corners represent Red, Green, Blue and their
  composites: Cyan, Yellow, Purple. Within the cube, all the
  usual 3D geometry computations apply to colors just the
  same as it applies to (x, y, z) vectors.
   
  The following shows you have to modify the RGB components.
  The Alpha channel can in a similar way be modified. However,
  you usually do not want to change the alpha from the colors
  and thus it is likely that the only thing you will do with
  the alpha is a simple translation (change a0,
  a1, a2) and a scaling (change a3).
  By default, set the alpha row to [ 0 0 0 1 0 ] and the last
  column to [ 0 0 0 0 1 ].
   
    Fig 2 — Color Matrix with no effect on the alpha channel
 
  In the following pretty much all the values are assumed to
  be defined between 0.0 and 1.0. Though there is no real
  limits, using larger values or negative values can have
  unexpected effects such as a clamping of one or more of
  the color components.
   
    Grey Vector
    The Grey Vector is the vector going from (0, 0, 0) to
    (1, 1, 1). It represents all the greys from black to
    white. It is important since it is used to represent
    the luminance of the image.
     Brightness (Matrix B)
    Use the scaling matrix B to change the brightness. This
    has the effect of making the color vector longer or
    shorter, but it still points in the same direction.
    Some people call this the image Intensity.
     
      Fig 3 — Brightness Matrix B
 
    In general, you want to set all scaling factors to the same
    value to change the brightness in a uniform way. By changing
    the scaling factors to different values you in effect
    change the color balance.
     Luminance (Matrix L)
    The luminance matrix L is used to determine how close your
    image is to the grey vector. The closer to the grey vector,
    the closer to a black and white image you will get. This
    is a saturation toward grey. The effect in the color cube
    is to move your color vector closer to the grey vector.
     
      Fig 4 — Luminance Matrix (L)
 
    The luminance matrix requires three weights
    (Rw, Gw, Bw)
    which are defined as (0.3086, 0.6094, 0.082).
    Note that the sum of these weights is 1.0.
     
    The weights used here are linear. It is possible
    to use different weights for images which have
    different gammas. For instance, an NTSC image
    with a gamma of 2.2 has these weights:
    (0.299, 0.587, 0.114).
     Saturation (Matrix S)
    The saturation matrix S is used to saturate the colors. This
    matrix uses the weights defined for the Luminance matrix L.
    The effect in the color cube is to move your vector toward
    another vector. The Luminance is a special case which moves
    your vector toward the grey vector. And the identity matrix,
    which can also be considered a saturation matrix, is
    a special case which does not move your vector.
     
      Fig 5 — Saturation Matrix (S)
 
    The saturation parameter s shall be set to a value from -1 to 1.
    Note that a saturation of 1 generates an Identity Matrix and thus has
    no effect. A saturation of 0 generates a Luminance Matrix
    (s = 0 <=> S = L). A saturation of -1 generates a matrix
    which inverse all the colors of your image (negative).
     Contrast (Matrix C)
    Using the Brightness Matrix B and a translation matrix, it is possible
    to modify the contrast of your image by scaling the colors toward or
    away from the center (or some other point) of the color cube.
     
      Fig 6 — Translation Matrix (T)
 
    To apply a standard contrast c create a matrix Ts
    with offsets (0.5, 0.5, 0.5), a matrix Bc with the
    scaling factors set to c and compute the contrast matrix C as:
    C = -Ts · Bc · Ts
     
    It is also possible to use a translation to change the colors
    of your image. This is not very useful since it is a simple addition
    (C' = C + T).
     Hue (Matrix H)
    To change the hue of a color, it is necessary to rotate the color
    vector around the grey vector. It is easy to see that rotating
    the grey vector around itself generates itself. A grey hue cannot
    be changed. If you rotate the colors by 120°, red becomes green,
    green becomes blue and blue becomes red.
     
    Note however that by only rotating the color, you generate a
    luminance error. This is because blue is not as bright as red or
    green and green is not as bright as red. To avoid the luminance
    loss, you need to apply a shear to make the luminance plane
    horizontal.
     
    The following are all the steps used to rotate the Hue. Note that
    most matrices can be precomputed (in other words, you can very
    much optimize your code!)
     
      X Rotation
      Rotate the grey vector around the X axis by 45°. This
      places the the vector on the (x, y) plane.
       
        Fig 7 — rotation around the X axis
 
      Because we want to rotate by 45° the sine and cosine of the
      angle can directly be set to the inverse of the square root of 2.
       
        Fig 8 — sine and cosine in the rotation around the X axis
 Y Rotation
      Rotate the grey vector from the (x, y) plane to the positive Z
      direction. We want to rotate by about 35.2644°.
       
        Fig 9 — rotation around the Y axis
 
      The sine and cosine values of this equation can be computed with
      the square root of 2 and 3 as presented below:
       
        Fig 10 — sine and cosine in the rotation around the Y axis
 Luminance Shear (Matrix K)
      Apply the Rx and Ry matrices to the luminance offsets,
      and use the result to compute the shear matrix.
       
        Fig 11 — How to compute the shear factors
 
      The Rw, Gw and Bw are the Luminance factors
      as defined for matrix L.
       
      Now we can compute matrix K which is used for the luminance shear correction:
       
        Fig 12 — Hue Shear Matrix K
 Hue rotation
      Once you applied the Rx, Ry and K matrices to your
      color, you can safely rotate the result around the Z axis. This
      rotates the hue of the color. The rotation angle is expected to go from
      0 to 2π.
       
        Fig 13 — Matrix to rotate the hue
 
      θ is set to the hue rotation angle.
       Remove the shear, y rotation and x rotation
      Once you rotated your vector using Rz you need to put your
      vector back where it belongs. This is done by multiplying by the inverse
      of the K, Ry and Rx in that order. Note that since
      these matrices are quite simple, calculating their inverse is very easy.
       
      K-1 is obtained by replacing B'w in the K matrix by
      –B'w.
       
        Fig 14 — Inverse of Matrix K
 
      Ry-1 and Rx-1 are obtained by
      replacing the sine values by their opposite.
       
        Fig 15 — Inverse of Matrix Ry
 
        Fig 16 — Inverse of Matrix Rx
 Final Hue Rotation Equation
      Given the hue rotation angle θ you can write:
       
      H = Rx · Ry · K · Rz · K-1 · Rx-1 · Ry-1
       And finally the SWF Color Matrix
    Once you computed each of the matrices, you can merge them all together
    by multiplying them. The order should not matter except if you use a translation
    which isn't cancelled (like the one for the contrast.)
     
    M = B · S · C · H
     
    Note that you do not need a Saturation and a Luminance since these are
    the same. However, you may still want to separate them for the sake of
    simplicity.
     
    M = B · L · S · C · H
     
 
 Filters Union 
  The any filter is simply a union of all the filters. Note
  that only one type of filter can be defined in an any filter
  and also the size will depend on that filter (it is not the largest
  size of all filters, anyway, some filters use a dynamically determined
  size!)
   	struct swf_any_filter {
		swf_filter_type			f_fitler_type;
		swf_filter_blur			f_filter_blur;
		swf_filter_colormatrix		f_filter_colormatrix;
		swf_filter_convolution		f_filter_convolution;
		swf_filter_glow			f_filter_glow;
	};
swf_action
  An action is defined with an identifier, a size and some data (pretty much
  like a tag). Because the number of actions is much more limited than tags,
  the ID is only 7 bits. There is one bit used to know whether there is a
  size parameter. If not, then there is no data for that action. If there
  is a size, then a 2 byte value is used to save the information about that
  action.
   
  Please, see the DoAction tag for a list of all
  the supported actions.
   	/* basic definition of an action entry */
	struct swf_action {
		char align;
		unsigned		f_action_has_length : 1;
		unsigned		f_action_id : 7;
		if(f_action_has_length) {
			unsigned short		f_action_length;
			unsigned char		f_action_data[f_action_length];
		}
	};
    swf_action3
      | WARNING: | the f_action_has_length is actually taken in
		account in the determination of the f_action_id; thus
		if the first byte is 0x0A, it is not the same as 0x8A. |  
  Since Flash version 9, actions can be saved in a new format named abcFormat
  by the Tamarin project from the Mozilla
  organization.
   
  The code itself (action script) is the same, but the structure of an
  swf_action3 holds object oriented information about classes, methods
  and such in a really clean way (really! in comparison to the old way,
  that's dead clean!).
   
  At this time, the swf_action3 is fully(?)
  documented in the abcFormat.html file.
   
  I will duplicate and test the structures at a later time.
  swf_button 
  A button structure defines a state and a corresponding shape reference.
  The shape will be affected by the specified matrix whenever used.
   
  There are many acceptable combinaisons. The object which is referenced
  is drawn when its state matches the current state of the button. If only the
  f_button_state_hit_test is set, then the shape is always displayed.
   
  In order to define the area where the button can be clicked, it is necessary
  to set the f_button_state_hit_test flag to 1. Also, when this flag is
  set, only a shape can be referenced (no edit text, sprite or text object will
  work in this case).
   
  When the f_button_state_hit_test is set, the square used to delimit
  the referenced shape will be used to determine whether the mouse is over
  the button or not.
   
  Shapes referenced with the f_button_state_down flag set are drawn when
  a mouse button is being pushed over this button.
   
  Shapes referenced with the f_button_state_up flag set are drawn when
  no mouse button is being pushed over this button. When neither up or down
  is specified, up us assumed.
   
  Shapes referenced with the f_button_state_over flag set are drawn when
  the mouse is moved over this button.
   
  The f_button_layer is used like a depth parameter. The smallest layer
  is drawn first (behind) and the highest layer is drawn last (on top of all
  the other shapes).
   
  Though four flags allow for 16 different states, you are likely to only use
  a few. The hit test can appear on each state. The down and up won't
  usually be used together, though, if they are the shape will be drawn
  when the button is clicked or not.
   
  Since version 8, this structure supports blending modes and a list of filters.
   
  The structure is always aligned to a byte. If all of the f_button_state_... flags
  are zeroes, then the entry is an EOB (End Of Buttons) entry.
   	struct swf_button {
		char align;
		unsigned		f_button_reserved : 2;
		if(version >= 8) {
			unsigned		f_button_blend_mode : 1;
			unsigned		f_button_filter_list : 1;
		}
		else {
			unsigned		f_button_reserved : 2;
		}
		unsigned		f_button_state_hit_test : 1;
		unsigned		f_button_state_down : 1;
		unsigned		f_button_state_over : 1;
		unsigned		f_button_state_up : 1;
		if(any f_button_state_... != 0) {
			unsigned short		f_button_id_ref;
			unsigned short		f_button_layer;
			swf_matrix		f_matrix;
			if(f_tag == DefineButton2) {
				swf_color_transform		f_color_transform;
			}
			if(f_button_filter_list) {
				unsigned char		f_filter_count;
				swf_any_filter		f_filter;
			}
			if(f_button_blend_mode) {
				unsigned char		f_blend_mode;
			}
		}
	};
swf_event
  An event is defined in a PlaceObject2 tag. It
  is a record of events terminated with a set of zero flags.
  Events are similar to conditions.
   	struct swf_event {
		char align;
		if(version >= 6) {
			unsigned	f_event_reserved : 13;
			if(version >= 7) {
				unsigned	f_event_construct : 1;
			}
			else {
				unsigned	f_event_reserved : 1;
			}
			unsigned	f_event_key_press : 1;
			unsigned	f_event_drag_out : 1;
			unsigned	f_event_drag_over : 1;
			unsigned	f_event_roll_out : 1;
			unsigned	f_event_roll_over : 1;
			unsigned	f_event_release_outside : 1;
			unsigned	f_event_release : 1;
			unsigned	f_event_press : 1;
			unsigned	f_event_initialize : 1;
		}
		else {
			unsigned	f_event_reserved : 7;
		}
		unsigned		f_event_data : 1;
		unsigned		f_event_key_up : 1;
		unsigned		f_event_key_down : 1;
		unsigned		f_event_mouse_up : 1;
		unsigned		f_event_mouse_down : 1;
		unsigned		f_event_mouse_move : 1;
		unsigned		f_event_unload : 1;
		unsigned		f_event_enter_frame : 1;
		unsigned		f_event_onload : 1;
		unsigned long		f_event_length;
		swf_action		f_action_record[variable];
	};
  Note: the number of actions is variable, the f_event_length parameter indicates
  the number of bytes and can be used to skip all the actions at once. The action
  array must always be terminated by an End action entry.
  swf_condition 
  A condition is defined in a DefineButton2
  tag. It is a record of conditions. The record terminates when the size of
  the current (i.e. last) condition is zero. The length of that condition
  can be deduced from the total size of the tag minus the offset where
  the condition starts.
  Conditions are similar to events.
   	struct swf_condition {
		unsigned short		f_condition_length;
		unsigned		f_condition_key : 7;
		unsigned		f_condition_menu_leave : 1;
		unsigned		f_condition_menu_enter : 1;
		unsigned		f_condition_pointer_release_ouside : 1;
		unsigned		f_condition_pointer_drag_enter : 1;
		unsigned		f_condition_pointer_drag_leave : 1;
		unsigned		f_condition_pointer_release_inside : 1;
		unsigned		f_condition_pointer_push : 1;
		unsigned		f_condition_pointer_leave : 1;
		unsigned		f_condition_pointer_enter : 1;
		swf_action		f_action_record[variable];
	};
  Note: the number of actions is variable, the f_condition_length
  parameter indicates the number of bytes and can be used to skip one
  condition and all of its actions at once. The action array must always
  be terminated by an End action entry (i.e
  0x00).
   
  The f_key field represents a key code since version 4. The following
  table gives the code equivalence. Note that 0 means no key.
   swf_external| 
      
        | Key Code | Name | Version |  
        | 0 (0x00) | No key activation | 3 |  
        | 1 (0x01) | Left Arrow | 4 |  
        | 2 (0x02) | Right Arrow | 4 |  
        | 3 (0x03) | Home | 4 |  
        | 4 (0x04) | End | 4 |  
        | 5 (0x05) | Insert | 4 |  
        | 6 (0x06) | Delete | 4 |  
        | 8 (0x08) | Backspace | 4 |  
        | 13 (0x0D) | Enter | 4 |  
        | 14 (0x0E) | Up Arrow | 4 |  
        | 15 (0x0F) | Down Arrow | 4 |  
        | 16 (0x10) | Page Up | 4 |  
        | 17 (0x11) | Page Down | 4 |  
        | 18 (0x12) | Tab | 4 |  
        | 19 (0x13) | Escape | 4 |  
        | 32-126 | The corresponding ASCII code | 4 |  | 
 
  An external reference is a per of entries: an identifier and a name.
  The name is called the external symbol and is used to match the
  necessary definitions between two movies using
  Export,
  Import and
  Import2
   	struct swf_external {
		unsigned short		f_object_id;
		string			f_symbol_name;
	};
swf_soundinfo
  Information on how to playback a sound effect. These are
  found in a StartSound and
  a DefineButtonSound.
   	struct swf_soundinfo {
		unsigned short		f_sound_id_ref;
		unsigned		f_reserved : 2;
		unsigned		f_stop_playback : 1;
		unsigned		f_no_multiple : 1;
		unsigned		f_has_envelope : 1;
		unsigned		f_has_loops : 1;
		unsigned		f_has_out_point : 1;
		unsigned		f_has_in_point : 1;
		if(f_has_in_point) {
			unsigned long	f_in_point;
		}
		if(f_has_out_point) {
			unsigned long	f_out_point;
		}
		if(f_has_loop_count) {
			unsigned short	f_loop_count;
		}
		if(f_has_envelope) {
			unsigned char	f_envelope_count;
			swf_envelope	f_envelope[f_envelope_count];
		}
	};
  The f_sound_id_ref is a reference to an earlier DefineSound
  tag.
   
  The f_stop_playback can be set to 1 in which case the sound
  stops as soon as the next ShowFrame is reached.
  All the other flags should be set to 0 when this one is 1.
   
  The f_no_multiple flag indicates whether the same sound effect
  can be played more than once at a time.
   
  The f_in/out_point indicate the start and end points where the
  sound should start playing and where it will end. f_in_point
  should always be smaller than f_out_point. By default,
  f_in_point is taken as being 0 and f_out_point is set
  to the f_sound_samples_count value.
   
  The f_loop_count defines the number of time the sound will
  be played back. I don't know yet whether there is a special value
  which means playback forever.
  swf_envelope 
  When playing back a sound effect it is possible to modulate the
  sound to generate different effects (such as a fade in and out).
  The following defines the stereo volume of the sound.
   	struct swf_envelope {
		unsigned long		f_position;
		unsigned short		f_volume_left;
		unsigned short		f_volume_right;
	};
  The position is always given as if the sample data was defined with
  a rate of 44100 bytes per seconds. For instance, the sample number 1
  in a sound effect with a sample rate of 5.5K is given as position
  8 in the envelope. All of these positions should be within the
  f_in_point and f_out_point.
   
  Mono sound should use the same value for the left and right volumes.
  Note that it will automatically be averaged if necessary.
   
  Note that the volume goes from 0 to 32768.
  swf_params 
  Since version 7 of SWF, there is a new way to create a function
  which allows you to not only name parameters but also to put
  their content in a register. This is done by specifying a
  register number along an (optional) parameter name.
   	struct swf_params {
		unsigned char		f_param_register;
		string			f_param_name;
	};
  The f_param_register specifies whether the corresponding parameter
  will be saved in a register (when it's not zero) or in a named variable
  or both.
   
  Note that the auto-generated variables (those defined by the "preload" flags
  to the Declare Function (V7))
  are also saved in registers. You have to make sure you save your own variables
  in registers that are not already in use by these system variables.
   
  The f_param_name string will be ignored whenever the
  f_param_register parameter is not zero. Otherwise, it is used to
  save the corresponding parameter in a variable of that name. Since up to
  255 registers can be used, it rarely will be necessary to save local
  variables in named variables.
  swf_zone_array 
  An array of alignment zones defines hints about glyphs defined in a
  DefineFont3.
   	struct swf_zone_array {
		unsigned char		f_zone_count;		/* always 2 in V8.0 */
		swf_zone_data		f_zone_data[f_zone_count];
		unsigned		f_zone_x : 1;		/* probably always 1 in V8.0 */
		unsigned		f_zone_y : 1;		/* probably always 1 in V8.0 */
		unsigned		f_reserved : 6;
	};
  The f_zone_count specifies how many zones are defined in a zone array.
  In version 8 of SWF, the count must be set to 2.
   
  The f_zone_data is an array of zones, each defining a position and a size.
   
  The f_zone_x and f_zone_y defines whether the horizontal and
  vertical positions and sizes are defined. At least one of these flag shall be
  set to 1. IMPORTANT NOTE: since in version 8 you must have 2 in f_zone_count,
  you most certainly need to set both of these flags to 1 in that version. In
  effect, all you can currently do is define one rectangle (zone).
  swf_zone_data 
  The swf_zone_array includes
  an array of zone data as described below:
   	struct swf_zone_data {
		short float		f_zone_position;
		short float		f_zone_size;
	};
  The f_zone_position specifies the X or Y coordinate.
  The array
  can either include only horizontal, only vertical or both sets of
  coordinates.
   
  The f_zone_size specifies the Width or Height of the zone.
   
 Appendix A — The geometry in SWF
    Coordinates
      
      The most common and simple geometric information are the
      object coordinates on the output screen. These are defined
      in TWIPs. There are 20 twips per pixels. Note that an embedded
      SWF file can be enlarged and/or reduced thus changing this
      basic scaling factor. To have exactly 20 twips per pixel you
      must ensure that the EMBED and/or OBJECT tags use a WIDTH and
      HEIGHT with exactly the same value as in the rectangle defined
      in the SWF header file divided by 20.
      The coordinates are defined from the top-left of the screen
      area to the bottom-right (x increases from the left to the
      right as expected; y increases from top to bottom as on most
      graphical devices on computers).
      The following shows you the coordinates system.
         Coordinates - Fig 1.
 
      Because one can use scaling and translations, the coordinates
      can easilly be inverted to have the y coordinates grow from
      bottom to top. However, to create your own player or generate
      proper SWF files, you need to know how the raw coordinates
      system works.
       
      There are limits to everything including coordinates. In order
      to enable all sorts of objects to be drawn, one should look
      at the result in a pixel environment (ie. as it will be drawn
      on the final screen). The idea of using TWIPs is to enable
      some interested people to zoom in (up to 20 times!) and still
      keep a high quality (this isn't true for images though).
      Matrix 
      The coordinates are often transformed with the use of a matrix.
      The matrix is similar to a transformation matrix in Postscript.
      It includes a set of scaling factors, rotation angles and
      translations.
       
      When only the scaling factors are used (no rotation) then these
      are ratios as one would expect. If a rotation is also applied,
      then the scaling ratios will be affected accordingly.
       
      The translations are in TWIPS like any coordinates and also
      they are applied last (thus, it represents the position at which
      the shape is drawn on the output screen).
       
      The math formula is as simple as: Q = MP + T. Q is the resulting
      point, P is the source point, M is the scaling and rotation
      factors and T is the final translation.
       
      With the use of a three dimensional set of matrices, one can
      compute a single matrix which includes all the transformations.
       | 
        
	  | T = |   Matrix - Fig 1.
 | The Tx and Ty are set as defined
	    in the SWF file. Tz can be set to zero. |  
	  | S = |   Matrix - Fig 2.
 | The Sx and Sy are set as defined
	    in the SWF file when no rotation are defined.
	    Sz is always set to 1. |  
	  | Rx = |   Matrix - Fig 3.
 | This matrix shows you a rotation over the X axis. This
	    is not necessary for the SWF format. |  
	  | Ry = |   Matrix - Fig 4.
 | This matrix shows you a rotation over the Y axis. This
	    is not necessary for the SWF format. |  
	  | Rz = |   Matrix - Fig 5.
 | This matrix shows you a rotation over the Z axis. This
	    is used by the SWF format. However, it is mixed with
	    the scaling factors. It is rare not to have a scaling
	    factor when a rotation is applied. |  | 
 
      Thus, the matrix saved in the SWF file is the product of the matrix in
      figure 2 and the matrix in figure 5.
         Matrix - Fig 6.
 
      A matrix multiplication is the sum of the products of rows (left
      matrix) and columns (right matrix).
       	m11 = s11 * r11 + s12 * r21 + s13 * r31 + s14 * r41
	m12 = s21 * r11 + s22 * r21 + s23 * r31 + s24 * r41
	m13 = s31 * r11 + s32 * r21 + s33 * r31 + s34 * r41
	m14 = s41 * r11 + s42 * r21 + s43 * r31 + s44 * r41
	m21 = s11 * r12 + s12 * r22 + s13 * r32 + s14 * r42
	m22 = s21 * r12 + s22 * r22 + s23 * r32 + s24 * r42
	m23 = s31 * r12 + s32 * r22 + s33 * r32 + s34 * r42
	m24 = s41 * r12 + s42 * r22 + s43 * r32 + s44 * r42
	m31 = s11 * r13 + s12 * r23 + s13 * r33 + s14 * r43
	m32 = s21 * r13 + s22 * r23 + s23 * r33 + s24 * r43
	m33 = s31 * r13 + s32 * r23 + s33 * r33 + s34 * r43
	m34 = s41 * r13 + s42 * r23 + s43 * r33 + s44 * r43
	m41 = s11 * r14 + s12 * r24 + s13 * r34 + s14 * r44
	m42 = s21 * r14 + s22 * r24 + s23 * r34 + s24 * r44
	m43 = s31 * r14 + s32 * r24 + s33 * r34 + s34 * r44
	m44 = s41 * r14 + s42 * r24 + s43 * r34 + s44 * r44
 
      Though you shouldn't need to find the scaling factors and rotation
      angle from an SWF matrix, it is possible to find one if you know
      the other. This is done using a multiplication of either the inverse
      scaling (use: 1/Sxand1/Syinstead ofSxandSyfor the scaling matrix) or the
      inverse rotation (use:-angleinstead ofanglein the Z rotation
      matrix). 
      For those who still wonder what I'm talking about, there are the
      four computations you need from a scaling factor and an angle in
      radiant:
       	SWFmatrix11 =  Sx * cos(angle)
	SWFmatrix12 =  Sy * sin(angle)
	SWFmatrix21 = -Sx * sin(angle)
	SWFmatrix22 =  Sy * cos(angle)
 
      EdgesSWFmatrix11andSWFmatrix22are saved in the
      (x, y) scale respectively and theSWFmatrix21andSWFmatrix12are the rotation skew0 and skew1 values
      respectively. 
      Edges are used to define a shape vector based and also coordinates
      where images need to be drawn. The edges are always coordinates
      from where ever your last point was to where ever you want the
      next point to be (a little like a turtle in LOGO).
       
      For vector based shapes to be placed anywhere in the screen and
      easilly transformed with matrices, you should always create them
      centered properly (i.e. the center of the shape should be placed
      whereever you think it is the most appropriate in order to enable
      easy rotations - i.e. in a cercle, the center of the circle should
      be selected and in a square the center of that square).
       
      The fill styles and line styles can all be used together. The
      line style is fairly easy to understand. There is a width in
      TWIPS and a color. When a filled shape is being drawn using a
      line style it is used to draw the borders of the shape.
      There can be one or two fill styles. They both are
      drawn one after another wherever an area has to be filled.
      The filling scheme is a very simple even-odd scheme (i.e.
      don't draw till first line being crossed, then draw till
      next line, then don't draw till next line, etc.)
         Fig 1. — Edges
 
      The edges are defined either as a straight line record (a set of
      (x, y) coordinates) or a curve record (two sets of (x, y)
      coordinates). These coordinates are not absolute. Instead these
      are added to the previous coordinates. This usually enables for
      much better compression since these numbers are always very
      small.
       
      The encoding even enables the definition of straight lines with
      the use of only the x or y offset for straight lines. Thus, if
      you create a square, with coordinates (-10,-10) and (+10,+10)
      you would define it as follow in SWF:
       
      |   |  | Move to (-10, -10) [a setup edge]
	Draw to +20 by x
	Draw to +20 by y
	Draw to -20 by x
	Draw to -20 by y
	End |  | Fig 2. — Edges |  |  
      The curves are simple B-splines defined by only three points (see
      Edges - Fig 3.):
       
	the starting point defined as the current position;the edge control point; it is the point which has
	    an effect on the shape of the curve;and the anchor point which is the ending point of the
	    curve; 
      Curves perfectly go through the starting and ending points which
      can therefore be perfectly continued by a straight line or another
      curve.
         Fig 3. — Edges
 
      A curve is defined as six curve segments Q3
      to Q8. These are defined by duplicating the
      starting and ending points four times each giving a set
      of points similar to [A, A, A, A, B, C, C, C, C].
      Edges - Fig. 4 shows the computation used to
      define each segment (i varying from 3 to 8).
      The parameter u can be given values from 0
      to 1. The number of values will depend on the
      precision you need to draw the resulting curve.
         Fig 4. — Edges
 
      Though the math can be simplified in the case of SWF (since we only
      have three points), the following shows you a simple C code that
      can be used to draw such a curve (this is a cubic spline rendering.)
       	struct point {
	double		x;
	double		y;
};
const double	Bmatrix[4][4] = {
	{ -1,  3, -3, 1 },
	{  3, -6,  3, 0 },
	{ -3,  0,  3, 0 },
	{  1,  4,  1, 0 }
};
void compute_point(double u, const struct point *input_points, struct point *result_point)
{
	double		Umatrix[4], Pmatrix[4][4], Imatrix[4], Rmatrix[4];
	/* compute the U factors */
	Umatrix[0] = u * u * u;
	Umatrix[1] = u * u;
	Umatrix[2] = u;
	Umatrix[3] = 1;
	/* because there is no Z it is set to zero */
	Pmatrix[0][0] = input_points[0].x;
	Pmatrix[0][1] = input_points[0].y;
	Pmatrix[0][2] = 0;
	Pmatrix[0][3] = 1;
	Pmatrix[1][0] = input_points[1].x;
	Pmatrix[1][1] = input_points[1].y;
	Pmatrix[1][2] = 0;
	Pmatrix[1][3] = 1;
	Pmatrix[2][0] = input_points[2].x;
	Pmatrix[2][1] = input_points[2].y;
	Pmatrix[2][2] = 0;
	Pmatrix[2][3] = 1;
	Pmatrix[3][0] = input_points[3].x;
	Pmatrix[3][1] = input_points[3].y;
	Pmatrix[3][2] = 0;
	Pmatrix[3][3] = 1;
	/* compute I = UB */
	Imatrix[0] =    Umatrix[0] * Bmatrix[0][0] +
			Umatrix[1] * Bmatrix[1][0] +
			Umatrix[2] * Bmatrix[2][0] +
			Umatrix[3] * Bmatrix[3][0];
	Imatrix[1] =    Umatrix[0] * Bmatrix[0][1] +
			Umatrix[1] * Bmatrix[1][1] +
			Umatrix[2] * Bmatrix[2][1] +
			Umatrix[3] * Bmatrix[3][1];
	Imatrix[2] =    Umatrix[0] * Bmatrix[0][2] +
			Umatrix[1] * Bmatrix[1][2] +
			Umatrix[2] * Bmatrix[2][2] +
			Umatrix[3] * Bmatrix[3][2];
	Imatrix[3] =    Umatrix[0] * Bmatrix[0][3] +
			Umatrix[1] * Bmatrix[1][3] +
			Umatrix[2] * Bmatrix[2][3] +
			Umatrix[3] * Bmatrix[3][3];
	/* I = I x 1/6 */
	Imatrix[0] /= 6.0;
	Imatrix[1] /= 6.0;
	Imatrix[2] /= 6.0;
	Imatrix[3] /= 6.0;
	/* R = IP */
	Rmatrix[0] =    Imatrix[0] * Pmatrix[0][0] +
			Imatrix[1] * Pmatrix[1][0] +
			Imatrix[2] * Pmatrix[2][0] +
			Imatrix[3] * Pmatrix[3][0];
	Rmatrix[1] =    Imatrix[0] * Pmatrix[0][1] +
			Imatrix[1] * Pmatrix[1][1] +
			Imatrix[2] * Pmatrix[2][1] +
			Imatrix[3] * Pmatrix[3][1];
	Rmatrix[2] =    Imatrix[0] * Pmatrix[0][2] +
			Imatrix[1] * Pmatrix[1][2] +
			Imatrix[2] * Pmatrix[2][2] +
			Imatrix[3] * Pmatrix[3][2];
	Rmatrix[3] =    Imatrix[0] * Pmatrix[0][3] +
			Imatrix[1] * Pmatrix[1][3] +
			Imatrix[2] * Pmatrix[2][3] +
			Imatrix[3] * Pmatrix[3][3];
	/* copy the result in user supplied result point */
	result_point[0].x = Rmatrix[0];
	result_point[0].y = Rmatrix[1];
}
void compute_curve(long repeat, const struct point *input_points, struct point *result_points)
{
	/* we assume that the input_points are the three points of interest
	   (namely: start, control and end) */
	/* we assume that the result_points is a large enough array to receive
	   the resulting points (depends on the repeat parameter) */
	struct point		*points[9];
	int			p, i;
	double			u;
	/* transform so compute_point() can easilly be used */
	points[0] = input_points[0];
	points[1] = input_points[0];
	points[2] = input_points[0];
	points[3] = input_points[0];
	points[4] = input_points[1];
	points[5] = input_points[2];
	points[6] = input_points[2];
	points[7] = input_points[2];
	points[8] = input_points[2];
	/* we could have a way to define the very first and last points without
	   calling the sub-function since these are equal to the input_points[0] and
	   input_points[2] respectively */
	for(p = 0, i = 0; i <= 5; i++) {
		for(u = 0.0; u < 1.0; u += 1.0 / repeat, p++) {
			compute_point(u, points + i, result_points + p);
		}
	}
}
      Any good C programmer will see many possible simplifications
      in the compute_pointcode. The two main simplications
      are theRmatrix[2]andRmatrix[3]which
      are not required (and therefore don't need to be computed). The
      division by 6 could be applied to the B matrix.Umatrix[3]being 1.0, it could be ignored in the
      computations. etc. etc. etc. 
      With 3 points, you can also use the following code that is a
      quadratic spline computation with only (x, y) coordinates.
       struct point {
        float x;
        float y;
};
point cp[3];
point *rp;
... // initialize the 3 points of an SWF curve
int LOD = 10; // number of segments per spline
for(int i = 0; i < LOD; i++, rp++) {
	float t = (float) i / (float) LOD;
	float it = 1.0f - t;
	// calculate blending factors
	float b0 = it * it;
	float b1 = 2 * it * t;
	float b2 = t * t;
	// calculate curve point
	rp->x = b0 * cp[0].x + b1 * cp[1].x + b2 * cp[2].x;
	rp->y = b0 * cp[0].y + b1 * cp[1].y + b2 * cp[2].y;
}
Gradient Fills
      It is possible in SWF to use gradient fills. The gradient definitions are
      pretty raw and require you to draw large objects (that you can scale down
      later if you wish). A radial fill will usually be used to draw a
      round corner or a big & smooth dot. A linear fill can be used to draw
      objects which go from one color to another. The linear fill goes from left
      to right by default. It can be rotation as required though. Yet, in either
      case what is drawn in the shape object needs to be at the right scale and
      in the right direction. This may not always prove easy to deal with!
       
      There are some additional technical information with the description of
      the gradient records.
      Images 
      When appropriate, images can also be included in SWF files. All the images
      can be full color and also have an alpha channel.
       
      In order to draw an image on the screen, it is necessary to use a fill style
      and a shape. Thus, you need at least three tags: TagLossless or TagJPEG,
      a DefineShape and a
      PlaceObject in order
      to draw an image on the screen. The fill
      style of the shape needs to include a matrix with a scale of 20x20 in
      order to draw the image at the original sizes. Also the rectangle used to
      draw around the image will use 20 twips per pixels of the image. Like
      with other shapes, if it is necessary to rotate the image by the center,
      then the shape will have to be defined with a MOVE to
      (width / -2.0, height / -2.0)and the image rectangle draw
      around the center. With edges, this means a set of positions
      such as: 
        Move to (width/-2, height/-2)+(width, 0)+(0, height)+(-width, 0)+(0, -height) 
      If you want to draw the image only once, you should make sure that the fill
      is of type clipped. A tilled image could be drawn multiple times.
       
      There is an example of a 640x480 image:
       
      Tag: DefineBitsLosslessObject ID: 1
 Format: 5 (32 bits ARGB)
 Bitmap sizes: 640x480
 
      Tag: DefineShapeObject ID: 2
 Rectangle: (0, 0) - (12800, 9600)
 Fill Style #1:
 Clipped Bitmap, ID: 1
 Matrix:
 Scale 20x20
 Translate: (-6400, -4800)
 Edges:
 Move (-6400, -4800)
 Use fill #1
 Delta (12800, 0)
 Delta (0, 9600)
 Delta (-12800, 0)
 Delta (0, -9600)
 
      Tag: PlaceObjectPlace Object: #2
 Depth: 1
 Matrix:
 Translate: (6400, 4800)
 
      Note that it is possible that one pixel will be missing
      using such values. It isn't rare to add 20 to the Edges
      deltas in order to include the missing pixel (this
      is mainly due to the computation of the anti-aliasing
      effect).
       
 Appendix B — History of this reference
  
    
      | June 23, 2007 | 
      Fixed the definition of the Join Style in swf_line_style.
       
      Fixed the definition of the gradient fill.
      The focal gradient does include a matrix as I was thinking it would.
       
      Added information about the miter limit factor of
      swf_line_style.
       
      Fixed the Add, Subtract and Difference encodings, as noted by Benjamin Otte,
      it was wrong in the Flash 8 documentation. A proper table is defined on Adobe
      website
      here.
      (link valid on Aug 15, 2007)
       
      Fixed the B-Spline matrix. 2nd column, 4th row was 3, the correct value is 4.
      This error was found by Michael Heyse who also offered a code snipet to compute
      the quadratic B-spline curve directly instead of using the cubic spline computation
      that I was offering.
       |  
      | October 14, 2006 | 
      Applied a fix to the FSCommand2
      description by Ammar Mardawi.
       
      Fixed the tag_showframe number which
      is 1, not 2. Noticed by Peter D.
       
      Fixed the swf_line_style the second
      f_no_hscale was supposed to be f_no_vscale.
       
      Fixed the String Length
      (multi-byte) instruction which is mbslen()and notwcslen(). 
      Fixed the information about the size saved in an
      swf_tag structure since some tags
      require you to ALWAYS save the tag with a long form even
      if the size is small. The Player will not display the image
      properly if you do not do so!
       
      Added the three DoAction3 tags.
       |  
      | September 30, 2006 | Complete review of the document to fix what was out of date such as
      the brief history and tags. I improved a bit on the look... (maybe not?!)
      I tried to include all of Version 8 information.
      I will need to tweak the version 8 information as
      I start testing (fixing swapped bytes, etc.) 
      In particular, I added the following tags from version 8:
      CSMTextSettings,
      DefineFont3,
      DefineFontAlignZones,
      DefineMorphShape2.
      DefineScalingGrid,
      DefineShape4,
      FileAttributes,
      Import2,
      Metadata and
      PlaceObject3.
       
      I added the missing
      JPEGTables and
      End tags.
       
      Also, I fixed and updated the following tags:
      DefineFont2,
      DefineFontInfo,
      DefineSprite and
      DefineVideoStream.
       
      Along the version 8 tags, I added their corresponding common
      structures and made changes to existing but extended structures
      such as:
      swf_any_fitler,
      swf_fill_style,
      swf_filter_blur,
      swf_filter_colormatrix,
      swf_filter_convolution,
      swf_filter_glow,
      swf_filter_type,
      swf_gradient,
      swf_line_style,
      swf_zone_array and
      swf_zone_data.
       
      I changed all the references from one object to another to use
      f_<name>_id_ref. This way you know whether it is a
      reference without having to read the information about that
      identifier.
       |  
      | December 8, 2005 | Added the PlaceObject3 definitions along the filters (filters need to
      be defined properly!). 
      Added the missing definition of the text field.
       
      Fixed a few things here and there.
       |  
      | October 10, 2005 | Some fixes to the size fields used by the DefineButton2. The last
      size field will be zero indicating that it is the last. This includes
      the field indicating the size of the buttons. |  
      | May 10, 2005 | Many changes to the Declare Function (V7)
      for clarification and some error fixes (i.e. it only supports 255 variables for
      parameters, I mentioned 256 in different places; the bits are defined on a short
      which means the bytes are swapped in the SWF files; I added the arguments
      as one of the internal parameters; I added some comments about how to load or
      generate these flags; better explanation for the preload vs. suppress flags). |  
      | March 25, 2005 | Fixed the name swf_protect
      pointed out by Benoit Perrot (thanks!). |  
      | January 18, 2005 | Fixed the text record information (swf_text_record) which
      changed with version 7. The change was pinpointed by Thatcher Ulrich (thanks!), the author
      of gameswf. |  
      | October 15, 2004 | Fixed the sound sample definition so it properly defines the samples as being signed. |  
      | October 03, 2004 | Added Declare Function (V7). 
	Added swf_params.
	 
	Added information about the 256 registers available in SWF version 7.
	 
	Ameliorated the Push Register Data documentation.
	 
	Added Extends (SWF version 7).
	 
	Added Throw (SWF version 7).
	 
	Added Try (SWF version 7).
	 
	Added Cast Object (SWF version 7).
	 
	Added Implements (SWF version 7).
	 
	Added ScriptLimits (SWF version 7).
	 
	Added SetTabIndex (SWF version 7).
	 |  
      | September 30, 2004 | Moved the geometry explainations at the end in Appendix A.
	If I ever decide to cut the file in parts, that would become a seperate part. |  
      | September 14, 2004 | Fixed the sample shown for the computation of the SWF coordinates. |  
      | July 17, 2004 | Fixed some English grammar. 
	Added a link back to the home page.
	 
	Added a warning about non-existant fonts on a system
	when referencing a system font from an
	swf_defineedittextobject. |  
      | February 20, 2004 | Fixed many points by adding a new line (it looks nicer). |  
      | June 07, 2003 | Fixed the tag_importto 57 instead of 56 (tag_export).
	(Special thanks to Thatcher Ulrich - http://tulrich.com.) |  
      | May 30, 2003 | Fixed the f_edit_indent&f_edit_leadingfrom
	unsigned short to signed short.
	(by Thatcher Ulrich - http://tulrich.com.) |  
      | December 6, 2002 | Added different sound tags and the corresponding common structures. 
	Added the DefineButtonSound tag.
	 |  
      | November 28, 2002 | Added the language entry in the DefineFont2 and DefineFontInfo
	tags. Added some other information about fonts. |  
      | October 30, 2002 | The DefineFont2 tag was fixed. It is necessary to have an
	extra offset which actually represents the total size of
	the glyphs. 
	Added the Color and Math objects.
	 
	Changed the limit on the number of entries in a dictionary
	from 256 to 65534 (not sure what 65535 may be used for).
	 
	Removed the 2nd instance of properties.
	 
	The PlaceObject2 describes the clipping mechanism available
	with it and which objects can be used to clip others.
	 
	Added the DoInitAction tag with complete definitions (V6.0)
	 
	Added the ProtectDebug[2] tags with complete definitions (V5.0 & V6.0)
	 
	Added the Export and Export tags with complete definitions (V5.0)
	 |  
      | October 10, 2002 | Fixed some information about several tags and actions. Added tag
	58 (Password?). |  
      | October 8, 2002 | Added tag 49 (comment about the generator of an SWF movie).
	Fixed some information about the property sets. |  
      | October 3, 2002 | Fixed the definition of the DefineEditText.
	It doesn't talk about the button anymore and includes what and how it works. |  
      | June 17, 2002 | Creation of this document based on the different documents available on the
	now extinct
	OpenSWF.org web site (it was mainly the SWF File Reference
	version 4 and 5.)
	And once the sswf tool started to work, on how the plugin would behave with the
	files generated by it. |  This document was last modified on Dec 27 2007. 
   
	Links:sswf
 Support by Made to Order Software
 
   |