Пример #1
0
_NR<ASObject> Proxy::getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt)
{
	//It seems that various kind of implementation works only with the empty namespace
	assert_and_throw(name.ns.size()>0);
	if(!name.ns[0].hasEmptyName() || ASObject::hasPropertyByMultiname(name, true, true) || !implEnable || (opt & ASObject::SKIP_IMPL)!=0)
		return ASObject::getVariableByMultiname(name,opt);

	//Check if there is a custom getter defined, skipping implementation to avoid recursive calls
	multiname getPropertyName(NULL);
	getPropertyName.name_type=multiname::NAME_STRING;
	getPropertyName.name_s_id=getSys()->getUniqueStringId("getProperty");
	getPropertyName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
	_NR<ASObject> o=getVariableByMultiname(getPropertyName,ASObject::SKIP_IMPL);

	if(o.isNull())
		return ASObject::getVariableByMultiname(name,opt);

	assert_and_throw(o->getObjectType()==T_FUNCTION);

	IFunction* f=static_cast<IFunction*>(o.getPtr());

	//Well, I don't how to pass multiname to an as function. I'll just pass the name as a string
	ASObject* arg=Class<ASString>::getInstanceS(name.normalizedName());
	//We now suppress special handling
	implEnable=false;
	LOG(LOG_CALLS,"Proxy::getProperty");
	incRef();
	_NR<ASObject> ret=_MNR(f->call(this,&arg,1));
	implEnable=true;
	return ret;
}
Пример #2
0
void variables_map::initializeVar(const multiname& mname, ASObject* obj, multiname* typemname)
{
	tiny_string name=mname.normalizedName();

	const Type* type = NULL;
	 /* If typename is resolvable right now, we coerce obj.
	  * It it's not resolvable, then it must be a user defined class,
	  * so we only allow Null and Undefined (which are both coerced to Null) */
	if(!Type::isTypeResolvable(typemname))
	{
		assert_and_throw(obj->is<Null>() || obj->is<Undefined>());
		if(obj->is<Undefined>())
		{
			//Casting undefined to an object (of unknown class)
			//results in Null
			obj->decRef();
			obj = new Null;
		}
	}
	else
	{
		type = Type::getTypeFromMultiname(typemname);
		obj = type->coerce(obj);
	}

	Variables.insert(make_pair(name, variable(mname.ns[0], DECLARED_TRAIT, obj, typemname, type)));
}
Пример #3
0
bool Proxy::deleteVariableByMultiname(const multiname& name)
{
	//If a variable named like this already exist, use that
	if(ASObject::hasPropertyByMultiname(name, true, false) || !implEnable)
	{
		return ASObject::deleteVariableByMultiname(name);
	}

	//Check if there is a custom deleter defined, skipping implementation to avoid recursive calls
	multiname deletePropertyName(NULL);
	deletePropertyName.name_type=multiname::NAME_STRING;
	deletePropertyName.name_s_id=getSys()->getUniqueStringId("deleteProperty");
	deletePropertyName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
	_NR<ASObject> proxyDeleter=getVariableByMultiname(deletePropertyName,ASObject::SKIP_IMPL);

	if(proxyDeleter.isNull())
	{
		return ASObject::deleteVariableByMultiname(name);
	}

	assert_and_throw(proxyDeleter->getObjectType()==T_FUNCTION);

	IFunction* f=static_cast<IFunction*>(proxyDeleter.getPtr());

	//Well, I don't how to pass multiname to an as function. I'll just pass the name as a string
	ASObject* arg=Class<ASString>::getInstanceS(name.normalizedName());
	//We now suppress special handling
	implEnable=false;
	LOG(LOG_CALLS,_("Proxy::deleteProperty"));
	incRef();
	_NR<ASObject> ret=_MNR(f->call(this,&arg,1));
	implEnable=true;
	Boolean* b = static_cast<Boolean*>(ret.getPtr());
	return b->val;
}
Пример #4
0
void Array::setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOWED_FLAG allowConst)
{
	assert_and_throw(implEnable);
	uint32_t index=0;
	if(!isValidMultiname(name,index))
		return ASObject::setVariableByMultiname(name,o,allowConst);
	// Derived classes may be sealed!
	if (getClass() && getClass()->isSealed)
		throwError<ReferenceError>(kWriteSealedError,
					   name.normalizedName(),
					   getClass()->getQualifiedClassName());
	if (index==0xFFFFFFFF)
		return;
	if(index>=size())
		resize((uint64_t)index+1);

	if(data.count(index) && data[index].type==DATA_OBJECT && data[index].data)
		data[index].data->decRef();
	if(!data.count(index))
		data[index] = data_slot();

	if(o->getObjectType()==T_INTEGER)
	{
		Integer* i=static_cast<Integer*>(o);
		data[index].data_i=i->val;
		data[index].type=DATA_INT;
		o->decRef();
	}
	else
	{
		data[index].data=o;
		data[index].type=DATA_OBJECT;
	}
}
Пример #5
0
bool Array::isValidMultiname(const multiname& name, uint32_t& index)
{
	//First of all the multiname has to contain the null namespace
	//As the namespace vector is sorted, we check only the first one
	assert_and_throw(name.ns.size()!=0);
	if(!name.ns[0].hasEmptyName())
		return false;
	if (name.name_type == multiname::NAME_STRING && 
	    !isIntegerWithoutLeadingZeros(name.normalizedName()))
		return false;

	return name.toUInt(index);
}
Пример #6
0
void Vector::setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOWED_FLAG allowConst)
{
	assert_and_throw(name.ns.size()>0);
	if(!name.ns[0].hasEmptyName())
		return ASObject::setVariableByMultiname(name, o, allowConst);

	unsigned int index=0;
	if(!Vector::isValidMultiname(getSystemState(),name,index))
	{
		if (name.name_type == multiname::NAME_INT ||
				(name.name_type == multiname::NAME_NUMBER && Number::isInteger(name.name_d)))
			throwError<RangeError>(kOutOfRangeError,name.normalizedName(getSystemState()),Integer::toString(vec.size()));
		
		if (!ASObject::hasPropertyByMultiname(name,false,true))
			throwError<ReferenceError>(kWriteSealedError, name.normalizedName(getSystemState()), this->getClass()->getQualifiedClassName());
		return ASObject::setVariableByMultiname(name, o, allowConst);
	}
	ASObject* o2 = this->vec_type->coerce(o);
	  
	if(index < vec.size())
	{
		if (vec[index])
			vec[index]->decRef();
		vec[index] = o2;
	}
	else if(!fixed && index == vec.size())
	{
		vec.push_back( o2 );
	}
	else
	{
		/* Spec says: one may not set a value with an index more than
		 * one beyond the current final index. */
		throwError<RangeError>(kOutOfRangeError,
				       Integer::toString(index),
				       Integer::toString(vec.size()));
	}
}
Пример #7
0
bool Proxy::hasPropertyByMultiname(const multiname& name, bool considerDynamic, bool considerPrototype)
{
	if (name.normalizedName() == "isAttribute")
		return true;
	//If a variable named like this already exist, use that
	bool asobject_has_property=ASObject::hasPropertyByMultiname(name, considerDynamic, considerPrototype);
	if(asobject_has_property || !implEnable)
		return asobject_has_property;

	//Check if there is a custom hasProperty defined, skipping implementation to avoid recursive calls
	multiname hasPropertyName(NULL);
	hasPropertyName.name_type=multiname::NAME_STRING;
	hasPropertyName.name_s_id=getSys()->getUniqueStringId("hasProperty");
	hasPropertyName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
	_NR<ASObject> proxyHasProperty=getVariableByMultiname(hasPropertyName,ASObject::SKIP_IMPL);

	if(proxyHasProperty.isNull())
	{
		return false;
	}

	assert_and_throw(proxyHasProperty->getObjectType()==T_FUNCTION);

	IFunction* f=static_cast<IFunction*>(proxyHasProperty.getPtr());

	ASObject* namearg = Class<ASString>::getInstanceS(name.normalizedName());
	namearg->setProxyProperty(name);
	ASObject* arg = namearg;
	//We now suppress special handling
	implEnable=false;
	LOG(LOG_CALLS,_("Proxy::hasProperty"));
	incRef();
	_NR<ASObject> ret=_MNR(f->call(this,&arg,1));
	implEnable=true;
	Boolean* b = static_cast<Boolean*>(ret.getPtr());
	return b->val;
}
Пример #8
0
bool Vector::isValidMultiname(const multiname& name, uint32_t& index)
{
	//First of all the multiname has to contain the null namespace
	//As the namespace vector is sorted, we check only the first one
	assert_and_throw(name.ns.size()!=0);
	if(!name.ns[0].hasEmptyName())
		return false;

	bool validIndex=name.toUInt(index, true);
	// Don't throw for non-numeric NAME_STRING or NAME_OBJECT
	// because they can still be valid built-in property names.
	if(!validIndex && (name.name_type==multiname::NAME_INT || name.name_type==multiname::NAME_NUMBER))
		throwError<RangeError>(kOutOfRangeError, name.normalizedName(), "?");

	return validIndex;
}
Пример #9
0
void variables_map::killObjVar(const multiname& mname)
{
	tiny_string name=mname.normalizedName();
	const pair<var_iterator, var_iterator> ret=Variables.equal_range(name);
	assert_and_throw(ret.first!=ret.second);

	//Find the namespace
	var_iterator start=ret.first;
	for(;start!=ret.second;++start)
	{
		if(!is_disjoint(mname.ns,start->second.ns))
		{
			Variables.erase(start);
			return;
		}
	}

	throw RunTimeException("Variable to kill not found");
}
Пример #10
0
/* this handles the [] operator, because vec[12] becomes vec.12 in bytecode */
_NR<ASObject> Vector::getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt)
{
	if((opt & SKIP_IMPL)!=0 || !implEnable)
		return ASObject::getVariableByMultiname(name,opt);

	assert_and_throw(name.ns.size()>0);
	if(!name.ns[0].hasEmptyName())
		return ASObject::getVariableByMultiname(name,opt);

	unsigned int index=0;
	if(!Vector::isValidMultiname(getSystemState(),name,index) || index == UINT32_MAX)
	{
		if (name.name_type == multiname::NAME_INT ||
				(name.name_type == multiname::NAME_NUMBER && Number::isInteger(name.name_d)))
			throwError<RangeError>(kOutOfRangeError,Integer::toString(name.name_i),Integer::toString(vec.size()));

		_NR<ASObject> ret = ASObject::getVariableByMultiname(name,opt);
		if (ret.isNull()) 
			throwError<ReferenceError>(kReadSealedError, name.normalizedName(getSystemState()), this->getClass()->getQualifiedClassName());
		return ret;
	}
	if(index < vec.size())
	{
		if (vec[index])
		{
			vec[index]->incRef();
			return _MNR(vec[index]);
		}
		else
			return _MNR(vec_type->coerce( getSystemState()->getNullRef() ));
	}
	else
	{
		throwError<RangeError>(kOutOfRangeError,
				       Integer::toString(index),
				       Integer::toString(vec.size()));
	}

	return NullRef;
}
Пример #11
0
void Proxy::setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOWED_FLAG allowConst)
{
	//If a variable named like this already exist, use that
	if(ASObject::hasPropertyByMultiname(name, true, false) || !implEnable)
	{
		ASObject::setVariableByMultiname(name,o,allowConst);
		return;
	}

	//Check if there is a custom setter defined, skipping implementation to avoid recursive calls
	multiname setPropertyName(NULL);
	setPropertyName.name_type=multiname::NAME_STRING;
	setPropertyName.name_s_id=getSys()->getUniqueStringId("setProperty");
	setPropertyName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
	_NR<ASObject> proxySetter=getVariableByMultiname(setPropertyName,ASObject::SKIP_IMPL);

	if(proxySetter.isNull())
	{
		ASObject::setVariableByMultiname(name,o,allowConst);
		return;
	}

	assert_and_throw(proxySetter->getObjectType()==T_FUNCTION);

	IFunction* f=static_cast<IFunction*>(proxySetter.getPtr());

	ASObject* namearg = Class<ASString>::getInstanceS(name.normalizedName());
	namearg->setProxyProperty(name);
	ASObject* args[2];
	args[0]=namearg;
	args[1]=o;
	//We now suppress special handling
	implEnable=false;
	LOG(LOG_CALLS,_("Proxy::setProperty"));
	incRef();
	_R<ASObject> ret=_MR( f->call(this,args,2) );
	assert_and_throw(ret->is<Undefined>());
	implEnable=true;
}
Пример #12
0
void ASObject::setVariableByMultiname(const multiname& name, ASObject* o, Class_base* cls)
{
	check();
	assert(!cls || classdef->isSubClass(cls));
	//NOTE: we assume that [gs]etSuper and [sg]etProperty correctly manipulate the cur_level (for getActualClass)
	bool has_getter=false;
	variable* obj=findSettable(name, false, &has_getter);

	if(!obj && cls)
	{
		//Look for borrowed traits before
		//It's valid to override only a getter, so keep
		//looking for a settable even if a super class sets
		//has_getter to true.
		obj=cls->findSettable(name,true,&has_getter);
	}

	if(!obj && cls)
	{
		//Look in prototype chain
		ASObject* proto = cls->prototype.getPtr();
		while(proto)
		{
			variable* tmp = proto->findSettable(name, false, NULL /*prototypes never have getters/setters*/);
			
			if(tmp)
			{
				if (tmp->kind != DYNAMIC_TRAIT) // dynamic prototype properties can be overridden 
					obj = tmp;
				break;
			}
			proto = proto->getprop_prototype();
		}
	}

	if(!obj)
	{
		if(has_getter)
		{
			tiny_string err=tiny_string("Error #1074: Illegal write to read-only property ")+name.normalizedName();
			if(cls)
				err+=tiny_string(" on type ")+cls->getQualifiedClassName();
			throw Class<ReferenceError>::getInstanceS(err);
		}
		//Create a new dynamic variable
		obj=Variables.findObjVar(name,DYNAMIC_TRAIT,DYNAMIC_TRAIT);
	}

	if(obj->setter)
	{
		//Call the setter
		LOG(LOG_CALLS,_("Calling the setter"));
		//Overriding function is automatically done by using cur_level
		IFunction* setter=obj->setter;
		//One argument can be passed without creating an array
		ASObject* target=this;
		target->incRef();
		_R<ASObject> ret= _MR( setter->call(target,&o,1) );
		assert_and_throw(ret->is<Undefined>());
		LOG(LOG_CALLS,_("End of setter"));
	}
	else
	{
		assert_and_throw(!obj->getter);
		obj->setVar(o);
	}
}
Пример #13
0
int JSON::parse(const tiny_string &jsonstring, int pos, ASObject** parent , const multiname& key, IFunction *reviver)
{
	while (jsonstring.charAt(pos) == ' ' ||
		   jsonstring.charAt(pos) == '\t' ||
		   jsonstring.charAt(pos) == '\n' ||
		   jsonstring.charAt(pos) == '\r'
		   )
		   pos++;
	int len = jsonstring.numBytes();
	if (pos < len)
	{
		char c = jsonstring.charAt(pos);
		switch(c)
		{
			case '{':
				pos = parseObject(jsonstring,pos,parent,key, reviver);
				break;
			case '[': 
				pos = parseArray(jsonstring,pos,parent,key, reviver);
				break;
			case '"':
				pos = parseString(jsonstring,pos,parent,key);
				break;
			case '0':
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9':
			case '-':
				pos = parseNumber(jsonstring,pos,parent,key);
				break;
			case 't':
				pos = parseTrue(jsonstring,pos,parent,key);
				break;
			case 'f':
				pos = parseFalse(jsonstring,pos,parent,key);
				break;
			case 'n':
				pos = parseNull(jsonstring,pos,parent,key);
				break;
			default:
				throwError<SyntaxError>(kJSONInvalidParseInput);
		}
	}
	if (reviver)
	{
		bool haskey = key.name_type!= multiname::NAME_OBJECT;
		ASObject* params[2];
		
		if (haskey)
		{
			params[0] = Class<ASString>::getInstanceS(key.normalizedName());
			if ((*parent)->hasPropertyByMultiname(key,true,false))
			{
				params[1] = (*parent)->getVariableByMultiname(key).getPtr();
				params[1]->incRef();
			}
			else
				params[1] = getSys()->getNullRef();
		}
		else
		{
			params[0] = Class<ASString>::getInstanceS("");
			params[1] = *parent;
			params[1]->incRef();
		}

		ASObject *funcret=reviver->call(getSys()->getNullRef(), params, 2);
		if(funcret)
		{
			if (haskey)
			{
				if (funcret->is<Undefined>())
				{
					(*parent)->deleteVariableByMultiname(key);
					funcret->decRef();
				}
				else
				{
					(*parent)->setVariableByMultiname(key,funcret,ASObject::CONST_NOT_ALLOWED);
				}
			}
			else 
				*parent= funcret;
		}
	}
	return pos;
}
Пример #14
0
void ASObject::setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOWED_FLAG allowConst, Class_base* cls)
{
	check();
	assert(!cls || classdef->isSubClass(cls));
	//NOTE: we assume that [gs]etSuper and [sg]etProperty correctly manipulate the cur_level (for getActualClass)
	bool has_getter=false;
	variable* obj=findSettable(name, &has_getter);

	if (obj && (obj->kind == CONSTANT_TRAIT && allowConst==CONST_NOT_ALLOWED))
	{
		tiny_string err=tiny_string("Error #1074: Illegal write to read-only property ")+name.normalizedName();
		if(classdef)
			err+=tiny_string(" on type ")+classdef->as<Class_base>()->getQualifiedClassName();
		throw Class<ReferenceError>::getInstanceS(err);
	}
	if(!obj && cls)
	{
		//Look for borrowed traits before
		//It's valid to override only a getter, so keep
		//looking for a settable even if a super class sets
		//has_getter to true.
		obj=cls->findBorrowedSettable(name,&has_getter);
		if(obj && cls->isFinal && !obj->setter)
		{
			tiny_string err=tiny_string("Error #1037: Cannot assign to a method ")+name.normalizedName()+tiny_string(" on ")+cls->getQualifiedClassName();
			throw Class<ReferenceError>::getInstanceS(err);
		}
	}

	//Do not lookup in the prototype chain. This is tested behaviour

	if(!obj)
	{
		if(has_getter)
		{
			tiny_string err=tiny_string("Error #1074: Illegal write to read-only property ")+name.normalizedName();
			if(cls)
				err+=tiny_string(" on type ")+cls->getQualifiedClassName();
			throw Class<ReferenceError>::getInstanceS(err);
		}
		//Create a new dynamic variable
		obj=Variables.findObjVar(name,DYNAMIC_TRAIT,DYNAMIC_TRAIT);
	}

	if(obj->setter)
	{
		//Call the setter
		LOG(LOG_CALLS,_("Calling the setter"));
		//Overriding function is automatically done by using cur_level
		IFunction* setter=obj->setter;
		//One argument can be passed without creating an array
		ASObject* target=this;
		target->incRef();
		_R<ASObject> ret= _MR( setter->call(target,&o,1) );
		assert_and_throw(ret->is<Undefined>());
		LOG(LOG_CALLS,_("End of setter"));
	}
	else
	{
		assert_and_throw(!obj->getter);
		obj->setVar(o);
	}
}