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

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

GDK used by developers since 1999, distributed on the web since 2002

  • 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) 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 <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.