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

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

Unified parsing of ints and floats; hex notation

  • Property svn:eol-style set to native
File size: 21.7 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, bool error)
613{
614        ExtValue tmp;
615        const char* after = tmp.parseNumber(s, strict ? TInt : TUnknown);
616        if ((after == NULL) || (after[0] != 0))
617                {
618                if (error)
619                        FMprintf("ExtValue", "parseInt", FMLV_ERROR, "Could not parse '%s'%s", s, strict?" (strict)":"");
620                return false;
621                }
622        result = tmp.getInt();
623        return true;
624}
625
626bool ExtValue::parseDouble(const char* s, double &result, bool error)
627{
628        ExtValue tmp;
629        const char* after = tmp.parseNumber(s, TDouble);
630        if ((after == NULL) || (after[0] != 0))
631                {
632                if (error)
633                        FMprintf("ExtValue", "parseDouble", FMLV_ERROR, "Could not parse '%s'", s);
634                return false;
635                }
636        result = tmp.getDouble();
637        return true;
638}
639
640paInt ExtValue::getInt(const char* s,bool strict)
641{
642        paInt result;
643        if (parseInt(s, result, strict, true))
644                return result;
645        return 0;
646}
647
648double ExtValue::getDouble(const char* s)
649{
650        double result;
651        if (parseDouble(s, result, true))
652                return result;
653        return 0;
654}
655
656paInt ExtValue::getInt() const
657{
658        switch (type)
659        {
660        case TInt: return idata();
661        case TDouble: return (int)ddata();
662        case TString: return getInt((const char*)sdata());
663        case TObj:
664                FMprintf("ExtValue", "getInt", FMLV_WARN, "Getting integer value from object reference (%s)", (const char*)getString());
665                return (paInt)(intptr_t)odata().param;
666        default:;
667        }
668        return 0;
669}
670
671double ExtValue::getDouble() const
672{
673        switch (type)
674        {
675        case TDouble: return ddata();
676        case TInt: return (double)idata();
677        case TString: return getDouble((const char*)sdata());
678        case TObj:
679                FMprintf("ExtValue", "getDouble", FMLV_WARN, "Getting floating point value from object reference (%s)", (const char*)getString());
680                return (double)(intptr_t)odata().param;
681        default:;
682        }
683        return 0.0;
684}
685
686SString ExtValue::getString() const
687{
688        switch (type)
689        {
690        case TString: return sdata();
691        case TInt: return SString::valueOf(idata());
692        case TDouble: return SString::valueOf(ddata());
693        case TObj: return odata().toString();
694        case TInvalid:  return SString("invalid");
695        default: return SString("null");
696        }
697}
698
699const SString* ExtValue::getStringPtr() const
700{
701        if (type == TString)
702                return &sdata();
703        return NULL;
704}
705
706SString ExtValue::serialize() const
707{
708switch(type)
709        {
710        case TString:
711                {
712                SString q=sdata();
713                sstringQuote(q);
714                return SString("\"")+q+SString("\"");
715                }
716        case TInt:
717                return SString::valueOf(idata());
718        case TDouble:
719                return SString::valueOf(ddata());
720        case TObj:
721                return odata().serialize();
722        case TInvalid:
723                return SString("invalid");
724        default:
725                return SString("null");
726        }
727}
728
729/// returns the first character after the parsed number, or NULL if not a number
730/// @param strict_type = restrict the allowed return value (TUnknown = unrestricted)
731const char* ExtValue::parseNumber(const char* in, ExtPType strict_type)
732{
733        char* after;
734        if (in == NULL) return NULL;
735        if (in[0] == 0) return NULL;
736        while (isspace(*in)) in++;
737        bool minus = (in[0] == '-');
738        bool plus = (in[0] == '+');
739        if (((in[0] == '0') && ((in[1] == 'x') || (in[1]=='X')))
740             || (((minus || plus) && (in[1] == '0') && ((in[2] == 'x') || (in[2] == 'X')))))
741        {
742                in += (minus || plus) ? 3 : 2;
743                if (isspace(*in)) return NULL;
744                errno = 0;
745                unsigned long intvalue = strtoul(in, &after, 16);
746                if ((after > in) && (errno == 0) && (intvalue <= 0xffffffff))
747                {
748                        if (strict_type == TDouble)
749                                setDouble(minus ? -(double)intvalue : (double)intvalue);
750                        else
751                                setInt(minus ? -intvalue : intvalue);
752                        return after;
753                }
754                else
755                        return NULL;
756        }
757
758        errno = 0;
759        double fpvalue = strtod(in, &after);
760        if ((after > in) && (errno == 0))
761        {
762                if (strict_type != TDouble)
763                {
764                        if ((memchr(in, '.', after - in) == NULL) && (memchr(in, 'e', after - in) == NULL) && (memchr(in, 'E', after - in) == NULL) // no "special" characters
765                                && (fpvalue == floor(fpvalue)) // value is integer
766                                && (fpvalue >= INT_MIN) && (fpvalue <= INT_MAX)) // within limits
767                        {
768                                setInt(fpvalue);
769                                return after;
770                        }
771                        else if (strict_type == TInt)
772                                return NULL;
773                }
774                setDouble(fpvalue);
775                return after;
776        }
777        return NULL;
778}
779
780PtrListTempl<ParamInterface*> &ExtValue::getDeserializableClasses()
781{
782static PtrListTempl<ParamInterface*> classes;
783return classes;
784}
785
786ParamInterface *ExtValue::findDeserializableClass(const char* name)
787{
788FOREACH(ParamInterface*,cls,getDeserializableClasses())
789        if (!strcmp(cls->getName(),name))
790                return cls;
791return NULL;
792}
793
794static const char* skipWord(const char* in)
795{
796while(isalpha(*in)||(*in=='_'))
797        in++;
798return in;
799}
800
801//returns the first character after the parsed portion or NULL if invalid format
802const char* ExtValue::deserialize_inner(const char* in)
803{
804const char* ret=parseNumber(in);
805if (ret)
806        return ret;
807else if (*in=='\"')
808        {
809        ret=skipQuoteString(in+1,NULL);
810        SString s(in+1,(int)(ret-(in+1)));
811        sstringUnquote(s);
812        setString(s);
813        if (*ret=='\"')
814                return ret+1;
815        else
816                return NULL;
817        }
818else if (*in=='[')
819        {
820        VectorObject *vec=new VectorObject;
821        ExtObject o(&VectorObject::par,vec);
822        tlsGetRef(ExtObject::serialization).add(o);
823        const char* p=in+1;
824        ExtValue tmp;
825        while(*p)
826                {
827                if (*p==']') {p++;break;}
828                ret=tmp.deserialize(p);
829                if (ret)
830                        {
831                        vec->data+=new ExtValue(tmp);
832                        p=ret;
833                        if (*p==',') p++;
834                        }
835                else
836                        {
837                        p=NULL;
838                        break;
839                        }
840                }
841        setObject(o);
842        return p;
843        }
844else if (*in=='{')
845        {
846        DictionaryObject *dic=new DictionaryObject;
847        ExtObject o(&DictionaryObject::par,dic);
848        tlsGetRef(ExtObject::serialization).add(o);
849        const char* p=in+1;
850        ExtValue args[2]/*={value,key}*/, dummy_ret;
851        while(*p)
852                {
853                if (*p=='}') {p++;break;}
854                ret=args[1].deserialize(p);
855                if ((!ret)||(args[1].getType()!=TString)) {p=NULL;break;}
856                p=ret;
857                if (*p!=':') {p=NULL;break;}
858                p++;
859                ret=args[0].deserialize(p);
860                if (!ret) {p=NULL;break;}
861                p=ret;
862                dic->p_set(args,&dummy_ret);
863                if (*p==',') p++;
864                }
865        setObject(o);
866        return p;
867        }
868else if (!strncmp(in,"null",4))
869        {
870        setEmpty();
871        return in+4;
872        }
873else if (!strncmp(in,"invalid",9))
874        {
875        setInvalid();
876        return in+9;
877        }
878else if (*in=='<')
879        { //unserializable object
880        setInvalid();
881        while(*in)
882                if (*in=='>')
883                        return in+1;
884                else in++;
885        return in;
886        }
887else if (*in=='^')
888        {
889        in++;
890        ExtValue ref;
891        ret=ref.parseNumber(in,TInt);
892        if (ret && (ref.getType()==TInt))
893                {
894                const ExtObject* o=tlsGetRef(ExtObject::serialization).get(ref.getInt());
895                if (o)
896                        {
897                        setObject(*o);
898                        return ret;
899                        }
900                }
901        return NULL;
902        }
903else if ((ret=skipWord(in))&&(ret!=in))
904        {
905        SString clsname(in,(int)(ret-in));
906        ExtValue tmp;
907        ret=tmp.deserialize(ret);
908        ParamInterface *cls=findDeserializableClass(clsname);
909        if (cls && (tmp.getType()!=TUnknown) && (tmp.getType()!=TInvalid))
910                {
911                VectorObject *vec=VectorObject::fromObject(tmp.getObject(),false);
912                if (vec)
913                        {
914                        int m=cls->findId("newFromVector");
915                        if (m>=0)
916                                {
917                                cls->call(m,&tmp,this);
918                                tlsGetRef(ExtObject::serialization).replace(tmp.getObject(),getObject());
919                                return ret;
920                                }
921                        }
922                DictionaryObject *dic=DictionaryObject::fromObject(tmp.getObject(),false);
923                if (dic)
924                        {
925                        int m=cls->findId("newFromDictionary");
926                        if (m>=0)
927                                {
928                                cls->call(m,&tmp,this);
929                                tlsGetRef(ExtObject::serialization).replace(tmp.getObject(),getObject());
930                                return ret;
931                                }
932                        }
933                if (tmp.getType()==TString)
934                        {
935                        int m=cls->findId("newFromString");
936                        if (m>=0)
937                                {
938                                cls->call(m,&tmp,this);
939                                tlsGetRef(ExtObject::serialization).replace(tmp.getObject(),getObject());
940                                return ret;
941                                }
942                        }
943                tlsGetRef(ExtObject::serialization).remove(tmp.getObject());
944                setEmpty();
945                }
946        setEmpty();
947        FMprintf("ExtValue","deserialize",FMLV_WARN,"object of class \"%s\" could not be deserialized",(const char*)clsname);
948        return ret;
949        }
950setEmpty();
951return NULL;
952}
953
954const char* ExtValue::deserialize(const char* in)
955{
956tlsGetRef(ExtObject::serialization).begin();
957const char* ret=deserialize_inner(in);
958tlsGetRef(ExtObject::serialization).end();
959return ret;
960}
961
962ExtObject ExtValue::getObject() const
963{
964if (type==TObj) return odata();
965return ExtObject();
966}
967
968ExtValue ExtValue::getExtType()
969{
970if (getType()!=TObj) return ExtValue((paInt)getType());
971ExtObject& o=odata();
972return ExtValue(SString(o.isEmpty()?"":o.interfaceName()));
973}
974
975SString SString::valueOf(const ExtValue& v)
976{
977return v.getString();
978}
979SString SString::valueOf(const ExtObject& v)
980{
981return v.toString();
982}
Note: See TracBrowser for help on using the repository browser.