📄 gameswf_action.cpp
字号:
log_error("error in call_function: '%s' is not a function\n", function_name.c_str()); } } else { // Hopefully the actual function object is here. function = env->top(0); } int nargs = (int) env->top(1).to_number(); as_value result = call_method(function, env, NULL, nargs, env->get_top_index() - 2); env->drop(nargs + 1); env->top(0) = result; break; } case 0x3E: // return { // Put top of stack in the provided return slot, if // it's not NULL. if (retval) { *retval = env->top(0); } env->drop(1); // Skip the rest of this buffer (return from this action_buffer). pc = stop_pc; break; } case 0x3F: // modulo { as_value result; double y = env->pop().to_number(); double x = env->pop().to_number(); if (y != 0) {// env->top(1).set_double(fmod(env->top(1).to_bool() && env->top(0).to_bool());// env->drop(1); result = fmod(x, y); }// log_error("modulo x=%f, y=%f, z=%f\n",x,y,result.to_number()); env->push(result); break; } case 0x40: // new { as_value classname = env->pop(); IF_VERBOSE_ACTION(log_msg("---new object: %s\n", classname.to_tu_string().c_str())); int nargs = (int) env->pop().to_number(); as_value constructor = env->get_variable(classname.to_tu_string(), with_stack); as_value new_obj; if (constructor.get_type() == as_value::C_FUNCTION) { // C function is responsible for creating the new object and setting members. (constructor.to_c_function())(fn_call(&new_obj, NULL, env, nargs, env->get_top_index())); } else if (as_as_function* ctor_as_func = constructor.to_as_function()) { // This function is being used as a constructor; make sure // it has a prototype object. ctor_as_func->lazy_create_properties(); assert(ctor_as_func->m_properties); // Set up the prototype. as_value proto; ctor_as_func->m_properties->get_member("prototype", &proto); assert(proto.to_object() != NULL); // Create an empty object, with a ref to the constructor's prototype. smart_ptr<as_object> new_obj_ptr(new as_object(proto.to_object())); // Set up the constructor member. new_obj_ptr->set_member("constructor", constructor); new_obj_ptr->set_member_flags("constructor", 1); new_obj.set_as_object_interface(new_obj_ptr.get_ptr()); // Call the actual constructor function; new_obj is its 'this'. // We don't need the function result. call_method(constructor, env, new_obj_ptr.get_ptr(), nargs, env->get_top_index()); } else { if (classname != "String") { log_error("can't create object with unknown class '%s'\n", classname.to_tu_string().c_str()); } else { log_msg("Created special String class\n"); } } env->drop(nargs); env->push(new_obj);#if 0 log_msg("new object %s at %p\n", classname.to_tu_string().c_str(), new_obj);#endif break; } case 0x41: // declare local { const tu_string& varname = env->top(0).to_tu_string(); env->declare_local(varname); env->drop(1); break; } case 0x42: // init array { int array_size = (int) env->pop().to_number(); //log_msg("xxx init array: size = %d, top of stack = %d\n", // // array_size, env->get_top_index());//xxxxx// // Call the array constructor, to create an empty array.// as_value result;// as_global_array_ctor(fn_call(&result, NULL, env, 0, env->get_top_index()));// as_object_interface* ao = result.to_object();// assert(ao);// // @@ TODO Set array size.// // ao->set_length(whatever); or something// // Fill the elements with the initial values from the stack.// as_value index_number;// for (int i = 0; i < array_size; i++)// {// // @@ TODO a set_member that takes an int or as_value?// index_number.set_int(i);// ao->set_member(index_number.to_string(), env->pop());// }// env->push(result);// //log_msg("xxx init array end: top of stack = %d, trace(top(0)) =",// // env->get_top_index());//xxxxxxx as_global_trace(fn_call(NULL, NULL, env, 1, env->get_top_index())); //xxxx break; } case 0x43: // declare object { // @@ TODO log_error("todo opcode: %02X\n", action_id); break; } case 0x44: // type of { switch(env->top(0).get_type()) { case as_value::UNDEFINED: env->top(0).set_string("undefined"); break; case as_value::STRING: env->top(0).set_string("string"); break; case as_value::NUMBER: env->top(0).set_string("number"); break; case as_value::BOOLEAN: env->top(0).set_string("boolean"); break; case as_value::OBJECT: env->top(0).set_string("object"); break; case as_value::NULLTYPE: env->top(0).set_string("null"); break; case as_value::AS_FUNCTION: case as_value::C_FUNCTION: env->top(0).set_string("function"); break; default: log_error("typeof unknown type: %02X\n", env->top(0).get_type()); break; } break; } case 0x45: // get target { // @@ TODO log_error("todo opcode: %02X\n", action_id); break; } case 0x46: // enumerate { as_value var_name = env->pop(); const tu_string& var_string = var_name.to_tu_string(); as_value variable = env->get_variable(var_string, with_stack); if (variable.to_object() == NULL) { break; } const as_object* object = (as_object*) (variable.to_object()); // The end of the enumeration as_value nullvalue; nullvalue.set_null(); env->push(nullvalue); IF_VERBOSE_ACTION(log_msg("---enumerate - push: NULL\n")); stringi_hash<as_member>::const_iterator it = object->m_members.begin(); while (it != object->m_members.end()) { const as_member member = (it.get_value()); if (! member.get_member_flags().get_dont_enum()) { env->push(as_value(it.get_key())); IF_VERBOSE_ACTION(log_msg("---enumerate - push: %s\n", it.get_key().c_str())); } ++it; } const as_object * prototype = (as_object *) object->m_prototype; if (prototype != NULL) { stringi_hash<as_member>::const_iterator it = prototype->m_members.begin(); while (it != prototype->m_members.end()) { const as_member member = (it.get_value()); if (! member.get_member_flags().get_dont_enum()) { env->push(as_value(it.get_key())); IF_VERBOSE_ACTION(log_msg("---enumerate - push: %s\n", it.get_key().c_str())); } ++it; }; } break; } case 0x47: // add_t (typed) { if (env->top(0).get_type() == as_value::STRING || env->top(1).get_type() == as_value::STRING) { env->top(1).convert_to_string_versioned(version); env->top(1).string_concat(env->top(0).to_tu_string_versioned(version)); } else { env->top(1) += env->top(0); } env->drop(1); break; } case 0x48: // less than (typed) { if (env->top(1).get_type() == as_value::STRING) { env->top(1).set_bool(env->top(1).to_tu_string() < env->top(0).to_tu_string()); } else { env->top(1).set_bool(env->top(1) < env->top(0)); } env->drop(1); break; } case 0x49: // equal (typed) { // @@ identical to untyped equal, as far as I can tell... env->top(1).set_bool(env->top(1) == env->top(0)); env->drop(1); break; } case 0x4A: // to number { env->top(0).convert_to_number(); break; } case 0x4B: // to string { env->top(0).convert_to_string_versioned(version); break; } case 0x4C: // dup env->push(env->top(0)); break; case 0x4D: // swap { as_value temp = env->top(1); env->top(1) = env->top(0); env->top(0) = temp; break; } case 0x4E: // get member { as_object_interface* obj = env->top(1).to_object(); // Special case: String has a member "length" if (obj == NULL && env->top(1).get_type() == as_value::STRING && env->top(0).to_tu_stringi() == "length") { int len = env->top(1).to_tu_string_versioned(version).utf8_length(); env->top(1).set_int(len); } else { env->top(1).set_undefined(); // int nargs = (int) env->top(1).to_number(); if (obj) { obj->get_member(env->top(0).to_tu_string(), &(env->top(1))); if (env->top(1).to_object() == NULL) { IF_VERBOSE_ACTION(log_msg("-- get_member %s=%s\n", env->top(0).to_tu_string().c_str(), env->top(1).to_tu_string().c_str())); } else { IF_VERBOSE_ACTION(log_msg("-- get_member %s=%s at %p\n", env->top(0).to_tu_string().c_str(), env->top(1).to_tu_string().c_str(), env->top(1).to_object())); } } else { // @@ log error? } } env->drop(1); break; } case 0x4F: // set member { as_object_interface* obj = env->top(2).to_object(); if (obj) { obj->set_member(env->top(1).to_tu_string(), env->top(0)); IF_VERBOSE_ACTION( log_msg("-- set_member %s.%s=%s\n", env->top(2).to_tu_string().c_str(), env->top(1).to_tu_string().c_str(), env->top(0).to_tu_string().c_str())); } else { // Invalid object, can't set. IF_VERBOSE_ACTION( log_msg("-- set_member %s.%s=%s on invalid object!\n", env->top(2).to_tu_string().c_str(), env->top(1).to_tu_string().c_str(), env->top(0).to_tu_string().c_str())); } env->drop(3); break; } case 0x50: // increment env->top(0) += 1; break; case 0x51: // decrement env->top(0) -= 1; break; case 0x52: // call method { int nargs = (int) env->top(2).to_number(); as_value result; const tu_string& method_name = env->top(0).to_tu_string(); as_object_interface* obj = env->top(1).to_object(); if (obj) { as_value method; if (obj->get_member(method_name, &method)) { if (method.get_type() != as_value::C_FUNCTION && method.get_type() != as_value::AS_FUNCTION) { log_error("error: call_method: '%s' is not a method\n", method_name.c_str()); } else { result = call_method( method, env, obj, nargs, env->get_top_index() - 3); } } else { log_error("error: call_method can't find method %s\n", method_name.c_str()); } } else if (env->top(1).get_type() == as_value::STRING) { // Handle methods on literal strings. string_method( fn_call(&result, NULL, env, nargs, env->get_top_index() - 3), method_name.to_tu_stringi(), env->top(1).to_tu_string_versioned(version)); } else if (env->top(1).get_type() == as_value::C_FUNCTION) { // Catch method calls on String // constructor. There may be a cleaner // way to do this. Perhaps we call the // constructor function with a special flag, to // indicate that it's a method call? if (env->top(1).to_c_function() == string_ctor) { tu_string dummy; string_method( fn_call(&result, NULL, env, nargs, env->get_top_index() - 3), method_name.to_tu_stringi(), dummy); } else { log_error("error: method call on unknown c function.\n"); } } else { if (env->top(1).get_type() == as_value::NUMBER && method_name == "toString") { // Numbers have a .toString() method. result.set_tu_string(env->top(1).to_tu_string()); } else { log_error("error: call_method '%s' on invalid object.\n", method_name.c_str()); } } env->drop(nargs + 2); env->top(0) = result; break; } case 0x53: // new method // @@ TODO log_error("todo opcode: %02X\n", action_id); break; case 0x54: // instance of // @@ TODO log_error("todo opcode: %02X\n", action_id); break; case 0x55: // enumerate object // @@ TODO log_error("todo opcode: %02X\n", action_id); break; case 0x60: // bitwise and env->top(1) &= env->top(0); env->drop(1); break; case 0x61: // bitwise or env->top(1) |= env->top(0); env->drop(1); break; case 0x62: // bitwise xor env->top(1) ^= env->top(0); env->drop(1); break; case 0x63: // shift left env->top(1).shl(env->top(0)); env->drop(1); break; case 0x64: // shift right (signed) env->top(1).asr(env->top(0)); env->drop(1); break; case 0x65: // shift right (unsigned) env->top(1).lsr(env->top(0)); env->drop(1); break; case 0x66: // strict equal if (env->top(1).get_type() != env->top(0).get_type()) { // Types don't match. env->top(1).set_bool(false); env->drop(1); } else { env->top(1).set_bool(env->top(1) == env->top(0)); env->drop(1); } break; case 0x67: // gt (typed) if (env->top(1).get_type() == as_value::STRING) { env->top(1).set_bool(env->top(1).to_tu_string() > env->top(0).to_tu_string()); } else { env->top(1).set_bool(env->top(1).to_number() > env->top(0).to_number()); } env->drop(1); break; case 0x68: // string gt env->top(1).set_bool(env->top(1).to_tu_string() > env->top(0).to_tu_string()); env->drop(1); break; case 0x69: // extends log_error("todo opcode: %02X\n", action_id); break; } pc++; // advance to next action. } else { IF_VERBOSE_ACTION(log_msg("EX:\t"); log_disasm(&m_buffer[pc])); // Action containing extra data. int length =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -