source: cpp/frams/util/extvalue.cpp @ 171

Last change on this file since 171 was 171, checked in by sz, 10 years ago

getObjectTarget is now the recommended way to retrieve object from ExtValue?, can post the standard warning message about missing object

  • Property svn:eol-style set to native
File size: 18.8 KB
Line 
1// This file is a part of the Framsticks GDK.
2// Copyright (C) 2002-2014  Maciej Komosinski and Szymon Ulatowski.  See LICENSE.txt for details.
3// Refer to http://www.framsticks.com/ for further information.
4
5#include "extvalue.h"
6#include <frams/param/param.h>
7#include "sstringutils.h"
8#include <ctype.h>
9#include <frams/vm/classes/collectionobj.h>
10#include <frams/vm/classes/3dobject.h>
11#include <common/nonstd_math.h>
12#include <common/Convert.h>
13
14#ifndef NO_BARRIER
15#include <frams/simul/barrier.h>
16#include <common/threads.h>
17#endif
18
19#ifdef MULTITHREADED
20#include <pthread.h>
21//this lock only protects against ref.counter corruption caused by concurrent reads.
22//read/write conficts and nonatomicity are handled by BarrierObject (at least in theory ;-))
23static pthread_mutex_t extobject_ref_lock=PTHREAD_MUTEX_INITIALIZER;
24#define REF_LOCK pthread_mutex_lock(&extobject_ref_lock)
25#define REF_UNLOCK pthread_mutex_unlock(&extobject_ref_lock)
26#else
27#define REF_LOCK
28#define REF_UNLOCK
29#endif
30
31void ExtObject::incref() const
32{
33if (subtype&1)
34        {
35        REF_LOCK;
36        dbobject->refcount++;
37        REF_UNLOCK;
38        }
39}
40
41void ExtObject::decref() const
42{
43if (subtype&1)
44        {
45        REF_LOCK;
46        bool destroy=!--dbobject->refcount;
47        REF_UNLOCK;
48        //another thread can now access the object while we are deleting it
49        //but this is not a bug since we only guarantee read/read safety
50        if (destroy) delete dbobject;
51        }
52}
53
54bool ExtObject::makeUnique()
55{
56if (!(subtype&1)) return false;
57if (dbobject->refcount==1) return false;
58VectorObject* v=VectorObject::fromObject(*this,false);
59if (v)
60        {
61        VectorObject* n=new VectorObject;
62        n->data.setSize(n->data.size());
63        for(int i=0;i<v->data.size();i++)
64                {
65                ExtValue *x=(ExtValue*)v->data(i);
66                n->data.set(i,x?new ExtValue(*x):NULL);
67                }
68        operator=(n->makeObject());
69        return true;
70        }
71return false;
72}
73
74void* ExtObject::getTarget(const char* classname, bool through_barrier, bool warn) const
75{
76if (!strcmp(interfaceName(),classname))
77        return getTarget();
78#ifndef NO_BARRIER
79if (through_barrier)
80        {
81        BarrierObject *bo=BarrierObject::fromObject(*this);
82        if (bo)
83                return bo->getSourceObject().getTarget(classname,true,warn);
84        }
85#endif
86
87if (warn)
88        {
89        FMprintf("ExtValue","getObjectTarget",FMLV_WARN,"%s object expected, %s found",classname,interfaceName());
90        }
91
92return NULL;
93}
94
95
96SString ExtObject::toString() const
97{
98if (isEmpty()) return SString("<empty object>");
99Param tmp_param;
100ParamInterface *p=getParamInterface(tmp_param);
101int tostr=p->findId("toString");
102if (tostr>=0)
103        {
104        return SString(p->getString(tostr));
105        }
106else
107        {
108        SString tmp("<");
109        tmp+=p->getName();
110        tmp+=SString::sprintf(" object at %p>",object?object:paraminterface);
111        return tmp;
112        }
113}
114
115THREAD_LOCAL_DEF(ExtObject::Serialization,ExtObject::serialization);
116
117void ExtObject::Serialization::begin()
118{
119if (level==0)
120        refs.clear();
121level++;
122}
123
124int ExtObject::Serialization::add(const ExtObject &o)
125{
126if (o.isEmpty()) return -1;
127for(int i=0;i<(int)refs.size();i++)
128        {
129        ExtObject& r=refs[i];
130        if (r==o) return i;
131        }
132refs.push_back(o);
133return -1;
134}
135
136void ExtObject::Serialization::replace(const ExtObject& o,const ExtObject& other)
137{
138if (o.isEmpty()) return;
139for(int i=0;i<(int)refs.size();i++)
140        {
141        ExtObject& r=refs[i];
142        if (r==o)
143                {
144                r=other;
145                return;
146                }
147        }
148}
149
150void ExtObject::Serialization::remove(const ExtObject& o)
151{
152if (o.isEmpty()) return;
153for(int i=0;i<(int)refs.size();i++)
154        {
155        ExtObject& r=refs[i];
156        if (o==r) refs.erase(refs.begin()+i);
157        }
158}
159
160const ExtObject* ExtObject::Serialization::get(int ref)
161{
162if (ref<0) return NULL;
163if (ref>=(int)refs.size()) return NULL;
164return &refs[ref];
165}
166
167void ExtObject::Serialization::end()
168{
169level--;
170if (level==0)
171        refs.clear();
172}
173
174SString ExtObject::serialize_inner() const
175{
176int ref=tlsGetRef(serialization).add(*this);
177if (ref>=0)
178        return SString::sprintf("^%d",ref);
179
180if (isEmpty()) return SString();
181VectorObject *vec=VectorObject::fromObject(*this,false);
182if (vec)
183        return vec->serialize();
184DictionaryObject *dic=DictionaryObject::fromObject(*this,false);
185if (dic)
186        return dic->serialize();
187Param tmp_param;
188ParamInterface *p=getParamInterface(tmp_param);
189int m=p->findId("toVector");
190if (m<0)
191        m=p->findId("toDictionary");
192if (m>=0)
193        {
194        ExtObject o(p->getObject(m));
195        SString ret=SString(interfaceName())+o.serialize();
196        return ret;
197        }
198m=p->findId("toString");
199if (m>=0)
200        {
201        SString str=p->getString(m);
202        sstringQuote(str);
203        SString ret=SString(interfaceName())+"\""+str+"\"";
204        return ret;
205        }
206
207tlsGetRef(serialization).remove(*this);//undo nonserializable reference
208SString ret=interfaceName();
209ret+=SString::sprintf("<%p>",object?object:paraminterface);
210return ret;
211}
212
213SString ExtObject::serialize() const
214{
215tlsGetRef(serialization).begin();
216SString ret=serialize_inner();
217tlsGetRef(serialization).end();
218return ret;
219}
220
221///////////////////////////////////////
222
223void *ExtValue::getObjectTarget(const char* classname,bool warn) const
224{
225if (type!=TObj)
226        {
227        if (warn)
228                {
229                SString tmp=getString();
230                if (tmp.len()>30) tmp=tmp.substr(0,30)+"...";
231                if (type==TString) tmp=SString("\"")+tmp+SString("\"");
232                FMprintf("ExtValue","getObjectTarget",FMLV_WARN,"%s object expected, %s found",classname,(const char*)tmp);
233                }
234        return NULL;
235        }
236
237return getObject().getTarget(classname,true,warn);
238}
239
240void ExtValue::set(const ExtValue& src)
241{
242switch(src.type)
243        {
244        case TString: sets(src.sdata()); break;
245        case TInt: seti(src.idata()); break;
246        case TDouble: setd(src.ddata()); break;
247        case TObj: seto(src.odata()); break;
248        default:type=src.type; break;
249        }
250}
251
252void ExtValue::setEmpty()
253{
254switch(type)
255        {
256#ifdef EXTVALUEUNION
257        case TString: sdata().~SString(); break;
258        case TObj: odata().~ExtObject(); break;
259#else
260        case TString: delete s; break;
261        case TObj: delete o; break;
262#endif
263        default:;
264        }
265type=TUnknown;
266}
267
268static long longsign(long x)
269{
270if (x<0) return -1;
271if (x>0) return 1;
272return 0;
273}
274
275static long compareNull(const ExtValue& v)
276{
277switch(v.type)
278        {
279        case TDouble: return v.getDouble()!=0.0;
280        case TInt: return v.getInt()?1:0;
281        case TString: return 1;
282        default: return !v.isNull();
283        }
284}
285
286long ExtValue::compare(const ExtValue& src) const
287{
288if (type==TUnknown)
289        return compareNull(src);
290else if (src.type==TUnknown)
291        return compareNull(*this);
292switch(type)
293        {
294        case TInt:
295        {
296        long t=src.getInt();
297        if (idata()>0)
298                {if (t>0) return longsign(idata()-t); else return +1;}
299        else
300                {if (t<=0) return longsign(idata()-t); else return -1;}
301        }
302        case TDouble:
303                {
304                double t=ddata()-src.getDouble();
305                if (t<0) return -1;
306                else if (t>0) return 1;
307                return 0;
308                }
309        case TString:
310        {
311        SString t=src.getString();
312        SString& t2=sdata();
313        const char* s1=(const char*)t2;
314        const char* s2=(const char*)t;
315        return longsign(strcmp(s1,s2));
316        }
317        case TObj:
318        {
319        if (src.type==TObj)
320                return !(odata()==src.odata());
321        return 1;
322        }
323        default:;
324        }
325return 1;
326}
327
328int ExtValue::operator==(const ExtValue& src) const
329{
330if (type!=src.type) return 0;
331switch(type)
332        {
333        case TInt: return idata()==src.idata();
334        case TDouble: return ddata()==src.ddata();
335        case TString: return sdata()==src.sdata();
336        case TObj: return odata()==src.odata();
337        default:;
338        }
339return 1;
340}
341
342void ExtValue::operator+=(const ExtValue& src)
343{
344switch(type)
345        {
346        case TInt: idata()+=src.getInt(); break;
347        case TDouble: ddata()+=src.getDouble(); break;
348        case TString: sdata()+=src.getString(); break;
349        case TObj:
350                {
351                VectorObject *vec=VectorObject::fromObject(getObject(),false);
352                VectorObject *vec2=VectorObject::fromObject(src.getObject(),false);
353                if (vec && vec2)
354                        {
355                        for(int i=0;i<vec2->data.size();i++)
356                                {
357                                ExtValue *s=(ExtValue*)vec2->data(i);
358                                ExtValue *d=s?new ExtValue(*s):NULL;
359                                vec->data+=d;
360                                }
361                        }
362                }
363        default:;
364        }
365}
366
367void ExtValue::operator-=(const ExtValue& src)
368{
369switch(type)
370        {
371        case TInt: idata()-=src.getInt(); break;
372        case TDouble: ddata()-=src.getDouble(); break;
373        default:;
374        }
375}
376
377void ExtValue::operator*=(const ExtValue& src)
378{
379switch(type)
380        {
381        case TInt: idata()*=src.getInt(); break;
382        case TDouble: ddata()*=src.getDouble(); break;
383        case TString:
384        {
385        SString t;
386        for(int n=src.getInt();n>0;n--)
387                t+=getString();
388        setString(t);
389        break;
390        }
391        case TObj:
392                {
393                VectorObject *vec=VectorObject::fromObject(getObject(),false);
394                if (vec)
395                        {
396                        int n=src.getInt();
397                        int orig_size=vec->data.size();
398                        if (n<=0)
399                                {vec->clear();return;}
400                        for(;n>1;n--)
401                                {
402                                for(int i=0;i<orig_size;i++)
403                                        {
404                                        ExtValue *s=(ExtValue*)vec->data(i);
405                                        ExtValue *d=s?new ExtValue(*s):NULL;
406                                        vec->data+=d;
407                                        }
408                                }
409                        }
410                break;
411                }
412        default:;
413        }
414}
415
416#include <common/framsg.h>
417/*#include "fpu_control.h"
418#include <signal.h>
419
420static int fpuexception;
421void mathhandler(int sig)
422{
423printf("fpu exception!\n");
424fpuexception=1;
425signal(SIGFPE,SIG_IGN);
426} */
427
428void ExtValue::operator/=(const ExtValue& src)
429{
430switch(type)
431        {
432        case TInt:
433        { int a=src.getInt();
434//              idata()/=src.getInt();
435        if (a) idata()/=a;
436        else {FMprintf("ExtValue","divide",FMLV_CRITICAL,"%d/0",idata()); setInvalid();}
437        }
438                break;
439
440        case TDouble:
441                {
442                double d=src.getDouble();
443                if (d==0.0)
444                        {
445                        FMprintf("ExtValue","divide",FMLV_CRITICAL,"%s/0.0",(const char*)getString());
446                        setInvalid();
447                        }
448                else
449                        {
450                        fpExceptDisable();
451                        double tmp=ddata()/d;
452                        if (!finite(tmp))
453                                { FMprintf("ExtValue","divide",FMLV_CRITICAL,"overflow %s/%s",(const char*)getString(),(const char*)src.getString()); setInvalid(); }
454                        else
455                                ddata()=tmp;
456                        // niby dobrze ale lepiej byloby to robic bardziej systematycznie a nie tylko w dzieleniu?
457                        //if (isnan(ddata())) //http://www.digitalmars.com/d/archives/c++/Traping_divide_by_zero_5728.html
458                        //        { FMprintf("ExtValue","divide",FMLV_ERROR,"not-a-number",(const char*)getString()); setInvalid(); }
459                        fpExceptEnable();
460                        }
461                }
462                break;
463
464        default:;
465        }
466}
467
468SString ExtValue::format(SString& fmt,const ExtValue **values,int count)
469{
470SString ret;
471// "..........%.........%..........%........"
472//  ^_cur     ^_next
473//  ^^^^^^^^^^___sub
474//
475// "..........%.........%..........%........"
476//            ^-cur     ^-next
477//            ^^^^^^^^^^___sub
478const char* begin=(const char*)fmt, *end=begin+fmt.len(), *curr=begin;
479int type=0;
480
481class Args
482{
483const ExtValue **values;
484int count;
485int arg;
486public:
487Args(const ExtValue **v,int c):values(v),count(c),arg(0) {}
488bool finished() {return arg>=count;}
489const ExtValue *getNext() {const ExtValue *ret=NULL; if ((arg<count)&&values[arg]) ret=values[arg]; arg++; return ret;}
490};
491Args args(values,count);
492
493while(curr<end)
494        {
495        const char* next=strchr(curr,'%');
496        if (!next) next=end; else if ((next==curr)&&(curr>begin))
497                {next=strchr(next+1,'%'); if (!next) next=end;}
498        type=0;
499        if (curr>begin)
500                {
501                type=0;
502                for(const char* t=curr;t<next;t++)
503                        switch(*t)
504                                {
505                                case 'd': case 'x': case 'X': case 'u': case 'p': case 'c': type='d'; t=next; break;
506                                case 'f': case 'g': case 'e': type='f'; t=next; break;
507                                case 's': type='s'; t=next; break;
508                                case 't': case 'T': type=*t; t=next; break;
509                                case '%': if (t>begin) {type=*t; t=next;} break;
510                                }
511                }
512        if (curr>begin) curr--;
513        const ExtValue *a;
514        if (args.finished() && (type!=0) && (type!='%'))
515                {
516                ret+=fmt.substr(curr-begin);
517                break;
518                }
519        SString sub=fmt.substr(curr-begin,next-curr);
520        switch(type)
521                {
522                case 'd': a=args.getNext(); ret+=SString::sprintf((const char*)sub,a?a->getInt():0); break;
523                case 'f': a=args.getNext(); ret+=SString::sprintf((const char*)sub,a?a->getDouble():0); break;
524                case 's': {a=args.getNext(); SString tmp; if (a) tmp=a->getString(); ret+=SString::sprintf((const char*)sub,(const char*)tmp);} break;
525                case 't': case 'T':
526                        {
527                        a=args.getNext();
528                        time_t ti=a?a->getInt():0;
529                        struct tm tm=Convert::localtime(ti);
530                        SString timtxt;
531                        if (type=='T')
532                                timtxt=SString::sprintf("%04d-%02d-%02d %02d:%02d:%02d",1900+tm.tm_year,1+tm.tm_mon,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec);
533                        else
534                                timtxt=Convert::asctime(tm).c_str();
535                        ret+=timtxt;
536                        ret+=sub.substr(2);
537                        }
538                        break;
539                case '%': ret+='%'; ret+=sub.substr(2); break;
540                case 0: ret+=sub; break;
541                }
542        curr=next+1;
543        }
544return ret;
545}
546
547
548void ExtValue::operator%=(const ExtValue& src)
549{
550switch(type)
551        {
552        case TInt: idata()=idata()%src.getInt(); break;
553        case TDouble: ddata()=fmod(ddata(),src.getDouble()); break;
554
555        case TString:
556        {
557        VectorObject *vec=VectorObject::fromObject(src.getObject(),false);
558        if (vec)
559                sdata()=format(sdata(),(const ExtValue**)&vec->data.getref(0),vec->data.size());
560        else
561                {const ExtValue *ptr=&src; sdata()=ExtValue::format(sdata(),&ptr,1);}
562        }
563        break;
564
565        default:;
566        }
567}
568
569long ExtValue::getInt(const char* s)
570{
571if ((s[0]=='0')&&(s[1]=='x'))
572        {
573        long val;
574        sscanf(s+2,"%lx",&val);
575        return val;
576        }
577else
578        {
579        if (strchr(s,'e')||(strchr(s,'E')))
580                return (long)atof(s);
581        else
582                return atol(s);
583        }
584}
585
586double ExtValue::getDouble(const char* s)
587{
588if ((s[0]=='0')&&(s[1]=='x'))
589        {
590        long val;
591        sscanf(s+2,"%lx",&val);
592        return val;
593        }
594else
595        return atof(s);
596}
597
598long ExtValue::getInt() const
599{
600switch(type)
601        {
602        case TInt: return idata();
603        case TDouble: return (int)ddata();
604        case TString: return getInt((const char*)sdata());
605        case TObj:
606                FMprintf("ExtValue","getInt",FMLV_WARN,"Getting integer value from object reference (%s)",(const char*)getString());
607                return (long)odata().param;
608        default:;
609        }
610return 0;
611}
612
613double ExtValue::getDouble() const
614{
615switch(type)
616        {
617        case TDouble: return ddata();
618        case TInt: return (double)idata();
619        case TString: return getDouble((const char*)sdata());
620        case TObj:
621                FMprintf("ExtValue","getDouble",FMLV_WARN,"Getting floating point value from object reference (%s)",(const char*)getString());
622                return (double)(long)odata().param;
623        default:;
624        }
625return 0.0;
626}
627SString ExtValue::getString() const
628{
629switch(type)
630        {
631        case TString: return sdata();
632        case TInt: return SString::valueOf(idata());
633        case TDouble: return SString::valueOf(ddata());
634        case TObj: return odata().toString();
635        case TInvalid:  return SString("invalid");
636        default: return SString("null");
637        }
638}
639
640const SString* ExtValue::getStringPtr() const
641{
642if (type==TString)
643        return &sdata();
644return NULL;
645}
646
647SString ExtValue::serialize() const
648{
649switch(type)
650        {
651        case TString:
652                {
653                SString q=sdata();
654                sstringQuote(q);
655                return SString("\"")+q+SString("\"");
656                }
657        case TInt:
658                return SString::valueOf(idata());
659        case TDouble:
660                return SString::valueOf(ddata());
661        case TObj:
662                return odata().serialize();
663        case TInvalid:
664                return SString("invalid");
665        default:
666                return SString("null");
667        }
668}
669
670//returns the first character after the parsed number or NULL if not a number
671const char* ExtValue::parseNumber(const char* in)
672{
673if (isdigit(*in)||((*in=='-')&&(isdigit(in[1]))))
674        {
675        const char* p=in;
676        if (*p=='-') p++;
677        while(isdigit(*p)) p++;
678        bool fp=false;
679        if ((*p=='.') && isdigit(p[1]))
680                {
681                p++;
682                while(isdigit(*p)) p++;
683                fp=true;
684                }
685        if (((*p=='e')||(*p=='E')) && (isdigit(p[1]) || (((p[1]=='-') || (p[1]=='+')) && isdigit(p[2]))))
686                {
687                p++;
688                if ((*p=='-')||(*p=='+')) p++;
689                while(isdigit(*p)) p++;
690                fp=true;
691                }
692
693        if (fp)
694                {
695                setDouble(atof(in));
696                return p;
697                }
698        else
699                {
700                setInt(atol(in));
701                return p;
702                }
703        }
704return NULL;
705}
706
707PtrListTempl<ParamInterface*> ExtValue::deserializable_classes;
708
709void ExtValue::initDeserializableClasses()
710{
711deserializable_classes+=&Pt3D_Ext::getStaticParam();
712deserializable_classes+=&Orient_Ext::getStaticParam();
713}
714
715ParamInterface *ExtValue::findDeserializableClass(const char* name)
716{
717FOREACH(ParamInterface*,cls,deserializable_classes)
718        if (!strcmp(cls->getName(),name))
719                return cls;
720return NULL;
721}
722
723static const char* skipWord(const char* in)
724{
725while(isalpha(*in)||(*in=='_'))
726        in++;
727return in;
728}
729
730//returns the first character after the parsed portion or NULL if invalid format
731const char* ExtValue::deserialize_inner(const char* in)
732{
733const char* ret=parseNumber(in);
734if (ret)
735        return ret;
736else if (*in=='\"')
737        {
738        ret=skipQuoteString(in+1,NULL);
739        SString s(in+1,ret-(in+1));
740        sstringUnquote(s);
741        setString(s);
742        if (*ret=='\"')
743                return ret+1;
744        else
745                return NULL;
746        }
747else if (*in=='[')
748        {
749        VectorObject *vec=new VectorObject;
750        ExtObject o(&VectorObject::par,vec);
751        tlsGetRef(ExtObject::serialization).add(o);
752        const char* p=in+1;
753        ExtValue tmp;
754        while(*p)
755                {
756                if (*p==']') {p++;break;}
757                ret=tmp.deserialize(p);
758                if (ret)
759                        {
760                        vec->data+=new ExtValue(tmp);
761                        p=ret;
762                        if (*p==',') p++;
763                        }
764                else
765                        {
766                        p=NULL;
767                        break;
768                        }
769                }
770        setObject(o);
771        return p;
772        }
773else if (*in=='{')
774        {
775        DictionaryObject *dic=new DictionaryObject;
776        ExtObject o(&DictionaryObject::par,dic);
777        tlsGetRef(ExtObject::serialization).add(o);
778        const char* p=in+1;
779        ExtValue args[2]/*={value,key}*/, dummy_ret;
780        while(*p)
781                {
782                if (*p=='}') {p++;break;}
783                ret=args[1].deserialize(p);
784                if ((!ret)||(args[1].getType()!=TString)) {p=NULL;break;}
785                p=ret;
786                if (*p!=':') {p=NULL;break;}
787                p++;
788                ret=args[0].deserialize(p);
789                if (!ret) {p=NULL;break;}
790                p=ret;
791                dic->p_set(args,&dummy_ret);
792                if (*p==',') p++;
793                }
794        setObject(o);
795        return p;
796        }
797else if (!strncmp(in,"null",4))
798        {
799        setEmpty();
800        return in+4;
801        }
802else if (!strncmp(in,"invalid",9))
803        {
804        setInvalid();
805        return in+9;
806        }
807else if (*in=='<')
808        { //unserializable object
809        setInvalid();
810        while(*in)
811                if (*in=='>')
812                        return in+1;
813                else in++;
814        return in;
815        }
816else if (*in=='^')
817        {
818        in++;
819        ExtValue ref;
820        ret=ref.parseNumber(in);
821        if (ret && (ref.getType()==TInt))
822                {
823                const ExtObject* o=tlsGetRef(ExtObject::serialization).get(ref.getInt());
824                if (o)
825                        {
826                        setObject(*o);
827                        return ret;
828                        }
829                }
830        return NULL;
831        }
832else if ((ret=skipWord(in))&&(ret!=in))
833        {
834        SString clsname(in,ret-in);
835        ExtValue tmp;
836        ret=tmp.deserialize(ret);
837        ParamInterface *cls=findDeserializableClass(clsname);
838        if (cls && (tmp.getType()!=TUnknown) && (tmp.getType()!=TInvalid))
839                {
840                VectorObject *vec=VectorObject::fromObject(tmp.getObject(),false);
841                if (vec)
842                        {
843                        int m=cls->findId("newFromVector");
844                        if (m>=0)
845                                {
846                                cls->call(m,&tmp,this);
847                                tlsGetRef(ExtObject::serialization).replace(tmp.getObject(),getObject());
848                                return ret;
849                                }
850                        }
851                DictionaryObject *dic=DictionaryObject::fromObject(tmp.getObject(),false);
852                if (dic)
853                        {
854                        int m=cls->findId("newFromDictionary");
855                        if (m>=0)
856                                {
857                                cls->call(m,&tmp,this);
858                                tlsGetRef(ExtObject::serialization).replace(tmp.getObject(),getObject());
859                                return ret;
860                                }
861                        }
862                if (tmp.getType()==TString)
863                        {
864                        int m=cls->findId("newFromString");
865                        if (m>=0)
866                                {
867                                cls->call(m,&tmp,this);
868                                tlsGetRef(ExtObject::serialization).replace(tmp.getObject(),getObject());
869                                return ret;
870                                }
871                        }
872                tlsGetRef(ExtObject::serialization).remove(tmp.getObject());
873                setEmpty();
874                }
875        setEmpty();
876        FMprintf("ExtValue","deserialize",FMLV_WARN,"object of class \"%s\" could not be deserialized",(const char*)clsname);
877        return ret;
878        }
879setEmpty();
880return NULL;
881}
882
883const char* ExtValue::deserialize(const char* in)
884{
885tlsGetRef(ExtObject::serialization).begin();
886const char* ret=deserialize_inner(in);
887tlsGetRef(ExtObject::serialization).end();
888return ret;
889}
890
891ExtObject ExtValue::getObject() const
892{
893if (type==TObj) return odata();
894return ExtObject();
895}
896
897ExtValue ExtValue::getExtType()
898{
899if (getType()!=TObj) return ExtValue((long)getType());
900ExtObject& o=odata();
901return ExtValue(SString(o.isEmpty()?"":o.interfaceName()));
902}
903
904SString SString::valueOf(const ExtValue& v)
905{
906return v.getString();
907}
908SString SString::valueOf(const ExtObject& v)
909{
910return v.toString();
911}
Note: See TracBrowser for help on using the repository browser.