📄 gameswf_action.cpp
字号:
// gameswf_action.cpp -- 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.#include "gameswf_action.h"#include "gameswf_impl.h"#include "gameswf_log.h"#include "gameswf_stream.h"#include "base/tu_random.h"#include "gameswf_string.h"#include "gameswf_movie.h"#include "gameswf_timers.h"#include "gameswf_textformat.h"#include "gameswf_sound.h"#ifdef HAVE_LIBXML#include "gameswf_xml.h"#include "gameswf_xmlsocket.h"#endif#ifdef _WIN32#define snprintf _snprintf#endif // _WIN32// NOTES://// Buttons// on (press) onPress// on (release) onRelease// on (releaseOutside) onReleaseOutside// on (rollOver) onRollOver// on (rollOut) onRollOut// on (dragOver) onDragOver// on (dragOut) onDragOut// on (keyPress"...") onKeyDown, onKeyUp <----- IMPORTANT//// Sprites// onClipEvent (load) onLoad// onClipEvent (unload) onUnload Hm.// onClipEvent (enterFrame) onEnterFrame// onClipEvent (mouseDown) onMouseDown// onClipEvent (mouseUp) onMouseUp// onClipEvent (mouseMove) onMouseMove// onClipEvent (keyDown) onKeyDown// onClipEvent (keyUp) onKeyUp// onClipEvent (data) onData// Text fields have event handlers too!// Sprite built in methods:// play()// stop()// gotoAndStop()// gotoAndPlay()// nextFrame()// startDrag()// getURL()// getBytesLoaded()// getBytesTotal()// Built-in functions: (do these actually exist in the VM, or are they just opcodes?)// Number()// String()// TODO builtins//// Number.toString() -- takes an optional arg that specifies the base//// parseInt(), parseFloat()//// Boolean() type cast//// typeof operator --> "number", "string", "boolean", "object" (also// for arrays), "null", "movieclip", "function", "undefined"//// isNaN()//// Number.MAX_VALUE, Number.MIN_VALUE//// String.fromCharCode()namespace gameswf{ // // action stuff // void action_init(); // Statics. bool s_inited = false; smart_ptr<as_object> s_global; fscommand_callback s_fscommand_handler = NULL;#define EXTERN_MOVIE #ifdef EXTERN_MOVIE void attach_extern_movie(const char* url, const movie* target, const movie* root_movie) { tu_string infile = get_workdir(); infile += url; movie_definition_sub* md = create_library_movie_sub(infile.c_str()); if (md == NULL) { log_error("can't create movie_definition_sub for %s\n", infile.c_str()); return; } gameswf::movie_interface* extern_movie; if (target == root_movie) { extern_movie = create_library_movie_inst_sub(md); if (extern_movie == NULL) { log_error("can't create extern root movie_interface for %s\n", infile.c_str()); return; } set_current_root(extern_movie); movie* m = extern_movie->get_root_movie(); m->on_event(event_id::LOAD); } else { extern_movie = md->create_instance(); if (extern_movie == NULL) { log_error("can't create extern movie_interface for %s\n", infile.c_str()); return; } save_extern_movie(extern_movie); character* tar = (character*)target; const char* name = tar->get_name(); Uint16 depth = tar->get_depth(); bool use_cxform = false; cxform color_transform = tar->get_cxform(); bool use_matrix = false; matrix mat = tar->get_matrix(); float ratio = tar->get_ratio(); Uint16 clip_depth = tar->get_clip_depth(); movie* parent = tar->get_parent(); movie* new_movie = extern_movie->get_root_movie(); assert(parent != NULL); ((character*)new_movie)->set_parent(parent); parent->replace_display_object( (character*) new_movie, name, depth, use_cxform, color_transform, use_matrix, mat, ratio, clip_depth); } }#endif // EXTERN_MOVIE void register_fscommand_callback(fscommand_callback handler) // External interface. { s_fscommand_handler = handler; } static bool string_to_number(double* result, const char* str) // Utility. Try to convert str to a number. If successful, // put the result in *result, and return true. If not // successful, put 0 in *result, and return false. { char* tail = 0; *result = strtod(str, &tail); if (tail == str || *tail != 0) { // Failed conversion to Number. return false; } return true; } // // array object // struct as_array_object : public as_object {// @@ TODO// as_array_object()// {// this->set_member("length", &array_not_impl);// this->set_member("join", &array_not_impl);// this->set_member("concat", &array_not_impl);// this->set_member("slice", &array_not_impl);// this->set_member("push", &array_not_impl);// this->set_member("unshift", &array_not_impl);// this->set_member("pop", &array_not_impl);// this->set_member("shift", &array_not_impl);// this->set_member("splice", &array_not_impl);// this->set_member("sort", &array_not_impl);// this->set_member("sortOn", &array_not_impl);// this->set_member("reverse", &array_not_impl);// this->set_member("toString", &array_not_impl);// } }; void array_not_impl(const fn_call& fn) { log_error("array methods not implemented yet\n"); } // // as_as_function // void as_as_function::operator()(const fn_call& fn) // Dispatch. { as_environment* our_env = m_env; if (our_env == NULL) { our_env = fn.env; } assert(our_env); // Set up local stack frame, for parameters and locals. int local_stack_top = our_env->get_local_frame_top(); our_env->add_frame_barrier(); if (m_is_function2 == false) { // Conventional function. // Push the arguments onto the local frame. int args_to_pass = imin(fn.nargs, m_args.size()); for (int i = 0; i < args_to_pass; i++) { assert(m_args[i].m_register == 0); our_env->add_local(m_args[i].m_name, fn.arg(i)); } } else { // function2: most args go in registers; any others get pushed. // Create local registers. our_env->add_local_registers(m_local_register_count); // Handle the explicit args. int args_to_pass = imin(fn.nargs, m_args.size()); for (int i = 0; i < args_to_pass; i++) { if (m_args[i].m_register == 0) { // Conventional arg passing: create a local var. our_env->add_local(m_args[i].m_name, fn.arg(i)); } else { // Pass argument into a register. int reg = m_args[i].m_register; *(our_env->local_register_ptr(reg)) = fn.arg(i); } } // Handle the implicit args. int current_reg = 1; if (m_function2_flags & 0x01) { // preload 'this' into a register. (*(our_env->local_register_ptr(current_reg))).set_as_object_interface(our_env->m_target); current_reg++; } if (m_function2_flags & 0x02) { // Don't put 'this' into a local var. } else { // Put 'this' in a local var. our_env->add_local("this", as_value(our_env->m_target)); } // Init arguments array, if it's going to be needed. smart_ptr<as_array_object> arg_array; if ((m_function2_flags & 0x04) || ! (m_function2_flags & 0x08)) { arg_array = new as_array_object; as_value index_number; for (int i = 0; i < fn.nargs; i++) { index_number.set_int(i); arg_array->set_member(index_number.to_string(), fn.arg(i)); } } if (m_function2_flags & 0x04) { // preload 'arguments' into a register. (*(our_env->local_register_ptr(current_reg))).set_as_object_interface(arg_array.get_ptr()); current_reg++; } if (m_function2_flags & 0x08) { // Don't put 'arguments' in a local var. } else { // Put 'arguments' in a local var. our_env->add_local("arguments", as_value(arg_array.get_ptr())); } if (m_function2_flags & 0x10) { // Put 'super' in a register. log_error("TODO: implement 'super' in function2 dispatch (reg)\n"); current_reg++; } if (m_function2_flags & 0x20) { // Don't put 'super' in a local var. } else { // Put 'super' in a local var. log_error("TODO: implement 'super' in function2 dispatch (var)\n"); } if (m_function2_flags & 0x40) { // Put '_root' in a register. (*(our_env->local_register_ptr(current_reg))).set_as_object_interface( our_env->m_target->get_root_movie()); current_reg++; } if (m_function2_flags & 0x80) { // Put '_parent' in a register. array<with_stack_entry> dummy; as_value parent = our_env->get_variable("_parent", dummy); (*(our_env->local_register_ptr(current_reg))) = parent; current_reg++; } if (m_function2_flags & 0x100) { // Put '_global' in a register. (*(our_env->local_register_ptr(current_reg))).set_as_object_interface(s_global.get_ptr()); current_reg++; } } // Execute the actions. m_action_buffer->execute(our_env, m_start_pc, m_length, fn.result, m_with_stack, m_is_function2); // Clean up stack frame. our_env->set_local_frame_top(local_stack_top); if (m_is_function2) { // Clean up the local registers. our_env->drop_local_registers(m_local_register_count); } } // // Function/method dispatch. // as_value call_method( const as_value& method, as_environment* env, as_object_interface* this_ptr, int nargs, int first_arg_bottom_index) // first_arg_bottom_index is the stack index, from the bottom, of the first argument. // Subsequent arguments are at *lower* indices. E.g. if first_arg_bottom_index = 7, // then arg1 is at env->bottom(7), arg2 is at env->bottom(6), etc. { as_value val; as_c_function_ptr func = method.to_c_function(); if (func) { // It's a C function. Call it. (*func)(fn_call(&val, this_ptr, env, nargs, first_arg_bottom_index)); } else if (as_as_function* as_func = method.to_as_function()) { // It's an ActionScript function. Call it. (*as_func)(fn_call(&val, this_ptr, env, nargs, first_arg_bottom_index)); } else { log_error("error in call_method(): method is not a function\n"); } return val; } as_value call_method0( const as_value& method, as_environment* env, as_object_interface* this_ptr) { return call_method(method, env, this_ptr, 0, env->get_top_index() + 1); } const char* call_method_parsed( as_environment* env, as_object_interface* this_ptr, const char* method_name, const char* method_arg_fmt, va_list args) // Printf-like vararg interface for calling ActionScript. // Handy for external binding. { log_msg("FIXME(%d): %s\n", __LINE__, __FUNCTION__);#if 0 static const int BUFSIZE = 1000; char buffer[BUFSIZE]; array<const char*> tokens; // Brutal crap parsing. Basically null out any // delimiter characters, so that the method name and // args sit in the buffer as null-terminated C // strings. Leave an intial ' character as the first // char in a string argument. // Don't verify parens or matching quotes or anything. { strncpy(buffer, method_call, BUFSIZE); buffer[BUFSIZE - 1] = 0; char* p = buffer; char in_quote = 0; bool in_arg = false; for (;; p++) { char c = *p; if (c == 0) { // End of string. break; } else if (c == in_quote) { // End of quotation. assert(in_arg); *p = 0; in_quote = 0; in_arg = false; } else if (in_arg) { if (in_quote == 0) { if (c == ')' || c == '(' || c == ',' || c == ' ') { // End of arg. *p = 0; in_arg = false; } } } else { // Not in arg. Watch for start of arg. assert(in_quote == 0); if (c == '\'' || c == '\"') { // Start of quote. in_quote = c; in_arg = true; *p = '\''; // ' at the start of the arg, so later we know this is a string. tokens.push_back(p); } else if (c == ' ' || c == ',') { // Non-arg junk, null it out. *p = 0; } else { // Must be the start of a numeric arg. in_arg = true; tokens.push_back(p); } } } }#endif // 0 // Parse va_list args int starting_index = env->get_top_index();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -