📄 gameswf_action.h
字号:
// gameswf_action.h -- Thatcher Ulrich <tu@tulrich.com> 2003// This source code has been donated to the Public Domain. Do// whatever you want with it.// Implementation and helpers for SWF actions.#ifndef GAMESWF_ACTION_H#define GAMESWF_ACTION_H#include "gameswf.h"#include "gameswf_types.h"#include <wchar.h>#include "base/container.h"#include "base/smart_ptr.h"namespace gameswf{ struct movie; struct as_environment; struct as_object_interface; struct as_value; struct as_as_function; // // event_id // // For keyDown and stuff like that. struct event_id { // These must match the function names in event_id::get_function_name() enum id_code { INVALID, // These are for buttons & sprites. PRESS, RELEASE, RELEASE_OUTSIDE, ROLL_OVER, ROLL_OUT, DRAG_OVER, DRAG_OUT, KEY_PRESS, // These are for sprites only. INITIALIZE, LOAD, UNLOAD, ENTER_FRAME, MOUSE_DOWN, MOUSE_UP, MOUSE_MOVE, KEY_DOWN, KEY_UP, DATA, // These are for the MoveClipLoader ActionScript only LOAD_START, LOAD_ERROR, LOAD_PROGRESS, LOAD_INIT, // These are for the XMLSocket ActionScript only SOCK_CLOSE, SOCK_CONNECT, SOCK_DATA, SOCK_XML, // These are for the XML ActionScript only XML_LOAD, XML_DATA, // This is for setInterval TIMER, EVENT_COUNT }; unsigned char m_id; unsigned char m_key_code; event_id() : m_id(INVALID), m_key_code(key::INVALID) {} event_id(id_code id, key::code c = key::INVALID) : m_id((unsigned char) id), m_key_code((unsigned char) c) { // For the button key events, you must supply a keycode. // Otherwise, don't. assert((m_key_code == key::INVALID && (m_id != KEY_PRESS)) || (m_key_code != key::INVALID && (m_id == KEY_PRESS))); } bool operator==(const event_id& id) const { return m_id == id.m_id && m_key_code == id.m_key_code; } // Return the name of a method-handler function corresponding to this event. const tu_string& get_function_name() const; }; // // with_stack_entry // // The "with" stack is for Pascal-like with-scoping. struct with_stack_entry { smart_ptr<as_object_interface> m_object; int m_block_end_pc; with_stack_entry() : m_object(NULL), m_block_end_pc(0) { } with_stack_entry(as_object_interface* obj, int end) : m_object(obj), m_block_end_pc(end) { } }; // Base class for actions. struct action_buffer { action_buffer(); void read(stream* in); void execute(as_environment* env); void execute( as_environment* env, int start_pc, int exec_bytes, as_value* retval, const array<with_stack_entry>& initial_with_stack, bool is_function2); bool is_null() { return m_buffer.size() < 1 || m_buffer[0] == 0; } int get_length() const { return m_buffer.size(); } private: // Don't put these as values in array<>! They contain // internal pointers and cannot be moved or copied. // If you need to keep an array of them, keep pointers // to new'd instances. action_buffer(const action_buffer& a) { assert(0); } void operator=(const action_buffer& a) { assert(0); } void process_decl_dict(int start_pc, int stop_pc); // data: array<unsigned char> m_buffer; array<const char*> m_dictionary; int m_decl_dict_processed_at; }; struct fn_call; typedef void (*as_c_function_ptr)(const fn_call& fn); struct as_property_interface { virtual bool set_property(int index, const as_value& val) = 0; }; // ActionScript value type. struct as_value { enum type { UNDEFINED, NULLTYPE, BOOLEAN, STRING, NUMBER, OBJECT, C_FUNCTION, AS_FUNCTION, // ActionScript function. }; type m_type; mutable tu_string m_string_value; union { bool m_boolean_value; // @@ hm, what about PS2, where double is bad? should maybe have int&float types. mutable double m_number_value; as_object_interface* m_object_value; as_c_function_ptr m_c_function_value; as_as_function* m_as_function_value; }; as_value() : m_type(UNDEFINED), m_number_value(0.0) { } as_value(const as_value& v) : m_type(UNDEFINED), m_number_value(0.0) { *this = v; } as_value(const char* str) : m_type(STRING), m_string_value(str), m_number_value(0.0) { } as_value(const wchar_t* wstr) : m_type(STRING), m_string_value(""), m_number_value(0.0) { // Encode the string value as UTF-8. // // Is this dumb? Alternatives: // // 1. store a tu_wstring instead of tu_string? // Bloats typical ASCII strings, needs a // tu_wstring type, and conversion back the // other way to interface with char[]. // // 2. store a tu_wstring as a union with // tu_string? Extra complexity. // // 3. ?? // // Storing UTF-8 seems like a pretty decent // way to do it. Everything else just // continues to work.#if (WCHAR_MAX != MAXINT) tu_string::encode_utf8_from_wchar(&m_string_value, (const uint16 *)wstr);#else# if (WCHAR_MAX != MAXSHORT)# error "Can't determine the size of wchar_t"# else tu_string::encode_utf8_from_wchar(&m_string_value, (const uint32 *)wstr);# endif#endif } as_value(bool val) : m_type(BOOLEAN), m_boolean_value(val) { } as_value(int val) : m_type(NUMBER), m_number_value(double(val)) { } as_value(float val) : m_type(NUMBER), m_number_value(double(val)) { } as_value(double val) : m_type(NUMBER), m_number_value(val) { } as_value(as_object_interface* obj); as_value(as_c_function_ptr func) : m_type(C_FUNCTION), m_c_function_value(func) { m_c_function_value = func; } as_value(as_as_function* func); ~as_value() { drop_refs(); } // Useful when changing types/values. void drop_refs(); type get_type() const { return m_type; } // Return true if this value is callable. bool is_function() const { return m_type == C_FUNCTION || m_type == AS_FUNCTION; } const char* to_string() const; const tu_string& to_tu_string() const; const tu_string& to_tu_string_versioned(int version) const; const tu_stringi& to_tu_stringi() const; double to_number() const; bool to_bool() const; as_object_interface* to_object() const; as_c_function_ptr to_c_function() const; as_as_function* to_as_function() const; void convert_to_number(); void convert_to_string(); void convert_to_string_versioned(int version); // These set_*()'s are more type-safe; should be used // in preference to generic overloaded set(). You are // more likely to get a warning/error if misused. void set_tu_string(const tu_string& str) { drop_refs(); m_type = STRING; m_string_value = str; } void set_string(const char* str) { drop_refs(); m_type = STRING; m_string_value = str; } void set_double(double val) { drop_refs(); m_type = NUMBER; m_number_value = val; } void set_bool(bool val) { drop_refs(); m_type = BOOLEAN; m_boolean_value = val; } void set_int(int val) { set_double(val); } void set_as_object_interface(as_object_interface* obj); void set_as_c_function_ptr(as_c_function_ptr func) { drop_refs(); m_type = C_FUNCTION; m_c_function_value = func; } void set_as_as_function(as_as_function* func); void set_undefined() { drop_refs(); m_type = UNDEFINED; } void set_null() { drop_refs(); m_type = NULLTYPE; } void operator=(const as_value& v) { if (v.m_type == UNDEFINED) set_undefined(); else if (v.m_type == NULLTYPE) set_null(); else if (v.m_type == BOOLEAN) set_bool(v.m_boolean_value); else if (v.m_type == STRING) set_tu_string(v.m_string_value); else if (v.m_type == NUMBER) set_double(v.m_number_value); else if (v.m_type == OBJECT) set_as_object_interface(v.m_object_value); else if (v.m_type == C_FUNCTION) set_as_c_function_ptr(v.m_c_function_value); else if (v.m_type == AS_FUNCTION) set_as_as_function(v.m_as_function_value); } bool operator==(const as_value& v) const; bool operator!=(const as_value& v) const; bool operator<(const as_value& v) const { return to_number() < v.to_number(); } void operator+=(const as_value& v) { set_double(this->to_number() + v.to_number()); } void operator-=(const as_value& v) { set_double(this->to_number() - v.to_number()); } void operator*=(const as_value& v) { set_double(this->to_number() * v.to_number()); } void operator/=(const as_value& v) { set_double(this->to_number() / v.to_number()); } // @@ check for div/0 void operator&=(const as_value& v) { set_int(int(this->to_number()) & int(v.to_number())); } void operator|=(const as_value& v) { set_int(int(this->to_number()) | int(v.to_number())); } void operator^=(const as_value& v) { set_int(int(this->to_number()) ^ int(v.to_number())); } void shl(const as_value& v) { set_int(int(this->to_number()) << int(v.to_number())); } void asr(const as_value& v) { set_int(int(this->to_number()) >> int(v.to_number())); } void lsr(const as_value& v) { set_int((Uint32(this->to_number()) >> int(v.to_number()))); } void string_concat(const tu_string& str); tu_string* get_mutable_tu_string() { assert(m_type == STRING); return &m_string_value; } };// tulrich: I'm not too sure this is useful. For things like// xml_as_object, is it sufficient to always store the event handlers// as ordinary members using their canonical names, instead of this// special table? I have a feeling that's what Macromedia does// (though I'm not sure).#if 0 // This class is just as_object_interface, with an event // handler table added. struct as_object_with_handlers : public as_object_interface { // ActionScript event handler table. hash<event_id, gameswf::as_value> m_event_handlers; // ActionScript event handler. void set_event_handler(event_id id, const as_value& method) { // m_event_handlers.push_back(as); //m_event_handlers.set(id, method); } bool get_event_handler(event_id id, gameswf::as_value* result) { //return m_event_handlers.get(id, result); return false; } };#endif // 0 // // as_prop_flags // // flags defining the level of protection of a member struct as_prop_flags { // Numeric flags int m_flags; // if true, this value is protected (internal to gameswf) bool m_is_protected; // mask for flags const static int as_prop_flags_mask = 0x7; // Default constructor as_prop_flags() : m_flags(0), m_is_protected(false) { } // Constructor as_prop_flags(const bool read_only, const bool dont_delete, const bool dont_enum) : m_flags(((read_only) ? 0x4 : 0) | ((dont_delete) ? 0x2 : 0) | ((dont_enum) ? 0x1 : 0)), m_is_protected(false) { } // Constructor, from numerical value as_prop_flags(const int flags) : m_flags(flags), m_is_protected(false) { } // accessor to m_readOnly bool get_read_only() const { return (((this->m_flags & 0x4)!=0)?true:false); } // accessor to m_dontDelete bool get_dont_delete() const { return (((this->m_flags & 0x2)!=0)?true:false); } // accessor to m_dontEnum bool get_dont_enum() const { return (((this->m_flags & 0x1)!=0)?true:false); } // accesor to the numerical flags value int get_flags() const { return this->m_flags; } // accessor to m_is_protected
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -