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

Last change on this file since 247 was 247, checked in by Maciej Komosinski, 9 years ago

Sources support both 32-bit and 64-bit, and more compilers

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