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