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

Last change on this file since 205 was 205, checked in by Maciej Komosinski, 10 years ago

Easier way to get an invalid ExtValue?

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