void	as_environment::set_variable_raw (
	    const tu_string &varname,
	    const as_value &val,
	    const array<with_stack_entry>& with_stack )
	// No path rigamarole.
	{
		// Check the with-stack.
		for ( int i = with_stack.size() - 1; i >= 0; i-- )
		{
			as_object	*obj = with_stack[i].m_object.get_ptr();
			as_value unused;

			if ( obj && obj->get_member ( varname, &unused ) )
			{
				// This object has the member; so set it here.
				obj->set_member ( varname, val );
				return;
			}
		}

		// Check locals.
		int	local_index = find_local ( varname, true );

		if ( local_index >= 0 )
		{
			// Set local var.
			m_local_frames[local_index].m_value = val;
			return;
		}

		if ( m_target != NULL )
		{
			m_target->set_member ( varname, val );
		}

		else
		{
			// assume local var
			// This case happens for example so
			// class myclass
			// {
			//		function myfunc()
			//		{
			//			for (i=0;...)		should be for (var i=0; ...)
			//			{
			//			}
			//		}
			//	}
			add_local ( varname, val );
			IF_VERBOSE_ACTION ( log_error ( "can't set_variable_raw %s=%s, target is NULL, it's assumed as local\n",
			                                varname.c_str(), val.to_string() ) );
			IF_VERBOSE_ACTION ( log_error ( "probably you forgot to declare variable '%s'\n", varname.c_str() ) );
		}
	}
	as_value *as_environment::get_register ( int reg )
	{
		as_value *val = local_register_ptr ( reg );
		IF_VERBOSE_ACTION ( log_msg ( "-------------- get_register(%d): %s at %p\n",
		                              reg, val->to_string(), val->to_object() ) );
		return val;
	}
Beispiel #3
0
	void	as_mcloader_loadclip(const fn_call& fn)
	{
		as_mcloader* mcl = cast_to<as_mcloader>(fn.this_ptr);
		assert(mcl);

		fn.result->set_bool(false);	// on default
		if (fn.nargs == 2)
		{
			array<as_value> event_args;	// for event handler args
			event_args.push_back(as_value());	// undefined

			tu_string infile = get_full_url(fn.get_player()->get_workdir(), fn.arg(0).to_string());
			movie_definition*	md = fn.get_player()->create_movie(infile.c_str());
			if (md == NULL)
			{
				IF_VERBOSE_ACTION(log_msg("can't create movie from %s\n", fn.arg(0).to_string()));
				event_args.push_back("URLNotFound");	// 2-d param
				mcl->m_listeners.notify(event_id(event_id::ONLOAD_ERROR, &event_args));
				return;
			}

			as_mcloader::loadable_movie lm;
			lm.m_def = cast_to<movie_def_impl>(md);
			lm.m_target = cast_to<character>(fn.env->find_target(fn.arg(1)));
			mcl->m_lm.push_back(lm);

			mcl->m_listeners.notify(event_id(event_id::ONLOAD_START, &event_args));
			fn.result->set_bool(true);
		}
	}
	void	as_environment::set_variable (
	    const tu_string &varname,
	    const as_value &val,
	    const array<with_stack_entry>& with_stack )
	// Given a path to variable, set its value.
	{
		IF_VERBOSE_ACTION ( log_msg ( "-------------- %s = %s\n", varname.c_str(), val.to_string() ) ); //xxxxxxxxxx
		// Path lookup rigamarole.
		character	*target = get_target();
		tu_string	path;
		tu_string	var;

		if ( parse_path ( varname, &path, &var ) )
		{
			target = cast_to<character> ( find_target ( path.c_str() ) );

			if ( target )
			{
				target->set_member ( var, val );
			}
		}

		else
		{
			set_variable_raw ( varname, val, with_stack );
		}
	}
Beispiel #5
0
	void	sound_attach(const fn_call& fn)
	{
		if (fn.nargs < 1)
		{
			log_error("attach sound needs one argument\n");
			return;
		}

		as_sound*	snd = cast_to<as_sound>(fn.this_ptr);
		assert(snd);

		assert(fn.env);

		// find target movieclip
		character* target = snd->m_target.get_ptr();
		if (target == NULL)
		{
			target = fn.env->get_target();
		}
			
		// find resource
		character_def* res = NULL;
		if (target)
		{
			res = target->find_exported_resource(fn.arg(0).to_string());
		}

		if (res == NULL)
		{
			IF_VERBOSE_ACTION(log_msg("import error: resource '%s' is not exported\n",
				fn.arg(0).to_string()));
			return;
		}

		int si = 0;
		sound_sample* ss = cast_to<sound_sample>(res);

		if (ss != NULL)
		{
			si = ss->m_sound_handler_id;
		}
		else
		{
			log_error("sound sample is NULL\n");
			return;
		}

		snd->clear();

		// sanity check
		assert(si >= 0 && si < 1000);
		snd->m_id = si;

		snd->m_is_loaded_sound = false;
	}
	void as_environment::set_target ( as_value &target, character *original_target )
	{
		if ( target.is_string() )
		{
			tu_string path = target.to_tu_string();
			IF_VERBOSE_ACTION ( log_msg ( "-------------- ActionSetTarget2: %s", path.c_str() ) );

			if ( path.size() > 0 )
			{
				character *tar = cast_to<character> ( find_target ( path.c_str() ) );

				if ( tar )
				{
					set_target ( tar );
					return;
				}
			}

			else
			{
				set_target ( original_target );
				return;
			}
		}

		else if ( target.is_object() )
		{
			IF_VERBOSE_ACTION ( log_msg ( "-------------- ActionSetTarget2: %s", target.to_string() ) );
			character *tar = cast_to<character> ( find_target ( target ) );

			if ( tar )
			{
				set_target ( tar );
				return;
			}
		}

		IF_VERBOSE_ACTION ( log_msg ( "can't set target %s\n", target.to_string() ) );
	}
						static void call( const char * name, array<as_value> & stack )
						{
							as_value& val = stack[stack.size() - 1];
							as_object* obj = stack[stack.size() - 2].to_object();
							if (obj)
							{
								obj->set_member(name, val);
							}

							IF_VERBOSE_ACTION(log_msg("EX: initproperty\t 0x%p.%s=%s\n", obj, name, val.to_xstring()));

							stack.resize(stack.size() - 2);
						}
						static void call( array<as_value> & stack, int arg_count )
						{
							as_object* obj = stack.back().to_object();
							stack.resize(stack.size() - 1);
							for (int i = 0; i < arg_count; i++)
							{
								as_value& val = stack.back();
								stack.resize(stack.size() - 1);
							}

							//TODO: construct super of obj

							IF_VERBOSE_ACTION(log_msg("EX: constructsuper\t 0x%p(args:%d)\n", obj, arg_count));
						}
Beispiel #9
0
	bool	root::goto_labeled_frame(const char* label)
	{
		int	target_frame = -1;
		if (m_def->get_labeled_frame(label, &target_frame))
		{
			goto_frame(target_frame);
			return true;
		}
		else
		{
			IF_VERBOSE_ACTION(
				log_error("error: movie_impl::goto_labeled_frame('%s') unknown label\n", label));
			return false;
		}
	}
						static void call( const char* name, array<as_value> & scope, array<as_value> &stack )
						{
							// search property in scope
							as_value val;
							for (int i = scope.size() - 1; i >= 0; i--)
							{
								if (scope[i].find_property(name, &val))
								{
									break;
								}
							}

							IF_VERBOSE_ACTION(log_msg("EX: getlex\t %s, value=%s\n", name, val.to_xstring()));

							stack.push_back(val);
						}
						static void call( const char* name, array<as_value> & scope, array<as_value> & stack )
						{
							as_object* obj = NULL;
							for (int i = scope.size() - 1; i >= 0; i--)
							{
								as_value val;
								if (scope[i].find_property(name, &val))
								{
									obj = scope[i].to_object();
									break;
								}
							}

							IF_VERBOSE_ACTION(log_msg("EX: findproperty\t %s, obj=0x%p\n", name, obj));

							stack.push_back(obj);
						}
		static void call( const as_object *_this, const char* name, int arg_count, array<as_value> & stack )
		{
			as_environment env(_this->get_player());
			for (int i = 0; i < arg_count; i++)
			{
				as_value& val = stack[stack.size() - 1 - i];
				env.push(val);
			}
			stack.resize(stack.size() - arg_count);

			as_object* obj = stack.back().to_object();
			stack.resize(stack.size() - 1);

			as_value func;
			if (obj && obj->get_member(name, &func))
			{
				call_method(func, &env, obj,	arg_count, env.get_top_index());
			}

			IF_VERBOSE_ACTION(log_msg("EX: callpropvoid\t 0x%p.%s(args:%d)\n", obj, name, arg_count));

		}
Beispiel #13
0
	//static registerClass(name:String, theClass:Function) : Boolean
	void	as_object_registerclass(const fn_call& fn)
	{
		fn.result->set_bool(false);
		if (fn.nargs == 2 && fn.env->get_target() != NULL)
		{
			character_def* def = fn.env->get_target()->find_exported_resource(fn.arg(0).to_tu_string());
			if (def)
			{
				as_function* func = cast_to<as_function>(fn.arg(1).to_object());
				if (func)
				{
					IF_VERBOSE_ACTION(log_msg("registerClass '%s'\n",	fn.arg(0).to_string()));
					fn.result->set_bool(true);
					def->set_registered_class_constructor(func);
				}
			}
			else
			{
				log_error("can't find exported resource '%s'\n", fn.arg(0).to_string());
			}
		}
	}
	as_value	as_environment::get_variable ( const tu_string &varname, const array<with_stack_entry>& with_stack ) const
	// Return the value of the given var, if it's defined.
	{
		// Path lookup rigamarole.
		as_object	*target = get_target();
		tu_string	path;
		tu_string	var;

		if ( parse_path ( varname, &path, &var ) )
		{
			// @@ Use with_stack here too???  Need to test.
			target = find_target ( path.c_str() );

			if ( target )
			{
				as_value	val;
				target->get_member ( var, &val );
				return val;
			}

			else if ( ( target = get_player()->get_global()->find_target ( path.c_str() ) ) )
			{
				as_value	val;
				target->get_member ( var, &val );
				return val;
			}

			else
			{
				IF_VERBOSE_ACTION ( log_msg ( "find_target(\"%s\") failed\n", path.c_str() ) );
				return as_value();
			}
		}

		else
		{
			return get_variable_raw ( varname, with_stack );
		}
	}
Beispiel #15
0
	void as_object::enumerate(as_environment* env)
	// retrieves members & pushes them into env
	{
		stringi_hash<as_value>::const_iterator it = m_members.begin();
		while (it != m_members.end())
		{
			if (it->second.is_enum())
			{
				env->push(it->first);

				IF_VERBOSE_ACTION(log_msg("-------------- enumerate - push: %s\n",
					it->first.c_str()));
			}

			++it;
		}

//		as_object_interface* proto = get_proto();
//		if (proto)
//		{
//			proto->enumerate(env);
//		}
	}
	void	as_s_function::operator()(const fn_call& fn)
	// Dispatch.
	{

		assert(fn.env);

		// Keep target alive during execution!
		smart_ptr<as_object> target = m_target;

		// try to use caller environment
		// if the caller object has own environment then we use its environment
		as_environment* env = fn.env;
		if (fn.this_ptr)
		{
			if (fn.this_ptr->get_environment())
			{
				env = fn.this_ptr->get_environment();
			}
		}

		// set 'this'
		as_object* this_ptr = env->get_target();
		if (fn.this_ptr)
		{
			this_ptr = fn.this_ptr;
			if (this_ptr->m_this_ptr != NULL)
			{
				this_ptr = this_ptr->m_this_ptr.get_ptr();
			}
		}

		// Function has been declared in moviclip ==> we should use its environment
		// At the same time 'this_ptr' may refers to another object
		// see testcase in .h file
		if (m_target != NULL)
		{
			character* ch = cast_to<character>(m_target.get_ptr());
			if (ch)
			{
				if (ch->is_alive())
				{
					env = m_target->get_environment();
				}
			}
		}

		// Set up local stack frame, for parameters and locals.
		int	local_stack_top = env->get_local_frame_top();
		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);
				env->add_local(m_args[i].m_name, fn.arg(i));
			}

			env->set_local("this", this_ptr);

			// Put 'super' in a local var.
			if (fn.this_ptr)
			{
				env->add_local("super", fn.this_ptr->get_proto());
			}
		}
		else
		{
			// function2: most args go in registers; any others get pushed.
			
			// Create local registers.
			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.
					env->add_local(m_args[i].m_name, fn.arg(i));
				}
				else
				{
					// Pass argument into a register.
					int	reg = m_args[i].m_register;
					env->set_register(reg, fn.arg(i));
				}
			}

			// Handle the implicit args.
			int	current_reg = 1;

			if (m_function2_flags & 0x01)
			{
				// preload 'this' into a register.
				IF_VERBOSE_ACTION(log_msg("-------------- preload this=0x%X to register %d\n",
					this_ptr, current_reg));
				env->set_register(current_reg, this_ptr);
				current_reg++;

			}

			if (m_function2_flags & 0x02)
			{
				// Don't put 'this' into a local var.
			}
			else
			{
				// Put 'this' in a local var.
				env->add_local("this", as_value(this_ptr));
			}

			// Init arguments array, if it's going to be needed.
			smart_ptr<as_array>	arg_array;
			if ((m_function2_flags & 0x04) || ! (m_function2_flags & 0x08))
			{
				arg_array = new as_array(env->get_player());

				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.
				env->set_register(current_reg, 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.
 				env->add_local("arguments", as_value(arg_array.get_ptr()));
			}

			if (m_function2_flags & 0x10)
			{
				// Put 'super' in a register.
				IF_VERBOSE_ACTION(log_msg("-------------- preload super=0x%X to register %d\n",
					fn.this_ptr->get_proto(), current_reg));
				env->set_register(current_reg, fn.this_ptr->get_proto());
				current_reg++;
			}

			if (m_function2_flags & 0x20)
			{
				// Don't put 'super' in a local var.
			}
			else
			{
				// Put 'super' in a local var.
				env->add_local("super", fn.this_ptr->get_proto());
			}

			if (m_function2_flags & 0x40)
			{
				// Put '_root' in a register.
				env->set_register(current_reg, env->get_root()->get_root_movie());
				current_reg++;
			}

			if (m_function2_flags & 0x80)
			{
				// Put '_parent' in a register.
				array<with_stack_entry>	dummy;
				as_value	parent = env->get_variable("_parent", dummy);
				IF_VERBOSE_ACTION(log_msg("-------------- preload _parent=0x%X to register %d\n", parent, current_reg));
				env->set_register(current_reg, parent);
				current_reg++;
			}

			if (m_function2_flags & 0x100)
			{
				// Put '_global' in a register.
				IF_VERBOSE_ACTION(log_msg("-------------- preload _global=0x%X to register %d\n", 
					get_global(), current_reg));
				env->set_register(current_reg, get_global());
				current_reg++;
			}
		}

		// keep stack size
		int stack_size = env->m_stack.size();
//		printf("***on entry*** %d\n", stack_size);

		// Execute the actions.
		m_action_buffer.execute(env, m_start_pc, m_length, fn.result, m_with_stack, m_is_function2);

		// restore stack size
		// it should not be but it happens
		if (stack_size != env->m_stack.size())
		{
//			log_error("s_function: on entry stack size (%d) != on exit stack size (%d)\n", 
//				stack_size, env->m_stack.size());
			env->m_stack.resize(stack_size);
		}

		// Clean up stack frame.
		env->set_local_frame_top(local_stack_top);

		if (m_is_function2)
		{
			// Clean up the local registers.
			env->drop_local_registers(m_local_register_count);
		}
				
	}
Beispiel #17
0
void	as_3_function::operator() ( const fn_call &fn )
// dispatch
{
    assert ( fn.env );
    // try to use caller environment
    // if the caller object has own environment then we use its environment
    as_environment *env = fn.env;

    if ( fn.this_ptr )
    {
        if ( fn.this_ptr->get_environment() )
        {
            env = fn.this_ptr->get_environment();
        }
    }

    // set 'this'
    as_object *this_ptr = env->get_target();

    if ( fn.this_ptr )
    {
        this_ptr = fn.this_ptr;

        if ( this_ptr->m_this_ptr != NULL )
        {
            this_ptr = this_ptr->m_this_ptr.get_ptr();
        }
    }

    // Create local registers.
    array<as_value>	local_register;
    local_register.resize ( m_local_count + 1 );
    // Register 0 holds the ?this? object. This value is never null.
    assert ( this_ptr );
    local_register[0] = this_ptr;

    // Registers 1 through method_info.param_count holds parameter values.
    // If fewer than method_body_info.local_count values are supplied to the call then
    // the remaining values are either the values provided by default value declarations
    // or the value undefined.
    for ( int i = 0; i < m_param_type.size(); i++ )
    {
        // A zero value denotes the any (?*?) type.
        //const char* name = m_abc->get_multiname(m_param_type[i]);
        local_register[i + 1] = fn.arg ( i );	// hack
    }

#ifdef __GAMESWF_ENABLE_JIT__

    if ( !m_compiled_code.is_valid() )
    {
        compile();
        m_compiled_code.initialize();
    }

#endif

    if ( m_compiled_code.is_valid() )
    {
        try
        {
            m_compiled_code.call< array<as_value>&, vm_stack &, vm_stack &, as_value * >
            ( local_register, *env, env->m_scope, fn.result );
        }

        catch ( ... )
        {
            log_msg ( "jitted code crashed" );
        }
    }

    else
    {
        // keep stack size on entry
        int stack_size = env->size();
        IF_VERBOSE_ACTION ( log_msg ( "\nEX: call method #%d\n", m_method ) );
        // Execute the actions.
        execute ( local_register, env, fn.result );
        IF_VERBOSE_ACTION ( log_msg ( "EX: ended #%d.\n\n", m_method ) );

        if ( stack_size != env->size() )
        {
            log_error ( "error: stack size on exit must be same as on entry, %d:%d \n",
                        stack_size, env->size() );
            // restore stack size
            env->resize ( stack_size );
        }
    }
}
	void as_environment::set_register ( int reg, const as_value &val )
	{
		IF_VERBOSE_ACTION ( log_msg ( "-------------- set_register(%d): %s at %p\n",
		                              reg, val.to_string(), val.to_object() ) );
		*local_register_ptr ( reg ) = val;
	}
Beispiel #19
0
// interperate action script bytecode
void	as_3_function::execute ( array<as_value>& lregister, as_environment *env, as_value *result )
{
    // m_abc may be destroyed
    assert ( m_abc != NULL );
    vm_stack &stack = *env;
    vm_stack &scope = env->m_scope;

    // some method have no body
    if ( m_code.size() == 0 )
    {
        return;
    }

    int ip = 0;

    do
    {
        Uint8 opcode = m_code[ip++];

        switch ( opcode )
        {
        case 0x11: // iftrue
        {
            bool taken;
            //Follows ECMA-262 11.9.3
            taken = stack.top ( 0 ).to_bool();
            stack.drop ( 1 );

            if ( taken )
            {
                int offset = m_code[ip] | m_code[ip+1]<<8 | m_code[ip+2]<<16;
                ip += offset;
            }

            ip += 3;
            IF_VERBOSE_ACTION ( log_msg ( "EX: iftrue\t %s\n", taken? "taken": "not taken" ) );
        }
        break;

        case 0x12: // iffalse
        {
            bool taken;
            //Follows ECMA-262 11.9.3
            taken = !stack.top ( 0 ).to_bool();
            stack.drop ( 1 );

            if ( taken )
            {
                int offset = m_code[ip] | m_code[ip+1]<<8 | m_code[ip+2]<<16;
                ip += offset;
            }

            ip += 3;
            IF_VERBOSE_ACTION ( log_msg ( "EX: iffalse\t %s\n", taken? "taken": "not taken" ) );
        }
        break;

        case 0x14: // ifne
        {
            bool taken;
            //Follows ECMA-262 11.9.3
            taken = !as_value::abstract_equality_comparison ( scope[ scope.size() - 2 ], scope[ scope.size() - 1 ] );

            if ( taken )
            {
                int offset = m_code[ip] | m_code[ip+1]<<8 | m_code[ip+2]<<16;
                ip += offset;
            }

            ip += 3;
            IF_VERBOSE_ACTION ( log_msg ( "EX: ifne\t %s\n", taken? "taken": "not taken" ) );
        }
        break;

        case 0x1D: // popscope
        {
            scope.pop();
            IF_VERBOSE_ACTION ( log_msg ( "EX: popscope\n" ) );
            break;
        }

        case 0x20:  // pushnull
        {
            as_value value;
            value.set_null();
            stack.push ( value );
            IF_VERBOSE_ACTION ( log_msg ( "EX: pushnull\n" ) );
        }
        break;

        case 0x24:	// pushbyte
        {
            int byte_value;
            ip += read_vu30 ( byte_value, &m_code[ip] );
            stack.push ( byte_value );
            IF_VERBOSE_ACTION ( log_msg ( "EX: pushbyte\t %d\n", byte_value ) );
            break;
        }

        case 0x25:  // pushshort
        {
            int val;
            ip += read_vu30 ( val, &m_code[ip] );
            stack.push ( val );
            IF_VERBOSE_ACTION ( log_msg ( "EX: pushshort\t %d\n", val ) );
            break;
        }

        case 0x26:  // pushtrue
        {
            stack.push ( true );
            IF_VERBOSE_ACTION ( log_msg ( "EX: pushtrue\n" ) );
        }
        break;

        case 0x27:  // pushfalse
        {
            stack.push ( false );
            IF_VERBOSE_ACTION ( log_msg ( "EX: pushfalse\n" ) );
        }
        break;

        case 0x29:  // pop the value from stack and discard it
        {
            stack.pop();
            IF_VERBOSE_ACTION ( log_msg ( "EX: pop\n" ) );
            break;
        }

        case 0x2A:  // dup
        {
            IF_VERBOSE_ACTION ( log_msg ( "EX: dup %s\n", stack.top ( 0 ).to_xstring() ) );
            stack.push ( stack.top ( 0 ) );
        }
        break;

        case 0x2D:	// pushint
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            int val = m_abc->get_integer ( index );
            stack.push ( val );
            IF_VERBOSE_ACTION ( log_msg ( "EX: pushint\t %d\n", val ) );
            break;
        }

        case 0x2C:	// pushstring
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            const char *val = m_abc->get_string ( index );
            stack.push ( val );
            IF_VERBOSE_ACTION ( log_msg ( "EX: pushstring\t '%s'\n", val ) );
            break;
        }

        case 0x2F:	// pushdouble
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            double val = m_abc->get_double ( index );
            stack.push ( val );
            IF_VERBOSE_ACTION ( log_msg ( "EX: pushdouble\t %f\n", val ) );
            break;
        }

        case 0x30:	// pushscope
        {
            as_value val = stack.pop();
            scope.push ( val );
            IF_VERBOSE_ACTION ( log_msg ( "EX: pushscope\t %s\n", val.to_xstring() ) );
            break;
        }

        case 0x46:  // callproperty
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            const char *name = m_abc->get_multiname ( index );
            int arg_count;
            ip += read_vu30 ( arg_count, &m_code[ip] );
            as_environment env ( get_player() );

            for ( int i = 0; i < arg_count; i++ )
            {
                env.push ( stack.top ( i ) );
            }

            stack.drop ( arg_count );
            as_value result;

            if ( stack.top ( 0 ).is_object() )
            {
                as_object *obj = stack.top ( 0 ).to_object();
                as_value func, func2;
                result.set_undefined();

                if ( obj &&  obj->get_member ( name, &func ) )
                {
                    if ( func.is_function() )
                    {
                        result = call_method ( func, &env, obj, arg_count, env.get_top_index() );
                    }

                    else if ( func.to_object()->get_member ( "__call__", &func2 ) )
                    {
                        //todo patch scope
                        result = call_method ( func2, &env, obj, arg_count, env.get_top_index() );
                    }
                }
            }

            else
            {
                as_value func;

                if ( stack.top ( 0 ).find_property ( name, &func ) )
                {
                    result = call_method ( func, &env, stack.top ( 0 ), arg_count, env.get_top_index() );
                }
            }

            IF_VERBOSE_ACTION ( log_msg ( "EX: callproperty\t 0x%p.%s(args:%d), result %s\n", stack.top ( 0 ).to_xstring(), name, arg_count, result.to_xstring() ) );
            stack.drop ( 1 );
            stack.push ( result );
        }
        break;

        case 0x47:	// returnvoid
        {
            IF_VERBOSE_ACTION ( log_msg ( "EX: returnvoid\t\n" ) );
            result->set_undefined();
            return;
        }

        case 0x48:	// returnvalue
        {
            IF_VERBOSE_ACTION ( log_msg ( "EX: returnvalue \t%s\n", stack.top ( 0 ).to_xstring() ) );
            *result = stack.pop();
            return;
        }

        case 0x49:	// constructsuper
        {
            // stack: object, arg1, arg2, ..., argn
            int arg_count;
            ip += read_vu30 ( arg_count, &m_code[ip] );
            as_environment env ( get_player() );

            for ( int i = 0; i < arg_count; i++ )
            {
                env.push ( stack.pop() );
            }

            gc_ptr<as_object> obj = stack.pop().to_object();
            // Assume we are in a constructor
            tu_string class_name = m_abc->get_class_from_constructor ( m_method );
            tu_string super_class_name = m_abc->get_super_class ( class_name );
            as_object *super = obj.get_ptr();

            while ( super->get_proto() )
            {
                super = super->get_proto();
            }

            as_function *function = m_abc->get_class_constructor ( super_class_name );

            if ( !function )
            {
                as_value value;

                if ( get_player()->get_global()->get_member ( super_class_name, &value ) )
                {
                    function = cast_to<as_function> ( value.to_object() );
                }
            }

            assert ( function );
            as_object *proto = super->create_proto ( function );
            UNUSED ( proto );
            call_method ( function, &env, obj.get_ptr(), arg_count, 0 );
            //stack.top(0) = obj.get_ptr();
            IF_VERBOSE_ACTION ( log_msg ( "EX: constructsuper\t 0x%p(args:%d)\n", obj.get_ptr(), arg_count ) );
            break;
        }

        case 0x4A: //constructprop
            // Stack ..., obj, [ns], [name], arg1,...,argn => ..., value
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            const char *name = m_abc->get_multiname ( index );
            const char *name_space = m_abc->get_multiname_namespace ( index );
            UNUSED ( name_space );
            int arg_count;
            ip += read_vu30 ( arg_count, &m_code[ip] );
            as_environment env ( get_player() );

            for ( int i = 0; i < arg_count; i++ )
            {
                env.push ( stack.top ( i ) );
            }

            stack.drop ( arg_count );
            as_object *obj = stack.pop().to_object();
            as_value func, func2;
            gc_ptr<as_object> new_object;

            if ( obj && obj->get_member ( name, &func ) )
            {
                instance_info *ii = m_abc->get_instance_info ( name );
                new_object = new as_object ( get_player() );
                //:TODO: create prototype .... ( move instanciate class from character -> as_object )
                new_object->set_instance ( ii );
                new_object->create_traits ( m_abc.get_ptr(), ii );
                call_method ( m_abc->get_class_constructor ( name ), &env, new_object.get_ptr(), arg_count, 0 );
            }

            IF_VERBOSE_ACTION ( log_msg ( "EX: constructprop\t 0x%p.%s(args:%d)\n", obj, name, arg_count ) );
            stack.push ( new_object.get_ptr() );
        }
        break;

        case 0x4F:	// callpropvoid, Call a property, discarding the return value.
            // Stack: ..., obj, [ns], [name], arg1,...,argn => ...
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            const char *name = m_abc->get_multiname ( index );
            int arg_count;
            ip += read_vu30 ( arg_count, &m_code[ip] );
            as_environment env ( get_player() );

            for ( int i = 0; i < arg_count; i++ )
            {
                env.push ( stack.top ( i ) );
            }

            stack.drop ( arg_count );
            as_object *obj = stack.pop().to_object();
            as_value func, func2;

            if ( obj &&  obj->get_member ( name, &func ) )
            {
                if ( func.is_function() )
                {
                    call_method ( func, &env, obj, arg_count, env.get_top_index() );
                }

                else if ( func.to_object()->get_member ( "__call__", &func2 ) )
                {
                    //todo patch scope
                    call_method ( func2, &env, obj, arg_count, env.get_top_index() );
                }
            }

            else
            {
                if ( !obj )
                {
                    log_msg ( "Error #1010: A term is undefined and has no properties (%s call)\n", name );
                }

                else
                {
                    log_msg ( "Error #1006: value is not a function (%s call)\n", name );
                }
            }

            IF_VERBOSE_ACTION ( log_msg ( "EX: callpropvoid\t 0x%p.%s(args:%d)\n", obj, name, arg_count ) );
            break;
        }

        case 0x56: //newarray
        {
            int arg_count;
            ip += read_vu30 ( arg_count, &m_code[ip] );
            as_array *array = new as_array ( get_player() );
            int offset = stack.size() - arg_count;

            for ( int arg_index = 0; arg_index < arg_count; ++arg_index )
            {
                array->push ( stack[ offset + arg_index ] );
            }

            stack.resize ( offset + 1 );
            stack.top ( 0 ) = array;
            IF_VERBOSE_ACTION ( log_msg ( "EX: newarray\t arg_count:%i\n", arg_count ) );
        }
        break;

        case 0x58: // newclass
        {
            // stack:	..., basetype => ..., newclass
            int class_index;
            ip += read_vu30 ( class_index, &m_code[ip] );
            IF_VERBOSE_ACTION ( log_msg ( "EX: newclass\t class index:%i\n", class_index ) );
            //					as_object* basetype = stack.top(0).to_object();
            gc_ptr<as_class> new_class = new as_class ( get_player() );
            //new_class->set_proto(basetype);
            new_class->set_class ( m_abc->get_class_info ( class_index ) );
            as_environment env ( get_player() );
            call_method ( m_abc->get_class_function ( class_index ), &env, new_class.get_ptr(), 0, 0 );
            stack.top ( 0 ).set_as_object ( new_class.get_ptr() );
            break;
        }

        case 0x5D:	// findpropstrict
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            const char *name = m_abc->get_multiname ( index );
            // search property in scope
            as_object *obj = scope.find_property ( name );
            //Search for a script entry to execute
            as_function *func = m_abc->get_script_function ( name );

            if ( obj == NULL && func != NULL )
            {
                get_global()->set_member ( name, new as_object ( get_player() ) );
                as_environment env ( get_player() );
                call_method ( func, &env, get_global(), 0, 0 );
                obj = get_global();
            }

            IF_VERBOSE_ACTION ( log_msg ( "EX: findpropstrict\t %s, obj=0x%p\n", name, obj ) );
            stack.push ( obj );
            break;
        }

        case 0x5E:	// findproperty, Search the scope stack for a property
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            const char *name = m_abc->get_multiname ( index );
            const char *name_space = m_abc->get_multiname_namespace ( index );
            UNUSED ( name_space );
            as_object *obj = scope.find_property ( name );

            if ( obj )
            {
                IF_VERBOSE_ACTION ( log_msg ( "EX: findproperty\t '%s', obj=0x%p\n", name, obj ) );
                stack.push ( obj );
            }

            else
            {
                IF_VERBOSE_ACTION ( log_msg ( "EX: findproperty\t '%s', obj=global\n", name ) );
                stack.push ( get_global() );
            }

            break;
        }

        case 0x60:	// getlex, Find and get a property.
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            const char *name = m_abc->get_multiname ( index );
            // search and get property in scope
            as_value val;
            scope.get_property ( name, &val );

            if ( val.is_undefined() )
            {
                as_function *func = m_abc->get_script_function ( name );

                if ( func != NULL )
                {
                    gc_ptr<as_object> object = new as_object ( get_player() );
                    get_global()->set_member ( name, object.get() );
                    as_environment env ( get_player() );
                    call_method ( func, &env, get_global(), 0, 0 );
                    val.set_as_object ( object );
                }
            }

            IF_VERBOSE_ACTION ( log_msg ( "EX: getlex\t %s, value=%s\n", name, val.to_xstring() ) );
            stack.push ( val );
            break;
        }

        case 0x61: // setproperty
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            const char *name = m_abc->get_multiname ( index );
            IF_VERBOSE_ACTION ( log_msg ( "EX: setproperty\t %s.%s, value=%s\n", stack.top ( 1 ).to_xstring(), name, stack.top ( 0 ).to_xstring() ) );
            as_object *object = stack.top ( 1 ).to_object();

            if ( object )
            {
                object->set_member ( name, stack.top ( 0 ) );
            }

            stack.drop ( 2 );
        }
        break;

        case 0x62: // getlocal
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            IF_VERBOSE_ACTION ( log_msg ( "EX: getlocal\t index=%i, value=%s\n", index, lregister[index].to_xstring() ) );
            stack.push ( lregister[index] );
        }
        break;

        case 0x63: // setlocal
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            IF_VERBOSE_ACTION ( log_msg ( "EX: setlocal\t index=%i, value=%s\n", index, stack.top ( 0 ).to_xstring() ) );
            lregister[index] = stack.pop();
        }
        break;

        case 0x65: // getscopeobject
        {
            int index = m_code[ip];
            ++ip;
            assert ( index < scope.size() );
            stack.push ( scope[index] );
            IF_VERBOSE_ACTION ( log_msg ( "EX: getscopeobject\t index=%i, value=%s\n", index, stack.top ( 0 ).to_xstring() ) );
        }
        break;

        case 0x66:	// getproperty
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            tu_string name = get_multiname ( index, stack );
            as_object *obj = stack.top ( 0 ).to_object();

            if ( obj )
            {
                obj->get_member ( name, &stack.top ( 0 ) );
            }

            else
            {
                stack.top ( 0 ).set_undefined();
            }

            IF_VERBOSE_ACTION ( log_msg ( "EX: getproperty\t %s, value=%s\n", name.c_str(), stack.top ( 0 ).to_xstring() ) );
            break;
        }

        case 0x68:	// initproperty, Initialize a property.
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            const char *name = m_abc->get_multiname ( index );
            as_value &val = stack.top ( 0 );
            as_object *obj = stack.top ( 1 ).to_object();

            if ( obj )
            {
                obj->set_member ( name, val );
            }

            IF_VERBOSE_ACTION ( log_msg ( "EX: initproperty\t 0x%p.%s=%s\n", obj, name, val.to_xstring() ) );
            stack.drop ( 2 );
            break;
        }

        case 0x73: //convert_i
        {
            stack.top ( 0 ).set_int ( stack.top ( 0 ).to_int() );
            IF_VERBOSE_ACTION ( log_msg ( "EX: convert_i : %i \n", stack.top ( 0 ).to_int() ) );
        }
        break;

        case 0x80: // coerce
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            const char *type_name = m_abc->get_multiname ( index );
            //	stack.push( stack.top( index ) );
            IF_VERBOSE_ACTION ( log_msg ( "EX: coerce : %s todo\n", type_name ) );
        }
        break;

        case 0x85: // coerce_s
        {
            stack.top ( 0 ).set_string ( stack.top ( 0 ).to_string() );
            IF_VERBOSE_ACTION ( log_msg ( "EX: coerce_s : %s\n", stack.top ( 0 ).to_string() ) );
        }
        break;

        case 0x96: // not
        {
            stack.top ( 0 ).set_bool ( !stack.top ( 0 ).to_bool() );
            IF_VERBOSE_ACTION ( log_msg ( "EX: not\n" ) );
        }
        break;

        case 0xA0:	// Add two values
        {
            if ( stack.top ( 0 ).is_string() || stack.top ( 1 ).is_string() )
            {
                tu_string str = stack.top ( 1 ).to_string();
                str += stack.top ( 0 ).to_string();
                stack.top ( 1 ).set_tu_string ( str );
            }

            else
            {
                stack.top ( 1 ) += stack.top ( 0 ).to_number();
            }

            stack.drop ( 1 );
            break;
        }

        case 0xA2: // multiply
        {
            stack.top ( 1 ) = stack.top ( 1 ).to_number() * stack.top ( 0 ).to_number();
            stack.drop ( 1 );
            IF_VERBOSE_ACTION ( log_msg ( "EX: multiply\n" ) );
            break;
        }

        case 0xAB: // equals
        {
            bool result = as_value::abstract_equality_comparison ( stack.top ( 1 ), stack.top ( 0 ) );
            IF_VERBOSE_ACTION ( log_msg ( "EX: equals %s & %s : %s\n", stack.top ( 0 ).to_xstring(), stack.top ( 1 ).to_xstring(), result? "true":"false" ) );
            stack.drop ( 1 );
            stack.top ( 0 ).set_bool ( result );
        }
        break;

        case 0xAD: //lessthan
        {
            as_value result = as_value::abstract_relational_comparison ( stack.top ( 1 ), stack.top ( 0 ) );
            IF_VERBOSE_ACTION ( log_msg ( "EX: lessthan %s & %s : %s\n", stack.top ( 1 ).to_xstring(), stack.top ( 0 ).to_xstring(), result.to_string() ) );
            stack.drop ( 1 );
            stack.top ( 0 ) = result;
        }
        break;

        case 0xC2:  // inclocal_i
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            as_value &reg = lregister[ index ];
            reg.set_int ( reg.to_int() + 1 );
            IF_VERBOSE_ACTION ( log_msg ( "EX: inclocal_i %i\n", index ) );
        }
        break;

        case 0xD0:	// getlocal_0
        case 0xD1:	// getlocal_1
        case 0xD2:	// getlocal_2
        case 0xD3:	// getlocal_3
        {
            as_value &val = lregister[opcode & 0x03];
            stack.push ( val );
            IF_VERBOSE_ACTION ( log_msg ( "EX: getlocal_%d\t %s\n", opcode & 0x03, val.to_xstring() ) );
            break;
        }

        case 0xD4:	// setlocal_0
        case 0xD5:	// setlocal_1
        case 0xD6:	// setlocal_2
        case 0xD7:	// setlocal_3
        {
            lregister[opcode & 0x03] = stack.pop();
            IF_VERBOSE_ACTION ( log_msg ( "EX: setlocal_%d\t %s\n", opcode & 0x03, lregister[opcode & 0x03].to_xstring() ) );
            break;
        }

        default:
            log_msg ( "TODO opcode 0x%02X\n", opcode );
            return;
        }
    }
    while ( ip < m_code.size() );
}
	as_value	as_environment::get_variable_raw (
	    const tu_string &varname,
	    const array<with_stack_entry>& with_stack ) const
	// varname must be a plain variable name; no path parsing.
	{
		as_value	val;

		// First check the with-stack.
		for ( int i = with_stack.size() - 1; i >= 0; i-- )
		{
			as_object	*obj = with_stack[i].m_object.get_ptr();

			if ( obj && obj->get_member ( varname, &val ) )
			{
				// Found the var in this context.
				return val;
			}
		}

		// Then check locals.
		int	local_index = find_local ( varname, true );

		if ( local_index >= 0 )
		{
			return m_local_frames[local_index].m_value;
		}

		// Check movie members.
		if ( m_target != NULL && m_target->get_member ( varname, &val ) )
		{
			return val;
		}

		// Check this, _global, _root
		as_standard_member	varname_id = get_standard_member ( varname );

		switch ( varname_id )
		{
			default:
				break;

			case M_GLOBAL:
				val.set_as_object ( get_player()->get_global() );
				return val;

			case MTHIS:
				val.set_as_object ( get_target() );
				return val;

			case M_ROOT:
			case M_LEVEL0:
				val.set_as_object ( get_root()->get_root_movie() );
				return val;
		}

		// check _global.member
		if ( get_player()->get_global()->get_member ( varname, &val ) )
		{
			return val;
		}

		// Fallback.
		IF_VERBOSE_ACTION ( log_msg ( "get_variable_raw(\"%s\") failed, returning UNDEFINED.\n", varname.c_str() ) );
		return val;
	}
	// Implementation of:
	//
	// loadVariables(url:String, target:Object, [method:String]) : Void
	// loadMovie(url:String, target:Object, [method:String]) : Void
	// loadMovie(url:String, target:String, [method:String]) : Void
	// unloadMovie(target:MovieClip) : Void
	// unloadMovie(target:String) : Void
	//
	// url=="" means that the load_file() works as unloadMovie(target)
	// TODO: implement [method]
	character *as_environment::load_file ( const char *url, const as_value &target_value, int method )
	{
		character *target = cast_to<character> ( find_target ( target_value ) );

		if ( target == NULL )
		{
			IF_VERBOSE_ACTION ( log_msg ( "load_file: target %s is't found\n", target_value.to_string() ) );
			return NULL;
		}

		// is unloadMovie() ?
		if ( strlen ( url ) == 0 )
		{
			character *parent = target->get_parent();

			if ( parent )
			{
				parent->remove_display_object ( target );
			}

			else	// target is _root, unloadMovie(_root)
			{
				target->clear_display_objects();
			}

			return NULL;
		}

		// is path relative ?
		tu_string file_name = get_full_url ( get_player()->get_workdir(), url );

		switch ( get_file_type ( file_name.c_str() ) )
		{
			default:
				break;

			case TXT:
				{
					// Reads data from an external file, such as a text file and sets the values for
					// variables in a target movie clip. This action can also be used
					// to update variables in the active SWF file with new values.
					tu_file fi ( file_name.c_str(), "r" );

					if ( fi.get_error() == TU_FILE_NO_ERROR )
					{
						fi.go_to_end();
						int len = fi.get_position();
						fi.set_position ( 0 );
						char *buf = ( char * ) malloc ( len );

						if ( fi.read_string ( buf, len ) > 0 )
						{
							// decode data in the standard MIME format and copy theirs into target
#if TU_ENABLE_NETWORK == 1
							as_loadvars lv ( get_player() );
							lv.decode ( buf );
							lv.copy_to ( target );
#else
							log_error ( "Compile gameswf with TU_ENABLE_NETWORK=1 to use loadVariable() function" );
#endif
						}

						free ( buf );
					}

					break;
				}

			case URL:
			case SWF:
				{
					movie_definition	*md = get_player()->create_movie ( file_name.c_str() );

					if ( md && md->get_frame_count() > 0 )
					{
						return target->replace_me ( md );
					}

					break;
				}

			case X3DS:
				{
#if TU_CONFIG_LINK_TO_LIB3DS == 0
					log_error ( "gameswf is not linked to lib3ds -- can't load 3DS file\n" );
#else
					x3ds_definition *x3ds = create_3ds_definition ( get_player(), file_name.c_str() );

					if ( x3ds )
					{
						if ( x3ds->is_loaded() )
						{
							rect bound;
							target->get_bound ( &bound );
							x3ds->set_bound ( bound );
							return target->replace_me ( x3ds );
						}
					}

#endif
					break;
				}

			case JPG:
				{
#if TU_CONFIG_LINK_TO_JPEGLIB == 0
					log_error ( "gameswf is not linked to jpeglib -- can't load jpeg image data!\n" );
#else
					image::rgb *im = image::read_jpeg ( file_name.c_str() );

					if ( im )
					{
						bitmap_info *bi = render::create_bitmap_info_rgb ( im );
						delete im;
						movie_definition *rdef = get_root()->get_movie_definition();
						assert ( rdef );
						bitmap_character	*jpeg = new bitmap_character ( rdef, bi );
						return target->replace_me ( jpeg );
					}

#endif
					break;
				}
		}

		return NULL;
	}