ecere/dataTypes: Fixed prototypes for invoking OnGetString
[sdk] / ecere / src / com / dataTypes.ec
1 namespace com;
2
3 #if defined(ECERE_BOOTSTRAP)
4 #define dllexport
5 #endif
6
7 import "instance"
8
9 default extern Platform runtimePlatform;
10
11 // Limit Definitions
12 public define MAXBYTE = 0xff;
13 public define MAXWORD = 0xffff;
14 public define MININT = ((int)0x80000000);
15 public define MAXINT = ((int)0x7fffffff);
16 public define MININT64 = ((int64)0x8000000000000000LL);
17 public define MAXINT64 = ((int64)0x7fffffffffffffffLL);
18 public define MAXDWORD = 0xffffffff;
19 public define MAXQWORD = 0xffffffffffffffffLL;
20 public define MINFLOAT = ((float)1.17549435082228750e-38);
21 public define MAXFLOAT = ((float)3.40282346638528860e+38);
22 public define MINDOUBLE = ((double) 2.2250738585072014e-308);
23 public define MAXDOUBLE = ((double) 1.7976931348623158e+308);
24
25 public define FORMAT64HEXLL  = (GetRuntimePlatform() == win32) ? "0x%I64XLL" : "0x%llXLL";
26 public define FORMAT64HEX    = (GetRuntimePlatform() == win32) ? "0x%I64X" : "0x%llX";
27 public define FORMAT64DLL    = (GetRuntimePlatform() == win32) ? "%I64dLL" : "%lldLL";
28 public define FORMAT64D      = (GetRuntimePlatform() == win32) ? "%I64d" : "%lld";
29 public define FORMAT64U      = (GetRuntimePlatform() == win32) ? "%I64u" : "%llu";
30
31 #define PUTXWORD(b, w) \
32    (b)[0] = (byte)(((w) >> 8) & 0xFF); \
33    (b)[1] = (byte)(((w)     ) & 0xFF);
34
35 #define GETXWORD(b) (uint16)(((b)[0] << 8) | (b)[1])
36
37 #define PUTXDWORD(b, d) \
38    (b)[0] = (byte)(((d) >> 24) & 0xFF); \
39    (b)[1] = (byte)(((d) >> 16) & 0xFF); \
40    (b)[2] = (byte)(((d) >> 8)  & 0xFF); \
41    (b)[3] = (byte)( (d)        & 0xFF);
42
43 #define GETXDWORD(b) (uint32)(((b)[0] << 24) | ((b)[1] << 16) | ((b)[2] << 8) | (b)[3])
44
45 #define PUTXQWORD(b, d) \
46    (b)[0] = (byte)(((d) >> 56) & 0xFF); \
47    (b)[1] = (byte)(((d) >> 48) & 0xFF); \
48    (b)[2] = (byte)(((d) >> 40) & 0xFF); \
49    (b)[3] = (byte)(((d) >> 32) & 0xFF); \
50    (b)[4] = (byte)(((d) >> 24) & 0xFF); \
51    (b)[5] = (byte)(((d) >> 16) & 0xFF); \
52    (b)[6] = (byte)(((d) >> 8)  & 0xFF); \
53    (b)[7] = (byte)( (d)        & 0xFF);
54
55 #define GETXQWORD(b) (uint64)(((uint64)(b)[0] << 56) | ((uint64)(b)[1] << 48) | ((uint64)(b)[2] << 40) | ((uint64)(b)[3] << 32) | ((uint64)(b)[4] << 24) | ((b)[5] << 16) | ((b)[6] << 8) | (b)[7])
56
57 static void UnusedFunction()
58 {
59    int a;
60    a.OnGetString(0,0,0);
61    a.OnFree();
62    a.OnCopy(null);
63    a.OnCompare(null);
64    a.OnSaveEdit(null,0);
65    a.OnEdit(null,null,0,0,0,0,0);
66    a.OnDisplay(null,0,0,0,0,null,null);
67    a.OnGetDataFromString(null);
68 }
69
70 default:
71 extern int __ecereVMethodID_class_OnGetString;
72 extern int __ecereVMethodID_class_OnGetDataFromString;
73 extern int __ecereVMethodID_class_OnCompare;
74 extern int __ecereVMethodID_class_OnSerialize;
75 extern int __ecereVMethodID_class_OnUnserialize;
76 extern int __ecereVMethodID_class_OnCopy;
77 public:
78
79 #if defined(ECERE_BOOTSTRAP) || defined(ECERE_STATIC)
80 #define dllexport
81 #endif
82
83 // TOFIX: Declaration ordering (Required on gcc 3.4.5)
84 dllexport void eSystem_Delete(void * memory);
85
86 public class IOChannel
87 {
88 public:
89    virtual uint WriteData(byte * data, uint numBytes);
90    virtual uint ReadData(byte * data, uint numBytes);
91
92    dllexport void Serialize(typed_object data)
93    {
94       data.OnSerialize(this);
95    }
96
97    dllexport void Unserialize(typed_object & data)
98    {
99       data.OnUnserialize(this);
100    }
101
102    dllexport void Put(typed_object data)
103    {
104       data.OnSerialize(this);
105    }
106
107    dllexport void Get(typed_object & data)
108    {
109       data.OnUnserialize(this);
110    }
111 };
112
113 public class SerialBuffer : IOChannel
114 {
115 public:
116    byte * _buffer;
117    uint count;
118    uint _size;
119    uint pos;
120
121    uint WriteData(byte * bytes, uint numBytes)
122    {
123       if(this != null)
124       {
125          if(count + numBytes > _size)
126          {
127             _size = count + numBytes;
128             _size += _size/2;
129             _buffer = renew _buffer byte[_size];
130          }
131          memcpy(_buffer + count, bytes, numBytes);
132          count += numBytes;
133          return numBytes;
134       }
135       return 0;
136    }
137
138    uint ReadData(byte * bytes, uint numBytes)
139    {
140       if(this != null)
141       {
142          int read = Min(numBytes, count - pos);
143          memcpy(bytes, _buffer + pos, read);
144          pos += read;
145          return read;
146       }
147       return 0;
148    }
149
150    ~SerialBuffer()
151    {
152       Free();
153    }
154
155    dllexport void Free()
156    {
157       if(this)
158       {
159          delete _buffer;
160          count = 0;
161          _size = 0;
162          pos = 0;
163       }
164    }
165
166    // TODO: THIS IS VERY BAD!
167    property byte * buffer
168    {
169       get { return _buffer + pos; }
170       set { _buffer = value; }
171    }
172
173    property uint size
174    {
175       get { return count - pos; }
176       set { count = value; }
177    }
178 };
179
180 /*static */char * Enum_OnGetString(Class _class, int * data, char * tempString, void * fieldData, bool * needClass)
181 {
182    EnumClassData enumeration = (EnumClassData)_class.data;
183    NamedLink item;
184    for(item = enumeration.values.first; item; item = item.next)
185       if((int)item.data == *data)
186          break;
187    if(item)
188    {
189       strcpy(tempString, item.name);
190       if(!needClass || !*needClass)
191          tempString[0] = (char)toupper(tempString[0]);
192       return tempString;
193       //return item.name;
194    }
195    else
196       return null;
197 }
198
199 static bool Enum_OnGetDataFromString(Class _class, int * data, char * string)
200 {
201    EnumClassData enumeration = (EnumClassData)_class.data;
202    NamedLink item;
203    for(item = enumeration.values.first; item; item = item.next)
204    {
205       if(item.name && !strcmpi(item.name, string))
206          break;
207    }
208    if(item)
209    {
210       *data = (int)item.data;
211       return true;
212    }
213    else
214       return Integer_OnGetDataFromString(_class, data, string);
215    return false;
216 }
217
218 static void OnFree(Class _class, void * data)
219 {
220    if(_class.templateClass) _class = _class.templateClass;
221    if(_class.type == normalClass)
222    {
223       // eInstance_Delete(data);
224       eInstance_DecRef(data);
225    }
226    else if(_class.type == noHeadClass && data)
227    {
228       while(_class && _class.type == noHeadClass)
229       {
230          if(_class.Destructor)
231             _class.Destructor(data);
232          _class = _class.base;
233       }
234       delete data;
235    }
236 }
237
238 static int DataMember_OnCompare(DataMember parentMember, void * data1, void * data2)
239 {
240    DataMember member;
241    Module module = parentMember._class.module;
242    for(member = parentMember.members.first; member; member = member.next)
243    {
244       int memberResult = 0;
245       if(member.type == normalMember)
246       {
247          Class memberType = member.dataTypeClass;
248
249          if(!memberType)
250             memberType = member.dataTypeClass = eSystem_FindClass(module, member.dataTypeString);
251          if(!memberType)
252             memberType = member.dataTypeClass = eSystem_FindClass(module, "int");
253
254          if(memberType.type == structClass || memberType.type == normalClass || memberType.type == noHeadClass)
255          {
256             memberResult = memberType._vTbl[__ecereVMethodID_class_OnCompare](memberType, 
257                (byte *)data1 + member.offset, 
258                (byte *)data2 + member.offset);
259             if(memberResult)
260                return memberResult;
261          }
262          else
263          {
264             DataValue value1, value2;
265             value1.i = *(int *)((byte *)data1 + member.offset);
266             value2.i = *(int *)((byte *)data2 + member.offset);
267             memberResult = memberType._vTbl[__ecereVMethodID_class_OnCompare](memberType, &value1, &value2);
268             if(memberResult)
269                return memberResult;
270          }
271       }
272       else
273       {
274          memberResult = DataMember_OnCompare(member, 
275             (byte *)data1 + member.offset, 
276             (byte *)data2 + member.offset);
277          if(memberResult)
278             return memberResult;
279       }
280    }
281    return 0;
282 }
283
284 static int OnCompare(Class _class, void * data1, void * data2)
285 {
286    Module module = _class.module;
287    if(_class.type == normalClass || _class.type == noHeadClass || _class.type == structClass)
288    {
289       if(data1 && data2)
290       {
291          // NOTE: Comparing from top class down here... might want to reverse it
292          for(; _class && _class.type != systemClass; _class = _class.base)
293          {
294             DataMember member;
295
296             // TESTING THIS HERE...
297             if(_class.noExpansion)
298             {
299                if(data1 > data2) return 1;
300                else if(data1 < data2) return -1;
301                else
302                   return 0;
303             }
304
305             for(member = _class.membersAndProperties.first; member; member = member.next)
306             {
307                int memberResult = 0;
308                if(member.isProperty || member.type == normalMember)
309                {
310                   Class memberType = member.dataTypeClass;
311                         
312                   if(!memberType)
313                      memberType = member.dataTypeClass = eSystem_FindClass(module, member.dataTypeString);
314                   /*
315                   if(!memberType)
316                      memberType = member.dataTypeClass = eSystem_FindClass(module, "int");
317                   */
318                   if(memberType)
319                   {
320                      if(member.isProperty)
321                      {
322                         Property prop = (Property)member;
323                         if(!prop.conversion && prop.Get && prop.Set)
324                         {
325                            if(memberType.type == structClass || memberType.type == normalClass || memberType.type == noHeadClass)
326                            {
327                               if(!strcmp(memberType.dataTypeString, "char *"))
328                               {
329                                  String a = ((String(*)())(void *)prop.Get)(data1);
330                                  String b = ((String(*)())(void *)prop.Get)(data2);
331                                  memberResult = memberType._vTbl[__ecereVMethodID_class_OnCompare](memberType, a, b);
332                               }
333                            }
334                            else
335                            {
336                               DataValue value1, value2;
337                               if(!strcmp(memberType.dataTypeString, "float"))
338                               {
339                                  value1.f = ((float(*)())(void *)prop.Get)(data1);
340                                  value2.f = ((float(*)())(void *)prop.Get)(data2);
341                               }
342                               else
343                               {
344                                  value1.i = prop.Get(data1);
345                                  value2.i = prop.Get(data2);
346                               }
347                               memberResult = memberType._vTbl[__ecereVMethodID_class_OnCompare](memberType, &value1, &value2);
348                            }
349                         }
350                      }
351                      else
352                      {
353                         if(memberType.type == structClass || memberType.type == normalClass || memberType.type == noHeadClass)
354                         {
355                            if(memberType.type == normalClass || memberType.type == noHeadClass)
356                            {
357                               // TESTING THIS!
358                               memberResult = memberType._vTbl[__ecereVMethodID_class_OnCompare](memberType, 
359                                  *(void **)((byte *)data1 + (((member._class.type == normalClass) ? member._class.offset : 0) + member.offset)), 
360                                  *(void **)((byte *)data2 + (((member._class.type == normalClass) ? member._class.offset : 0) + member.offset)));
361                            }
362                            else
363                            {
364                               memberResult = memberType._vTbl[__ecereVMethodID_class_OnCompare](memberType, 
365                                  (byte *)data1 + (((member._class.type == normalClass) ? member._class.offset : 0) + member.offset), 
366                                  (byte *)data2 + (((member._class.type == normalClass) ? member._class.offset : 0) + member.offset));
367                            }
368                         }
369                         else
370                         {
371                            DataValue value1, value2;
372                            if(memberType.typeSize == 8)
373                            {
374                               value1.ui64 = *(uint64 *)((byte *)data1 + (((member._class.type == normalClass) ? member._class.offset : 0) + member.offset));
375                               value2.ui64 = *(uint64 *)((byte *)data2 + (((member._class.type == normalClass) ? member._class.offset : 0) + member.offset));
376                            }
377                            else
378                            {
379                               value1.i = *(int *)((byte *)data1 + (((member._class.type == normalClass) ? member._class.offset : 0) + member.offset));
380                               value2.i = *(int *)((byte *)data2 + (((member._class.type == normalClass) ? member._class.offset : 0) + member.offset));
381                            }
382                            memberResult = memberType._vTbl[__ecereVMethodID_class_OnCompare](memberType, &value1, &value2);
383                         }
384                      }
385                   }
386                   else
387                   {
388                      // printf("Unknown type\n");
389                   }
390                }
391                else
392                {
393                   memberResult = DataMember_OnCompare(member, 
394                      (byte *)data1 + (((member._class.type == normalClass) ? member._class.offset : 0) + member.offset), 
395                      (byte *)data2 + (((member._class.type == normalClass) ? member._class.offset : 0) + member.offset));
396                }
397                if(memberResult)
398                   return memberResult;
399             }
400          }
401       }
402       else if(!data1 && data2)
403          return 1;
404       else if(data1 && !data2)
405          return -1;
406    }
407    else if(_class.type == unitClass)
408    {
409       Class dataType = eSystem_FindClass(module, _class.dataTypeString);
410       return dataType._vTbl[__ecereVMethodID_class_OnCompare](dataType, data1, data2);
411    }
412    else
413    {
414       int result = 0;
415       if(data1 && data2)
416       {
417          if(*(void **)data1 > *(void **)data2)
418             result = 1;
419          else if(*(void **)data1 < *(void **)data2)
420             result = -1;
421       }
422       else if(!data1 && data2)
423          return 1;
424       else if(data1 && !data2)
425          return -1;
426       return result;
427    }
428    return 0;
429 }
430
431 static char * OnGetString(Class _class, void * data, char * tempString, void * fieldData, bool * needClass)
432 {
433    // WHY DOES _class.module NOT SEEM TO WORK?
434    Module module = _class.templateClass ? _class.templateClass.module : _class.module;
435    if(_class.type == enumClass)
436    {
437       return Enum_OnGetString(_class, data, tempString, fieldData, needClass);
438    }
439    else if(_class.type == unitClass)
440    {
441       Class dataType = eSystem_FindClass(module, _class.dataTypeString);
442       return ((char *(*)(void *, void *, char *, void *, bool *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, data, tempString, fieldData, needClass);
443    }
444    else
445    {
446       bool atMember = true;
447       bool prev = false;
448       Class mainClass = _class;
449       _class = null;
450       tempString[0] = '\0';
451       if(!data && (mainClass.type == normalClass || mainClass.type == noHeadClass)) return tempString;
452
453       while(_class != mainClass)
454       {
455          DataMember member;
456          Class lastClass = _class;
457
458          for(_class = mainClass; _class.base != lastClass && _class.base.type != systemClass; _class = _class.base);
459
460          for(member = _class.membersAndProperties.first; member; member = member.next)
461          {
462             char memberString[1024];
463             Class memberType = member.dataTypeClass;
464             char * name = member.name;
465                   
466             memberString[0] = 0;
467
468             if(!memberType)
469                memberType = member.dataTypeClass = eSystem_FindClass(module, member.dataTypeString);
470             if(!memberType)
471                memberType = member.dataTypeClass = eSystem_FindClass(module, "int");
472
473             if(member.isProperty)
474             {
475                Property prop = (Property) member;
476
477                if(!prop.conversion && prop.Get && prop.Set && (!prop.IsSet || prop.IsSet(data)))
478                {
479                   if(memberType.type != structClass && (memberType.type != normalClass || !strcmp(memberType.dataTypeString, "char *")) && memberType.type != bitClass && data)
480                   {
481                      DataValue value = { 0 };
482                      if(!strcmp(prop.dataTypeString, "float"))
483                      {
484                         value.f = ((float(*)())(void *)prop.Get)(data);
485                         if(value.f)
486                         {
487                            bool needClass = true;
488                            char * result = ((char *(*)(void *, void *, char *, void *, bool *))(void *)memberType._vTbl[__ecereVMethodID_class_OnGetString])(memberType, &value, memberString, null, &needClass);
489                            if(result && result != memberString)
490                               strcpy(memberString, result);
491                            // TESTING THIS HERE
492                            if(strchr(memberString, '.'))
493                               strcat(memberString, "f");
494                         }
495                      }
496                      else
497                      {
498                         value.i = prop.Get(data);
499                         if(value.i || prop.IsSet)
500                         {
501                            bool needClass = true;
502                            char * result = ((char *(*)(void *, void *, char *, void *, bool *))(void *)memberType._vTbl[__ecereVMethodID_class_OnGetString])(memberType, 
503                               (memberType.type == normalClass) ? value.p : &value, memberString, null, &needClass);
504                            if(result && result != memberString)
505                               strcpy(memberString, result);
506                         }
507                      }
508                   }
509                }
510             }
511             else
512             {
513                if(member.type == normalMember)
514                {
515                   if(memberType.type == structClass || memberType.type == normalClass)
516                   {
517                      char internalMemberString[1024];
518                      byte * memberData = ((byte *)data + (((member._class.type == normalClass) ? member._class.offset : 0) + member.offset));
519                      int c;
520                      for(c = 0; c < memberType.structSize; c++)
521                         if(memberData[c])
522                            break;
523                      if(c < memberType.structSize)
524                      {
525                         bool needClass = true;
526                         char * result;
527                         if(memberType.type == normalClass)
528                            result = ((char *(*)(void *, void *, char *, void *, bool *))(void *)memberType._vTbl[__ecereVMethodID_class_OnGetString])(memberType, *(Instance *)memberData, internalMemberString, null, &needClass);
529                         else
530                            result = ((char *(*)(void *, void *, char *, void *, bool *))(void *)memberType._vTbl[__ecereVMethodID_class_OnGetString])(memberType, memberData, internalMemberString, null, &needClass);
531                         if(needClass)
532                         {
533                            //strcpy(memberString, memberType.name);
534                            strcat(memberString, "{ ");
535                            if(result) strcat(memberString, result);
536                            strcat(memberString, " }");
537                         }
538                         else if(result)
539                            strcpy(memberString, result);
540                      }
541                   }
542                   //else if(_class /*memberType*/.type != bitClass)
543                   else // if(_class /*memberType*/.type != bitClass)
544                   {
545                      DataValue value = { 0 };
546                      if(_class.type == bitClass)
547                      {
548                         BitMember bitMember = (BitMember) member;
549                         // TODO: Check if base type is 32 or 64 bit
550
551                         //value.ui = (((uint)data & bitMember.mask) >> bitMember.pos);
552                         value.ui64 = ((*(uint*)data & bitMember.mask) >> bitMember.pos);
553                         if(value.ui64)
554                         {
555                            bool needClass = true;
556                            char internalMemberString[1024];
557                            char * result = ((char *(*)(void *, void *, char *, void *, bool *))(void *)memberType._vTbl[__ecereVMethodID_class_OnGetString])(memberType, &value, internalMemberString, null, &needClass);
558
559                            if(needClass && memberType.type != systemClass && memberType.type != enumClass && memberType.type != unitClass)
560                            {
561                               //strcpy(memberString, memberType.name);
562                               strcat(memberString, " { ");
563                               if(result) strcat(memberString, result);
564                               strcat(memberString, " }");
565                            }
566                            else if(result)
567                               strcpy(memberString, result);
568                            /*
569                            if(result && memberString != result)
570                               strcpy(memberString, result);
571                            */
572                         }
573                      }
574                      else if(!memberType.noExpansion)
575                      {
576                         // TOCHECK: Is this still right??
577                         if(memberType.typeSize <= 4)
578                         {
579                            value.i = *(int *)((byte *)data + (((member._class.type == normalClass) ? member._class.offset : 0) + member.offset));
580                            if(value.i)
581                            {
582                               bool needClass = true;
583                               char * result = ((char *(*)(void *, void *, char *, void *, bool *))(void *)memberType._vTbl[__ecereVMethodID_class_OnGetString])(memberType, &value, memberString, null, &needClass);
584                               if(result && memberString != result)
585                                  strcpy(memberString, result);
586                            }
587                         }
588                         else
589                         {
590                            bool needClass = true;
591                            char * result = ((char *(*)(void *, void *, char *, void *, bool *))(void *)memberType._vTbl[__ecereVMethodID_class_OnGetString])(memberType, ((byte *)data + (((member._class.type == normalClass) ? member._class.offset : 0) + member.offset)), memberString, null, &needClass);
592                            if(result && memberString != result)
593                               strcpy(memberString, result);
594                         }
595                      }
596                   }
597                   /*else
598                   {
599                      char internalMemberString[1024];
600                      byte * memberData = ((byte *)data + (((member._class.type == normalClass) ? member._class.offset : 0) + member.offset));
601                      bool needClass = true;
602                      char * result;
603                      result = ((char *(*)(void *, void *, char *, void *, bool *))(void *)memberType._vTbl[__ecereVMethodID_class_OnGetString])(memberType, memberData, internalMemberString, null, &needClass);
604                      if(needClass)
605                      {
606                         //strcpy(memberString, memberType.name);
607                         strcat(memberString, "{ ");
608                         if(result) strcat(memberString, result);
609                         strcat(memberString, " }");
610                      }
611                      else if(result)
612                         strcpy(memberString, result);
613                   }*/
614                }
615                // MemberUnion
616                // MemberStruct
617             }
618             // TODO: Fix atID stuff
619             if(memberString[0])
620             {
621                if(prev)
622                   strcat(tempString, ", ");
623                if(!atMember || !strcmp(memberType.name, "bool"))
624                {
625                   strcat(tempString, name);
626                   strcat(tempString, " = ");
627                }
628
629                if(!strcmp(memberType.name, "char *"))
630                {
631                   int len = strlen(tempString);
632                   int c;
633                   strcat(tempString, "\"");
634                   len ++;
635                   for(c = 0; memberString[c]; c++)
636                   {
637                      if(memberString[c] == '\"')
638                      {
639                         strcat(tempString, "\\\"");
640                         len+=2;
641                      }
642                      else if(memberString[c] == '\\')
643                      {
644                         strcat(tempString, "\\\\");
645                         len+=2;
646                      }
647                      else
648                      {
649                         tempString[len++] = memberString[c];
650                         tempString[len] = 0;
651                      }
652                   }                              
653                   strcat(tempString, "\"");
654                }
655                else
656                   strcat(tempString, memberString);
657                atMember = true;
658
659                prev = true;
660             }
661             else if(member && (!member.isProperty || !((Property)member).conversion))
662                atMember = false;
663          }
664       }
665    }
666    return tempString;
667 }
668
669 static bool OnGetDataFromString(Class _class, void ** data, char * string)
670 {
671    bool result;
672    Module module = _class.module;
673    if(_class.type == enumClass)
674       result = Enum_OnGetDataFromString(_class, (int *)data, string);
675    else if(_class.type == unitClass)
676    {
677       Class dataType = eSystem_FindClass(module, _class.dataTypeString);
678       return dataType._vTbl[__ecereVMethodID_class_OnGetDataFromString](dataType, data, string);
679    }
680    else if(!string[0] && _class.type == normalClass)
681    {
682       // result = false;  // Why was this data = null commented?
683       *data = null;
684       return true;
685    }
686    else
687    {
688       int c;
689       char memberName[1024];
690       char memberString[10240];
691       int count = 0;
692       bool quoted = false;
693       int brackets = 0;
694       char ch;
695       bool escape = false;
696       bool gotChar;
697       uint memberOffset;
698       Class curClass = null;
699       DataMember curMember = null;
700       DataMember subMemberStack[256];
701       int subMemberStackPos = 0;
702
703       result = true;
704
705       if(_class.type == noHeadClass || _class.type == normalClass) 
706       {
707          data = *data = eInstance_New(_class);
708          if(_class.type == normalClass) 
709             ((Instance)data)._refCount++;
710       }
711       else if(/*_class.type == noHeadClass || */_class.type == structClass) 
712          memset(data, 0, _class.structSize);
713       // Bit classes cleared outside?
714
715       memberName[0] = '\0';
716
717       for(c = 0; string[c] && count < sizeof(memberString); )
718       {
719          bool found = false;
720          DataMember thisMember = null;
721
722          brackets = 0;
723          gotChar = false;
724          for(; (ch = string[c]) && count < sizeof(memberString); c++)
725          {
726             if(ch == '\"' && !escape)
727             {
728                quoted ^= true;
729             }
730             else if(quoted)
731             {
732                if(!escape && ch == '\\')
733                {
734                   escape = true;
735                }
736                else
737                {
738                   memberString[count++] = ch;
739                   escape = false;
740                }
741             }
742             // TOFIX: OnGetDataFromString is far from ready as a generic object notation reader...
743             // It has mostly been tested/used for entering data in the IDE's property sheet, as well as for parsing code in the Code Editor
744             // Is it used by the compiler?
745             else if(ch == ' ') // || ch == '\n' || ch == '\t' || ch == '\r')
746             {
747                if(gotChar) 
748                   memberString[count++] = ch;
749             }
750             else if(ch == ',')
751             {
752                if(brackets)
753                {
754                   memberString[count++] = ch;
755                }
756                else
757                {
758                   c++;
759                   break;
760                }
761             }
762             else if(ch == '{')
763             {
764                // If bracket is not initialization
765                if(gotChar && !brackets) 
766                {
767                   count = 0;
768                   gotChar = false;
769                }
770
771                if(brackets)
772                {
773                   memberString[count++] = ch;
774                   gotChar = true;
775                }
776                brackets++;
777             }
778             else if(ch == '}')
779             {
780                brackets--;
781                if(brackets)
782                {
783                   gotChar = true;
784                   memberString[count++] = ch;
785                }
786             }
787             else if(ch == '=')
788             {
789                if(brackets)
790                {
791                   memberString[count++] = ch;
792                }
793                else
794                {
795                   memberString[count] = '\0';
796                   //TrimLSpaces(memberString, memberName);
797                   //TrimRSpaces(memberName, memberString);
798                   //strcpy(memberName, memberString);
799             
800                   TrimRSpaces(memberString, memberName);
801                   count = 0;
802                   gotChar = false;
803                }
804             }
805             else
806             {
807                memberString[count++] = ch;
808                gotChar = true;
809             }
810          }
811
812          memberString[count] = '\0';
813          TrimRSpaces(memberString, memberString);
814
815          if(memberName[0])
816          {
817             DataMember _subMemberStack[256];
818             int _subMemberStackPos = 0;
819
820             thisMember = eClass_FindDataMemberAndOffset(_class, memberName, &memberOffset, _class.module, _subMemberStack, &_subMemberStackPos);
821
822             if(!thisMember)
823                thisMember = (DataMember)eClass_FindProperty(_class, memberName, _class.module);
824             if(thisMember)
825             {
826                if(thisMember.memberAccess == publicAccess)
827                {
828                   curMember = thisMember;
829                   curClass = thisMember._class;
830                   memcpy(subMemberStack, _subMemberStack, sizeof(int) * _subMemberStackPos);
831                   subMemberStackPos = _subMemberStackPos;
832                }
833                found = true;
834             }
835          }
836          else
837          {
838             eClass_FindNextMember(_class, &curClass, (DataMember *)&curMember, subMemberStack, &subMemberStackPos);
839             thisMember = curMember;
840             if(thisMember)
841             {
842                found = true;
843                eClass_FindDataMemberAndOffset(_class, thisMember.name, &memberOffset, _class.module, null, null);
844             }
845          }
846          if(found)
847          {
848             Class memberType = thisMember.dataTypeClass;
849             
850             if(!memberType)
851                memberType = thisMember.dataTypeClass = eSystem_FindClass(module, thisMember.dataTypeString);
852             if(!memberType)
853                memberType = thisMember.dataTypeClass = eSystem_FindClass(module, "int");
854             if(memberType.type == structClass)
855             {
856                if(thisMember)
857                {
858                   if(!memberType._vTbl[__ecereVMethodID_class_OnGetDataFromString](memberType, 
859                      (byte *)data + (((thisMember._class.type == normalClass) ? thisMember._class.offset : 0) + memberOffset), memberString))
860                      result = false;
861                }
862             }
863             else
864             {
865                DataValue value = { 0 };
866                // Patch for hotKey crash ( #556 )
867                // Key has a member KeyCode, which inherits from Key
868                // We don't want KeyCode to use its base class OnGetDataFromString
869                if(memberType._vTbl[__ecereVMethodID_class_OnGetDataFromString] == _class._vTbl[__ecereVMethodID_class_OnGetDataFromString])
870                {
871                   if(!OnGetDataFromString(memberType, &value, memberString))
872                      result = false;
873                }
874                else if(!memberType._vTbl[__ecereVMethodID_class_OnGetDataFromString](memberType, &value, memberString))
875                   result = false;
876                if(thisMember && !thisMember.isProperty)
877                {
878                   if(_class.type == bitClass)
879                   {
880                      BitMember bitMember = (BitMember) thisMember;
881                      // TODO: Check if bit _class is 32 or 64 bit
882                      *(uint *)data = (uint32)(((*(uint *)data & ~bitMember.mask)) | ((value.ui64<<bitMember.pos)&bitMember.mask));
883                   }
884                   else
885                      *(int *)((byte *)data + (((thisMember._class.type == normalClass) ? thisMember._class.offset : 0) + thisMember.offset)) = value.i;
886                }
887                else if(thisMember.isProperty && ((Property)thisMember).Set)
888                   ((Property)thisMember).Set(data, value.i);
889             }
890          }
891          else
892             result = false;
893             
894          count = 0;
895          memberName[0] = '\0';
896       }
897    }
898    return result;
899 }
900
901 static void OnCopy(Class _class, void ** data, void * newData)
902 {
903    // TO IMPROVE: Inherit from Unit class for better performance?
904    if(_class.type == unitClass || _class.type == bitClass || _class.type == enumClass)
905    {
906       Class dataType = eSystem_FindClass(_class.module, _class.dataTypeString);
907       if(dataType)
908          dataType._vTbl[__ecereVMethodID_class_OnCopy](dataType, data, newData);
909    }
910    else if(_class.type != structClass && _class.type != systemClass)
911    {
912       *data = newData;
913    }
914    // Here we have either a structClass or a systemClass
915    else if(newData)
916       memcpy(data, newData, _class.typeSize);
917    else
918       memset(data, 0, _class.typeSize);
919 }
920
921 static int DataMember_OnSerialize(DataMember parentMember, void * data, IOChannel channel)
922 {
923    DataMember member;
924    Module module = parentMember._class.module;
925    for(member = parentMember.members.first; member; member = member.next)
926    {
927       if(member.type == normalMember)
928       {
929          Class memberType = member.dataTypeClass;
930
931          if(!memberType)
932             memberType = member.dataTypeClass = eSystem_FindClass(module, member.dataTypeString);
933          if(!memberType)
934             memberType = member.dataTypeClass = eSystem_FindClass(module, "int");
935
936          if(memberType.type == structClass || memberType.type == normalClass || memberType.type == noHeadClass)
937          {
938             memberType._vTbl[__ecereVMethodID_class_OnSerialize](memberType, (byte *)data + member.offset, channel);
939          }
940          else
941          {
942             DataValue value;
943             value.i = *(int *)((byte *)data + member.offset);
944             memberType._vTbl[__ecereVMethodID_class_OnSerialize](memberType, &value);
945          }
946       }
947       else
948       {
949          DataMember_OnSerialize(member, (byte *)data + member.offset, channel);
950       }
951    }
952    return 0;
953 }
954
955 static void OnSerialize(Class _class, void * data, IOChannel channel)
956 {
957    Module module = _class.module;
958    // TO IMPROVE: Inherit from Unit class for better performance?
959    if(_class.type == unitClass || _class.type == bitClass || _class.type == enumClass)
960    {
961       Class dataType = eSystem_FindClass(module, _class.dataTypeString);
962       if(dataType)
963          dataType._vTbl[__ecereVMethodID_class_OnSerialize](dataType, data, channel);
964    }
965    else if(_class.type == normalClass || _class.type == noHeadClass || _class.type == structClass)
966    {
967       //if(data)
968       {
969          Class lastClass = null;
970          while(lastClass != _class)
971          {
972             DataMember member;
973             for(; _class && (!_class.base || _class.base.type != systemClass) && _class != lastClass; _class = _class.base);
974             lastClass = _class;
975
976             for(member = _class.membersAndProperties.first; member; member = member.next)
977             {
978                if(member.isProperty || member.type == normalMember)
979                {
980                   Class memberType = member.dataTypeClass;
981                         
982                   if(!memberType)
983                      memberType = member.dataTypeClass = eSystem_FindClass(module, member.dataTypeString);
984                   if(memberType)
985                   {
986                      if(member.isProperty)
987                      {
988                         /*Property prop = (Property)member;
989                         if(!prop.conversion && prop.Get && prop.Set)
990                         {
991                            if(memberType.type == structClass || memberType.type == normalClass || memberType.type == noHeadClass)
992                            {
993
994                            }
995                            else
996                            {
997                               DataValue value;
998                               if(!strcmp(memberType.dataTypeString, "float"))
999                               {
1000                                  value.f = ((float(*)())(void *)prop.Get)(data);
1001                               }
1002                               else
1003                               {
1004                                  value.i = prop.Get(data);
1005                               }
1006                               memberType._vTbl[__ecereVMethodID_class_OnSerialize](memberType, &value, channel);
1007                            }
1008                         }*/
1009                      }
1010                      else
1011                      {
1012                         if(!strcmp(memberType.name, "String") || memberType.type == normalClass || memberType.type == noHeadClass)
1013                         {
1014                            memberType._vTbl[__ecereVMethodID_class_OnSerialize](memberType, data ? (*(void **)((byte *)data + member._class.offset + member.offset)) : null, channel);
1015                         }
1016                         else
1017                            memberType._vTbl[__ecereVMethodID_class_OnSerialize](memberType, data ? (((byte *)data + (((member._class.type == normalClass) ? member._class.offset : 0) + member.offset))) : null, channel);
1018                      }
1019                   }
1020                   else
1021                   {
1022                      // printf("Unknown type\n");
1023                   }
1024                }
1025                else
1026                {
1027                   DataMember_OnSerialize(member, data ? ((byte *)data + (((member._class.type == normalClass) ? member._class.offset : 0) + member.offset)) : null, channel);
1028                }
1029             }
1030          }
1031       }
1032    }
1033 }
1034
1035 static int DataMember_OnUnserialize(DataMember parentMember, void * data, IOChannel channel)
1036 {
1037    DataMember member;
1038    Module module = parentMember._class.module;
1039    for(member = parentMember.members.first; member; member = member.next)
1040    {
1041       if(member.type == normalMember)
1042       {
1043          Class memberType = member.dataTypeClass;
1044
1045          if(!memberType)
1046             memberType = member.dataTypeClass = eSystem_FindClass(module, member.dataTypeString);
1047          if(!memberType)
1048             memberType = member.dataTypeClass = eSystem_FindClass(module, "int");
1049
1050          if(memberType.type == structClass || memberType.type == normalClass || memberType.type == noHeadClass)
1051          {
1052             memberType._vTbl[__ecereVMethodID_class_OnUnserialize](memberType, (byte *)data + member.offset, channel);
1053          }
1054          else
1055          {
1056             DataValue value;
1057             memberType._vTbl[__ecereVMethodID_class_OnUnserialize](memberType, &value, channel);  // channel was missing here?
1058             *(int *)((byte *)data + member.offset) = value.i;
1059          }
1060       }
1061       else
1062       {
1063          DataMember_OnUnserialize(member, (byte *)data + member.offset, channel);
1064       }
1065    }
1066    return 0;
1067 }
1068  
1069 static void OnUnserialize(Class _class, void ** data, IOChannel channel)
1070 {
1071    Module module = _class.module;
1072    if(_class.type == unitClass || _class.type == bitClass || _class.type == enumClass)
1073    {
1074       Class dataType = eSystem_FindClass(module, _class.dataTypeString);
1075       if(dataType)
1076          dataType._vTbl[__ecereVMethodID_class_OnUnserialize](dataType, data, channel);
1077    }
1078    else if(_class.type == normalClass || _class.type == noHeadClass || _class.type == structClass)
1079    {
1080       if(data)
1081       {
1082          Class lastClass = null;
1083          if(_class.type == normalClass || _class.type == noHeadClass)
1084          {
1085             // TOFIX: Seriously!?!?? Fix me!
1086             data = *data = eInstance_New(_class);
1087             if(_class.type == normalClass) 
1088                ((Instance)data)._refCount++;
1089          }
1090          else if(/*_class.type == noHeadClass || */_class.type == structClass) 
1091             memset(data, 0, _class.structSize);
1092
1093          while(lastClass != _class)
1094          {
1095             DataMember member;
1096             for(; _class && (!_class.base || _class.base.type != systemClass) && _class != lastClass; _class = _class.base);
1097             lastClass = _class;
1098
1099             for(member = _class.membersAndProperties.first; member; member = member.next)
1100             {
1101                if(member.isProperty || member.type == normalMember)
1102                {
1103                   Class memberType = member.dataTypeClass;
1104                         
1105                   if(!memberType)
1106                      memberType = member.dataTypeClass = eSystem_FindClass(module, member.dataTypeString);
1107                   if(memberType)
1108                   {
1109                      if(member.isProperty)
1110                      {
1111                         /*Property prop = (Property)member;
1112                         if(!prop.conversion && prop.Get && prop.Set)
1113                         {
1114                            if(memberType.type == structClass || memberType.type == normalClass || memberType.type == noHeadClass)
1115                            {
1116
1117                            }
1118                            else
1119                            {
1120                               DataValue value;
1121                               memberType._vTbl[__ecereVMethodID_class_OnUnserialize](memberType, &value, channel);
1122                               prop.Set(data, value.i);
1123                            }
1124                         }*/
1125                      }
1126                      else
1127                         memberType._vTbl[__ecereVMethodID_class_OnUnserialize](memberType, 
1128                            (byte *)data + (((member._class.type == normalClass) ? member._class.offset : 0) + member.offset), channel);
1129                   }
1130                   else
1131                   {
1132                      // printf("Unknown type\n");
1133                   }
1134                }
1135                else
1136                {
1137                   DataMember_OnUnserialize(member, (byte *)data + (((member._class.type == normalClass) ? member._class.offset : 0) + member.offset), channel);
1138                }
1139             }
1140          }
1141       }
1142    }
1143 }
1144
1145 // Integer
1146 static int Integer_OnCompare(Class _class, int * data1, int * data2)
1147 {
1148    int result = 0;
1149    if(!data1 && !data2) result = 0;
1150    else if(data1 && !data2) result = 1;
1151    else if(!data1 && data2) result = -1;
1152    else if(*data1 > *data2) result = 1;
1153    else if(*data1 < *data2) result = -1;
1154    return result;
1155 }
1156
1157 /*static */char * Integer_OnGetString(Class _class, int * data, char * string, void * fieldData, bool * needClass)
1158 {
1159    sprintf(string, "%d", *data);
1160    return string;
1161 }
1162
1163 static bool Integer_OnGetDataFromString(Class _class, int * data, char * string)
1164 {
1165    char * end;
1166    int result = strtol(string, &end, 0);
1167
1168    if(end > string)
1169    {
1170       *data = result;
1171       return true;
1172    }
1173    return false;
1174 }
1175
1176 static int UInteger_OnCompare(Class _class, unsigned int * data1, unsigned int * data2)
1177 {
1178    int result = 0;
1179    if(!data1 && !data2) result = 0;
1180    else if(data1 && !data2) result = 1;
1181    else if(!data1 && data2) result = -1;
1182    else if(*data1 > *data2) result = 1;
1183    else if(*data1 < *data2) result = -1;
1184    return result;
1185 }
1186
1187 static char * UInteger_OnGetString(Class _class, unsigned int * data, char * string, void * fieldData, bool * needClass)
1188 {
1189    sprintf(string, "%u", *data);
1190    return string;
1191 }
1192
1193 static bool UInteger_OnGetDataFromString(Class _class, unsigned int * data, char * string)
1194 {
1195    char * end;
1196    uint result = strtoul(string, &end, 0);
1197    if(end > string)
1198    {
1199       *data = result;
1200       return true;
1201    }
1202    return false;
1203 }
1204
1205 static int Byte_OnCompare(Class _class, byte * data1, byte * data2)
1206 {
1207    int result = 0;
1208    if(!data1 && !data2) result = 0;
1209    else if(data1 && !data2) result = 1;
1210    else if(!data1 && data2) result = -1;
1211    else if(*data1 > *data2) result = 1;
1212    else if(*data1 < *data2) result = -1;
1213    return result;
1214 }
1215
1216 static char * Byte_OnGetString(Class _class, byte * data, char * string, void * fieldData, bool * needClass)
1217 {
1218    sprintf(string, "%u", (int)*data);
1219    return string;
1220 }
1221
1222 static char * Char_OnGetString(Class _class, char * data, char * string, void * fieldData, bool * needClass)
1223 {
1224    if(needClass && *needClass)
1225    {
1226       char ch = *data;
1227       if(ch == '\t')      strcpy(string, "'\t'");
1228       else if(ch == '\n') strcpy(string, "'\n'");
1229       else if(ch == '\r') strcpy(string, "'\r'");
1230       else if(ch == '\a') strcpy(string, "'\a'");
1231       else if(ch == '\\') strcpy(string, "'\\'");
1232       else if(ch < 32 || ch >= 127)    sprintf(string, "'\o'", ch);
1233       else sprintf(string, "'%c'", ch);
1234    }
1235    else
1236       sprintf(string, "%c", *data);
1237    return string;
1238 }
1239
1240 static bool Byte_OnGetDataFromString(Class _class, byte * data, char * string)
1241 {
1242    char * end;
1243    byte result = (byte)strtoul(string, &end, 0);
1244    if(end > string)
1245    {
1246       *data = result;
1247       return true;
1248    }
1249    return false;
1250 }
1251
1252 static int Int64_OnCompare(Class _class, int64 * data1, int64 * data2)
1253 {
1254    int result = 0;
1255    if(!data1 && !data2) result = 0;
1256    else if(data1 && !data2) result = 1;
1257    else if(!data1 && data2) result = -1;
1258    else if(*data1 > *data2) result = 1;
1259    else if(*data1 < *data2) result = -1;
1260    return result;
1261 }
1262
1263 static int UInt64_OnCompare(Class _class, uint64 * data1, uint64 * data2)
1264 {
1265    int result = 0;
1266    if(!data1 && !data2) result = 0;
1267    else if(data1 && !data2) result = 1;
1268    else if(!data1 && data2) result = -1;
1269    else if(*data1 > *data2) result = 1;
1270    else if(*data1 < *data2) result = -1;
1271    return result;
1272 }
1273
1274 static char * Int64_OnGetString(Class _class, int64 * data, char * string, void * fieldData, bool * needClass)
1275 {
1276    sprintf(string, FORMAT64D, *data);
1277    return string;
1278 }
1279
1280 static char * UInt64_OnGetString(Class _class, uint64 * data, char * string, void * fieldData, bool * needClass)
1281 {
1282    sprintf(string, FORMAT64U, *data);
1283    return string;
1284 }
1285
1286 /*static */void Byte_OnSerialize(Class _class, byte * data, IOChannel channel)
1287 {
1288    channel.WriteData(data, 1);
1289 }
1290
1291 /*static */void Byte_OnUnserialize(Class _class, byte * data, IOChannel channel)
1292 {
1293    if(channel.ReadData(data, 1) != 1)
1294       *data = 0;
1295 }
1296
1297
1298 /*static */void Int_OnSerialize(Class _class, int * data, IOChannel channel)
1299 {
1300    byte bytes[4];
1301    PUTXDWORD(bytes, * data);
1302    channel.WriteData(bytes, 4);
1303 }
1304
1305 /*static */void Int_OnUnserialize(Class _class, int * data, IOChannel channel)
1306 {
1307    byte bytes[4];
1308    if(channel.ReadData(bytes, 4) == 4)
1309       *data = GETXDWORD(bytes);   
1310    else
1311       *data = 0;
1312 }
1313
1314 /*static */void Int64_OnSerialize(Class _class, int64 * data, IOChannel channel)
1315 {
1316    byte bytes[8];
1317    PUTXQWORD(bytes, * data);
1318    channel.WriteData(bytes, 8);
1319 }
1320
1321 /*static */void Int64_OnUnserialize(Class _class, int64 * data, IOChannel channel)
1322 {
1323    byte bytes[8];
1324    if(channel.ReadData(bytes, 8) == 8)
1325       *data = GETXQWORD(bytes);   
1326    else
1327       *data = 0;
1328 }
1329
1330 /*static */void Word_OnSerialize(Class _class, uint16 * data, IOChannel channel)
1331 {
1332    byte bytes[2];
1333    PUTXWORD(bytes, * data);
1334    channel.WriteData(bytes, 2);
1335 }
1336
1337 /*static */void Word_OnUnserialize(Class _class, uint16 * data, IOChannel channel)
1338 {
1339    byte bytes[2];
1340    if(channel.ReadData(bytes, 2) == 2)
1341       *data = GETXWORD(bytes);   
1342    else
1343       *data = 0;
1344 }
1345
1346 static void RegisterClass_Integer(Module module)
1347 {
1348    Class integerClass = eSystem_RegisterClass(normalClass, "int", null, 0, 0, null, null, module, baseSystemAccess, publicAccess);
1349    integerClass.type = systemClass;
1350    delete integerClass.dataTypeString;
1351    integerClass.dataTypeString = CopyString("int");
1352    integerClass.structSize = 0;
1353    integerClass.typeSize = sizeof(int);
1354    
1355    eClass_AddMethod(integerClass, "OnCompare", null, Integer_OnCompare, publicAccess);
1356    eClass_AddMethod(integerClass, "OnGetString", null, Integer_OnGetString, publicAccess);
1357    eClass_AddMethod(integerClass, "OnGetDataFromString", null, Integer_OnGetDataFromString, publicAccess);
1358    eClass_AddMethod(integerClass, "OnSerialize", null, Int_OnSerialize, publicAccess);
1359    eClass_AddMethod(integerClass, "OnUnserialize", null, Int_OnUnserialize, publicAccess);
1360
1361    integerClass = eSystem_RegisterClass(normalClass, "int64", null, 0, 0, null, null, module, baseSystemAccess, publicAccess);
1362    integerClass.type = systemClass;
1363    integerClass.structSize = 0;
1364    integerClass.typeSize = sizeof(int64);
1365    delete integerClass.dataTypeString;
1366    integerClass.dataTypeString = CopyString("int64");
1367    eClass_AddMethod(integerClass, "OnGetString", null, Int64_OnGetString, publicAccess);
1368    eClass_AddMethod(integerClass, "OnCompare", null, Int64_OnCompare, publicAccess);
1369    // eClass_AddMethod(integerClass, "OnGetDataFromString", null, Integer64_OnGetDataFromString, publicAccess);
1370    eClass_AddMethod(integerClass, "OnSerialize", null, Int64_OnSerialize, publicAccess);
1371    eClass_AddMethod(integerClass, "OnUnserialize", null, Int64_OnUnserialize, publicAccess);
1372
1373    integerClass = eSystem_RegisterClass(normalClass, "uint", null, 0, 0, null, null, module, baseSystemAccess, publicAccess);
1374    integerClass.type = systemClass;
1375    delete integerClass.dataTypeString;
1376    integerClass.dataTypeString = CopyString("unsigned int");
1377    integerClass.structSize = 0;
1378    integerClass.typeSize = sizeof(uint);
1379    eClass_AddMethod(integerClass, "OnCompare", null, UInteger_OnCompare, publicAccess);
1380    eClass_AddMethod(integerClass, "OnGetString", null, UInteger_OnGetString, publicAccess);
1381    eClass_AddMethod(integerClass, "OnGetDataFromString", null, UInteger_OnGetDataFromString, publicAccess);
1382    eClass_AddMethod(integerClass, "OnSerialize", null, Int_OnSerialize, publicAccess);
1383    eClass_AddMethod(integerClass, "OnUnserialize", null, Int_OnUnserialize, publicAccess);
1384
1385    integerClass = eSystem_RegisterClass(normalClass, "unsigned int", null, 0, 0, null, null, module, baseSystemAccess, publicAccess);
1386    integerClass.type = systemClass;
1387    delete integerClass.dataTypeString;
1388    integerClass.dataTypeString = CopyString("unsigned int");
1389    integerClass.structSize = 0;
1390    integerClass.typeSize = sizeof(uint);
1391
1392    eClass_AddMethod(integerClass, "OnCompare", null, UInteger_OnCompare, publicAccess);
1393    eClass_AddMethod(integerClass, "OnGetString", null, UInteger_OnGetString, publicAccess);
1394    eClass_AddMethod(integerClass, "OnGetDataFromString", null, UInteger_OnGetDataFromString, publicAccess);
1395    eClass_AddMethod(integerClass, "OnSerialize", null, Int_OnSerialize, publicAccess);
1396    eClass_AddMethod(integerClass, "OnUnserialize", null, Int_OnUnserialize, publicAccess);
1397
1398    integerClass = eSystem_RegisterClass(normalClass, "uint16", null, 0, 0, null, null, module, baseSystemAccess, publicAccess);
1399    integerClass.type = systemClass;
1400    delete integerClass.dataTypeString;
1401    integerClass.dataTypeString = CopyString("unsigned short");
1402    integerClass.structSize = 0;
1403    integerClass.typeSize = sizeof(uint16);
1404
1405    eClass_AddMethod(integerClass, "OnSerialize", null, Word_OnSerialize, publicAccess);
1406    eClass_AddMethod(integerClass, "OnUnserialize", null, Word_OnUnserialize, publicAccess);
1407
1408    integerClass = eSystem_RegisterClass(normalClass, "short", null, 0, 0, null, null, module, baseSystemAccess, publicAccess);
1409    integerClass.type = systemClass;
1410    delete integerClass.dataTypeString;
1411    integerClass.dataTypeString = CopyString("short");
1412    integerClass.structSize = 0;
1413    integerClass.typeSize = sizeof(short);
1414
1415    eClass_AddMethod(integerClass, "OnSerialize", null, Word_OnSerialize, publicAccess);
1416    eClass_AddMethod(integerClass, "OnUnserialize", null, Word_OnUnserialize, publicAccess);
1417
1418    /*
1419    integerClass = eSystem_RegisterClass(normalClass, "uint32", null, 0, 0, null, null, module, baseSystemAccess);
1420    integerClass.type = systemClass;
1421    delete integerClass.dataTypeString;
1422    integerClass.dataTypeString = CopyString("uint32");
1423    eClass_AddMethod(integerClass, "OnCompare", null, UInteger_OnCompare, publicAccess);
1424    eClass_AddMethod(integerClass, "OnGetString", null, UInteger_OnGetString, publicAccess);
1425    eClass_AddMethod(integerClass, "OnGetDataFromString", null, UInteger_OnGetDataFromString, publicAccess);
1426    */
1427    integerClass = eSystem_RegisterClass(normalClass, "uint32", "uint", 0, 0, null, null, module, baseSystemAccess, publicAccess);
1428    integerClass.type = systemClass;
1429    delete integerClass.dataTypeString;
1430    integerClass.dataTypeString = CopyString("unsigned int");
1431    integerClass.structSize = 0;
1432    integerClass.typeSize = sizeof(uint32);
1433
1434    integerClass = eSystem_RegisterClass(normalClass, "uint64", null, 0, 0, null, null, module, baseSystemAccess, publicAccess);
1435    integerClass.type = systemClass;
1436    delete integerClass.dataTypeString;
1437    integerClass.dataTypeString = CopyString("uint64");
1438    integerClass.structSize = 0;
1439    integerClass.typeSize = sizeof(uint64);
1440    eClass_AddMethod(integerClass, "OnGetString", null, UInt64_OnGetString, publicAccess);
1441    eClass_AddMethod(integerClass, "OnSerialize", null, Int64_OnSerialize, publicAccess);
1442    eClass_AddMethod(integerClass, "OnUnserialize", null, Int64_OnUnserialize, publicAccess);
1443    eClass_AddMethod(integerClass, "OnCompare", null, Int64_OnCompare, publicAccess);
1444
1445    integerClass = eSystem_RegisterClass(normalClass, "byte", null, 0, 0, null, null, module, baseSystemAccess, publicAccess);
1446    integerClass.type = systemClass;
1447    delete integerClass.dataTypeString;
1448    integerClass.dataTypeString = CopyString("unsigned char");
1449    integerClass.structSize = 0;
1450    integerClass.typeSize = sizeof(byte);
1451    eClass_AddMethod(integerClass, "OnCompare", null, Byte_OnCompare, publicAccess);
1452    eClass_AddMethod(integerClass, "OnGetString", null, Byte_OnGetString, publicAccess);
1453    eClass_AddMethod(integerClass, "OnGetDataFromString", null, Byte_OnGetDataFromString, publicAccess);
1454    eClass_AddMethod(integerClass, "OnSerialize", null, Byte_OnSerialize, publicAccess);
1455    eClass_AddMethod(integerClass, "OnUnserialize", null, Byte_OnUnserialize, publicAccess);
1456
1457    integerClass = eSystem_RegisterClass(normalClass, "char", null, 0, 0, null, null, module, baseSystemAccess, publicAccess);
1458    integerClass.type = systemClass;
1459    delete integerClass.dataTypeString;
1460    integerClass.dataTypeString = CopyString("char");
1461    integerClass.structSize = 0;
1462    integerClass.typeSize = sizeof(char);
1463    eClass_AddMethod(integerClass, "OnCompare", null, Byte_OnCompare, publicAccess);
1464    eClass_AddMethod(integerClass, "OnGetString", null, Char_OnGetString, publicAccess);
1465    eClass_AddMethod(integerClass, "OnGetDataFromString", null, Byte_OnGetDataFromString, publicAccess);
1466    eClass_AddMethod(integerClass, "OnSerialize", null, Byte_OnSerialize, publicAccess);
1467    eClass_AddMethod(integerClass, "OnUnserialize", null, Byte_OnUnserialize, publicAccess);
1468
1469    integerClass = eSystem_RegisterClass(normalClass, "uintptr", null, 0, 0, null, null, module, baseSystemAccess, publicAccess);
1470    integerClass.type = systemClass;
1471    delete integerClass.dataTypeString;
1472    integerClass.dataTypeString = CopyString("uintptr_t");
1473    integerClass.structSize = 0;
1474    integerClass.typeSize = sizeof(uintptr);
1475    if(sizeof(uintptr) == 8)
1476    {
1477       eClass_AddMethod(integerClass, "OnGetString", null, UInt64_OnGetString, publicAccess);
1478       eClass_AddMethod(integerClass, "OnSerialize", null, Int64_OnSerialize, publicAccess);
1479       eClass_AddMethod(integerClass, "OnUnserialize", null, Int64_OnUnserialize, publicAccess);
1480       eClass_AddMethod(integerClass, "OnCompare", null, UInt64_OnCompare, publicAccess);
1481    }
1482    else
1483    {
1484       eClass_AddMethod(integerClass, "OnCompare", null, UInteger_OnCompare, publicAccess);
1485       eClass_AddMethod(integerClass, "OnGetString", null, UInteger_OnGetString, publicAccess);
1486       eClass_AddMethod(integerClass, "OnGetDataFromString", null, UInteger_OnGetDataFromString, publicAccess);
1487       eClass_AddMethod(integerClass, "OnSerialize", null, Int_OnSerialize, publicAccess);
1488       eClass_AddMethod(integerClass, "OnUnserialize", null, Int_OnUnserialize, publicAccess);
1489    }
1490
1491    integerClass = eSystem_RegisterClass(normalClass, "intptr", null, 0, 0, null, null, module, baseSystemAccess, publicAccess);
1492    integerClass.type = systemClass;
1493    delete integerClass.dataTypeString;
1494    integerClass.dataTypeString = CopyString("intptr_t");
1495    integerClass.structSize = 0;
1496    integerClass.typeSize = sizeof(intptr);
1497    if(sizeof(intptr) == 8)
1498    {
1499       eClass_AddMethod(integerClass, "OnGetString", null, Int64_OnGetString, publicAccess);
1500       eClass_AddMethod(integerClass, "OnSerialize", null, Int64_OnSerialize, publicAccess);
1501       eClass_AddMethod(integerClass, "OnUnserialize", null, Int64_OnUnserialize, publicAccess);
1502       eClass_AddMethod(integerClass, "OnCompare", null, Int64_OnCompare, publicAccess);
1503    }
1504    else
1505    {
1506       eClass_AddMethod(integerClass, "OnCompare", null, Integer_OnCompare, publicAccess);
1507       eClass_AddMethod(integerClass, "OnGetString", null, Integer_OnGetString, publicAccess);
1508       eClass_AddMethod(integerClass, "OnGetDataFromString", null, Integer_OnGetDataFromString, publicAccess);
1509       eClass_AddMethod(integerClass, "OnSerialize", null, Int_OnSerialize, publicAccess);
1510       eClass_AddMethod(integerClass, "OnUnserialize", null, Int_OnUnserialize, publicAccess);
1511    }
1512 }
1513
1514 // Float
1515 static int Float_OnCompare(Class _class, float * data1, float * data2)
1516 {
1517    int result = 0;
1518    if(!data1 && !data2) result = 0;
1519    else if(data1 && !data2) result = 1;
1520    else if(!data1 && data2) result = -1;
1521    else if(*data1 > *data2) result = 1;
1522    else if(*data1 < *data2) result = -1;
1523    return result;
1524 }
1525
1526 static char * Float_OnGetString(Class _class, float * data, char * string, void * fieldData, bool * needClass)
1527 {
1528    int c;
1529    int last = 0;
1530    int numDigits = 7, num = 1;
1531    char format[10];
1532    while(numDigits && num < *data) numDigits--, num *= 10;
1533    sprintf(format, "%%.%df", numDigits);
1534
1535    //sprintf(string, "%f", *data);
1536    sprintf(string, format, *data);
1537
1538    c = strlen(string)-1;
1539    for( ; c >= 0; c--)
1540    {
1541       if(string[c] != '0') 
1542          last = Max(last, c);
1543       if(string[c] == '.')
1544       {
1545          if(last == c)
1546             string[c] = 0;
1547          else
1548             string[last+1] = 0;
1549          break;
1550       }
1551    }
1552    return string;
1553 }
1554
1555 static bool Float_OnGetDataFromString(Class _class, float * data, char * string)
1556 {
1557    char * end;
1558    float result = (float)strtod(string, &end);
1559    //*data = atof(string);
1560    if(end > string)
1561    {
1562       *data = result;
1563       return true;
1564    }
1565    return false;
1566 }
1567
1568 static void Float_OnSerialize(Class _class, float * data, IOChannel channel)
1569 {
1570    byte bytes[4];
1571    PUTXDWORD(bytes, * (uint *)data);
1572    channel.WriteData(bytes, 4);
1573 }
1574
1575 static void Float_OnUnserialize(Class _class, float * data, IOChannel channel)
1576 {
1577    byte bytes[4];
1578    if(channel.ReadData(bytes, 4) == 4)
1579       *(uint *)data = GETXDWORD(bytes);   
1580    else
1581       *data = 0;
1582 }
1583
1584 static void RegisterClass_Float(Module module)
1585 {
1586    Class floatClass = eSystem_RegisterClass(normalClass, "float", null, 0, 0, null, null, module, baseSystemAccess, publicAccess);
1587    floatClass.type = systemClass;
1588    delete floatClass.dataTypeString;
1589    floatClass.dataTypeString = CopyString("float");
1590    floatClass.structSize = 0;
1591    floatClass.typeSize = sizeof(float);
1592    eClass_AddMethod(floatClass, "OnCompare", null, Float_OnCompare, publicAccess);
1593    eClass_AddMethod(floatClass, "OnGetString", null, Float_OnGetString, publicAccess);
1594    eClass_AddMethod(floatClass, "OnGetDataFromString", null, Float_OnGetDataFromString, publicAccess);
1595    eClass_AddMethod(floatClass, "OnSerialize", null, Float_OnSerialize, publicAccess);
1596    eClass_AddMethod(floatClass, "OnUnserialize", null, Float_OnUnserialize, publicAccess);
1597 }
1598
1599 // Double
1600 static int Double_OnCompare(Class _class, double * data1, double * data2)
1601 {
1602    int result = 0;
1603    if(!data1 && !data2) result = 0;
1604    else if(data1 && !data2) result = 1;
1605    else if(!data1 && data2) result = -1;
1606    else if(*data1 > *data2) result = 1;
1607    else if(*data1 < *data2) result = -1;
1608    return result;
1609 }
1610
1611 static char * Double_OnGetString(Class _class, double * data, char * string, void * fieldData, bool * needClass)
1612 {
1613    int c;
1614    int last = 0;
1615    //sprintf(string, "%.20f", *data);
1616    if(runtimePlatform == win32)
1617    // sprintf(string, "%.16g", *data);
1618       sprintf(string, "%.15g", *data);
1619    else
1620       sprintf(string, "%.13lf", *data);
1621
1622    c = strlen(string)-1;
1623    for( ; c >= 0; c--)
1624    {
1625       if(string[c] != '0') 
1626          last = Max(last, c);
1627       if(string[c] == '.')
1628       {
1629          if(last == c)
1630             string[c] = 0;
1631          else
1632             string[last+1] = 0;
1633          break;
1634       }
1635    }
1636    return string;
1637 }
1638
1639 static bool Double_OnGetDataFromString(Class _class, double * data, char * string)
1640 {
1641    char * end;
1642    double result;
1643    //*data = (double)strtod(string, null);
1644    result = strtod(string, &end);
1645    if(end > string)
1646    {
1647       *data = result;
1648       return true;
1649    
1650     }
1651     return false;
1652 }
1653
1654 static void Double_OnSerialize(Class _class, double * data, IOChannel channel)
1655 {
1656    byte bytes[8];
1657    PUTXQWORD(bytes, * (uint64 *)data);
1658    channel.WriteData(bytes, 8);
1659 }
1660
1661 static void Double_OnUnserialize(Class _class, double * data, IOChannel channel)
1662 {
1663    byte bytes[8];
1664    if(channel.ReadData(bytes, 8) == 8)
1665       *(uint64 *)data = GETXQWORD(bytes);
1666    else
1667       *data = 0;
1668 }
1669
1670 static void RegisterClass_Double(Module module)
1671 {
1672    Class doubleClass = eSystem_RegisterClass(normalClass, "double", null, 0, 0, null, null, module, baseSystemAccess, publicAccess);
1673    doubleClass.type = systemClass;
1674    delete doubleClass.dataTypeString;
1675    doubleClass.dataTypeString = CopyString("double");
1676    doubleClass.structSize = 0;
1677    doubleClass.typeSize = sizeof(double);
1678    eClass_AddMethod(doubleClass, "OnCompare", null, Double_OnCompare, publicAccess);
1679    eClass_AddMethod(doubleClass, "OnGetString", null, Double_OnGetString, publicAccess);
1680    eClass_AddMethod(doubleClass, "OnGetDataFromString", null, Double_OnGetDataFromString, publicAccess);
1681    eClass_AddMethod(doubleClass, "OnSerialize", null, Double_OnSerialize, publicAccess);
1682    eClass_AddMethod(doubleClass, "OnUnserialize", null, Double_OnUnserialize, publicAccess);
1683 }
1684
1685 public struct StaticString
1686 {
1687    char string[1];
1688
1689    void OnSerialize(IOChannel channel)
1690    {
1691       int len = this ? strlen(string) : 0;
1692       channel.WriteData(this ? string : "", len+1);
1693    }
1694
1695    void OnUnserialize(IOChannel channel)
1696    {
1697       if(this)
1698       {
1699          int c;
1700          uint size;
1701
1702          for(c = 0; channel.ReadData(&string[c], 1) && string[c]; c++);
1703          string[c++] = '\0';
1704       }
1705    }
1706
1707    int OnCompare(StaticString string2)
1708    {
1709       int result = 0;
1710       if(this && string2)
1711          result = strcmpi(string, string2.string);
1712       else if(!this && string2)
1713          result = -1;   // INVERTED THESE 2 CASES
1714       else if(this && !string2)
1715          result = 1;
1716       return result;
1717    }
1718
1719    char * OnGetString(char * tempString, void * fieldData, bool * needClass)
1720    {
1721       return (char *)(this ? string : null); // Cast for memguard
1722    }
1723
1724    void OnFree()
1725    {
1726    }
1727 };
1728
1729 static void String_OnCopy(Class _class, char ** data, char * newData)
1730 {
1731    if(newData)
1732    {
1733       int len = strlen(newData);
1734       if(len)
1735       {
1736          *data = eSystem_New(len+1);
1737          memcpy(*data, newData, len+1);
1738       }
1739       else
1740          *data = null;
1741    }
1742    else
1743       *data = null;
1744 }
1745
1746 static bool String_OnGetDataFromString(Class _class, char ** data, char * newData)
1747 {
1748    if(newData)
1749    {
1750       int len = strlen(newData);
1751       if(len)
1752       {
1753          *data = eSystem_New(len+1);
1754          memcpy(*data, newData, len+1);
1755       }
1756       else
1757          *data = null;
1758    }
1759    return true;
1760 }
1761  
1762 /*static */int String_OnCompare(Class _class, char * string1, char * string2)
1763 {
1764    int result = 0;
1765    if(string1 && string2)
1766       result = strcmpi(string1, string2);
1767    else if(!string1 && string2)
1768       result = 1;
1769    else if(string1 && !string2)
1770       result = -1;
1771    return result;
1772 }
1773
1774 static char * String_OnGetString(Class _class, char * string, char * tempString, void * fieldData, bool * needClass)
1775 {
1776    return string;
1777 }
1778
1779 static void String_OnFree(Class _class, char * string)
1780 {
1781    if(string) 
1782    {
1783       eSystem_Delete(string);
1784    }
1785 }
1786
1787 static void String_OnSerialize(Class _class, char * string, IOChannel channel)
1788 {
1789    int len = string ? strlen(string) : 0;
1790    channel.WriteData(string ? string : "", len+1);
1791 }
1792
1793 static void String_OnUnserialize(Class _class, char * * string, IOChannel channel)
1794 {
1795    if(string)
1796    {
1797       int c;
1798       uint size = 64;
1799
1800       *string = new char[size];
1801       for(c = 0; channel.ReadData(&(*string)[c], 1) && (*string)[c]; c++)
1802       {
1803          if(c == size - 1)
1804          {
1805             size += size / 2;
1806             *string = renew *string char[size];
1807          }
1808       }
1809       (*string)[c++] = '\0';
1810       if(!UTF8Validate(*string))
1811       {
1812          char * newString = new char[c*2];
1813          ISO8859_1toUTF8(*string, newString, c*2);
1814          delete *string;
1815          *string = renew newString char[strlen(newString)+1];
1816       }
1817       else
1818          *string = renew *string char[c];
1819    }
1820 }
1821
1822 static void RegisterClass_String(Module module)
1823 {
1824    Class stringClass = eSystem_RegisterClass(normalClass, "char *", null, 0, 0, null, null, module, baseSystemAccess, publicAccess);
1825    delete stringClass.dataTypeString;
1826    stringClass.dataTypeString = CopyString("char *");
1827    stringClass.structSize = 0;
1828    
1829    eClass_AddMethod(stringClass, "OnCompare", null, String_OnCompare, publicAccess);
1830    eClass_AddMethod(stringClass, "OnCopy", null, String_OnCopy, publicAccess);
1831    eClass_AddMethod(stringClass, "OnFree", null, String_OnFree, publicAccess);
1832    eClass_AddMethod(stringClass, "OnGetString", null, String_OnGetString, publicAccess);
1833    eClass_AddMethod(stringClass, "OnGetDataFromString", null, String_OnGetDataFromString, publicAccess);
1834    eClass_AddMethod(stringClass, "OnSerialize", null, String_OnSerialize, publicAccess);
1835    eClass_AddMethod(stringClass, "OnUnserialize", null, String_OnUnserialize, publicAccess); 
1836    // eClass_AddProperty(stringClass, null, "Class", null, String_GetClass, publicAccess);
1837
1838    stringClass = eSystem_RegisterClass(normalClass, "String", "char *", 0, 0, null, null, module, baseSystemAccess, publicAccess);
1839    stringClass.structSize = 0;
1840    eClass_AddProperty(stringClass, null, "char *", null, null, publicAccess);
1841 }
1842
1843 void InitializeDataTypes1(Module module)
1844 {
1845    Class baseClass = eSystem_FindClass(module, "class");
1846
1847    eClass_AddVirtualMethod(baseClass, "OnDisplay", "void typed_object::OnDisplay(Surface surface, int x, int y, int width, void * fieldData, Alignment alignment, DataDisplayFlags displayFlags)", null, publicAccess);
1848    eClass_AddVirtualMethod(baseClass, "OnCompare", "int typed_object::OnCompare(any_object object)", OnCompare, publicAccess);
1849    eClass_AddVirtualMethod(baseClass, "OnCopy", "void typed_object&::OnCopy(any_object newData)", OnCopy, publicAccess);
1850    eClass_AddVirtualMethod(baseClass, "OnFree", "void typed_object::OnFree(void)", OnFree, publicAccess);
1851    eClass_AddVirtualMethod(baseClass, "OnGetString", "char * typed_object::OnGetString(char * tempString, void * fieldData, bool * needClass)", OnGetString, publicAccess);
1852    eClass_AddVirtualMethod(baseClass, "OnGetDataFromString", "bool typed_object&::OnGetDataFromString(char * string)", OnGetDataFromString, publicAccess);
1853    eClass_AddVirtualMethod(baseClass, "OnEdit", "Window typed_object::OnEdit(DataBox dataBox, DataBox obsolete, int x, int y, int w, int h, void * userData)", null, publicAccess);
1854    eClass_AddVirtualMethod(baseClass, "OnSerialize", "void typed_object::OnSerialize(IOChannel channel)", OnSerialize, publicAccess);
1855    eClass_AddVirtualMethod(baseClass, "OnUnserialize", "void typed_object&::OnUnserialize(IOChannel channel)", OnUnserialize, publicAccess);
1856    eClass_AddVirtualMethod(baseClass, "OnSaveEdit", "bool typed_object&::OnSaveEdit(Window window, void * object)", null, publicAccess);
1857 }
1858
1859 void InitializeDataTypes(Module module)
1860 {
1861    Class enumClass = eSystem_FindClass(module, "enum");
1862
1863    eClass_AddMethod(enumClass, "OnSerialize", null, Int_OnSerialize, publicAccess);
1864    eClass_AddMethod(enumClass, "OnUnserialize", null, Int_OnUnserialize, publicAccess);
1865
1866    // Data Types
1867    RegisterClass_Integer(module);
1868    RegisterClass_Float(module);
1869    RegisterClass_Double(module);
1870    RegisterClass_String(module);
1871 }
1872
1873 #define uint _uint
1874 #include <stdarg.h>
1875 #include <stdio.h>
1876 #undef uint
1877
1878 public int PrintStdArgsToBuffer(char * buffer, int maxLen, typed_object object, va_list args)
1879 {
1880    int len = 0;
1881    // TOFIX: OnGetString will need a maxLen as well
1882    char * result = object.OnGetString(buffer, null, null);
1883    if(result)
1884    {
1885       len = strlen(result);
1886       if(len >= maxLen) len = maxLen-1;
1887       if(result != buffer)
1888          memcpy(buffer, result, len);
1889    }
1890    while(true)
1891    {
1892       Class _class = null;
1893       void * data = null;
1894
1895       _class = va_arg(args, void *);
1896       if(!_class) break;
1897       data = va_arg(args, void *);
1898       if(data)
1899       {
1900          // TOFIX: OnGetString will need a maxLen as well
1901          result = ((char *(*)(void *, void *, char *, void *, bool *))(void *)_class._vTbl[__ecereVMethodID_class_OnGetString])(_class, data, buffer + len, null, null);
1902          if(result)
1903          {
1904             int newLen = strlen(result);
1905             if(len + newLen >= maxLen) newLen = maxLen-1-len;
1906             if(result != buffer + len)
1907                memcpy(buffer + len, result, newLen);
1908             len += newLen;              
1909          }
1910       }
1911    }
1912    buffer[len] = 0;
1913    return len;
1914 }
1915
1916 public int PrintBuf(char * buffer, int maxLen, typed_object object, ...)
1917 {
1918    va_list args;
1919    int len;
1920    va_start(args, object);
1921    len = PrintStdArgsToBuffer(buffer, maxLen, object, args);
1922    va_end(args);
1923    return len;
1924 }
1925
1926 public int PrintLnBuf(char * buffer, int maxLen, typed_object object, ...)
1927 {
1928    va_list args;
1929    int len;
1930    va_start(args, object);
1931    len = PrintStdArgsToBuffer(buffer, maxLen-1, object, args);
1932    buffer[len++] = '\n';
1933    buffer[len] = '\0';
1934    va_end(args);
1935    return len;
1936 }
1937
1938 public char * PrintString(typed_object object, ...)
1939 {
1940    char buffer[4096];
1941    va_list args;
1942    char * string;
1943    int len;
1944    va_start(args, object);
1945    len = PrintStdArgsToBuffer(buffer, sizeof(buffer), object, args);
1946    string = new char[len + 1];
1947    memcpy(string, buffer, len + 1);
1948    va_end(args);
1949    return string;
1950 }
1951
1952 public char * PrintLnString(typed_object object, ...)
1953 {
1954    char buffer[4096];
1955    va_list args;
1956    char * string;
1957    int len;
1958    va_start(args, object);
1959    len = PrintStdArgsToBuffer(buffer, sizeof(buffer), object, args);
1960    string = new char[len + 2];
1961    memcpy(string, buffer, len);
1962    string[len++] = '\n';
1963    string[len] = '\0';
1964    va_end(args);
1965    return string;
1966 }
1967
1968 #if defined(__ANDROID__)
1969 #include <android/log.h>
1970 #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "ecere-app", __VA_ARGS__))
1971 #endif
1972
1973 public void PrintLn(typed_object object, ...)
1974 {
1975    va_list args;
1976    char buffer[4096];
1977    va_start(args, object);
1978    PrintStdArgsToBuffer(buffer, sizeof(buffer), object, args);
1979    va_end(args);
1980 #if defined(__ANDROID__) && !defined(ECERE_NOFILE)
1981    LOGI("%s", buffer);
1982 #else
1983    puts(buffer);
1984 #endif
1985 }
1986
1987 public void Print(typed_object object, ...)
1988 {
1989    va_list args;
1990    char buffer[4096];
1991    va_start(args, object);
1992    PrintStdArgsToBuffer(buffer, sizeof(buffer), object, args);
1993    va_end(args);
1994    fputs(buffer, stdout);
1995 }