namespace sys; import "instance" import "System" import "Array" default: __attribute__((unused)) static void UnusedFunction() { int a; a.OnGetDataFromString(null); a.OnGetString(null, 0, 0); a.OnFree(); } extern int __ecereVMethodID_class_OnGetDataFromString; extern int __ecereVMethodID_class_OnGetString; extern int __ecereVMethodID_class_OnFree; private: public enum JSONResult { syntaxError, success, typeMismatch, noItem }; public enum SetBool : uint { unset, false, true; /*public property bool // NOT WORKING! { set { return value ? true : false; } get { return (this == true); } }*/ }; public class ECONParser : JSONParser { eCON = true; } public class JSONParser { public: File f; private: char ch; bool eCON; void SkipEmpty() { if(eCON) { char pch; bool lineComment = false; bool comment = false; while(!f.Eof() && (!ch || lineComment || comment || ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '/')) { pch = ch; f.Getc(&ch); if(!lineComment && !comment && pch == '/') { if(ch == '/') lineComment = true; else if(ch == '*') comment = true; } else if(lineComment && ch == '\n') lineComment = false; else if(comment && pch == '*' && ch == '/') comment = false; } } else { while(!f.Eof() && (!ch || ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '/')) { f.Getc(&ch); } } } void SkipExtraSemicolon() { while(!f.Eof() && (!ch || ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == ';')) { f.Getc(&ch); } } JSONResult GetValue(Class type, DataValue value) { JSONResult result = syntaxError; ch = 0; SkipEmpty(); if(ch == '\"') { String string; result = GetString(&string); if(result) { Property prop; if(type && (!strcmp(type.name, "String") || !strcmp(type.dataTypeString, "char *"))) { value.p = string; } else if(type && (type.type == enumClass || type.type == unitClass)) { if(((bool (*)(void *, void *, const char *))(void *)type._vTbl[__ecereVMethodID_class_OnGetDataFromString])(type, &value.i, string)) result = success; else result = typeMismatch; delete string; } else if(type && (prop = eClass_FindProperty(type, "String", type.module))) { // TOFIX: Add more conversion property support... Expecting void * compatible here value.p = ((void *(*)())(void *)prop.Set)(string); result = success; delete string; } else if(type && eClass_IsDerived(type, class(ColorAlpha))) { result = GetColorAlpha(string, value); delete string; } else if(type && (type.type == structClass)) { if(((bool (*)(void *, void *, const char *))(void *)type._vTbl[__ecereVMethodID_class_OnGetDataFromString])(type, value.p, string)) result = success; else result = typeMismatch; delete string; } else { delete string; result = typeMismatch; } } } else if(ch == '[') { Container array; if(type && eClass_IsDerived(type, class(Map))) { result = GetMap(type, (Map *)&array); } else result = GetArray(type, &array); if(result == success && type && eClass_IsDerived(type, class(Container))) { value.p = array; } else { if(array) array.Free(); delete array; if(result != success) result = typeMismatch; } } else if(ch == '-' || isdigit(ch)) { result = GetNumber(type, value); } else if(ch == '{') { void * object = value.p; result = GetObject(type, &object); if(result) { if(type && type.type == structClass); else if(type && (type.type == normalClass || type.type == noHeadClass || type.type == bitClass)) { value.p = object; } else { result = typeMismatch; if(type) ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, object); } } } else if(isalpha(ch) || ch == '_') { if(eCON) { String string; if(GetIdentifier(&string, null)) { result = success; if(eCON && (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)) result = success; else result = typeMismatch; } else if(type && !strcmp(type.name, "bool")) { if(!strcmpi(string, "false")) value.i = 0; else if(!strcmpi(string, "true")) value.i = 1; else result = typeMismatch; } else if(type && !strcmp(type.name, "SetBool")) { if(!strcmpi(string, "false")) value.i = SetBool::false; else if(!strcmpi(string, "true")) value.i = SetBool::true; else result = typeMismatch; } else if(type && !strcmpi(string, "null")) { if(type.type != structClass) value.p = 0; } else if(isSubclass(type, string)) { void * object = value.p; Class subtype = superFindClass(string, type.module); SkipEmpty(); result = GetObject(subtype, &object); if(result) { if(subtype && subtype.type == structClass); else if(subtype && (subtype.type == normalClass || subtype.type == noHeadClass || subtype.type == bitClass)) { value.p = object; } else { result = typeMismatch; if(subtype) ((void (*)(void *, void *))(void *)subtype._vTbl[__ecereVMethodID_class_OnFree])(subtype, object); } } } else result = typeMismatch; } delete string; } else { char buffer[256]; int c = 0; while(c < sizeof(buffer)-1 && (isalpha(ch) || isdigit(ch) || ch == '_')) { buffer[c++] = ch; if(!f.Getc(&ch)) break; } buffer[c] = 0; result = success; if(type) { if(!strcmp(type.name, "bool")) { if(!strcmpi(buffer, "false")) value.i = 0; else if(!strcmpi(buffer, "true")) value.i = 1; else result = typeMismatch; } else if(!strcmp(type.name, "SetBool")) { if(!strcmpi(buffer, "false")) value.i = SetBool::false; else if(!strcmpi(buffer, "true")) value.i = SetBool::true; else result = typeMismatch; } else if(!strcmpi(buffer, "null")) { if(type.type != structClass) value.p = 0; } else result = typeMismatch; } else result = typeMismatch; } } else if(ch == '}' || ch == ']') result = noItem; if(result == typeMismatch) PrintLn("Warning: Value type mismatch"); return result; } JSONResult GetArray(Class type, Container * array) { JSONResult result = syntaxError; SkipEmpty(); *array = null; if(ch == '[') { *array = eInstance_New(type); result = success; while(result) { DataValue value { }; Class arrayType = null; JSONResult itemResult; if(eClass_IsDerived(type, class(Container))) { arrayType = type.templateArgs[0].dataTypeClass; } if(arrayType && arrayType.type == structClass) value.p = new0 byte[arrayType.structSize]; itemResult = GetValue(arrayType, value); if(itemResult == success) { // TODO: Verify the matching between template type and uint64 uint64 t; if(arrayType.type == structClass) { t = (uint64)(uintptr)value.p; } else if(arrayType == class(double) || !strcmp(arrayType.dataTypeString, "double")) { t = value.ui64; //*(uint64 *)&value.d; } else if(arrayType == class(float) || !strcmp(arrayType.dataTypeString, "float")) { t = value.ui; //f*(uint *)&value.f; } else if(arrayType.typeSize == sizeof(int64) || !strcmp(arrayType.dataTypeString, "int64") || !strcmp(arrayType.dataTypeString, "unsigned int64") || !strcmp(arrayType.dataTypeString, "uint64")) { t = value.ui64; } else if(arrayType.typeSize == sizeof(int) || !strcmp(arrayType.dataTypeString, "int") || !strcmp(arrayType.dataTypeString, "unsigned int") || !strcmp(arrayType.dataTypeString, "uint")) { t = value.i; } else if(arrayType.typeSize == sizeof(short int) || !strcmp(arrayType.dataTypeString, "short") || !strcmp(arrayType.dataTypeString, "unsigned short") || !strcmp(arrayType.dataTypeString, "uint16") || !strcmp(arrayType.dataTypeString, "int16")) { t = value.s; } else if(arrayType.typeSize == sizeof(byte) || !strcmp(arrayType.dataTypeString, "char") || !strcmp(arrayType.dataTypeString, "unsigned char") || !strcmp(arrayType.dataTypeString, "byte")) { t = value.c; } else { t = (uint64)(uintptr)value.p; } ((void *(*)(void *, uint64))(void *)array->Add)(*array, t); if(arrayType && arrayType.type == structClass) delete value.p; } else { if(itemResult == typeMismatch) { if(arrayType) PrintLn("Warning: Incompatible value for array value, expected ", (String)arrayType.name); } else if(itemResult == noItem) result = success; else result = itemResult; } if(result != syntaxError) { if(ch != ']' && ch != ',') { ch = 0; SkipEmpty(); } if(ch == ']') { break; } else if(ch != ',') result = syntaxError; } } } ch = 0; return result; } JSONResult GetMap(Class type, Map * map) { JSONResult result = syntaxError; SkipEmpty(); *map = null; if(ch == '[') { Class mapNodeType = type.templateArgs[0].dataTypeClass; Class keyType = mapNodeType.templateArgs[0].dataTypeClass; Property keyProp = null; if(keyType && !strcmp(keyType.dataTypeString, "char *")) keyProp = eClass_FindProperty(mapNodeType, "key", mapNodeType.module); *map = eInstance_New(type); result = success; while(result) { DataValue value { }; JSONResult itemResult; itemResult = GetValue(mapNodeType, value); if(itemResult == success) { String s = keyProp ? ((void * (*)(void *))(void *)keyProp.Get)(value.p) : null; ((void *(*)(void *, uint64))(void *)map->Add)(*map, (uint64)(uintptr)value.p); // Must free String keys here delete s; } else { if(itemResult == typeMismatch) { if(mapNodeType) PrintLn("Warning: Incompatible value for array value, expected ", (String)mapNodeType.name); } else if(itemResult == noItem) result = success; else result = itemResult; } if(result != syntaxError) { if(ch != ']' && ch != ',') { ch = 0; SkipEmpty(); } if(ch == ']') { break; } else if(ch != ',') result = syntaxError; } } } ch = 0; return result; } JSONResult GetIdentifier(String * string, bool * wasQuoted) { JSONResult result = syntaxError; Array buffer { minAllocSize = 256 }; bool comment = false; bool quoted = false; *string = null; SkipEmpty(); if(ch == '\"') quoted = true; else buffer.Add(ch); result = success; while(f.Getc(&ch)) { if(!comment && ch == '/') { if(f.Getc(&ch)) { if(ch == '/') break; else if(ch == '*') comment = true; else { result = syntaxError; break; } } else { result = syntaxError; break; } } else if(comment && ch == '*') { if(f.Getc(&ch)) { if(ch == '/') { comment = false; ch = 0; } } else { result = syntaxError; break; } } else if(ch == '\"' || (!quoted && !comment && ch && !isalpha(ch) && !isdigit(ch) && ch != '_')) { if(quoted && ch == '\"' && wasQuoted) *wasQuoted = true; break; } else if(!comment && ch) { buffer.Add(ch); if(buffer.minAllocSize < buffer.count) buffer.minAllocSize *= 2; } } if(result != syntaxError) { buffer.Add(0); *string = CopyString(buffer.array); } delete buffer; if(ch != ',' && ch != '}' && ch != ';' && ch != '/' && ch != '=' && ch != ':') ch = 0; return result; } JSONResult GetString(String * string) { JSONResult result = syntaxError; Array buffer { minAllocSize = 256 }; bool escaped = false; *string = null; SkipEmpty(); if(ch == '\"' || eCON) { while(f.Getc(&ch)) { if(ch == '\\' && !escaped) escaped = true; else { if(escaped) { if(ch == 'b') ch = '\b'; else if(ch == 'f') ch = '\f'; else if(ch == 'n') ch = '\n'; else if(ch == 'r') ch = '\r'; else if(ch == 't') ch = '\t'; else if(ch == 'u') { // SKIP FOR NOW... char unicode[4]; f.Getc(&unicode[0]); f.Getc(&unicode[1]); f.Getc(&unicode[2]); f.Getc(&unicode[3]); } escaped = false; } else if(eCON && ch == '\"') { int seekback = 0; char pch; bool lineComment = false; bool comment = false; while(!f.Eof()) { pch = ch; f.Getc(&ch); seekback--; if(!lineComment && !comment && pch == '/') { if(ch == '/') lineComment = true; else if(ch == '*') comment = true; } else if(lineComment && ch == '\n') lineComment = false; else if(comment && pch == '*' && ch == '/') comment = false; else if(ch == '=' || ch == ':' || ch == ';' || ch == ',' || ch == ']' || ch == '}') { ch = 0; seekback = -1; break; } else if(ch == '\"') { seekback = 0; ch = 0; break; } } if(seekback != 0) { f.Seek(seekback, current); break; } } else if((!eCON && ch == '\"')) { break; } if(ch) { buffer.Add(ch); if(buffer.minAllocSize < buffer.count) buffer.minAllocSize *= 2; } } } buffer.Add(0); *string = CopyString(buffer.array); result = success; } delete buffer; if(ch != ',' && ch != '}' && (!eCON || (ch != ';' && ch != '/'))) ch = 0; return result; } public JSONResult GetObject(Class objectType, void ** object) { JSONResult result = syntaxError; if(!objectType || objectType.type != structClass) *object = null; SkipEmpty(); if(ch == '{') { Class mapKeyClass = null, mapDataClass = null; Class curClass = null; DataMember curMember = null; DataMember subMemberStack[256]; int subMemberStackPos = 0; if(objectType && objectType.templateClass && eClass_IsDerived(objectType.templateClass, class(MapNode))) { mapKeyClass = objectType.templateArgs[0].dataTypeClass; mapDataClass = objectType.templateArgs[2].dataTypeClass; } 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) { String string; bool wasQuoted = false; int seek; ch = 0; if(eCON) { SkipExtraSemicolon(); if(ch == '}') break; } SkipEmpty(); seek = f.Tell(); if(eCON ? GetIdentifier(&string, &wasQuoted) : GetString(&string)) { DataMember member = null; Property prop = null; Class type = null; bool isKey = false; bool isTemplateArg = false; uint offset = 0; if(eCON) { SkipEmpty(); prop = null; member = null; if(ch == '=' || ch == ':') { if(wasQuoted) string[0] = (char)tolower(string[0]); 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); if(curMember) { prop = curMember.isProperty ? (Property)curMember : null; member = curMember.isProperty ? null : curMember; if(mapKeyClass && !strcmp(prop ? prop.name : member.name, "key")) { type = mapKeyClass; isTemplateArg = true; isKey = true; } else if(mapDataClass && !strcmp(prop ? prop.name : member.name, "value")) { type = mapDataClass; isTemplateArg = true; if(member) offset = member._class.offset + member.offset; } else if(prop) type = superFindClass(prop.dataTypeString, objectType.module); else if(member) { type = superFindClass(member.dataTypeString, objectType.module); offset = member._class.offset + member.offset; } } else { 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) { string[0] = (char)tolower(string[0]); if(mapKeyClass && !strcmp(string, "key")) { prop = eClass_FindProperty(objectType, "key", objectType.module); type = mapKeyClass; isTemplateArg = true; isKey = true; } else if(mapDataClass && !strcmp(string, "value")) { prop = eClass_FindProperty(objectType, "value", objectType.module); type = mapDataClass; isTemplateArg = true; } else { member = eClass_FindDataMember(objectType, string, objectType.module, null, null); if(member) { type = superFindClass(member.dataTypeString, objectType.module); offset = member._class.offset + member.offset; } else if(!member) { prop = eClass_FindProperty(objectType, string, objectType.module); if(prop) type = superFindClass(prop.dataTypeString, objectType.module); else PrintLn("Warning: member ", string, " not found in class ", (String)objectType.name); } } } // Find Member in Object Class { DataValue value { }; if(type && type.type == structClass) { if(member) { value.p = (byte *)*object + offset; memset(value.p, 0, type.structSize); } else if(prop) { value.p = new0 byte[type.structSize]; } } if(!eCON) { ch = 0; SkipEmpty(); } if(eCON && ch != '=' && ch != ':') { f.Seek(seek-1, start); ch = 0; } if((ch == ':' || (eCON && ch == '=')) || (eCON && type && (prop || member))) { JSONResult itemResult = GetValue(type, value); if(itemResult != syntaxError) { if(prop || member) { if(!type) PrintLn("warning: Unresolved data type ", member ? (String)member.dataTypeString : (String)prop.dataTypeString); else if(itemResult == success) { // Set value if(member) { // TOFIX: How to swiftly handle classes with base data type? if(type.type == structClass) ; else if(type.type == normalClass || type.type == noHeadClass) { void ** ptr = (void**)((byte *)*object + offset); if(eClass_IsDerived(type, class(Container)) && *ptr) { Container container = (Container)*ptr; container.Free(); delete container; } *ptr = value.p; } else if(type == class(double) || !strcmp(type.dataTypeString, "double")) { *(double *)((byte *)*object + offset) = value.d; } else if(type == class(float) || !strcmp(type.dataTypeString, "float")) { *(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; } 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; } 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; } 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; } else { *(void **)((byte *)*object + offset) = value.p; } } else if(prop && prop.Set) { if(!strcmp(type.dataTypeString, "char *")) { ((void (*)(void *, void *))(void *)prop.Set)(*object, value.p); if(!isKey) delete value.p; } else if(type.type == enumClass || type.type == bitClass || type.type == unitClass || type.type == systemClass) { // 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 { if(isTemplateArg) ((void (*)(void *, uint64))(void *)prop.Set)(*object, (uint64)(uintptr)value.p); else ((void (*)(void *, void *))(void *)prop.Set)(*object, value.p); } } } else { PrintLn("Warning: Incompatible value for ", member ? (String)member.name : (String)prop.name, ", expected ", member ? (String)member.dataTypeString : (String)prop.dataTypeString); } } } } else result = syntaxError; if(prop && type && type.type == structClass) { delete value.p; } } } else if(ch && ch != '}' && ch != ',' && (!eCON || ch != ';')) result = syntaxError; delete string; if(result) { SkipEmpty(); if(ch == '}') { break; } else if(ch != ',' && (!eCON || ch != ';')) result = syntaxError; } } } ch = 0; return result; } JSONResult GetNumber(Class type, DataValue value) { JSONResult result = success; char buffer[256]; int c = 0; bool comment = false; if(eCON) { while(c < sizeof(buffer)-1 && (comment || ch == '-' || ch == '.' || tolower(ch) == 'f' || tolower(ch) == 'x' || tolower(ch) == 'e' || ch == '+' || isdigit(ch) || ch == '/')) { if(!comment && ch == '/') { if(f.Getc(&ch)) { if(ch == '*') comment = true; } else { result = syntaxError; break; } } else if(comment && ch == '*') { if(f.Getc(&ch)) { if(ch == '/') comment = false; } else { result = syntaxError; break; } } else if(!comment) buffer[c++] = ch; if(!f.Getc(&ch)) break; } } else { while(c < sizeof(buffer)-1 && (ch == '-' || ch == '.' || tolower(ch) == 'e' || ch == '+' || isdigit(ch))) { buffer[c++] = ch; if(!f.Getc(&ch)) break; } } buffer[c] = 0; //if(strchr(buffer, '.')) if(result == syntaxError) return result; if(!type) return success; result = syntaxError; // TOFIX: How to swiftly handle classes with base data type? if(type == class(double) || !strcmp(type.dataTypeString, "double")) { value.d = strtod(buffer, null); result = success; } else if(type == class(float) || !strcmp(type.dataTypeString, "float")) { value.f = (float)strtod(buffer, null); result = success; } // TOFIX: int64 looks for class long long? //else if(type == class(int64) || !strcmp(type.dataTypeString, "int64")) else if(!strcmp(type.dataTypeString, "int64")) { value.i64 = strtol(buffer, null, eCON ? 0 : 10); // TOFIX: 64 bit support result = success; } else if(type == class(uint64) || !strcmp(type.dataTypeString, "uint64")) { value.ui64 = strtoul(buffer, null, eCON ? 0 : 10); // TOFIX: 64 bit support result = success; } else if(type == class(uint) || !strcmp(type.dataTypeString, "unsigned int")) { value.ui = (uint)strtoul(buffer, null, eCON ? 0 : 10); // TOFIX: 64 bit support result = success; } else { value.i = (int)strtol(buffer, null, eCON ? 0 : 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; if(!strcmp(prop.name, type.base.fullName)) refProp = true; else { Class c = eSystem_FindClass(type.module, prop.name); if(!c) c = eSystem_FindClass(type.module.application, prop.name); if(c) { 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; } JSONResult GetColorAlpha(String string, DataValue value) { ColorAlpha color = 0; DefinedColor c = 0; if(string) { if(string[0] == '0' && string[1] == 'x') color = (uint)strtoul(string, null, 0); else { char *d; byte a = 255; if((d = strchr(string, ','))) { a = (byte)atoi(string); d += 2; } else d = string; if(c.class::OnGetDataFromString(d)) { color.a = a; color.color = c; } else color = (uint)strtoul(string, null, 16); } } value.i = color; return success; } } static bool WriteMap(File f, Class type, Map map, int indent, bool eCON) { if(map) { int i; bool isFirst = true; MapIterator it { map = map }; Class mapNodeClass = map._class.templateArgs[0].dataTypeClass; f.Puts("[\n"); indent++; while(it.Next()) { MapNode n = (MapNode)it.pointer; if(!isFirst) f.Puts(",\n"); else isFirst = false; for(i = 0; i bases { }; if(objectType.templateClass && eClass_IsDerived(objectType.templateClass, class(MapNode))) { mapKeyClass = objectType.templateArgs[0].dataTypeClass; mapDataClass = objectType.templateArgs[2].dataTypeClass; } if(eCON && _class != objectType && eClass_IsDerived(_class, objectType)) { f.Puts(_class.name); f.Puts(" "); } f.Puts("{\n"); indent++; for(baseClass = _class; baseClass; baseClass = baseClass.base) { if(baseClass.isInstanceClass || !baseClass.base) break; bases.Insert(null, baseClass); } for(baseClass : bases) { for(prop = baseClass.membersAndProperties.first; prop; prop = prop.next) { if(prop.memberAccess != publicAccess || (prop.isProperty && (!prop.Set || !prop.Get))) continue; if(prop.isProperty) { if(!prop.conversion && (!prop.IsSet || prop.IsSet(object))) { DataValue value { }; bool isTemplateArg = false; Class type; if(mapKeyClass && !strcmp(prop.name, "key")) { isTemplateArg = true; type = mapKeyClass; } else if(mapDataClass && !strcmp(prop.name, "value")) { isTemplateArg = true; type = mapDataClass; } else type = superFindClass(prop.dataTypeString, _class.module); if(!type) PrintLn("warning: Unresolved data type ", (String)prop.dataTypeString); else { if(type.type == enumClass || type.type == bitClass || type.type == unitClass || type.type == systemClass) { // TOFIX: How to swiftly handle classes with base data type? if(type == class(double) || !strcmp(type.dataTypeString, "double")) { value.d = ((double (*)(void *))(void *)prop.Get)(object); } else if(type == class(float) || !strcmp(type.dataTypeString, "float")) { value.f = ((float (*)(void *))(void *)prop.Get)(object); } else if(type.typeSize == sizeof(int64) || !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64")) { value.ui64 = ((uint64 (*)(void *))(void *)prop.Get)(object); } else if(type.typeSize == sizeof(int) || !strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") || !strcmp(type.dataTypeString, "uint")) { value.i = ((int (*)(void *))(void *)prop.Get)(object); } else if(type.typeSize == sizeof(short int) || !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") || !strcmp(type.dataTypeString, "int16")) { value.s = ((short (*)(void *))(void *)prop.Get)(object); } else if(type.typeSize == sizeof(byte) || !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte")) { 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 { if(isTemplateArg) value.p = (void *)(uintptr)((uint64 (*)(void *))(void *)prop.Get)(object); else value.p = ((void *(*)(void *))(void *)prop.Get)(object); } if(!isFirst) f.Puts(",\n"); for(c = 0; c