// This file is a part of the Framsticks GDK library. // Copyright (C) 2002-2011 Szymon Ulatowski. See LICENSE.txt for details. // Refer to http://www.framsticks.com/ for further information. #include "extvalue.h" #include "param.h" #include "sstringutils.h" #include #include #include "collectionobj.h" #include "3dobject.h" SString ExtObject::toString() const { if (isEmpty()) return SString(""); Param tmp_param; ParamInterface *p=getParamInterface(tmp_param); int tostr=p->findId("toString"); if (tostr>=0) { return SString(p->getString(tostr)); } else { SString tmp("<"); tmp+=p->getName(); sprintf(tmp.directAppend(30)," object at %p>", (object?object:paraminterface)); tmp.endAppend(); return tmp; } } ThreadSingleton ExtObject::serialization; void ExtObject::Serialization::begin() { if (level==0) refs.clear(); level++; } int ExtObject::Serialization::add(const ExtObject &o) { if (o.isEmpty()) return -1; for(int i=0;i=refs.size()) return NULL; return &refs[ref]; } void ExtObject::Serialization::end() { level--; if (level==0) refs.clear(); } SString ExtObject::serialize_inner() const { int ref=serialization.getref().add(*this); if (ref>=0) { SString ret; sprintf(ret.directAppend(20),"^%d",ref);ret.endAppend(); return ret; } if (isEmpty()) return SString(); VectorObject *vec=VectorObject::fromObject(*this); if (vec) return vec->serialize(); DictionaryObject *dic=DictionaryObject::fromObject(*this); if (dic) return dic->serialize(); Param tmp_param; ParamInterface *p=getParamInterface(tmp_param); int m=p->findId("toVector"); if (m<0) m=p->findId("toDictionary"); if (m>=0) { ExtObject o(p->getObject(m)); SString ret=SString(interfaceName())+o.serialize(); return ret; } m=p->findId("toString"); if (m>=0) { SString str=p->getString(m); sstringQuote(str); SString ret=SString(interfaceName())+"\""+str+"\""; return ret; } SString ret=interfaceName(); sprintf(ret.directAppend(30),"<%p>",object?object:paraminterface);ret.endAppend(); return ret; } SString ExtObject::serialize() const { serialization.getref().begin(); SString ret=serialize_inner(); serialization.getref().end(); return ret; } /////////////////////////////////////// void ExtValue::set(const ExtValue& src) { switch(src.type) { case TString: sets(src.sdata()); break; case TInt: seti(src.idata()); break; case TDouble: setd(src.ddata()); break; case TObj: seto(src.odata()); break; case TInvalid: type=TInvalid; break; } } void ExtValue::setEmpty() { switch(type) { #ifdef EXTVALUEUNION case TString: sdata().~SString(); break; case TObj: odata().~ExtObject(); break; #else case TString: delete s; break; case TObj: delete o; break; #endif } type=TUnknown; } static long longsign(long x) { if (x<0) return -1; if (x>0) return 1; return 0; } long ExtValue::compare(const ExtValue& src) const { if (type==TUnknown) { if (src.type==TDouble) return (src.getDouble()!=0.0); if (src.type==TString) return 1; return src.getInt()?1:0; } else if (src.type==TUnknown) { if (type==TDouble) return (getDouble()!=0.0); if (type==TString) return 1; return getInt()?1:0; } switch(type) { case TInt: { long t=src.getInt(); if (idata()>0) {if (t>0) return longsign(idata()-t); else return +1;} else {if (t<=0) return longsign(idata()-t); else return -1;} } case TDouble: { double t=ddata()-src.getDouble(); if (t<0) return -1; else if (t>0) return 1; return 0; } case TString: { SString t=src.getString(); SString& t2=sdata(); const char* s1=(const char*)t2; const char* s2=(const char*)t; return longsign(strcmp(s1,s2)); } case TObj: { if (src.type==TObj) return !(odata()==src.odata()); return 1; } } return 1; } int ExtValue::operator==(const ExtValue& src) const { if (type!=src.type) return 0; switch(type) { case TInt: return idata()==src.idata(); case TDouble: return ddata()==src.ddata(); case TString: return sdata()==src.sdata(); case TObj: return odata()==src.odata(); } return 1; } void ExtValue::operator+=(const ExtValue& src) { switch(type) { case TInt: idata()+=src.getInt(); break; case TDouble: ddata()+=src.getDouble(); break; case TString: sdata()+=src.getString(); break; } } void ExtValue::operator-=(const ExtValue& src) { switch(type) { case TInt: idata()-=src.getInt(); break; case TDouble: ddata()-=src.getDouble(); break; } } void ExtValue::operator*=(const ExtValue& src) { switch(type) { case TInt: idata()*=src.getInt(); break; case TDouble: ddata()*=src.getDouble(); break; } } #include "framsg.h" /*#include "fpu_control.h" #include static int fpuexception; void mathhandler(int sig) { printf("fpu exception!\n"); fpuexception=1; signal(SIGFPE,SIG_IGN); } */ void ExtValue::operator/=(const ExtValue& src) { switch(type) { case TInt: { int a=src.getInt(); // idata()/=src.getInt(); if (a) idata()/=a; else FMprintf("ExtValue","divide",FMLV_ERROR,"%s/0",(const char*)getString()); } break; case TDouble: // ugly ;-( #ifdef FPU_THROWS_EXCEPTIONS try { ddata()/=src.getDouble(); } catch(...) { FMprintf("ExtValue","divide",FMLV_ERROR,"%s/0.0",(const char*)getString()); } #else { double d=ddata(); d/=src.getDouble(); #ifdef IPHONE if (!isinf(d)) #else if (finite(d)) #endif ddata()=d; else FMprintf("ExtValue","divide",FMLV_ERROR,"%s/0.0",(const char*)getString()); } #endif break; } } void ExtValue::operator%=(const ExtValue& src) { switch(type) { case TInt: idata()=idata()%src.getInt(); break; case TDouble: ddata()=fmod(ddata(),src.getDouble()); break; } } long ExtValue::getInt() const { switch(type) { case TInt: return idata(); case TDouble: return (int)ddata(); case TString: { const char* s=(const char*)sdata(); if ((s[0]=='0')&&(s[1]=='x')) { long val; sscanf(s+2,"%lx",&val); return val; } else { if (strchr(s,'e')||(strchr(s,'E'))) return atof(s); else return atol(s); } } case TObj: return (long)odata().param; } return 0; } double ExtValue::getDouble() const { switch(type) { case TDouble: return ddata(); case TInt: return (double)idata(); case TString: { const char* s=(const char*)sdata(); if ((s[0]=='0')&&(s[1]=='x')) { long val; sscanf(s+2,"%lx",&val); return val; } else return atof(s); } case TObj: return (double)(long)odata().param; } return 0.0; } SString ExtValue::getString() const { switch(type) { case TString: return sdata(); case TInt: { SString tmp; sprintf(tmp.directAppend(20),"%d",idata()); tmp.endAppend(); return tmp; } case TDouble: { SString tmp; sprintf(tmp.directAppend(20),"%.15g",ddata()); tmp.endAppend(); if ((!strchr(tmp,'.'))&&(!strchr(tmp,'e'))) tmp+=".0"; return tmp; } case TObj: return odata().toString(); case TInvalid: return SString("undefined"); default: return SString("null"); } } SString ExtValue::serialize() const { switch(type) { case TString: { SString q=sdata(); sstringQuote(q); return SString("\"")+q+SString("\""); } case TInt: { SString tmp; sprintf(tmp.directAppend(20),"%d",idata()); tmp.endAppend(); return tmp; } case TDouble: { SString tmp; sprintf(tmp.directAppend(20),"%.15g",ddata()); tmp.endAppend(); if ((!strchr(tmp,'.'))&&(!strchr(tmp,'e'))) tmp+=".0"; return tmp; } case TObj: return odata().serialize(); case TInvalid: return SString("undefined"); default: return SString("null"); } } //returns the first character after the parsed number or NULL if not a number const char* ExtValue::parseNumber(const char* in) { if (isdigit(*in)||((*in=='-')&&(isdigit(in[1])))) { const char* p=in; if (*p=='-') p++; while(isdigit(*p)) p++; bool fp=false; if ((*p=='.') && isdigit(p[1])) { p++; while(isdigit(*p)) p++; fp=true; } if (((*p=='e')||(*p=='E')) && (isdigit(p[1]) || (((p[1]=='-') || (p[1]=='+')) && isdigit(p[2])))) { p++; if ((*p=='-')||(*p=='+')) p++; while(isdigit(*p)) p++; fp=true; } if (fp) { setDouble(atof(in)); return p; } else { setInt(atol(in)); return p; } } return NULL; } PtrListTempl ExtValue::deserializable_classes; void ExtValue::initDeserializableClasses() { deserializable_classes+=&Pt3D_Ext::getStaticParam(); deserializable_classes+=&Orient_Ext::getStaticParam(); } ParamInterface *ExtValue::findDeserializableClass(const char* name) { FOREACH(ParamInterface*,cls,deserializable_classes) if (!strcmp(cls->getName(),name)) return cls; return NULL; } static const char* skipWord(const char* in) { while(isalpha(*in)) in++; return in; } //returns the first character after the parsed portion or NULL if invalid format const char* ExtValue::deserialize_inner(const char* in) { const char* ret=parseNumber(in); if (ret) return ret; else if (*in=='\"') { ret=skipQuoteString(in+1,NULL); SString s(in+1,ret-(in+1)); sstringUnquote(s); setString(s); if (*ret=='\"') return ret+1; else return NULL; } else if (*in=='[') { VectorObject *vec=new VectorObject; ExtObject o(&VectorObject::par,vec); ExtObject::serialization.getref().add(o); const char* p=in+1; ExtValue tmp; while(*p) { if (*p==']') {p++;break;} ret=tmp.deserialize(p); if (ret) { vec->data+=new ExtValue(tmp); p=ret; if (*p==',') p++; } else { p=NULL; break; } } setObject(o); return p; } else if (*in=='{') { DictionaryObject *dic=new DictionaryObject; ExtObject o(&DictionaryObject::par,dic); ExtObject::serialization.getref().add(o); const char* p=in+1; ExtValue args[2]/*={value,key}*/, dummy_ret; while(*p) { if (*p=='}') {p++;break;} ret=args[1].deserialize(p); if ((!ret)||(args[1].getType()!=TString)) {p=NULL;break;} p=ret; if (*p!=':') {p=NULL;break;} p++; ret=args[0].deserialize(p); if (!ret) {p=NULL;break;} p=ret; dic->p_set(args,&dummy_ret); if (*p==',') p++; } setObject(o); return p; } else if (!strncmp(in,"null",4)) { setEmpty(); return in+4; } else if (!strncmp(in,"undefined",9)) { setInvalid(); return in+9; } else if (*in=='<') { //unserializable object setInvalid(); while(*in) if (*in=='>') return in+1; else in++; return in; } else if (*in=='^') { in++; ExtValue ref; ret=ref.parseNumber(in); if (ret && (ref.getType()==TInt)) { const ExtObject* o=ExtObject::serialization.getref().get(ref.getInt()); if (o) { setObject(*o); return ret; } } return NULL; } else if ((ret=skipWord(in))&&(ret!=in)) { SString clsname(in,ret-in); ExtValue tmp; ret=tmp.deserialize(ret); ParamInterface *cls=findDeserializableClass(clsname); if (cls && (tmp.getType()!=TUnknown) && (tmp.getType()!=TInvalid)) { VectorObject *vec=VectorObject::fromObject(tmp.getObject()); if (vec) { int m=cls->findId("newFromVector"); if (m>=0) { cls->call(m,&tmp,this); ExtObject::serialization.getref().replace(tmp.getObject(),getObject()); return ret; } } DictionaryObject *dic=DictionaryObject::fromObject(tmp.getObject()); if (dic) { int m=cls->findId("newFromDictionary"); if (m>=0) { cls->call(m,&tmp,this); ExtObject::serialization.getref().replace(tmp.getObject(),getObject()); return ret; } } if (tmp.getType()==TString) { int m=cls->findId("newFromString"); if (m>=0) { cls->call(m,&tmp,this); ExtObject::serialization.getref().replace(tmp.getObject(),getObject()); return ret; } } ExtObject::serialization.getref().remove(tmp.getObject()); setEmpty(); } FMprintf("ExtValue","deserialize",FMLV_WARN,"object of class \"%s\" could not be deserialized",(const char*)clsname); return ret; } return NULL; } const char* ExtValue::deserialize(const char* in) { ExtObject::serialization.getref().begin(); const char* ret=deserialize_inner(in); ExtObject::serialization.getref().end(); return ret; } ExtObject ExtValue::getObject() const { if (type==TObj) return odata(); return ExtObject(); } ExtValue ExtValue::getExtType() { if (getType()!=TObj) return ExtValue((long)getType()); ExtObject& o=odata(); return ExtValue(SString(o.isEmpty()?"":o.interfaceName())); }