ecere/sys/JSON: Fixed issues deserializing structs
[sdk] / ecere / src / sys / JSON.ec
index a6bebd7..08b87d1 100644 (file)
@@ -1,5 +1,6 @@
 namespace sys;
 
+import "instance"
 import "System"
 import "Array"
 
@@ -38,7 +39,7 @@ public:
 
    void SkipEmpty()
    {
-      while(!f.Eof() && (!ch || ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'))
+      while(!f.Eof() && (!ch || ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '/'))
       {
          f.Getc(&ch);
       }
@@ -166,7 +167,8 @@ public:
             }
             else if(!strcmpi(buffer, "null"))
             {
-               value.p = 0;
+               if(type.type != structClass)
+                  value.p = 0;
             }
             else
                result = typeMismatch;
@@ -199,6 +201,8 @@ public:
                arrayType = type.templateArgs[0].dataTypeClass;
             }
 
+            if(arrayType && arrayType.type == structClass)
+               value.p = new0 byte[arrayType.structSize];
             itemResult = GetValue(arrayType, value);
             if(itemResult == success)
             {
@@ -242,6 +246,9 @@ public:
                   t = (uint64)(uintptr)value.p;
                }
                ((void *(*)(void *, uint64))(void *)array->Add)(*array, t);
+
+               if(arrayType && arrayType.type == structClass)
+                  delete value.p;
             }
             else
             {
@@ -475,7 +482,15 @@ public:
 
                   if(type && type.type == structClass)
                   {
-                     value.p = (byte *)*object + offset;
+                     if(member)
+                     {
+                        value.p = (byte *)*object + offset;
+                        memset(value.p, 0, type.structSize);
+                     }
+                     else if(prop)
+                     {
+                        value.p = new0 byte[type.structSize];
+                     }
                   }
                   ch = 0;
                   SkipEmpty();
@@ -551,35 +566,42 @@ public:
                                     if(!isKey)
                                        delete value.p;
                                  }
-                                 // TOFIX: How to swiftly handle classes with base data type?
-                                 else if(type == class(double) || !strcmp(type.dataTypeString, "double"))
-                                 {
-                                    ((void (*)(void *, double))(void *)prop.Set)(*object, value.d);
-                                 }
-                                 else if(type == class(float) || !strcmp(type.dataTypeString, "float"))
+                                 else if(type.type == enumClass || type.type == bitClass || type.type == unitClass || type.type == systemClass)
                                  {
-                                    ((void (*)(void *, float))(void *)prop.Set)(*object, value.f);
-                                 }
-                                 else if(type.typeSize == sizeof(int64) || !strcmp(type.dataTypeString, "int64") ||
-                                    !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64"))
-                                 {
-                                    ((void (*)(void *, uint64))(void *)prop.Set)(*object, value.ui64);
-                                 }
-                                 else if(type.typeSize == sizeof(int) || !strcmp(type.dataTypeString, "int") ||
-                                    !strcmp(type.dataTypeString, "unsigned int") || !strcmp(type.dataTypeString, "uint"))
-                                 {
-                                    ((void (*)(void *, int))(void *)prop.Set)(*object, value.i);
-                                 }
-                                 else if(type.typeSize == sizeof(short int) || !strcmp(type.dataTypeString, "short") ||
-                                    !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
-                                    !strcmp(type.dataTypeString, "int16"))
-                                 {
-                                    ((void (*)(void *, short))(void *)prop.Set)(*object, value.s);
-                                 }
-                                 else if(type.typeSize == sizeof(byte) || !strcmp(type.dataTypeString, "char") ||
-                                    !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
-                                 {
-                                    ((void (*)(void *, char))(void *)prop.Set)(*object, value.c);
+                                    // TOFIX: How to swiftly handle classes with base data type?
+                                    if(type == class(double) || !strcmp(type.dataTypeString, "double"))
+                                    {
+                                       ((void (*)(void *, double))(void *)prop.Set)(*object, value.d);
+                                    }
+                                    else if(type == class(float) || !strcmp(type.dataTypeString, "float"))
+                                    {
+                                       ((void (*)(void *, float))(void *)prop.Set)(*object, value.f);
+                                    }
+                                    else if(type.typeSize == sizeof(int64) || !strcmp(type.dataTypeString, "int64") ||
+                                       !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64"))
+                                    {
+                                       ((void (*)(void *, uint64))(void *)prop.Set)(*object, value.ui64);
+                                    }
+                                    else if(type.typeSize == sizeof(int) || !strcmp(type.dataTypeString, "int") ||
+                                       !strcmp(type.dataTypeString, "unsigned int") || !strcmp(type.dataTypeString, "uint"))
+                                    {
+                                       ((void (*)(void *, int))(void *)prop.Set)(*object, value.i);
+                                    }
+                                    else if(type.typeSize == sizeof(short int) || !strcmp(type.dataTypeString, "short") ||
+                                       !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
+                                       !strcmp(type.dataTypeString, "int16"))
+                                    {
+                                       ((void (*)(void *, short))(void *)prop.Set)(*object, value.s);
+                                    }
+                                    else if(type.typeSize == sizeof(byte) || !strcmp(type.dataTypeString, "char") ||
+                                       !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
+                                    {
+                                       ((void (*)(void *, char))(void *)prop.Set)(*object, value.c);
+                                    }
+                                    else
+                                    {
+                                       ((void (*)(void *, int))(void *)prop.Set)(*object, value.i);
+                                    }
                                  }
                                  else
                                  {
@@ -597,6 +619,11 @@ public:
                   }
                   else
                      result = syntaxError;
+
+                  if(prop && type.type == structClass)
+                  {
+                     delete value.p;
+                  }
                }
             }
             else if(ch && ch != '}' && ch != ',')
@@ -631,6 +658,7 @@ public:
       }
       buffer[c] = 0;
       //if(strchr(buffer, '.'))
+      if(!type) return success;
 
       // TOFIX: How to swiftly handle classes with base data type?
       if(type == class(double) || !strcmp(type.dataTypeString, "double"))
@@ -652,14 +680,65 @@ public:
       }
       else if(type == class(uint64) || !strcmp(type.dataTypeString, "uint64"))
       {
-         value.ui64 = strtol(buffer, null, 10);  // TOFIX: 64 bit support
+         value.ui64 = strtoul(buffer, null, 10);  // TOFIX: 64 bit support
+         result = success;
+      }
+      else if(type == class(uint) || !strcmp(type.dataTypeString, "unsigned int"))
+      {
+         value.ui = (uint)strtoul(buffer, null, 10);  // TOFIX: 64 bit support
          result = success;
       }
       else
       {
-         value.i = strtol(buffer, null, 10);
+         value.i = (int)strtol(buffer, null, 10);
          result = success;
       }
+
+      if(result == success && type.type == unitClass)
+      {
+         // Convert to reference unit
+         Property prop;
+         for(prop = type.conversions.first; prop; prop = prop.next)
+         {
+            bool refProp = false;
+            Class c;
+            if(!strcmp(prop.name, type.base.fullName))
+               refProp = true;
+            else if( (c = eSystem_FindClass(type.module, prop.name) ) )
+            {
+               Property p;
+               for(p = c.conversions.first; p; p = p.next)
+               {
+                  if(!strcmp(p.name, type.base.fullName) && !p.Set && !p.Get)
+                  {
+                     refProp = true;
+                     break;
+                  }
+               }
+            }
+            if(refProp)
+            {
+               if(prop.Set && prop.Get)
+               {
+                  const String dts = type.base.dataTypeString;
+                  if(!strcmp(dts, "double"))
+                     value.d = ((double(*)(double))(void *)prop.Get)(value.d);
+                  else if(!strcmp(dts, "float"))
+                     value.f = ((float(*)(float))(void *)prop.Get)(value.f);
+                  else if(!strcmp(dts, "int"))
+                     value.i = ((int(*)(int))(void *)prop.Get)(value.i);
+                  else if(!strcmp(dts, "int64"))
+                     value.i64 = ((int64(*)(int64))(void *)prop.Get)(value.i64);
+                  else if(!strcmp(dts, "unsigned int"))
+                     value.ui = ((uint(*)(uint))(void *)prop.Get)(value.ui);
+                  else if(!strcmp(dts, "uint64"))
+                     value.ui64 = ((uint64(*)(uint64))(void *)prop.Get)(value.ui64);
+               }
+               else
+                  break;
+            }
+         }
+      }
       return result;
    }
 }
@@ -773,6 +852,7 @@ bool WriteNumber(File f, Class type, DataValue value, int indent)
 {
    char buffer[1024];
    bool needClass = false;
+   bool quote;
    buffer[0] = 0;
    if(type == class(double) || !strcmp(type.dataTypeString, "double"))
       ((const char *(*)(void *, void *, char *, void *, bool *))(void *)type._vTbl[__ecereVMethodID_class_OnGetString])(type, &value.d, buffer, 0, &needClass);
@@ -794,7 +874,11 @@ bool WriteNumber(File f, Class type, DataValue value, int indent)
       ((const char *(*)(void *, void *, char *, void *, bool *))(void *)type._vTbl[__ecereVMethodID_class_OnGetString])(type, &value.c, buffer, null, &needClass);
    else if(!strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte") || type.typeSize == sizeof(byte))
       ((const char *(*)(void *, void *, char *, void *, bool *))(void *)type._vTbl[__ecereVMethodID_class_OnGetString])(type, &value.uc, buffer, null, &needClass);
+
+   quote = (type.type == unitClass && ((buffer[0] != '.' && !isdigit(buffer[0])) || strchr(buffer, ' ')));
+   if(quote) f.Puts("\"");
    f.Puts(buffer);
+   if(quote) f.Puts("\"");
    return true;
 }
 
@@ -864,7 +948,7 @@ bool WriteValue(File f, Class type, DataValue value, int indent)
       else
          f.Puts("unset");
    }
-   else if(type.type == enumClass || type.type == unitClass)
+   else if(type.type == enumClass)
    {
       f.Puts("\"");
       WriteNumber(f, type, value, indent);
@@ -888,7 +972,7 @@ bool WriteValue(File f, Class type, DataValue value, int indent)
       dataType = eSystem_FindClass(__thisModule, type.dataTypeString);
       WriteNumber(f, dataType, value, indent);
    }
-   else if(type.type == systemClass)
+   else if(type.type == systemClass || type.type == unitClass)
    {
       WriteNumber(f, type, value, indent);
    }
@@ -1009,6 +1093,11 @@ static bool _WriteJSONObject(File f, Class objectType, void * object, int indent
                         {
                            value.c = ((char (*)(void *))(void *)prop.Get)(object);
                         }
+                        else if(type.type == structClass)
+                        {
+                           value.p = new0 byte[type.structSize];
+                           ((void (*)(void *, void *))(void *)prop.Get)(object, value.p);
+                        }
                         else
                         {
                            value.p = ((void *(*)(void *))(void *)prop.Get)(object);
@@ -1023,6 +1112,8 @@ static bool _WriteJSONObject(File f, Class objectType, void * object, int indent
                         f.Puts("\" : ");
                         WriteValue(f, type, value, indent);
                         isFirst = false;
+                        if(type.type == structClass)
+                           delete value.p;
                      }
                   }
                }