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

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