📄 gameswf_action.cpp
字号:
{ if (fn.nargs < 1) { log_error("key_remove_listener needs one argument (the listener object)\n"); return; } as_object_interface* listener = fn.arg(0).to_object(); if (listener == NULL) { log_error("key_remove_listener passed a NULL object; ignored\n"); return; } key_as_object* ko = (key_as_object*) (as_object*) fn.this_ptr; assert(ko); ko->remove_listener(listener); } void key_init() { // Create built-in key object. as_object* key_obj = new key_as_object; // constants#define KEY_CONST(k) key_obj->set_member(#k, key::k) KEY_CONST(BACKSPACE); KEY_CONST(CAPSLOCK); KEY_CONST(CONTROL); KEY_CONST(DELETEKEY); KEY_CONST(DOWN); KEY_CONST(END); KEY_CONST(ENTER); KEY_CONST(ESCAPE); KEY_CONST(HOME); KEY_CONST(INSERT); KEY_CONST(LEFT); KEY_CONST(PGDN); KEY_CONST(PGUP); KEY_CONST(RIGHT); KEY_CONST(SHIFT); KEY_CONST(SPACE); KEY_CONST(TAB); KEY_CONST(UP); // methods key_obj->set_member("addListener", &key_add_listener); key_obj->set_member("getAscii", &key_get_ascii); key_obj->set_member("getCode", &key_get_code); key_obj->set_member("isDown", &key_is_down); key_obj->set_member("isToggled", &key_is_toggled); key_obj->set_member("removeListener", &key_remove_listener); s_global->set_member("Key", key_obj); } void notify_key_event(key::code k, bool down) // External interface for the host to report key events. { action_init(); // @@ put this in some global init somewhere else... static tu_string key_obj_name("Key"); as_value kval; s_global->get_member(key_obj_name, &kval); if (kval.get_type() == as_value::OBJECT) { key_as_object* ko = (key_as_object*) kval.to_object(); assert(ko); if (down) ko->set_key_down(k); else ko->set_key_up(k); } else { log_error("gameswf::notify_key_event(): no Key built-in\n"); } } // // global init // void as_global_trace(const fn_call& fn) { assert(fn.nargs >= 1); // Special case for objects: try the toString() method. if (fn.arg(0).get_type() == as_value::OBJECT) { as_object_interface* obj = fn.arg(0).to_object(); assert(obj); as_value method; if (obj->get_member("toString", &method) && method.is_function()) { as_value result = call_method0(method, fn.env, obj); log_msg("%s\n", result.to_string()); return; } } // Log our argument. // // @@ what if we get extra args? // // @@ Array gets special treatment. const char* arg0 = fn.arg(0).to_string(); log_msg("%s\n", arg0); } void as_global_sound_ctor(const fn_call& fn) // Constructor for ActionScript class Sound. { smart_ptr<as_object> sound_obj(new sound_as_object); // methods sound_obj->set_member("attachSound", &sound_attach); sound_obj->set_member("start", &sound_start); sound_obj->set_member("stop", &sound_stop); fn.result->set_as_object_interface(sound_obj.get_ptr()); } void as_global_object_ctor(const fn_call& fn) // Constructor for ActionScript class Object. { fn.result->set_as_object_interface(new as_object); } void as_global_array_ctor(const fn_call& fn) // Constructor for ActionScript class Array. { smart_ptr<as_array_object> ao = new as_array_object; if (fn.nargs == 0) { // Empty array. } else if (fn.nargs == 1 && fn.arg(0).get_type() == as_value::NUMBER) { // Create an empty array with the given number of undefined elements. // // @@ TODO set length property; no need to // actually create the elements now, since // they're undefined. } else { // Use the arguments as initializers. as_value index_number; for (int i = 0; i < fn.nargs; i++) { index_number.set_int(i); ao->set_member(index_number.to_string(), fn.arg(i)); } // @@ TODO set length property } fn.result->set_as_object_interface(ao.get_ptr()); } void as_global_assetpropflags(const fn_call& fn) // ASSetPropFlags function { const int version = fn.env->get_target()->get_movie_definition()->get_version(); // Check the arguments assert(fn.nargs == 3 || fn.nargs == 4); assert((version == 5) ? (fn.nargs == 3) : true); // object as_object_interface* const obj = fn.arg(0).to_object(); assert(obj != NULL); // list of child names as_object_interface* props = fn.arg(1).to_object(); if (props == NULL) { // tulrich: this fires in test_ASSetPropFlags -- is it correct? assert(fn.arg(1).get_type() == as_value::NULLTYPE); } // a number which represents three bitwise flags which // are used to determine whether the list of child names should be hidden, // un-hidden, protected from over-write, un-protected from over-write, // protected from deletion and un-protected from deletion int set_true = int(fn.arg(2).to_number()) & as_prop_flags::as_prop_flags_mask; // Is another integer bitmask that works like set_true, // except it sets the attributes to false. The // set_false bitmask is applied before set_true is applied // ASSetPropFlags was exposed in Flash 5, however the fourth argument 'set_false' // was not required as it always defaulted to the value '~0'. int set_false = (fn.nargs == 3 ? (version == 5 ? ~0 : 0) : int(fn.arg(3).to_number())) & as_prop_flags::as_prop_flags_mask; // Evan: it seems that if set_true == 0 and set_false == 0, this function // acts as if the parameters where (object, null, 0x1, 0) ... if (set_false == 0 && set_true == 0) { props = NULL; set_false = 0; set_true = 0x1; } if (props == NULL) { // Take all the members of the object as_object* object = (as_object*) obj; stringi_hash<as_member>::const_iterator it = object->m_members.begin(); while (it != object->m_members.end()) { as_member member = it.get_value(); as_prop_flags f = member.get_member_flags(); const int oldflags = f.get_flags(); const int newflags = f.set_flags(set_true, set_false); member.set_member_flags(f); object->m_members.set(it.get_key(), member); ++it; } if (object->m_prototype != NULL) { const as_object* prototype = (as_object*) object->m_prototype; it = prototype->m_members.begin(); while (it != prototype->m_members.end()) { as_member member = it.get_value(); as_prop_flags f = member.get_member_flags(); const int oldflags = f.get_flags(); const int newflags = f.set_flags(set_true, set_false); member.set_member_flags(f); object->m_members.set(it.get_key(), member); ++it; } } } else { as_object* object = (as_object*) obj; as_object* object_props = (as_object*) props; stringi_hash<as_member>::iterator it = object_props->m_members.begin(); while(it != object_props->m_members.end()) { const tu_stringi key = (it.get_value()).get_member_value().to_string(); stringi_hash<as_member>::iterator it2 = object->m_members.find(key); if (it2 != object->m_members.end()) { as_member member = it2.get_value(); as_prop_flags f = member.get_member_flags(); const int oldflags = f.get_flags(); const int newflags = f.set_flags(set_true, set_false); member.set_member_flags(f); object->m_members.set((it.get_value()).get_member_value().to_string(), member); } ++it; } } } void action_init() // Create/hook built-ins. { if (s_inited == false) { s_inited = true; // @@ s_global should really be a // client-visible player object, which // contains one or more actual movie // instances. We're currently just hacking it // in as an app-global mutable object :( assert(s_global == NULL); s_global = new as_object; s_global->set_member("trace", as_value(as_global_trace)); s_global->set_member("Object", as_value(as_global_object_ctor)); s_global->set_member("Sound", as_value(as_global_sound_ctor)); s_global->set_member("Array", as_value(as_global_array_ctor)); s_global->set_member("TextFormat", as_value(textformat_new));#ifdef HAVE_LIBXML s_global->set_member("XML", as_value(xml_new)); //s_global->set_member("XML", as_value(xmlsocket_xml_new)); s_global->set_member("XMLSocket", as_value(xmlsocket_new));#endif // HAVE_LIBXML s_global->set_member("MovieClipLoader", as_value(moviecliploader_new)); s_global->set_member("String", as_value(string_ctor)); // ASSetPropFlags s_global->set_member("ASSetPropFlags", as_global_assetpropflags); math_init(); key_init(); } } void action_clear() { if (s_inited) { s_inited = false; s_global->clear(); s_global = NULL; } } // // properties by number // static const tu_string s_property_names[] = { tu_string("_x"), tu_string("_y"), tu_string("_xscale"), tu_string("_yscale"), tu_string("_currentframe"), tu_string("_totalframes"), tu_string("_alpha"), tu_string("_visible"), tu_string("_width"), tu_string("_height"), tu_string("_rotation"), tu_string("_target"), tu_string("_framesloaded"), tu_string("_name"), tu_string("_droptarget"), tu_string("_url"), tu_string("_highquality"), tu_string("_focusrect"), tu_string("_soundbuftime"), tu_string("@@ mystery quality member"), tu_string("_xmouse"), tu_string("_ymouse"), }; static as_value get_property(as_object_interface* obj, int prop_number) { as_value val; if (prop_number >= 0 && prop_number < int(sizeof(s_property_names)/sizeof(s_property_names[0]))) { obj->get_member(s_property_names[prop_number], &val); } else { log_error("error: invalid property query, property number %d\n", prop_number); } return val; } static void set_property(as_object_interface* obj, int prop_number, const as_value& val) { if (prop_number >= 0 && prop_number < int(sizeof(s_property_names)/sizeof(s_property_names[0]))) { obj->set_member(s_property_names[prop_number], val); } else { log_error("error: invalid set_property, property number %d\n", prop_number); } } // // do_action // // Thin wrapper around action_buffer. struct do_action : public execute_tag { action_buffer m_buf; void read(stream* in) { m_buf.read(in); } virtual void execute(movie* m) { m->add_action_buffer(&m_buf); } // Don't override because actions should not be replayed when seeking the movie. //void execute_state(movie* m) {} virtual bool is_action_tag() const // Tell the caller that we are an action tag. { return true; } }; void do_action_loader(stream* in, int tag_type, movie_definition_sub* m) { IF_VERBOSE_PARSE(log_msg("tag %d: do_action_loader\n", tag_type)); IF_VERBOSE_ACTION(log_msg("-- actions in frame %d\n", m->get_loading_frame())); assert(in); assert(tag_type == 12); assert(m); do_action* da = new do_action; da->read(in); m->add_execute_tag(da); } // // do_init_action // void do_init_action_loader(stream* in, int tag_type, movie_definition_sub* m) { assert(tag_type == 59); int sprite_character_id = in->read_u16(); IF_VERBOSE_PARSE(log_msg(" tag %d: do_init_action_loader\n", tag_type)); IF_VERBOSE_ACTION(log_msg(" -- init actions for sprite %d\n", sprite_character_id)); do_action* da = new do_action; da->read(in); m->add_init_action(sprite_character_id, da); } // // action_buffer // // Disassemble one instruction to the log. static void log_disasm(const unsigned char* instruction_data); action_buffer::action_buffer() : m_decl_dict_processed_at(-1) { } void action_buffer::read(stream* in) { // Read action bytes. for (;;) { int instruction_start = m_buffer.size(); int pc = m_buffer.size(); int action_id = in->read_u8(); m_buffer.push_back(action_id); if (action_id & 0x80) { // Action contains extra data. Read it. int length = in->read_u16(); m_buffer.push_back(length & 0x0FF); m_buffer.push_back((length >> 8) & 0x0FF); for (int i = 0; i < length; i++) { unsigned char b = in->read_u8(); m_buffer.push_back(b); } } IF_VERBOSE_ACTION(log_msg("%4d\t", pc); log_disasm(&m_buffer[instruction_start]); ); if (action_id == 0) { // end of action buffer. break; } } } void action_buffer::process_decl_dict(int start_pc, int stop_pc) // Interpret the decl_dict opcode. Don't read stop_pc or // later. A dictionary is some static strings embedded in the // action buffer; there should only be one dictionary per // action buffer. // // NOTE: Normally the dictionary is declared as the first // action in an action buffer, but I've seen what looks like // some form of copy protection that amounts to: // // <start of action buffer> // push true // branch_if_true label // decl_dict [0] // this is never executed, but has lots of orphan data declared in the opcode // label: // (embedded inside the previous opcode; looks like an invalid jump) // ... "protected" code here, including the real decl_dict opcode ...
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -