ecere/ECON: Fixed ECON parser expecting members in specific order
[sdk] / ecere / src / sys / JSON.ec
index 272db1a..9d63b68 100644 (file)
@@ -155,8 +155,6 @@ private:
             if(array)
                array.Free();
             delete array;
-            if(result != success)
-               result = typeMismatch;
          }
       }
       else if(ch == '-' || isdigit(ch))
@@ -165,16 +163,29 @@ private:
       }
       else if(ch == '{')
       {
-         void * object = value.p;
-         result = GetObject(type, &object);
-         if(result)
+         if(type.type == structClass || type.type == normalClass || type.type == noHeadClass)
          {
-            if(type && type.type == structClass);
-            else if(type && (type.type == normalClass || type.type == noHeadClass || type.type == bitClass))
+            void * object = value.p;
+            result = GetObject(type, &object);
+            if(result)
             {
-               value.p = object;
+               if(type && type.type == structClass);
+               else
+                  value.p = object;
             }
-            else
+         }
+         else if(type.type == bitClass)
+         {
+            uint64 object = 0;
+            result = GetObject(type, (void **)&object);
+            if(result)
+               value.ui64 = object;
+         }
+         else
+         {
+            void * object = value.p;
+            result = GetObject(type, &object);
+            if(result)
             {
                result = typeMismatch;
                if(type)
@@ -190,7 +201,7 @@ private:
             if(GetIdentifier(&string, null))
             {
                result = success;
-               if(eCON && (type.type == enumClass || type.type == unitClass))
+               if(eCON && type && (type.type == enumClass || type.type == unitClass))
                {
                   // should this be set by calling __ecereVMethodID_class_OnGetDataFromString ?
                   if(((bool (*)(void *, void *, const char *))(void *)type._vTbl[__ecereVMethodID_class_OnGetDataFromString])(type, &value.i, string))
@@ -507,7 +518,7 @@ private:
                break;
             }
          }
-         else if(ch == '\"' || (!comment && ch && !isalpha(ch) && !isdigit(ch) && ch != '_'))
+         else if(ch == '\"' || (!quoted && !comment && ch && !isalpha(ch) && !isdigit(ch) && ch != '_'))
          {
             if(quoted && ch == '\"' && wasQuoted)
                *wasQuoted = true;
@@ -526,7 +537,7 @@ private:
          *string = CopyString(buffer.array);
       }
       delete buffer;
-      if(ch != ',' && ch != '}' && ch != ';' && ch != '/' && ch != '=')
+      if(ch != ',' && ch != '}' && ch != ';' && ch != '/' && ch != '=' && ch != ':')
          ch = 0;
       return result;
    }
@@ -587,7 +598,7 @@ private:
                         lineComment = false;
                      else if(comment && pch == '*' && ch == '/')
                         comment = false;
-                     else if(ch == '=' || ch == ';' || ch == ',' || ch == ']' || ch == '}')
+                     else if(ch == '=' || ch == ':' || ch == ';' || ch == ',' || ch == ']' || ch == '}')
                      {
                         ch = 0;
                         seekback = -1;
@@ -632,7 +643,12 @@ private:
    {
       JSONResult result = syntaxError;
       if(!objectType || objectType.type != structClass)
-         *object = null;
+      {
+         if(objectType && objectType.type == bitClass)
+            *(uint64 *)object = 0;
+         else
+            *object = null;
+      }
       SkipEmpty();
       if(ch == '{')
       {
@@ -641,6 +657,18 @@ private:
          DataMember curMember = null;
          DataMember subMemberStack[256];
          int subMemberStackPos = 0;
+         uint64 bits = 0;
+
+         if(objectType.type == bitClass)
+         {
+            switch(objectType.typeSize)
+            {
+               case 1: bits = (byte  )*(uint64 *)object; break;
+               case 2: bits = (uint16)*(uint64 *)object; break;
+               case 4: bits = (uint32)*(uint64 *)object; break;
+               case 8: bits = (uint64)*(uint64 *)object; break;
+            }
+         }
 
          if(objectType && objectType.templateClass && eClass_IsDerived(objectType.templateClass, class(MapNode)))
          {
@@ -650,13 +678,7 @@ private:
 
          result = success;
          if(objectType && (objectType.type == noHeadClass || objectType.type == normalClass))
-         {
             *object = eInstance_New(objectType);
-         }
-         else if(objectType && objectType.type != structClass)
-         {
-            *object = eSystem_New(objectType.typeSize);
-         }
 
          while(result)
          {
@@ -680,22 +702,13 @@ private:
                bool isKey = false;
                bool isTemplateArg = false;
                uint offset = 0;
-               if(eCON)
+
+               ch = 0;
+               SkipEmpty();
+
+               if(eCON && (ch != '=' && ch != ':'))
                {
-                  SkipEmpty();
-                  prop = null; member = null;
-                  if(ch == '=')
-                  {
-                     while(1)
-                     {
-                        eClass_FindNextMember(objectType, &curClass, &curMember, subMemberStack, &subMemberStackPos);
-                        if(!curMember) break;
-                        if(!strcmp(curMember.name, string))
-                           break;
-                     }
-                  }
-                  else
-                     eClass_FindNextMember(objectType, &curClass, &curMember, subMemberStack, &subMemberStackPos);
+                  eClass_FindNextMember(objectType, &curClass, &curMember, subMemberStack, &subMemberStackPos);
                   if(curMember)
                   {
                      prop = curMember.isProperty ? (Property)curMember : null;
@@ -724,15 +737,16 @@ private:
                   }
                   else
                   {
-                     if(ch == '=')
+                     if(ch == '=' || ch == ':')
                         PrintLn("Warning: member ", string, " not found in class ", (String)objectType.name);
                      else
                         PrintLn("Warning: default member assignment: no more members");
                   }
                }
-               if(objectType && !eCON)
+               else if(objectType)
                {
-                  string[0] = (char)tolower(string[0]);
+                  if(!eCON || wasQuoted)
+                     string[0] = (char)tolower(string[0]);
                   if(mapKeyClass && !strcmp(string, "key"))
                   {
                      prop = eClass_FindProperty(objectType, "key", objectType.module);
@@ -748,22 +762,40 @@ private:
                   }
                   else
                   {
-                     member = eClass_FindDataMember(objectType, string, objectType.module, null, null);
+                     member = eClass_FindDataMember(objectType, string, objectType.module, subMemberStack, &subMemberStackPos);
                      if(member)
                      {
                         type = superFindClass(member.dataTypeString, objectType.module);
                         offset = member._class.offset + member.offset;
+                        curMember = member;
+                        curClass = member._class;
                      }
                      else if(!member)
                      {
                         prop = eClass_FindProperty(objectType, string, objectType.module);
                         if(prop)
+                        {
                            type = superFindClass(prop.dataTypeString, objectType.module);
+                           curMember = (DataMember)prop;
+                           curClass = prop._class;
+                        }
                         else
                            PrintLn("Warning: member ", string, " not found in class ", (String)objectType.name);
                      }
                   }
                }
+               if(type && type.templateClass && type.templateClass == class(Container))
+               {
+                  char * br = strchr(type.fullName, '<');
+                  if(br)
+                  {
+                     char className[1024];
+                     strcpy(className, "Array");
+                     strcat(className, br);
+                     type = superFindClass(className, objectType.module);
+                  }
+               }
+
                // Find Member in Object Class
                {
                   DataValue value { };
@@ -780,17 +812,12 @@ private:
                         value.p = new0 byte[type.structSize];
                      }
                   }
-                  if(!eCON)
-                  {
-                     ch = 0;
-                     SkipEmpty();
-                  }
-                  if(eCON && ch != '=')
+                  if(eCON && ch != '=' && ch != ':')
                   {
                      f.Seek(seek-1, start);
                      ch = 0;
                   }
-                  if(ch == (eCON ? '=' : ':') || (eCON && type && (prop || member)))
+                  if((ch == ':' || (eCON && ch == '=')) || (eCON && type && (prop || member)))
                   {
                      JSONResult itemResult = GetValue(type, value);
                      if(itemResult != syntaxError)
@@ -801,6 +828,7 @@ private:
                               PrintLn("warning: Unresolved data type ", member ? (String)member.dataTypeString : (String)prop.dataTypeString);
                            else if(itemResult == success)
                            {
+                              BitMember bitMember = objectType.type == bitClass ? (BitMember) member : null;
                               // Set value
                               if(member)
                               {
@@ -820,41 +848,127 @@ private:
                                  }
                                  else if(type == class(double) || !strcmp(type.dataTypeString, "double"))
                                  {
-                                    *(double *)((byte *)*object + offset) = value.d;
+                                    if(objectType.type != bitClass)
+                                    {
+                                       *(double *)((byte *)*object + offset) = value.d;
+                                    }
                                  }
                                  else if(type == class(float) || !strcmp(type.dataTypeString, "float"))
                                  {
-                                    *(float *)((byte *)*object + offset) = value.f;
+                                    if(objectType.type != bitClass)
+                                    {
+                                       *(float *)((byte *)*object + offset) = value.f;
+                                    }
                                  }
                                  else if(type.typeSize == sizeof(int64) || !strcmp(type.dataTypeString, "int64") ||
                                     !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64"))
                                  {
-                                    *(uint64 *)((byte *)*object + offset) = value.ui64;
+                                    if(objectType.type == bitClass)
+                                    {
+                                       bits &= ~bitMember.mask;
+                                       bits |= (value.ui64 << bitMember.pos) & bitMember.mask;
+                                    }
+                                    else
+                                    {
+                                       *(uint64 *)((byte *)*object + offset) = value.ui64;
+                                    }
                                  }
                                  else if(type.typeSize == sizeof(int) || !strcmp(type.dataTypeString, "int") ||
                                     !strcmp(type.dataTypeString, "unsigned int") || !strcmp(type.dataTypeString, "uint"))
                                  {
-                                    *(int *)((byte *)*object + offset) = value.i;
+                                    if(objectType.type == bitClass)
+                                    {
+                                       bits &= ~bitMember.mask;
+                                       bits |= (value.ui << bitMember.pos) & bitMember.mask;
+                                    }
+                                    else
+                                    {
+                                       *(int *)((byte *)*object + offset) = 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"))
                                  {
-                                    *(short *)((byte *)*object + offset) = value.s;
+                                    if(objectType.type == bitClass)
+                                    {
+                                       bits &= ~bitMember.mask;
+                                       bits |= (value.us << bitMember.pos) & bitMember.mask;
+                                    }
+                                    else
+                                    {
+                                       *(short *)((byte *)*object + offset) = value.s;
+                                    }
                                  }
                                  else if(type.typeSize == sizeof(byte) || !strcmp(type.dataTypeString, "char") ||
                                     !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
                                  {
-                                    *(char *)((byte *)*object + offset) = value.c;
+                                    if(objectType.type == bitClass)
+                                    {
+                                       bits &= ~bitMember.mask;
+                                       bits |= (value.uc << bitMember.pos) & bitMember.mask;
+                                    }
+                                    else
+                                    {
+                                       *(char *)((byte *)*object + offset) = value.c;
+                                    }
                                  }
                                  else
                                  {
-                                    *(void **)((byte *)*object + offset) = value.p;
+                                    if(objectType.type != bitClass)
+                                       *(void **)((byte *)*object + offset) = value.p;
                                  }
                               }
                               else if(prop && prop.Set)
                               {
-                                 if(!strcmp(type.dataTypeString, "char *"))
+                                 if(objectType.type == bitClass)
+                                 {
+                                    if(type.type == enumClass || type.type == bitClass || type.type == unitClass || type.type == systemClass)
+                                    {
+                                       switch(objectType.typeSize)
+                                       {
+                                          case 1:
+                                             switch(type.typeSize)
+                                             {
+                                                case 1: ((byte (*)(byte, byte))  (void *)prop.Set)((byte)bits, value.uc); break;
+                                                case 2: ((byte (*)(byte, uint16))(void *)prop.Set)((byte)bits, value.us); break;
+                                                case 4: ((byte (*)(byte, uint32))(void *)prop.Set)((byte)bits, value.ui); break;
+                                                case 8: ((byte (*)(byte, uint64))(void *)prop.Set)((byte)bits, value.ui64); break;
+                                             }
+                                             break;
+                                          case 2:
+                                             switch(type.typeSize)
+                                             {
+                                                case 1: ((uint16 (*)(uint16, byte))  (void *)prop.Set)((uint16)bits, value.uc); break;
+                                                case 2: ((uint16 (*)(uint16, uint16))(void *)prop.Set)((uint16)bits, value.us); break;
+                                                case 4: ((uint16 (*)(uint16, uint32))(void *)prop.Set)((uint16)bits, value.ui); break;
+                                                case 8: ((uint16 (*)(uint16, uint64))(void *)prop.Set)((uint16)bits, value.ui64); break;
+                                             }
+                                             break;
+                                          case 4:
+                                             switch(type.typeSize)
+                                             {
+                                                case 1: ((uint32 (*)(uint32, byte))  (void *)prop.Set)((uint32)bits, value.uc); break;
+                                                case 2: ((uint32 (*)(uint32, uint16))(void *)prop.Set)((uint32)bits, value.us); break;
+                                                case 4: ((uint32 (*)(uint32, uint32))(void *)prop.Set)((uint32)bits, value.ui); break;
+                                                case 8: ((uint32 (*)(uint32, uint64))(void *)prop.Set)((uint32)bits, value.ui64); break;
+                                             }
+                                             break;
+                                          case 8:
+                                             switch(type.typeSize)
+                                             {
+                                                case 1: ((uint64 (*)(uint64, byte))  (void *)prop.Set)((uint64)bits, value.uc); break;
+                                                case 2: ((uint64 (*)(uint64, uint16))(void *)prop.Set)((uint64)bits, value.us); break;
+                                                case 4: ((uint64 (*)(uint64, uint32))(void *)prop.Set)((uint64)bits, value.ui); break;
+                                                case 8: ((uint64 (*)(uint64, uint64))(void *)prop.Set)((uint64)bits, value.ui64); break;
+                                             }
+                                             break;
+                                       }
+                                    }
+                                    else
+                                       ; // TODO: Generate error
+                                 }
+                                 else if(!strcmp(type.dataTypeString, "char *"))
                                  {
                                     ((void (*)(void *, void *))(void *)prop.Set)(*object, value.p);
                                     if(!isKey)
@@ -938,6 +1052,17 @@ private:
                   result = syntaxError;
             }
          }
+
+         if(objectType.type == bitClass)
+         {
+            switch(objectType.typeSize)
+            {
+               case 1: *(uint64 *)object = (byte)   bits; break;
+               case 2: *(uint64 *)object = (uint16) bits; break;
+               case 4: *(uint64 *)object = (uint32) bits; break;
+               case 8: *(uint64 *)object = (uint64) bits; break;
+            }
+         }
       }
       ch = 0;
       return result;
@@ -949,10 +1074,12 @@ private:
       char buffer[256];
       int c = 0;
       bool comment = false;
+      bool hexMode = false;
       if(eCON)
       {
          while(c < sizeof(buffer)-1 && (comment || ch == '-' || ch == '.' || tolower(ch) == 'f' ||
-                     tolower(ch) == 'x' || tolower(ch) == 'e' || ch == '+' || isdigit(ch) || ch == '/'))
+                     (c == 1 && tolower(ch) == 'x' && buffer[0] == '0') || tolower(ch) == 'e' || ch == '+' || isdigit(ch) || ch == '/' ||
+                     (hexMode && ((ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')))))
          {
             if(!comment && ch == '/')
             {
@@ -981,7 +1108,11 @@ private:
                }
             }
             else if(!comment)
+            {
+               if(c == 1 && ch == 'x' && buffer[0] == '0')
+                  hexMode = true;
                buffer[c++] = ch;
+            }
             if(!f.Getc(&ch)) break;
          }
       }
@@ -1023,7 +1154,7 @@ private:
          value.ui64 = strtoul(buffer, null, eCON ? 0 : 10);  // TOFIX: 64 bit support
          result = success;
       }
-      else if(type == class(uint) || !strcmp(type.dataTypeString, "unsigned int"))
+      else if(type == class(uint) || !strcmp(type.dataTypeString, "unsigned int") || !strcmp(type.dataTypeString, "uint"))
       {
          value.ui = (uint)strtoul(buffer, null, eCON ? 0 : 10);  // TOFIX: 64 bit support
          result = success;
@@ -1225,7 +1356,7 @@ static bool WriteArray(File f, Class type, Container array, int indent, bool eCO
    return true;
 }
 
-static bool WriteNumber(File f, Class type, DataValue value, int indent, bool eCON)
+static bool WriteNumber(File f, Class type, DataValue value, int indent, bool eCON, bool useHex)
 {
    char buffer[1024];
    bool needClass = eCON;
@@ -1238,11 +1369,21 @@ static bool WriteNumber(File f, Class type, DataValue value, int indent, bool eC
    else if(!strcmp(type.dataTypeString, "int64"))
       ((const char *(*)(void *, void *, char *, void *, bool *))(void *)type._vTbl[__ecereVMethodID_class_OnGetString])(type, &value.i64, buffer, null, &needClass);
    else if(!strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") || type.typeSize == sizeof(int64))
-      ((const char *(*)(void *, void *, char *, void *, bool *))(void *)type._vTbl[__ecereVMethodID_class_OnGetString])(type, &value.ui64, buffer, null, &needClass);
+   {
+      if(useHex && eCON)
+         sprintf(buffer, __runtimePlatform == win32 ? "0x%016I64X" : "0x%016llX", value.ui64);
+      else
+         ((const char *(*)(void *, void *, char *, void *, bool *))(void *)type._vTbl[__ecereVMethodID_class_OnGetString])(type, &value.ui64, buffer, null, &needClass);
+   }
    else if(!strcmp(type.dataTypeString, "int"))
       ((const char *(*)(void *, void *, char *, void *, bool *))(void *)type._vTbl[__ecereVMethodID_class_OnGetString])(type, &value.i, buffer, null, &needClass);
    else if(!strcmp(type.dataTypeString, "unsigned int") || !strcmp(type.dataTypeString, "uint") || type.typeSize == sizeof(int))
-      ((const char *(*)(void *, void *, char *, void *, bool *))(void *)type._vTbl[__ecereVMethodID_class_OnGetString])(type, &value.ui, buffer, null, &needClass);
+   {
+      if(useHex && eCON)
+         sprintf(buffer, "0x%08X", value.ui);
+      else
+         ((const char *(*)(void *, void *, char *, void *, bool *))(void *)type._vTbl[__ecereVMethodID_class_OnGetString])(type, &value.ui, buffer, null, &needClass);
+   }
    else if(!strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "int16"))
       ((const char *(*)(void *, void *, char *, void *, bool *))(void *)type._vTbl[__ecereVMethodID_class_OnGetString])(type, &value.s, buffer, null, &needClass);
    else if(!strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") || type.typeSize == sizeof(short int))
@@ -1329,6 +1470,17 @@ static bool WriteValue(File f, Class type, DataValue value, int indent, bool eCO
                   f.Puts("\\t");
                   b = 0;
                }
+               else if(c >= 4 && ch == '>' && string[c-2] == 'r' && string[c-3] == 'b' && string[c-4] == '<')
+               {
+                  // Add an automatic newline for <br> as this is how we imported documentor data...
+                  int i;
+                  buffer[b] = 0;
+                  f.Puts(buffer);
+                  f.Puts(">\"\n");
+                  for(i = 0; i<indent; i++) f.Puts("   ");
+                  f.Puts("   \"");
+                  b = 0;
+               }
                else if(ch == '\n')
                {
                   int i;
@@ -1409,7 +1561,7 @@ static bool WriteValue(File f, Class type, DataValue value, int indent, bool eCO
          f.Puts("unset");
    }
    else if(type.type == enumClass)
-      WriteNumber(f, type, value, indent, eCON);
+      WriteNumber(f, type, value, indent, eCON, false);
    else if(eClass_IsDerived(type, class(Map)))
    {
       WriteMap(f, type, value.p, indent, eCON);
@@ -1430,11 +1582,11 @@ static bool WriteValue(File f, Class type, DataValue value, int indent, bool eCO
    {
       Class dataType;
       dataType = superFindClass(type.dataTypeString, type.module);
-      WriteNumber(f, dataType, value, indent, eCON);
+      WriteNumber(f, dataType, value, indent, eCON, true);
    }
    else if(type.type == systemClass || type.type == unitClass)
    {
-      WriteNumber(f, type, value, indent, eCON);
+      WriteNumber(f, type, value, indent, eCON, false);
    }
    return true;
 }