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

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

More strict parsing of int and float numbers from string

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