/* libsswf.h -- written by Alexis WILKE for Made to Order Software, Ltd. (c) 2002-2005 */
#ifndef LIBSSWF_H
#define	LIBSSWF_H

/*

Copyright (c) 2002-2005 Made to Order Software, Ltd.

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.

*/



#include	<stdarg.h>
#include	<stdio.h>
#include	<stdlib.h>
#ifndef _MSVC
#include	<unistd.h>
#endif
#include	<string.h>
#include	<limits.h>
#include	<errno.h>
#include	<zlib.h>
#include	<math.h>
#include	<ctype.h>
#ifdef STATIC_ICONV
#include	<iconv.h.static>
#else
#include	<iconv.h>
#endif

#if IRIX
#include	<sys/endian.h>
#endif

#include	"sswf/libsswf-config.h"

/* wint_t is an "equivalent" to wchar_t without being limited to 16 bits as on MS-Windows */
#ifndef _MSVC
#ifndef __APPLE_CC__
#ifndef _WINT_T
#define _WINT_T
typedef unsigned int	wint_t;
#endif
#endif
#endif

#ifndef	M_PI
#define	M_PI		3.14159265358979323846
#endif


#ifdef _MSVC
#define	strcasecmp	stricmp
#define	rint(x)		((double) (long) floor(x + 0.5))
#endif

#ifdef _LIBICONV_H
#define	ICONV_INPUT_CAST
#else
/* older versions of iconv() were broken in regard to the
 * input buffer which wasn't const; newer versions have the
 * _LIBICONV_H #define at the start so this is good to know
 * whether we have to cast or not.
 */
#define	ICONV_INPUT_CAST	(char**)
#endif



namespace sswf {

void assert(int cond, const char *format, ...)
#ifndef _MSVC
			__attribute__ ((format (printf, 2, 3)))
#endif
		;


#if DEBUG
inline void assert(int cond, const char *format, ...)
{
	va_list		ap;

	// if the condition is true then we have no problem!
	if(cond) {
		return;
	}
	fflush(stdout);
	fflush(stderr);
	fprintf(stderr, "\n");
	va_start(ap, format);
	vfprintf(stderr, format, ap);
	va_end(ap);
	fprintf(stderr, ".\n");
	fflush(stderr);		// some systems don't do this inside the abort()!
	abort();
}
#else
inline void assert(int /*cond*/, const char * /*format*/, ...) {}
#endif


typedef	unsigned short		sswf_id_t;		// object ID reference
typedef	unsigned short		sswf_frame_t;		// frame counter
typedef	signed long		sswf_ucs4_t;		// a wide character (must be at least 32 bits)


#define	SSWF_ID_NONE		((sswf_id_t) -1)	// this is an invalid ID (it seems)


extern	void			swap(void *s1, void *s2, size_t size);
extern	int			wctomb(const sswf_ucs4_t *wc, size_t wc_len, char *mb, size_t& mb_size);
extern	int			mbtowc(const char *mb, size_t mb_len, sswf_ucs4_t *& wc, size_t& wc_len);
extern	char *			wcname(sswf_ucs4_t wc, char *result);
extern	long			wclen(sswf_ucs4_t *wcstr);

inline unsigned short		swap_short(unsigned short s)
				{
					return (s >> 8) | (s << 8);
				}

inline unsigned int		swap_int(unsigned int l)
				{
					return (l >> 24) | (l << 24)
						| ((l >> 8) & 0x0000FF00)
						| ((l << 8) & 0x00FF0000);
				}

extern	const char *		sswf_version(void);



class Buffer;
class MemBuffer {
public:
				MemBuffer(void);
	virtual			~MemBuffer();

	void			AttachBuffer(Buffer *buffer);
	Buffer *		GetBuffer(void) const;

private:
	Buffer *		f_buffer;
};


class Buffer {
public:
				Buffer(Buffer **head, size_t size, const char *info);
				Buffer(Buffer **head, MemBuffer *ptr, size_t size, const char *info);
				//Buffer(Buffer **head, void *ptr, size_t size, const char *info);
				~Buffer();

	void *			Realloc(size_t size);
	void *			Data(void) const { return f_data; }
	Buffer *		Next(void) const { return (Buffer *) f_next; }
	Buffer *		Previous(void) const { return (Buffer *) f_previous; }
	size_t			Size(void) const { return f_size; }
	const char *		Info(void) const { return f_info; }

	static Buffer *		FindBuffer(void *ptr);
#if 0
// this is totally wrong and it simply can't be used safely
	static bool		IsBuffer(void *ptr);
#endif

private:
	struct mem_buffer_t {
		unsigned long	f_magic;	// to make sure we have indead a valid buffer
		Buffer *	f_buffer;	// reference back to 'this' buffer
	};
	enum {
		DMAGIC = (unsigned long) 0x53535746,	// direct (malloc)
		OMAGIC = (unsigned long) 0x5353574F	// object (new/delete)
	};
#define	SSWF_ALIGN(value, modulo)	(((value) + ((modulo) - 1)) & - (long) (modulo))
#define	SSWF_SPACE			SSWF_ALIGN(sizeof(mem_buffer_t), sizeof(double))
#if DEBUG
	void				Test(void);
#define SSWF_SAFE			(sizeof(double) * 32)
#define	SSWF_TEST			((long)0xBADC0FFE)
#else
#define	SSWF_SAFE			0
#endif

	Buffer **		f_head;		// header for this list of buffers
	Buffer *		f_next;
	Buffer *		f_previous;
	const char *		f_info;
	size_t			f_size;
	mutable void *		f_data;
};


class MemoryManager {
public:
				MemoryManager(void);
	virtual			~MemoryManager();

	void			MemAttach(MemBuffer *ptr, size_t size, const char *info);	// used when you require the use of a ::new ... call
	void *			MemAlloc(size_t size, const char *info);
	void *			MemRealloc(void *ptr, size_t size, const char *info);	// info used ONLY if ptr == 0
	void			MemFree(void *ptr);
	void			MemClean(void *ptr);
	char *			StrDup(const char *string);
	char *			StrCat(const char *s1, const char *s2);
#if DEBUG
	void			MemTest(void *ptr);
#endif
	unsigned long		Size(void *ptr);

private:
	Buffer *		f_head;
};



class ItemBase : public MemBuffer
{
public:
				ItemBase(void) {}
	virtual			~ItemBase() {}
};


class Vectors : public MemoryManager, public MemBuffer
{
public:
				Vectors(void);
				Vectors(const Vectors& vector);
				~Vectors();

	ItemBase *		Get(int index) const;
	void			Set(int index, ItemBase *vector);
	void			Insert(int index, ItemBase *vector);
	void			SetSize(int size);
	int			Count(void) const { return f_count; }
	void			Empty(void) { f_count = 0; }	// currently we keep the f_vectors buffer

	Vectors&		operator = (const Vectors& vectors);

private:
	int			f_count;		// # of valid pointers
	int			f_max;			// max. # of pointers until realloc
	ItemBase **		f_vectors;		// an array of pointers
};







class Data : public MemoryManager {
public:
				Data(void);
				~Data();

	void			Empty(void) { f_pos = 0; }		// make the buffer empty (reset/restart)
	void			Align(void);				// align to the next byte
	void			Overwrite(size_t offset, const void *ptr, size_t size);
	void			OverwriteByte(size_t offset, char c);
	void			OverwriteShort(size_t offset, short s);
	void			OverwriteLong(size_t offset, long l);
	void			Write(const void *ptr, size_t size);	// write bytes
	void			WriteBits(long value, size_t bits);	// write the 'bits' lower bits of value
	void			PutByte(char c);			// write one byte
	void			PutShort(short s);			// write one short (auto-swap)
	void			PutLong(long l);			// write one long (auto-swap)
	void			PutString(const char *string);		// write a null terminated string (including the terminator)
	void			Append(const Data& data);		// append another data buffer in here

	void			Read(void *& ptr, size_t& size);	// retrieve the buffer and its size rounded up to the next byte (Align() is called once)
									// if you want the size in bits, use the Size() function call

	unsigned long		ByteSize(void) const { return (f_pos + CHAR_BIT - 1) / CHAR_BIT; }
	unsigned long		Size(void) const { return f_pos; }	// total size in bits
	void			Size(unsigned long size);

private:
	void			SetSize(size_t size);

	unsigned long		f_pos;
	unsigned long		f_size;
	char *			f_data;
};






// the following are structures used within the tags defined afterward
class SRectangle {
public:
				SRectangle(void);

	void			Reset(void);
	void			Set(long xmin, long xmax, long ymin, long ymax);
	void			SetReorder(long xmin, long xmax, long ymin, long ymax);
	long			XMin(void) const;
	long			XMax(void) const;
	long			YMin(void) const;
	long			YMax(void) const;
	bool			IsEmpty(void) const;

	void			Save(Data& data) const;

private:
	long			f_xmin;
	long			f_xmax;
	long			f_ymin;
	long			f_ymax;
};


class Color {
public:
				Color(void) { Reset(); }

	void			Reset(void);
	void			Set(unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha = 255);
	unsigned char		Red(void)   const { return f_red;   }
	unsigned char		Green(void) const { return f_green; }
	unsigned char		Blue(void)  const { return f_blue;  }
	unsigned char		Alpha(void) const { return f_alpha; }

	void			Save(Data& data, bool save_alpha = true);

	bool			operator == (const Color& color) const;
	bool			operator != (const Color& color) const;
	bool			IsSolid(void) const { return f_alpha == 255; }
	bool			IsInvisible(void) const { return f_alpha == 0; }

private:
	unsigned char		f_red;
	unsigned char		f_green;
	unsigned char		f_blue;
	unsigned char		f_alpha;
};



class ColorTransform {
public:
				ColorTransform(void) { Reset(); }

	void			Reset(void);
	void			SetAdd(double red, double green, double blue, double alpha = 0.0);
	void			SetMult(double red, double green, double blue, double alpha = 1.0);
	double			AddRed(void)    const { return f_add_red;   }
	double			AddGreen(void)  const { return f_add_green; }
	double			AddBlue(void)   const { return f_add_blue;  }
	double			AddAlpha(void)  const { return f_add_alpha; }
	double			MultRed(void)   const { return f_add_red;   }
	double			MultGreen(void) const { return f_add_green; }
	double			MultBlue(void)  const { return f_add_blue;  }
	double			MultAlpha(void) const { return f_add_alpha; }

	void			Save(Data& data, bool save_alpha = true);

	bool			IsNull(bool with_alpha) const;		// if true we can ignore this transformation!
	bool			IsSolidCompatible(void) const { return f_add_alpha == 0.0 && f_mult_alpha == 1.0; }

private:
	double			f_add_red;
	double			f_add_green;
	double			f_add_blue;
	double			f_add_alpha;
	double			f_mult_red;
	double			f_mult_green;
	double			f_mult_blue;
	double			f_mult_alpha;
};



class Matrix {
public:
				Matrix(void);

	void			Reset(void);
	void			SetScale(double x, double y) { f_scale_x = x; f_scale_y = y; }
	void			SetScale(double scale) { f_scale_x = scale; f_scale_y = scale; }
	void			SetRotate(double rotate);
	void			SetSkew(double skew0, double skew1) { f_skew_0 = skew0; f_skew_1 = skew1; }
	void			SetTranslate(long x, long y) { f_translate_x = x; f_translate_y = y; }

	void			Save(Data& data);

	bool			IsNull(void) const;
	bool			operator == (const Matrix& matrix) const;
	bool			operator != (const Matrix& matrix) const;

private:
	double			f_scale_x;
	double			f_scale_y;
	double			f_rotate;
	long			f_translate_x;
	long			f_translate_y;
	double			f_skew_0;
	double			f_skew_1;
};



class Envelope : public ItemBase {
public:
				Envelope(unsigned long p, unsigned short l, unsigned short r);
				Envelope(const Envelope& envelope);

	unsigned long		Position(void) const;
	unsigned short		Left(void) const;
	unsigned short		Right(void) const;
	void			Save(Data& data) const;

private:
	unsigned long		f_position;
	unsigned short		f_left;
	unsigned short		f_right;
};


class SoundInfo : public MemoryManager {
public:
				SoundInfo(void);

	void			SetSoundID(sswf_id_t id);
	void			StopSound(bool stop = true);
	void			NoMultiple(bool no_multiple = true);
	void			SetRange(unsigned long start, unsigned long end);
	void			SetLoop(unsigned short loop);
	void			AddEnvelope(const Envelope& envelope);

	void			Save(Data& data) const;

private:
	sswf_id_t		f_sound_id;
	bool			f_stop;			// if true, ignore all the other info
	bool			f_no_multiple;		// never play this sound more than once
	unsigned long		f_start_position;	// start playing from this sample
	unsigned long		f_end_position;		// stop playing at this sample
	unsigned short		f_loop;			// repeat the sound this many times
	Vectors			f_envelopes;		// a list of position + volume information
};



class State : public ItemBase {
public:
				State(void);

	void			Reset(void);
	void			SetObjectID(sswf_id_t id);
	void			SetFlags(unsigned char flags);
	void			SetLayer(unsigned short layer);
	void			SetMatrix(const Matrix& matrix);
	void			SetColorTransform(const ColorTransform& color_transform);
	bool			HasColorTransform(void) const;
	void			Save(Data& data, bool color_transform = false);

private:
	sswf_id_t		f_id;
	bool			f_id_defined;
	bool			f_has_color_transform;
	unsigned char		f_flags;
	unsigned short		f_layer;
	Matrix			f_matrix;
	ColorTransform		f_color_transform;
};





class Action;
class Event : public MemoryManager, public ItemBase {
public:
				Event(void);

	void			Reset(void);
	void			SetEvents(unsigned long events);
	void			SetKey(unsigned char key);
	unsigned long		Events(void) const;	// PlaceObject2 flags
	unsigned long		Conditions(void) const;	// DefineButton2 flags
	unsigned char		Key(void) const;
	Vectors&		Actions(void);

	static unsigned long	StringToEvents(const char *s);
	static unsigned char	StringToKeyCode(const char *s);

	// the flags are saved with the following bits
	// in a PlaceObject2
	// these have to be converted when saved in a
	// DefineButton2 tag
	enum event_flag_t {
		EVENT_COND_MENU_LEAVE		= 0x80000000,	// for DefineButton2
		EVENT_COND_MENU_ENTER		= 0x40000000,	// for DefineButton2

		EVENT_KEY_PRESS			= 0x00020000,	// V6.x
		EVENT_POINTER_DRAG_LEAVE	= 0x00010000,	// V6.x
		EVENT_POINTER_DRAG_ENTER	= 0x00008000,	// V5.x
		EVENT_POINTER_LEAVE		= 0x00004000,	// V5.x
		EVENT_POINTER_ENTER		= 0x00002000,	// V5.x
		EVENT_POINTER_RELEASE_OUTSIDE	= 0x00001000,	// V5.x
		EVENT_POINTER_RELEASE_INSIDE	= 0x00000800,	// V5.x
		EVENT_POINTER_PUSH		= 0x00000400,	// V5.x
		EVENT_INITIALIZE		= 0x00000200,	// V5.x
		EVENT_DATA			= 0x00000100,	// V5.x
		EVENT_KEY_UP			= 0x00000080,	// V6.x
		EVENT_KEY_DOWN			= 0x00000040,	// V6.x
		EVENT_POINTER_UP		= 0x00000020,	// V6.x
		EVENT_POINTER_DOWN		= 0x00000010,	// V6.x
		EVENT_POINTER_MOVE		= 0x00000008,	// V6.x
		EVENT_UNLOAD			= 0x00000004,	// V6.x
		EVENT_ENTER_FRAME		= 0x00000002,	// V6.x
		EVENT_ONLOAD			= 0x00000001	// V5.x
	};
#define	SSWF_EVENT_V5			0x0000FF01	// flags present in V5
#define	SSWF_EVENT_V6			0x000300FE	// flags added in V6
#define	SSWF_EVENT_COUNT		20
	struct event_names_t {
		event_flag_t		f_flag;
		const char *		f_name;
	};
	static const event_names_t	f_event_names[SSWF_EVENT_COUNT];

	enum condition_flag_t {
		CONDITION_KEY_MASK			= 0xFE00,
		CONDITION_MENU_LEAVE			= 0x0100,	// OVER_DOWN_TO_IDLE
		CONDITION_MENU_ENTER			= 0x0080,	// IDLE_TO_OVER_DOWN
		CONDITION_POINTER_RELEASE_OUTSIDE	= 0x0040,	// OUT_DOWN_TO_IDLE
		CONDITION_POINTER_DRAG_ENTER		= 0x0020,	// OUT_DOWN_TO_OVER_DOWN
		CONDITION_POINTER_DRAG_LEAVE		= 0x0010,	// OVER_DOWN_TO_OUT_DOWN
		CONDITION_POINTER_RELEASE_INSIDE	= 0x0008,	// OVER_DOWN_TO_OVER_UP
		CONDITION_POINTER_PUSH			= 0x0004,	// OVER_UP_TO_OVER_DOWN
		CONDITION_POINTER_LEAVE			= 0x0002,	// OVER_UP_TO_IDLE
		CONDITION_POINTER_ENTER			= 0x0001	// IDLE_TO_OVER_UP
	};

	enum key_code_t {
		KEY_CODE_NONE = 0,
		KEY_CODE_LEFT_ARROW = 1,
		KEY_CODE_RIGHT_ARROW = 2,
		KEY_CODE_HOME = 3,
		KEY_CODE_END = 4,
		KEY_CODE_INSERT = 5,
		KEY_CODE_DELETE = 6,
		KEY_CODE_BACKSPACE = 8,
		KEY_CODE_ENTER = 13,
		KEY_CODE_UP_ARROW = 14,
		KEY_CODE_DOWN_ARROW = 15,
		KEY_CODE_PAGE_UP = 16,
		KEY_CODE_PAGE_DOWN = 17,
		KEY_CODE_TAB = 18,
		KEY_CODE_ESCAPE = 19,
		KEY_CODE_SPACE = 20,		// equal to ' '
		// and also all the ASCII codes from 32 to 126
	};
#define	SSWF_KEY_COUNT			15
	struct key_names_t {
		key_code_t		f_code;
		const char *		f_name;
	};
	static const key_names_t	f_key_names[SSWF_KEY_COUNT];

private:
	unsigned long		f_events;
	unsigned char		f_key;
	Vectors			f_actions;
};





class Style : public ItemBase {
public:
	enum style_t {
		STYLE_TYPE_UNKNOWN = 0,
		STYLE_TYPE_NO_LINE,
		STYLE_TYPE_NO_FILL,
		STYLE_TYPE_LINE,
		STYLE_TYPE_SOLID,
		STYLE_TYPE_GRADIENT_LINEAR,
		STYLE_TYPE_GRADIENT_RADIAL,
		STYLE_TYPE_BITMAP_TILLED,
		STYLE_TYPE_BITMAP_CLIPPED,
		STYLE_TYPE_BITMAP_HARDEDGE_TILLED,
		STYLE_TYPE_BITMAP_HARDEDGE_CLIPPED,

		STYLE_TYPE_MATRIX,		// intermediate type used when a matrix is defined before
						// a gradient or bitmap info (or the SetType() is called)

		STYLE_TYPE_max
	};

				Style(void);

	void			Reset(void);
	style_t			Type(void) const { return f_style; }
	bool			HasMorph(void) const { return f_morph; }
	bool			HasAlpha(void) const { return f_use_alpha; }
	bool			HasHardEdges(void) const { return f_style == STYLE_TYPE_BITMAP_HARDEDGE_TILLED
								|| f_style == STYLE_TYPE_BITMAP_HARDEDGE_CLIPPED; }
	void			SetType(style_t style);
	void			SetLine(int index, unsigned short width, const Color& color);
	void			SetColor(int index, const Color& color);
	void			SetGradient(int index, int pos, const Color& color);
	void			SetMatrix(int index, const Matrix& matrix);
	void			SetBitmap(sswf_id_t id);
	void			SetClipping(void);

	void			Save(Data& data, bool save_alpha, bool save_morph);
	bool			operator == (const Style& style) const;

private:
	// the style
	style_t			f_style;

	// whether this is for a DefineMorphShape or not
	bool			f_morph;

	// whether some color alpha is not 255
	bool			f_use_alpha;

	// a line width
	unsigned short		f_line_width[2];

	// solid fill or line colors
	Color			f_color[2];

	// bitmap reference (its ID)
	sswf_id_t		f_bitmap_ref;

	// matrices - 1 or 2 - regular of morph shapes
	Matrix			f_matrix[2];

	// gradient positions & colors - 8 or 16 - regular or morph shapes
	signed char		f_gradient;		// largest index used (0..7 only or -1 when no gradient)
	unsigned char		f_gradient_pos[16];
	Color			f_gradient_color[16];
};





class Edges : public MemoryManager, public ItemBase {
public:
	// This should be private by cl (from Microsoft) doesn't understand
	// the use of private too well...
	enum {
		// better with a power of two (we use * and / a lot with it!)
		EDGE_BLOCK = 64
	};

	struct edge_t {
		long		f_x;
		long		f_y;
		long		f_ctrl_x;		/* LONG_MIN if a line only */
		long		f_ctrl_y;

				edge_t(void)
				{
					f_x = 0;
					f_y = 0;
					f_ctrl_x = LONG_MIN;
					f_ctrl_y = LONG_MIN;
				}
				edge_t(long x, long y)
				{
					f_x = x;
					f_y = y;
					f_ctrl_x = LONG_MIN;
					f_ctrl_y = LONG_MIN;
				}
				edge_t(long x, long y, long ctrl_x, long ctrl_y)
				{
					f_x = x;
					f_y = y;
					f_ctrl_x = ctrl_x;
					f_ctrl_y = ctrl_y;
				}
				edge_t(const edge_t& edge)
				{
					f_x = edge.f_x;
					f_y = edge.f_y;
					f_ctrl_x = edge.f_ctrl_x;
					f_ctrl_y = edge.f_ctrl_y;
				}
		edge_t&		operator = (const edge_t& edge)
				{
					f_x = edge.f_x;
					f_y = edge.f_y;
					f_ctrl_x = edge.f_ctrl_x;
					f_ctrl_y = edge.f_ctrl_y;
					return *this;
				}
		bool		IsLine(void) const { return f_ctrl_x == LONG_MIN || f_ctrl_y == LONG_MIN; }
	};

				Edges(void);
	virtual			~Edges() {}

	void			Reset(void);
	void			Set(long x, long y) { edge_t edge(x, y); Set(-1, edge); }
	void			Set(long x, long y, long ctrl_x, long ctrl_y) { edge_t edge(x, y, ctrl_x, ctrl_y); Set(-1, edge); }
	void			Set(int index, long x, long y, long ctrl_x, long ctrl_y) { edge_t edge(x, y, ctrl_x, ctrl_y); Set(index, edge); }
	void			Set(const edge_t& edge) { Set(-1, edge); }
	void			Set(int index, const edge_t& edge);

	void			Save(Data& data, long& x, long& y);

private:
	struct array_edge_t : public ItemBase {
		edge_t		f_edge[EDGE_BLOCK];
	};

				// no copy operators at this time
				Edges(const Edges& edges) {}
	Edges&			operator = (const Edges& edges) { return *this; }

	void			SaveEdge(Data& data, const edge_t& edge, long& x, long& y);

	Vectors			f_edges;
	int			f_pos;		/* position in the current array */
	array_edge_t		f_array;	/* current array; when full, put in f_edges */
};







// one can't create a tag base, only full qualified
// tags can be created (see below)
class TagHeader;
class TagBase : public MemoryManager
{
public:
	// anything in the file is represented by a tag
	enum swf_tag_t {
		SWF_TAG_UNKNOWN = -1,		// undefined tag

		// V1.0
		SWF_TAG_END = 0,		// mark the end of the flash script
		SWF_TAG_SHOW_FRAME = 1,		// show the current frame
		SWF_TAG_DEFINE_SHAPE = 2,	// define a vector based shape
		SWF_TAG_PLACE_OBJECT = 4,	// place an object in the current frame
		SWF_TAG_REMOVE_OBJECT = 5,	// remove specified object
		SWF_TAG_DEFINE_BITS = 6,	// JPEG data bit stream
		SWF_TAG_DEFINE_BUTTON = 7,	// define an action button
		SWF_TAG_JPEG_TABLES = 8,	// define the JPEG tables
		SWF_TAG_SET_BACKGROUND_COLOR = 9,	// define the RGB color for the background
		SWF_TAG_DEFINE_FONT = 10,	// links a list of shapes to characters
		SWF_TAG_DEFINE_TEXT = 11,	// define a text to be printed with a font
		SWF_TAG_DO_ACTION = 12,		// action to perform in this frame
		SWF_TAG_DEFINE_FONT_INFO = 13,	// font metrics

		// V2.0
		SWF_TAG_DEFINE_SOUND = 14,	// define how a sound effect will be played
		SWF_TAG_START_SOUND = 15,	// start playing a sound effect
		SWF_TAG_DEFINE_BUTTON_SOUND = 17,	// sound effects attached to a button
		SWF_TAG_SOUND_STREAM_HEAD = 18,	// define how a sound effect will be loaded & played
		SWF_TAG_SOUND_STREAM_BLOCK = 19,// actual sound samples to play (embedded with the rest)
		SWF_TAG_DEFINE_BITS_LOSSLESS = 20,	// a loss less compressed image
		SWF_TAG_DEFINE_BITS_JPEG2 = 21,	// a complete JPEG definition
		SWF_TAG_DEFINE_SHAPE2 = 22,	// define a shape including large number of styles
		SWF_TAG_DEFINE_BUTTON_COLOR_TRANSFORM = 23,	// how a button changes color
		SWF_TAG_PROTECT = 24,		// whether the resulting file is protected against editing

		// V3.0
		SWF_TAG_PLACE_OBJECT2 = 26,	// extended place
		SWF_TAG_REMOVE_OBJECT2 = 28,	// simplified remove
		SWF_TAG_DEFINE_SHAPE3 = 32,	// define a shape including RGBA colors
		SWF_TAG_DEFINE_TEXT2 = 33,	// define a text to draw including RGBA colors
		SWF_TAG_DEFINE_BUTTON2 = 34,	// define an action button with RGBA colors and color transformation
		SWF_TAG_DEFINE_BITS_JPEG3 = 35,	// define two JPEG images, one RGB and one GREY used as the alpha channel
		SWF_TAG_DEFINE_BITS_LOSSLESS2 = 36,	// define a loss less image with an alpha channel
		SWF_TAG_DEFINE_SPRITE = 39,	// define a movie as an object to play in another movie
		SWF_TAG_FRAME_LABEL = 43,	// name a place holder in the movie
		SWF_TAG_SOUND_STREAM_HEAD2 = 45,// define a sound effect with more details for embedded playing
		SWF_TAG_DEFINE_MORPH_SHAPE = 46,// define a shape which can easilly be changed with a position
		SWF_TAG_DEFINE_FONT2 = 48,	// define a set of fonts
		SWF_TAG_DEFINE_INFO = 49,	// define a comment about the generator, etc.

		// V4.0
		SWF_TAG_TEXT_FIELD = 37,	// define an area with text which can be edited

		// V5.0
		SWF_TAG_EXPORT = 56,		// export a set of definitions to other files
		SWF_TAG_IMPORT = 57,		// look for definitions from another file
		SWF_TAG_PROTECT_DEBUG = 58,	// a password to protect debugging of flash movies -- use only in V5.x movies

		// V6.0
		SWF_TAG_DO_INIT_ACTION = 59,	// action to perform once on specified sprite in this frame
		SWF_TAG_DEFINE_FONT_INFO2 = 62,	// font metrics including language reference
		SWF_TAG_PROTECT_DEBUG2 = 64,	// a password to protect debugging of flash movies

		// V7.0
		SWF_TAG_SCRIPT_LIMITS = 65,	// the recursive depth and script timeout parameters
		SWF_TAG_SET_TAB_INDEX = 66,	// the depth of an object to be set at the given index (next/previous Tab key positioning)

		SWF_TAG_max		// just end this list really
	};
	typedef long		swf_type_t;

#define	SWF_TYPE_DEFINE		0x00000001	// a definition tag, must be in the main movie
#define	SWF_TYPE_CONTROL	0x00000002	// a control tag, can be in sprites as well
#define	SWF_TYPE_UNIQUE		0x00000004	// a unique tag, can't be duplicated in the movie (merge if possible)
#define	SWF_TYPE_START		0x00000008	// if present, put it near the start of the movie
#define	SWF_TYPE_ONE		0x00000010	// (should) use at most one per frame
#define	SWF_TYPE_REFERENCE	0x00000020	// object includes references to other objects
#define	SWF_TYPE_HAS_ID		0x00000040	// this object was derived from TagBaseID and has an ID

#define	SWF_TYPE_SCRIPT		0x20000000	// object can accept action scripts
#define	SWF_TYPE_SPRITE		0x40000000	// this is a sprite (can include other tags)
#define	SWF_TYPE_HEADER		0x80000000	// the header

	virtual			~TagBase();

	virtual int		Save(Data& data) = 0;	// print out a tag in a Data buffer
	int			SaveString(Data& data, const char *string);

	static int		SaveTag(Data& data, swf_tag_t tag, size_t size);
	static long		SIBitSize(long value);		// return the number of bits necessary to represent a signed integer
	static long		UIBitSize(unsigned long value);	// return the number of bits necessary to represent an unsigned integer
	static long		Double2Signed(double value);	// return a valid fixed value 16.16 bits from a double
	static double		Signed2Double(long value);	// return a valid double from a fixed value 16.16 bits

	virtual void		MinimumVersion(unsigned char version);
	virtual unsigned char	Version(void) const;
	virtual swf_type_t	TypeFlags(void) const = 0;

	const char *		Name(void) const;	// return the name (type) of this tag
	const char *		Label(void) const;
	void			ResetFrames(void);
	void			ShowFrame(void);
	sswf_frame_t		FrameCount(void) const;

	sswf_frame_t		WhichFrame(void) const;
	void			SetLabel(const char *label);
	TagBase *		FindLabelledTag(const char *label) const;
	TagBase *		FindTagWithID(sswf_id_t id, bool search_import = true) const;
	TagBase *		Children(void);
	TagBase *		Next(void);
	TagBase *		Previous(void);
	TagBase *		Parent(void);
	TagHeader *		Header(void) const;

	void *			f_userdata;		// anything you feel necessary!

protected:
				// only sub-classes can create a TagBase
				TagBase(const char *name, TagBase *parent);
	virtual int		PreSave(void);		// called by the header Save() function
	virtual int		PreSave2ndPass(void);	// called by the header Save() function after all the PreSave() were called

private:
	TagBase *		FindLabel(const TagBase *p, const char *label) const;
	TagBase *		FindID(const TagBase *p, sswf_id_t id, bool search_import) const;

	const char *		f_name;
	char *			f_label;

	TagBase *		f_parent;
	TagBase *		f_next;
	TagBase *		f_previous;
	TagBase *		f_children;

	sswf_frame_t		f_frames;		// total number of frames
};






/********************* TAGS WITHOUT IDs (possibly references though) ****/
class TagHeader : public TagBase
{
public:
				TagHeader(void);
	virtual			~TagHeader();

	virtual int		Save(Data& data);
	int			SaveEncodedString(Data& data, const char *string);
	virtual swf_type_t	TypeFlags(void) const;

	sswf_id_t		NextID(void);
	void			RemoveID(sswf_id_t id);

/////////////// SETUP FUNCTIONS
	virtual void		MinimumVersion(unsigned char version);
	virtual unsigned char	Version(void) const;
	void			SetVersion(unsigned char version);
	int			DefineMinimumVersion(void);

	void			SetAutoOrder(bool auto_order = true);
	void			SetCompress(bool compress = true);
	void			SetFrame(const SRectangle& rect);
	const SRectangle&	Frame(void) const;

	void			SetOutputEncoding(const char *encoding);
	void			SetRate(float rate);
	float			Rate(void) const;

private:
	// NOTE: use 0 to get a default version (a version computed from the options used)
	unsigned char		f_version;		// file version (0 to 7 at time of writing)
	unsigned char		f_min_version;		// once the whole file was saved, this is the minimum version we need to use
	SRectangle		f_frame;		// the frame rectangle
	float			f_rate;			// frames per second (8.8 fixed number in file)
	bool			f_compress;		// compress the resulting movie (v6.x upward)
	bool			f_auto_order;		// automatically order definition tags (discard unused definitions also)
	sswf_id_t		f_next_id;		// returned and then increased when NextID() is called
	char *			f_output_encoding;	// encoding used prior V6.x SWF files
	bool			f_iconvertor_open;	// whether the f_iconvertor is a valid descriptor
	iconv_t			f_iconvertor;		// to convert strings from U18N to user specified encoding
#if DEBUG
	bool			f_saving;		// if true the f_min_version can't be changed ever anymore
#endif
};






class ActionLabel;
class Action : public ItemBase
{
public:
	enum action_t {
		ACTION_UNKNOWN			= -1,	/* unknown action (invalid) */
		ACTION_LABEL			= -2,	/* used to mark a position within the actions */
		ACTION_min			= 0x00,	/* the minimum action number */

		/* all the valid Flash actions */
		ACTION_END			= 0x00,	/* this is automatically added by the higher level Save()'s */
		ACTION_NEXT_FRAME		= 0x04,
		ACTION_PREVIOUS_FRAME		= 0x05,
		ACTION_PLAY			= 0x06,
		ACTION_STOP			= 0x07,
		ACTION_TOGGLE_QUALITY		= 0x08,
		ACTION_STOP_SOUND		= 0x09,
		ACTION_ADD			= 0x0A,
		ACTION_SUBSTRACT		= 0x0B,	/* this is the wrong spelling */
		ACTION_SUBTRACT			= 0x0B,
		ACTION_MULTIPLY			= 0x0C,
		ACTION_DIVIDE			= 0x0D,
		ACTION_EQUAL			= 0x0E,
		ACTION_LESS_THAN		= 0x0F,
		ACTION_LOGICAL_AND		= 0x10,
		ACTION_LOGICAL_OR		= 0x11,
		ACTION_LOGICAL_NOT		= 0x12,
		ACTION_STRING_EQUAL		= 0x13,
		ACTION_STRING_LENGTH		= 0x14,
		ACTION_SUB_STRING		= 0x15,
		ACTION_POP			= 0x17,
		ACTION_INTEGRAL_PART		= 0x18,
		ACTION_GET_VARIABLE		= 0x1C,
		ACTION_SET_VARIABLE		= 0x1D,
		ACTION_SET_TARGET2		= 0x20,
		ACTION_CONCATENATE		= 0x21,
		ACTION_GET_PROPERTY		= 0x22,
		ACTION_SET_PROPERTY		= 0x23,
		ACTION_DUPLICATE_SPRITE		= 0x24,
		ACTION_REMOVE_SPRITE		= 0x25,
		ACTION_TRACE			= 0x26,
		ACTION_START_DRAG		= 0x27,
		ACTION_STOP_DRAG		= 0x28,
		ACTION_STRING_LESS_THAN		= 0x29,
		ACTION_THROW			= 0x2A,
		ACTION_CAST_OBJECT		= 0x2B,
		ACTION_IMPLEMENTS		= 0x2C,
		ACTION_RANDOM			= 0x30,
		ACTION_MBSTRING_LENGTH		= 0x31,
		ACTION_ORD			= 0x32,
		ACTION_CHR			= 0x33,
		ACTION_GET_TIMER		= 0x34,
		ACTION_SUB_MBSTRING		= 0x35,
		ACTION_MBORD			= 0x36,
		ACTION_MBCHR			= 0x37,
		ACTION_DELETE			= 0x3A,
		ACTION_SET_LOCAL_VAR		= 0x3C,
		ACTION_SET_LOCAL_VARIABLE	= 0x3C,
		ACTION_CALL_FUNCTION		= 0x3D,
		ACTION_RETURN			= 0x3E,
		ACTION_MODULO			= 0x3F,
		ACTION_NEW			= 0x40,
		ACTION_DECLARE_LOCAL_VAR	= 0x41,
		ACTION_DECLARE_LOCAL_VARIABLE	= 0x41,
		ACTION_DECLARE_ARRAY		= 0x42,
		ACTION_DECLARE_OBJECT		= 0x43,
		ACTION_TYPE_OF			= 0x44,
		ACTION_GET_TARGET		= 0x45,
		ACTION_ENUMERATE		= 0x46,
		ACTION_ADD_TYPED		= 0x47,
		ACTION_LESS_THAN_TYPED		= 0x48,
		ACTION_EQUAL_TYPED		= 0x49,
		ACTION_NUMBER			= 0x4A,
		ACTION_STRING			= 0x4B,
		ACTION_DUPLICATE		= 0x4C,
		ACTION_SWAP			= 0x4D,
		ACTION_GET_MEMBER		= 0x4E,
		ACTION_SET_MEMBER		= 0x4F,
		ACTION_INCREMENT		= 0x50,
		ACTION_DECREMENT		= 0x51,
		ACTION_CALL_METHOD		= 0x52,
		ACTION_NEW_METHOD		= 0x53,
		ACTION_INSTANCE_OF		= 0x54,
		ACTION_ENUMERATE_OBJECT		= 0x55,
		ACTION_AND			= 0x60,
		ACTION_OR			= 0x61,
		ACTION_XOR			= 0x62,
		ACTION_SHIFT_LEFT		= 0x63,
		ACTION_SHIFT_RIGHT		= 0x64,
		ACTION_SHIFT_RIGHT_UNSIGNED	= 0x65,
		ACTION_STRICT_EQUAL		= 0x66,
		ACTION_GREATER_THAN_TYPED	= 0x67,
		ACTION_STRING_GREATER_THAN	= 0x68,
		ACTION_EXTENDS			= 0x69,
		ACTION_GOTO_FRAME		= 0x81,
		ACTION_URL			= 0x83,
		ACTION_STORE_REGISTER		= 0x87,
		ACTION_DECLARE_DICTIONARY	= 0x88,
		ACTION_WAIT_FOR_FRAME		= 0x8A,
		ACTION_SET_TARGET		= 0x8B,
		ACTION_GOTO_LABEL		= 0x8C,
		ACTION_WAIT_FOR_FRAME2		= 0x8D,
		ACTION_DECLARE_FUNCTION2	= 0x8E,
		ACTION_TRY			= 0x8F,
		ACTION_WITH			= 0x94,
		ACTION_PUSH_DATA		= 0x96,
		ACTION_BRANCH_ALWAYS		= 0x99,
		ACTION_URL2			= 0x9A,
		ACTION_DECLARE_FUNCTION		= 0x9B,
		ACTION_BRANCH_IF_TRUE		= 0x9D,
		ACTION_CALL_FRAME		= 0x9E,
		ACTION_GOTO_EXPRESSION		= 0x9F,

		ACTION_max		= 0xFF		/* the maximum action number */
	};

				Action(TagBase *tag, action_t action);
	virtual			~Action() {}

	virtual Action *	Duplicate(void) const;
	unsigned long		Offset(void) const { return f_offset; }
	virtual unsigned char	Version(void) const { return f_min_version; }

	void			Save(Data& data);
	virtual Vectors *	SubList(void);
	static int		SaveList(TagBase *parent, const Vectors *list, Data& data, const Vectors *extra = 0);
	static int		MinimumListVersion(const Vectors& list);
	static int		GetMaximumRegister(const Vectors& list);
	static ActionLabel *	FindLabel(const Vectors& list, const char *label);

protected:
	virtual void		SaveData(Data& data, Data& nested_data);
	virtual void		Save2ndPass(const Vectors& list, Data& data);
	virtual int		GetMaxRegister(void) const { return 0; }
	int			SaveString(Data& data, const char *string);
	TagBase *		Tag(void) const { return const_cast<TagBase *>(f_tag); }

	const action_t		f_action;
	unsigned long		f_offset;		/* offset where this tag is being saved (saved for branches and with statments) */
	unsigned long		f_index;		/* this action index in the list of actions */

private:
#if DEBUG
	/*
	 * Forbid copies (only in DEBUG mode so we don't have extra functions
	 * for nothing otherwise) If you need a copy, use the Duplicate() instead
	 */
				Action(const Action& action);
	Action&			operator = (const Action& action);
#endif

	TagBase *		f_tag;
	unsigned char		f_min_version;		/* minimum version to use this action */
};


class ActionBranch : public Action, public MemoryManager
{
public:
	/* one of:
	 *	ACTION_BRANCH_ALWAYS
	 *	ACTION_BRANCH_IF_TRUE
	 */
				ActionBranch(TagBase *tag, action_t action = ACTION_BRANCH_ALWAYS);

	void			SetLabel(const char *label);

private:
	virtual Action *	Duplicate(void) const;
	virtual void		SaveData(Data& data, Data& nested_data);
	virtual void		Save2ndPass(const Vectors& list, Data& data);

	char *			f_label;
};



class ActionCallFrame : public Action, public MemoryManager
{
public:
				ActionCallFrame(TagBase *tag);

private:
	virtual void		SaveData(Data& data, Data& nested_data);
};



class ActionDictionary : public Action, public MemoryManager
{
public:
				ActionDictionary(TagBase *tag);

	void			AddString(const char *string);

private:
	struct string_t : public ItemBase {
		char *		f_string;
	};

	virtual Action *	Duplicate(void) const;
	virtual void		SaveData(Data& data, Data& nested_data);

	Vectors			f_strings;
};



class ActionFunction : public Action, public MemoryManager
{
public:
	/* one of:
	 *	ACTION_DECLARE_FUNCTION
	 *	ACTION_DECLARE_FUNCTION2
	 */
	enum action_function_t {
		ACTION_FUNCTION_LOAD_THIS          = 0x0001,
		ACTION_FUNCTION_SUPPRESS_THIS      = 0x0002,
		ACTION_FUNCTION_LOAD_ARGUMENTS     = 0x0004,
		ACTION_FUNCTION_SUPPRESS_ARGUMENTS = 0x0008,
		ACTION_FUNCTION_LOAD_SUPER         = 0x0010,
		ACTION_FUNCTION_SUPPRESS_SUPER     = 0x0020,
		ACTION_FUNCTION_LOAD_ROOT          = 0x0040,
		ACTION_FUNCTION_LOAD_PARENT        = 0x0080,
		ACTION_FUNCTION_LOAD_GLOBAL        = 0x0100
	};

				ActionFunction(TagBase *tag, action_t action = ACTION_DECLARE_FUNCTION);

	void			SetName(const char *name);
	void			SetRegistersCount(unsigned int count);
	void			AddParameter(const char *name, int register_number = -1);
	void			AddAction(Action *action);

private:
	struct parameter_t : public ItemBase {
		char *		f_name;
		int		f_register_number;	// if -1, use the name, if 0, auto-assign
	};

	virtual Action *	Duplicate(void) const;
	virtual void		SaveData(Data& data, Data& nested_data);
	virtual Vectors *	SubList(void);

	char *			f_name;
	unsigned int		f_registers_count;
	unsigned short		f_flags;
	Vectors			f_parameters;
	Vectors			f_actions;
};



class ActionTry : public Action, public MemoryManager
{
public:
				ActionTry(TagBase *tag);

	void			AddTryAction(Action *action);
	void			AddCatchAction(Action *action);
	void			AddFinallyAction(Action *action);
	void			SetIdentifier(int register_number);		// Catch(#)
	void			SetIdentifier(const char *variable_name);	// Catch(var)
	void			StartCatch(void);
	void			StartFinally(void);

	Vectors *		SubListTry(void);
	Vectors *		SubListCatch(void);
	Vectors *		SubListFinally(void);

private:
	virtual Action *	Duplicate(void) const;
	virtual void		SaveData(Data& data, Data& nested_data);
	virtual unsigned char	Version(void) const;

	int			f_register;
	char *			f_variable_name;
	bool			f_has_catch;
	bool			f_has_finally;
	Vectors			f_actions_try;
	Vectors			f_actions_catch;
	Vectors			f_actions_finally;
};



class ActionGoto : public Action, public MemoryManager
{
public:
	/* one of:
	 *	ACTION_GOTO_FRAME
	 *	ACTION_GOTO_LABEL
	 *	ACTION_GOTO_EXPRESSION
	 */
				ActionGoto(TagBase *tag, action_t action = ACTION_GOTO_FRAME);

	void			SetFrameName(const char *frame_name);
	void			SetPlay(bool play) { f_play = play; }

private:
	virtual Action *	Duplicate(void) const;
	virtual void		SaveData(Data& data, Data& nested_data);

	char *			f_frame_name;
	bool			f_play;
};



class ActionLabel : public Action, public MemoryManager {
public:
				ActionLabel(TagBase *tag);

	void			SetLabel(const char *label);
	const char *		GetLabel(void) const { return f_label; }

private:
	virtual Action *	Duplicate(void) const;
	// we shall never even try to save a label! so no SaveData() is necessary

	char *			f_label;
};




class ActionPushData : public Action, public MemoryManager {
public:
	enum action_immediate_type_t {
		ACTION_IMMEDIATE_TYPE_UNKNOWN		= -1,
		ACTION_IMMEDIATE_TYPE_STRING		= 0x00,
		ACTION_IMMEDIATE_TYPE_FLOAT		= 0x01,
		ACTION_IMMEDIATE_TYPE_NULL		= 0x02,
		ACTION_IMMEDIATE_TYPE_UNDEFINED		= 0x03,
		ACTION_IMMEDIATE_TYPE_REGISTER		= 0x04,
		ACTION_IMMEDIATE_TYPE_BOOLEAN		= 0x05,
		ACTION_IMMEDIATE_TYPE_DOUBLE		= 0x06,
		ACTION_IMMEDIATE_TYPE_INTEGER		= 0x07,
		ACTION_IMMEDIATE_TYPE_LOOKUP		= 0x08,
		ACTION_IMMEDIATE_TYPE_LOOKUP_LARGE	= 0x09
	};
	struct action_immediate_t : public ItemBase {
		action_immediate_type_t	f_type;
		union {
			char *		f_string;
			float		f_float32;
			double		f_float64;
			bool		f_boolean;
			long		f_integer32;
			unsigned short	f_lookup;
			unsigned char	f_register;
		} f_data;

		action_immediate_t(action_immediate_type_t type)
		{
			f_type = type;
			memset(&f_data, 0, sizeof(f_data));
		}
	};

				ActionPushData(TagBase *tag);

	void			AddEmptyString(void) { AddString(0); }
	void			AddString(const char *string);
	void			AddTrue(void) { AddBoolean(true); }
	void			AddFalse(void) { AddBoolean(false); }
	void			AddBoolean(bool value);
	void			AddInteger(long value);
	void			AddFloat(float value);
	void			AddDouble(double value);
	void			AddNull(void);
	void			AddLookup(unsigned short index);
	void			AddRegister(unsigned char reg_index);
	void			AddUndefined(void);

private:
	virtual Action *	Duplicate(void) const;
	virtual void		SaveData(Data& data, Data& nested_data);
	virtual int		GetMaxRegister(void) const;

	Vectors			f_data;
};




class ActionSetTarget : public Action, public MemoryManager {
public:
				ActionSetTarget(TagBase *tag);

	void			SetTarget(const char *target);

private:
	virtual Action *	Duplicate(void) const;
	virtual void		SaveData(Data& data, Data& nested_data);

	char *			f_target;
};


class ActionStoreRegister : public Action, public MemoryManager {
public:
				ActionStoreRegister(TagBase *tag);

	void			SetRegister(unsigned char reg);

private:
	virtual Action *	Duplicate(void) const;
	virtual void		SaveData(Data& data, Data& nested_data);
	virtual int		GetMaxRegister(void) const;

	unsigned char		f_reg;
};


class ActionURL : public Action, public MemoryManager {
public:
	/* one of:
	 *	ACTION_URL
	 *	ACTION_URL2
	 */
	enum url_method_t {
		URL_METHOD_NOVARIABLE = 0,
		URL_METHOD_GET = 1,
		URL_METHOD_POST = 2
	};

				ActionURL(TagBase *tag, action_t action = ACTION_URL);

	void			SetURL(const char *url, const char *target);
	void			SetMethod(url_method_t method);

private:
	virtual Action *	Duplicate(void) const;
	virtual void		SaveData(Data& data, Data& nested_data);

	char *			f_url;
	char *			f_target;
	url_method_t		f_method;
};



class ActionWaitForFrame : public Action, public MemoryManager {
public:
	/* one of:
	 *	ACTION_WAIT_FOR_FRAME
	 *	ACTION_WAIT_FOR_FRAME2
	 */
				ActionWaitForFrame(TagBase *tag, action_t action = ACTION_WAIT_FOR_FRAME);

	void			SetFrameName(const char *name);
	void			AddAction(Action *action);

private:
	virtual Action *	Duplicate(void) const;
	virtual void		SaveData(Data& data, Data& nested_data);
	virtual Vectors *	SubList(void);

	Vectors			f_actions;	// actions executed once frame is loaded
	char *			f_frame_name;
};



class ActionWith : public Action, public MemoryManager {
public:
				ActionWith(TagBase *tag);

	void			AddAction(Action *action);

private:
	virtual Action *	Duplicate(void) const;
	virtual void		SaveData(Data& data, Data& nested_data);
	virtual Vectors *	SubList(void);

	Vectors			f_actions;
};






class TagDoAction : public TagBase {
public:
	/* one of:
	 *	SWF_TAG_DO_ACTION
	 *	SWF_TAG_DO_INIT_ACTION (use this if sprite ID defined)
	 */
				TagDoAction(TagBase *parent);

	virtual int		Save(Data& data);
	virtual swf_type_t	TypeFlags(void) const;

/////////////// SETUP FUNCTIONS
	static int		SaveList(const Vectors& list, Data& data);
	void			SetAction(const Action& action);
	void			SetSprite(sswf_id_t sprite);
	Vectors&		Actions(void) { return f_actions; }

private:
	virtual int		PreSave(void);		// called by the header Save() function

	sswf_id_t		f_sprite;
	Vectors			f_actions;
};





class TagPlace : public TagBase {
public:
				TagPlace(TagBase *parent);

	virtual int		Save(Data& data);
	virtual swf_type_t	TypeFlags(void) const;

/////////////// SETUP FUNCTIONS
	void			SetObjectID(sswf_id_t id);
	void			SetDepth(int depth);
	void			SetClip(int depth);
	void			SetMatrix(const Matrix& matrix);
	void			SetColorTransform(const ColorTransform& color_transform);
	void			SetName(const char *name);
	void			SetMorphPosition(int position);
	void			Replace(void);
	void			Place(void);
	void			AddEvent(Event *event);

private:
	virtual int		PreSave(void);		// called by the header Save() function

	bool			f_id_defined;
	sswf_id_t		f_id;
	int			f_replace;
	int			f_depth;
	int			f_clip_depth;
	char *			f_name;
	unsigned long		f_events_all_flags;
	int			f_position;		// morph position
	bool			f_has_matrix;
	Matrix			f_matrix;
	ColorTransform		f_color_transform;
	Vectors			f_events;
};



class TagRemove : public TagBase
{
public:
				TagRemove(TagBase *parent);

	virtual int		Save(Data& data);
	virtual swf_type_t	TypeFlags(void) const;

/////////////// SETUP FUNCTIONS
	void			SetDepth(int depth) { f_depth = depth; }
	void			SetObjectID(sswf_id_t id) { f_id = id; }

private:
	virtual int		PreSave(void);		// called by the header Save() function

	int			f_depth;
	sswf_id_t		f_id;
};



class TagScriptLimits : public TagBase
{
public:
				TagScriptLimits(TagBase *parent);

	virtual int		Save(Data& data);
	virtual swf_type_t	TypeFlags(void) const;

/////////////// SETUP FUNCTIONS
	void			SetMaxRecursionDepth(int depth);
	void			SetTimeoutSeconds(int timeout);
	int			GetMaxRecursionDepth(void) const;
	int			GetTimeoutSeconds(void) const;

private:
	virtual int		PreSave(void);

	int			f_depth;
	int			f_timeout;
};



class TagSetTabIndex : public TagBase
{
public:
				TagSetTabIndex(TagBase *parent);

	virtual int		Save(Data& data);
	virtual swf_type_t	TypeFlags(void) const;

/////////////// SETUP FUNCTIONS
	void			SetDepth(int depth);
	void			SetIndex(int timeout);
	int			GetDepth(void) const;
	int			GetIndex(void) const;

private:
	virtual int		PreSave(void);

	int			f_depth;
	int			f_index;
};



class TagSetBackgroundColor : public TagBase {
public:
				TagSetBackgroundColor(TagBase *parent);

	virtual int		Save(Data& data);
	virtual swf_type_t	TypeFlags(void) const;

/////////////// SETUP FUNCTIONS
	void			SetColor(Color& color);
	Color&			GetColor(void);

private:
	Color			f_color;
};


class TagShowFrame : public TagBase {
public:
				TagShowFrame(TagBase *parent);

	virtual int		Save(Data& data);
	virtual swf_type_t	TypeFlags(void) const;
};


class TagEnd : public TagBase {
public:
				TagEnd(TagBase *parent);

	virtual int		Save(Data& data);
	virtual swf_type_t	TypeFlags(void) const;
};


class TagFrameLabel : public TagBase {
public:
				TagFrameLabel(TagBase *parent);

	virtual int		Save(Data& data);
	virtual swf_type_t	TypeFlags(void) const;

/////////////// SETUP FUNCTIONS
	void			SetFrameLabel(const char *label);

private:
	virtual int		PreSave(void);

	char *			f_label;
};



class TagExport : public TagBase {
public:
				TagExport(TagBase *parent);

	virtual int		Save(Data& data);
	virtual swf_type_t	TypeFlags(void) const;

/////////////// SETUP FUNCTIONS
	void			SetObject(sswf_id_t id, const char *name);

private:
	struct export_t : public ItemBase {
		sswf_id_t	f_id;
		const char *	f_name;
	};

	virtual int		PreSave(void);

	Vectors			f_objects;
};



class TagImport : public TagBase {
public:
				TagImport(TagBase *parent);

	virtual int		Save(Data& data);
	virtual swf_type_t	TypeFlags(void) const;
	const char *		HasID(sswf_id_t id) const;
	sswf_id_t		HasName(const char *name) const;

/////////////// SETUP FUNCTIONS
	void			SetURL(const char *url);
	void			SetFilename(const char *filename);
	void			AddName(const char *name, const char *type);

private:
	struct import_t : public ItemBase {
		sswf_id_t	f_id;		// dynamically allocated
		const char *	f_name;		// external symbol name
		const char *	f_type;		// user specified type
	};

	virtual int		PreSave(void);

	char *			f_url;
	char *			f_filename;
	Vectors			f_objects;
};



class TagProtect : public TagBase {
public:
	/* one of:
	 *	SWF_TAG_PROTECT
	 *	SWF_TAG_PROTECT_DEBUG
	 *	SWF_TAG_PROTECT_DEBUG2
	 */
				TagProtect(TagBase *parent, swf_tag_t tag = SWF_TAG_PROTECT);

	virtual int		Save(Data& data);
	virtual swf_type_t	TypeFlags(void) const;

/////////////// SETUP FUNCTIONS
	void			SetPassword(const char *password);
	void			SetEncodedPassword(const char *password);

private:
	virtual int		PreSave(void);

	swf_tag_t		f_tag;
	char *			f_password;
};



class TagInfo : public TagBase {
public:
				TagInfo(TagBase *parent);

	virtual int		Save(Data& data);
	virtual swf_type_t	TypeFlags(void) const;

/////////////// SETUP FUNCTIONS
	void			SetInfo(const char *info);
	void			SetVersion(long version);

private:
	virtual int		PreSave(void);

	char *			f_info;
	long			f_version;
};


class TagStartSound : public TagBase {
public:
				TagStartSound(TagBase *parent);

	virtual int		Save(Data& data);
	virtual swf_type_t	TypeFlags(void) const;

	void			SetInfo(SoundInfo *sound_info);

private:
	virtual int		PreSave(void);

	SoundInfo *		f_sound_info;
};





/****************************************/
/****************************************/
/********************* TAGS WITH IDs ****/
/****************************************/
/****************************************/

class TagBaseID : public TagBase {
public:
				TagBaseID(const char *name, TagBase *parent);

	virtual sswf_id_t	Identification(void) const;
	void			NoIdentification(void);

	int			SaveID(Data& data) const;

private:
	sswf_id_t		f_id;
	bool			f_identified;
};




class TagButton : public TagBaseID {
public:
				TagButton(TagBase *parent);

	virtual int		Save(Data& data);
	virtual swf_type_t	TypeFlags(void) const;

/////////////// SETUP FUNCTIONS
	void			SetState(const State& state);
	void			SetAction(const Action& action);
	void			SetMenu(bool menu = true);
	Vectors&		Actions(void);
	void			AddEvent(Event *event);

private:
	virtual int		PreSave(void);		// called by the header Save() function

	bool			f_save_button2;
	bool			f_menu;			// whether to track as a menu
	Vectors			f_states;
	Vectors			f_actions;
	Vectors			f_events;
};


class TagShape;
class TagFont : public TagBaseID {
public:
	enum font_type_t {
		FONT_TYPE_BEST = 0,		// create the best possible result
		FONT_TYPE_ASCII,
		FONT_TYPE_UNICODE,
		FONT_TYPE_SHIFTJIS,
	};
	enum font_language_t {
		FONT_LANGUAGE_UNKNOWN			= -1,
		FONT_LANGUAGE_LOCALE			= 0,
		FONT_LANGUAGE_LATIN			= 1,
		FONT_LANGUAGE_JAPANESE			= 2,
		FONT_LANGUAGE_KOREAN			= 3,
		FONT_LANGUAGE_SIMPLIFIED_CHINESE	= 4,
		FONT_LANGUAGE_TRADITIONAL_CHINESE	= 5,

		FONT_LANGUAGE_max			= 6
	};

#define	SSWF_FONT_SPACE_INDEX		static_cast<unsigned long>(-1)

	struct font_info_t {
		sswf_ucs4_t		f_glyph;	// the glyph name ('A', 'B', ...)
		unsigned short		f_saved_index;	// index in the SWF file (within the referenced glyphs)
		unsigned long		f_index;	// index in the memory array (of all glyphs)
		unsigned long		f_position;	// closest position or exact position in the list of glyphs
		long			f_advance;	// the advance in TWIPs
		bool			f_is_empty;	// if true, it's like a space (i.e. invisible)
	};

				TagFont(TagBase *parent);

	virtual int		Save(Data& data);
	virtual swf_type_t	TypeFlags(void) const;
	void			GlyphInfo(font_info_t& info) const;
	bool			HasGlyph(void) const;
	bool			FindGlyph(font_info_t& info, bool mark_empty_in_use = false) const;
	const char *		FontName(void) const;
	long			DefaultAscent(void) const;
	long			DefaultDescent(void) const;
	long			DefaultLeadingHeight(void) const;
	static font_language_t	StringToLanguage(const char *language);
	static const char *	LanguageToString(font_language_t language);

/////////////// SETUP FUNCTIONS
	// WARNING: shape referenced as kept as points (the shape isn't copied in any way)
	// so you have to make sure that these shapes still exist at the time the Save()
	// is called.
	void			AddGlyph(sswf_ucs4_t name, const TagBase *ref, long advance = LONG_MIN);
	void			SetName(const char *font_name);
	void			SetLayout(long ascent, long descent, long leading_height);
	void			SetDefaultAdvance(long advance);
	void			SetSpaceAdvance(long advance);
	void			SetType(font_type_t type);
	void			SetLanguage(font_language_t language);
	void			SetBold(bool bold);
	void			SetItalic(bool italic);
	void			SetWide(bool wide);
	int			SetUsedGlyphs(const char *used_glyphs, bool mark_empty_in_use = false);
	void			SetUsedByEditText(bool used = true);
	void			AddKern(sswf_ucs4_t code0, sswf_ucs4_t code1, long advance);

private:
	struct font_glyph_t : public ItemBase {
		sswf_ucs4_t	f_name;		/* "A", "B", "0", "1", etc. */
		unsigned short	f_index;	/* index of this item when saved in the output file */
		const TagShape *f_shape;	/* the shape used for this glyph */
		long		f_advance;	/* the number of TWIPs to advance */
		bool		f_in_use;	/* if true this glyph was referenced at least once */
	};
	struct font_kern_t : public ItemBase {
		sswf_ucs4_t	f_code[2];
		long		f_advance;
	};

	virtual int		PreSave(void);
	virtual int		PreSave2ndPass(void);

	static const char *	f_font_language_name[FONT_LANGUAGE_max];
	char *			f_font_name;
	font_language_t		f_language;		// v6.x language definition
	font_type_t		f_type;			// unused in v6.x
	bool			f_bold;
	bool			f_italic;
	bool			f_wide;
	bool			f_has_wide_char;	// defined in PreSave2ndPass()
	bool			f_has_wide_offsets;	// defined in PreSave2ndPass()
	bool			f_has_layout;		// defined in PreSave2ndPass()
	bool			f_used_by_edit_text;	// reset in PreSave() used in PreSave2ndPass()
	bool			f_define_font2;		// defined in PreSave2ndPass()
	long			f_ascent;
	long			f_descent;
	long			f_leading_height;
	long			f_default_advance;
	long			f_space_advance;
	long			f_offsets_max;		// size of the current f_offsets buffer
	unsigned long *		f_offsets;		// this is a list of unsigned shorts if f_has_wide_offset if false -- defined in PreSave2ndPass()
	unsigned long		f_count;		// the number of glyphs saved (defined in PreSave2ndPass())
	Data			f_save_glyphs;		// defined in PreSave2ndPass()
	Vectors			f_glyphs;
	Vectors			f_kerns;
};



class TagEditText : public TagBaseID {
public:
	enum edit_text_alignment_t {
		EDIT_TEXT_ALIGNMENT_LEFT = 0,
		EDIT_TEXT_ALIGNMENT_RIGHT = 1,
		EDIT_TEXT_ALIGNMENT_CENTER = 2,
		EDIT_TEXT_ALIGNMENT_JUSTIFY = 3
	};

				TagEditText(TagBase *parent);

	virtual int		Save(Data& data);
	virtual swf_type_t	TypeFlags(void) const;

/////////////// SETUP FUNCTIONS
	void			SetText(const char *text);
	void			SetVariableName(const char *name);
	void			SetFont(const TagFont *font, long height);
	void			SetMargins(long left, long right);
	void			SetBounds(const SRectangle& bounds);
	void			SetAlign(edit_text_alignment_t align);
	void			SetIndent(long indent);
	void			SetLeading(long leading);
	void			SetColor(Color& color);
	void			SetMaxLength(long length);
	void			SetWordWrap(bool status = true);
	void			SetMultiline(bool status = true);
	void			SetPassword(bool status = true);
	void			SetReadOnly(bool status = true);
	void			SetNoSelect(bool status = true);
	void			SetBorder(bool status = true);
	void			SetOutline(bool status = true);
	void			SetHTML(bool status = true);
	void			SetAutoSize(bool status = true);
	void			SetUsedGlyphs(const char *lists);
	void			AddUsedString(const char *string);

private:
	virtual int		PreSave(void);

	SRectangle		f_bounds;		// where the string is drawn
	edit_text_alignment_t	f_align;
	long			f_left_margin;
	long			f_right_margin;
	long			f_indent;
	long			f_leading;
	const TagFont *		f_font;
	unsigned short		f_font_height;
	long			f_max_length;		// maximum number of character, if <= 0 - undefined
	char *			f_text;			// if 0, no initialization text
	char *			f_var_name;		// required
	char *			f_used_glyphs;		// default to "*" if undefined
	char *			f_used_strings;		// concatenation of used strings
	Color			f_color;
	bool			f_has_color;		// if this is true then the user defined the color
	bool			f_word_wrap;
	bool			f_multiline;
	bool			f_password;
	bool			f_readonly;
	bool			f_no_select;
	bool			f_border;
	bool			f_outline;
	bool			f_html;
	bool			f_autosize;
};


class TagImage : public TagBaseID {
public:
	enum image_format_t {
		IMAGE_FORMAT_UNKNOWN = 0,
		IMAGE_FORMAT_LOSSLESS_BEST,
		IMAGE_FORMAT_LOSSLESS_8,
		IMAGE_FORMAT_LOSSLESS_16,
		IMAGE_FORMAT_LOSSLESS_32,
		IMAGE_FORMAT_JPEG,
		IMAGE_FORMAT_max
	};
	struct image_t {
		bool		f_alpha;		// whether the source had 4 components (depth = 20)
		long		f_width;		// size of the image in pixels
		long		f_height;
		unsigned char *	f_data;			// data of the image
	};


				TagImage(TagBase *parent);

	virtual int		Save(Data& data);
	virtual swf_type_t	TypeFlags(void) const;

/////////////// SETUP FUNCTIONS
	void			SetFormat(image_format_t format) { f_format = format; }
	void			SetQuality(int quality) { f_quality = quality; }
	int			SetFilename(const char *image, const char *mask);
	void			SetImage(long width, long height, unsigned char *data, bool alpha = false, long count = 0, unsigned char *colormap = 0);

	int			LoadTGA(const char *filename, image_t& im);
	int			LoadJPEG(const char *filename, image_t& im);
	int			SaveJPEG(Data& encoding, Data& image);
	int			SetAlpha(image_t& im, const image_t& mask);

private:
	virtual int		PreSave(void);

	image_format_t		f_format;		// one of the IMAGE_FORMAT_...
	image_t			f_image;		// the image
	int			f_quality;		// for JPEG, the quality level
	long			f_count;		// number of colors in the colormap
	unsigned char *		f_colormap;		// the colormap when it can be generated
};



class TagShape : public TagBaseID {
public:
	enum morph_t {
		MORPH_MODE_SHAPE0 = 0,
		MORPH_MODE_SHAPE1 = 1,
		MORPH_MODE_BOTH_SHAPES = 2
	};

				TagShape(TagBase *parent);

	virtual int		Save(Data& data);
	virtual swf_type_t	TypeFlags(void) const;
	int			SaveWithoutStyles(Data& data);
	bool			HasBounds(void) const { return !f_bounds[0].IsEmpty() || !f_bounds[1].IsEmpty(); }
	const SRectangle&	Bounds(int index) const { assert(index == 0 || index == 1, "invalid index to query bounds"); return f_bounds[index]; }
	bool			IsGlyph(void) const;
	bool			IsEmpty(void) const;


/////////////// SETUP FUNCTIONS
	void			AddMove(morph_t morph_mode, long x, long y);
	void			AddEdge(morph_t morph_mode, long x, long y) { Edges::edge_t edge(x, y); AddEdge(morph_mode, edge); }
	void			AddEdge(morph_t morph_mode, long x, long y, long ctrl_x, long ctrl_y) { Edges::edge_t edge(x, y, ctrl_x, ctrl_y); AddEdge(morph_mode, edge); };
	void			AddEdge(morph_t morph_mode, const Edges::edge_t& edge);
	void			NewStyles(void);
	void			AddStyle(const Style& style, int fill = 0);
	void			SetBounds(int index, const SRectangle& rect, bool show = false);
	void			ShowBounds(bool show = true) { f_show_bounds = show; }
	void			ShowOrigin(bool show = true) { f_show_origin = show; }
	void			Glyph(void);

private:
	enum what_t {
		SHAPE_EDGES,
		SHAPE_SETUP
	};

	struct shape_what_t : public ItemBase {
		what_t		f_what;
				shape_what_t(what_t what) { f_what = what; }
	};
	struct shape_edges_t : public shape_what_t {
		Edges		f_edges;
				shape_edges_t(what_t what) : shape_what_t(what) {}
	};
	struct shape_setup_t : public shape_what_t {
		int		f_fill_ref[2];
		int		f_line_ref;
		long		f_x;
		long		f_y;

				shape_setup_t(what_t what, bool origin = false) : shape_what_t(what)
				{
					f_fill_ref[0] = f_fill_ref[1] = f_line_ref = -1;
					if(origin) {
						f_x = f_y = 0;
					}
					else {
						f_x = f_y = LONG_MIN;
					}
				}
	};

	struct shape_record_t : public ItemBase {		// used to save in f_shapes
		Vectors *	f_fill_styles;
		Vectors *	f_line_styles;
		Vectors *	f_record;
	};

	struct save_info_t {
		shape_record_t	f_sr;
		bool		f_save_alpha;
		bool		f_ext_size;
		bool		f_first;
		bool		f_save_styles;
		Data		f_data;			// we save it all here (we need to have the size before to create the tag data)
		int		f_fill_bits_count;
		int		f_line_bits_count;
	};

	void			RecordEdges(void);
	void			RecordSetup(void);
	void			NewEdges(void);
	void			NewSetup(void);
	void			SetMorph(void);

	// save sub-functions
	int			SaveShape(save_info_t& info, shape_setup_t& last_setup);
	int			SaveMorph(Data& data);
	int			SaveSetup(save_info_t& info, const shape_setup_t& setup, shape_setup_t& last);
	int			SaveStyles(save_info_t& info);
	int			SaveStylesCount(save_info_t& info, long count);

	unsigned char		f_version;		// the minimum version necessary to save this shape (determines the tag)
	bool			f_morph;		// this is a morph shape
	bool			f_is_glyph;		// used only as a glyph (font character)
	bool			f_show_bounds;		// draw the bounding rectangle around the shape
	bool			f_show_origin;		// draw lines showing the origin
	SRectangle		f_bounds[2];		// where the shape is drawn

	Vectors			f_shapes;		// each shape saved here has its own set of fill & line style

	shape_edges_t *		f_edges;		// if not NULL that's the current Edges to fill
	shape_edges_t *		f_morph_edges;		// if not NULL that's the current Edges to fill the morph (2nd shape)
	shape_setup_t *		f_setup;		// if not NULL that's the current Setup to define
	Vectors			f_fill_styles;
	Vectors			f_line_styles;
	Vectors			f_record;		// the current shape being built
	Vectors			f_morph_record;		// the current morph shape being built
};



class TagSound : public TagBaseID {
public:
	enum sound_format_t {
		SOUND_FORMAT_UNKNOWN = -1,
		SOUND_FORMAT_RAW = 0,
		SOUND_FORMAT_ADPCM = 1,
		SOUND_FORMAT_MP3 = 2,
		SOUND_FORMAT_UNCOMPRESSED = 3,
		SOUND_FORMAT_NELLYMOSER = 6
	};
	enum sound_endian_t {
		SOUND_ENDIAN_LITTLE = 0,	// the user data is in little endian
		SOUND_ENDIAN_BIG,		// the user data is in big endian
		SOUND_ENDIAN_SAME,		// accept processor endianess as the data endianess
		SOUND_ENDIAN_DONTUSE,		// use this for 8bits data
		SOUND_ENDIAN_UNKNOWN		// undefined endianess -- the SetData() will always fail with this value
	};

	static const int	g_sound_rates[4];

				TagSound(TagBase *parent);

	virtual int		Save(Data& data);
	virtual swf_type_t	TypeFlags(void) const;

	size_t			GetSamplesCount(void) const;

/////////////// SETUP FUNCTIONS
	int			SetFilename(const char *filename);
	void			SetFormat(sound_format_t format);
	int			SetData(const void *data, size_t size, sound_endian_t endian, int width, unsigned int rate, bool stereo);
	void			SetMono(void);
	void			Set8Bits(void);

private:
	struct sound_wave_t {
		short		format;			// the data format (we only support PCM)
		short		channels;		// number of channels (1 - mono, 2 - stereo)
		int		rate;			// exact sample rate to play the sound at
		int		average_rate;		// average rate for the entire set of samples (this may vary in compressed files)
		short		align;			// byte alignment of the samples (every char, short, long...)
		/* the following is format dependent, but at this time doesn't vary for us */
		short		width;			// width of the samples (8 or 16)
	};

	virtual int		PreSave(void);
	short			ReadSample(const unsigned char *data, unsigned short adjust, int in_fmt);
	void			Resample(unsigned char *snd, unsigned int out_bytes, const unsigned char *src, size_t size, unsigned int in_bytes, size_t max, double fix, unsigned short adjust, int in_fmt);
	int			LoadWaveFile(FILE *f);
	int			LoadMP3File(FILE *f);
	int			CheckMP3Header(FILE *f, unsigned char *header, int& frame_size);
	int			ReadMP3Header(FILE *f, unsigned char *header);

	static const int	g_bitrates[2][16];
	static const int	g_frequencies[4][4];

	sound_format_t		f_format;
	bool			f_stereo;
	int			f_rate;
	int			f_width;
	size_t			f_samples;
	int			f_data_size;
	int			f_data_maxsize;
	unsigned char *		f_data;
	int			f_latency_seek;
};






class TagSprite : public TagBaseID {
public:
				TagSprite(TagBase *parent);

	virtual int		Save(Data& data);
	virtual swf_type_t	TypeFlags(void) const;

/////////////// SETUP FUNCTIONS
	// There aren't any (yet).
	// Add objects to a sprite by defining the sprite tag as
	// the parent of these objects.
	// The parent of a sprite must be a TagHeader object.

private:
	virtual int		PreSave(void);
};




class TagText : public TagBaseID {
public:
				TagText(TagBase *parent);

	virtual int		Save(Data& data);
	virtual swf_type_t	TypeFlags(void) const;

/////////////// SETUP FUNCTIONS
	void			SetMatrix(const Matrix& matrix);
	void			SetBounds(const SRectangle& bounds);
	void			AddText(const char *string, long advance = LONG_MIN);
	void			AddFont(const TagFont *font, long height);
	void			AddOffsets(long x, long y);
	void			AddColor(Color& color);

private:
	enum text_type_t {
		TEXT_ENTRY_TEXT = 0,
		TEXT_ENTRY_SETUP
	};

	struct text_define_t : public ItemBase {		// used to save in f_shapes
		const text_type_t	f_type;

					text_define_t(text_type_t type) : f_type(type) {}
	};

	struct text_setup_t : public text_define_t {		// used to save in f_shapes
		bool			f_has_font;
		const TagFont *		f_font;
		unsigned short		f_font_height;
		bool			f_has_xadjust;
		long			f_xadjust;
		bool			f_has_xoffset;
		long			f_x;
		bool			f_has_yoffset;
		long			f_y;
		bool			f_has_color;
		Color			f_color;

					text_setup_t(void);
					text_setup_t(const text_setup_t& setup);
		void			Unused(void);
		bool			IsUsed(void) const;
	};

	struct text_entry_t : public text_define_t {
		sswf_ucs4_t *		f_text;			// TODO: need support for wide characters
		long			f_advance;
		unsigned long		f_length;		// length of the string
		unsigned long		f_exact_length;		// length of string without spaces
		TagFont::font_info_t *	f_entries;		// an array of entries

					text_entry_t(sswf_ucs4_t *string, long advance);
	};

	virtual int		PreSave(void);
	int			DefineText(int start, text_setup_t *s, const TagFont *font, int font_height);
	void			RecordSetup(void);
	void			NewSetup(void);

	Matrix			f_matrix;		// a transformation matrix for this text
	SRectangle		f_bounds;		// where the string is drawn
	text_setup_t		f_setup;		// current setup definition
	bool			f_new_text;		// if true we need to recompute the text info entries
	int			f_version;		// the PreSave() defines this, Save() uses it
	Vectors			f_records;		// text records
};









};		// namespace sswf
#endif			/* #ifndef LIBSSWF_H */
