mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-10 12:32:20 +02:00
Simple XML support, string-to-num conversions
This commit is contained in:
parent
bdff67509c
commit
7ef88f4b9c
1 changed files with 327 additions and 47 deletions
|
@ -470,6 +470,7 @@ namespace Beefy.utils
|
|||
Object val = Get(name);
|
||||
|
||||
outString.Clear();
|
||||
|
||||
if (val is uint64)
|
||||
val.ToString(outString);
|
||||
|
||||
|
@ -493,61 +494,112 @@ namespace Beefy.utils
|
|||
return;
|
||||
}
|
||||
|
||||
public int32 GetInt(String name, int32 theDefault = 0)
|
||||
{
|
||||
Object aVal = Get(name);
|
||||
if ((aVal == null) || (!(aVal is int64)))
|
||||
return theDefault;
|
||||
return (int32)(int64)aVal;
|
||||
}
|
||||
|
||||
public int64 GetLong(String name, int64 theDefault = 0)
|
||||
{
|
||||
Object aVal = Get(name);
|
||||
|
||||
if (aVal is int32)
|
||||
return (int64)(int32)aVal;
|
||||
|
||||
if ((aVal == null) || (!(aVal is int64)))
|
||||
return theDefault;
|
||||
return (int64)aVal;
|
||||
}
|
||||
|
||||
public uint64 GetULong(String name, uint64 theDefault = 0)
|
||||
{
|
||||
Object aVal = Get(name);
|
||||
|
||||
if (aVal is int32)
|
||||
return (uint64)(int32)aVal;
|
||||
if (aVal is int64)
|
||||
return (uint64)(int64)aVal;
|
||||
|
||||
if ((aVal == null) || (!(aVal is uint64)))
|
||||
return theDefault;
|
||||
return (uint64)aVal;
|
||||
}
|
||||
|
||||
public float GetFloat(String name, float theDefault = 0)
|
||||
public int32 GetInt(String name, int32 defaultVal = 0)
|
||||
{
|
||||
Object val = Get(name);
|
||||
if (val == null)
|
||||
return theDefault;
|
||||
if (val == null)
|
||||
return defaultVal;
|
||||
switch (val.GetType())
|
||||
{
|
||||
case typeof(Float): return (float)val;
|
||||
case typeof(Int32): return (int32)val;
|
||||
case typeof(Int64): return (int64)val;
|
||||
case typeof(Int): return (int)val;
|
||||
default: return theDefault;
|
||||
case typeof(Float): return (.)(float)val;
|
||||
case typeof(Int32): return (.)(int32)val;
|
||||
case typeof(Int64): return (.)(int64)val;
|
||||
case typeof(Int): return (.)(int)val;
|
||||
case typeof(String):
|
||||
if (int32.Parse((String)val) case .Ok(var fVal))
|
||||
return (.)fVal;
|
||||
return defaultVal;
|
||||
case typeof(StringView):
|
||||
if (int32.Parse((StringView)val) case .Ok(var fVal))
|
||||
return (.)fVal;
|
||||
return defaultVal;
|
||||
default: return defaultVal;
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetBool(String name, bool theDefault = false)
|
||||
public int64 GetLong(String name, int64 defaultVal = 0)
|
||||
{
|
||||
Object aVal = Get(name);
|
||||
if ((aVal == null) || (!(aVal is bool)))
|
||||
return theDefault;
|
||||
return (bool)aVal;
|
||||
Object val = Get(name);
|
||||
if (val == null)
|
||||
return defaultVal;
|
||||
switch (val.GetType())
|
||||
{
|
||||
case typeof(Float): return (.)(float)val;
|
||||
case typeof(Int32): return (.)(int32)val;
|
||||
case typeof(Int64): return (.)(int64)val;
|
||||
case typeof(Int): return (.)(int)val;
|
||||
case typeof(String):
|
||||
if (int64.Parse((String)val) case .Ok(var parsedVal))
|
||||
return (.)parsedVal;
|
||||
return defaultVal;
|
||||
case typeof(StringView):
|
||||
if (int64.Parse((StringView)val) case .Ok(var parsedVal))
|
||||
return (.)parsedVal;
|
||||
return defaultVal;
|
||||
default: return defaultVal;
|
||||
}
|
||||
}
|
||||
|
||||
public uint64 GetULong(String name, uint64 defaultVal = 0)
|
||||
{
|
||||
Object val = Get(name);
|
||||
if (val == null)
|
||||
return defaultVal;
|
||||
switch (val.GetType())
|
||||
{
|
||||
case typeof(Float): return (.)(float)val;
|
||||
case typeof(Int32): return (.)(int32)val;
|
||||
case typeof(Int64): return (.)(int64)val;
|
||||
case typeof(Int): return (.)(int)val;
|
||||
case typeof(String):
|
||||
if (int64.Parse((String)val) case .Ok(var parsedVal))
|
||||
return (.)parsedVal;
|
||||
return defaultVal;
|
||||
case typeof(StringView):
|
||||
if (int64.Parse((StringView)val) case .Ok(var parsedVal))
|
||||
return (.)parsedVal;
|
||||
return defaultVal;
|
||||
default: return defaultVal;
|
||||
}
|
||||
}
|
||||
|
||||
public float GetFloat(String name, float defaultVal = 0)
|
||||
{
|
||||
Object val = Get(name);
|
||||
if (val == null)
|
||||
return defaultVal;
|
||||
switch (val.GetType())
|
||||
{
|
||||
case typeof(Float): return (.)(float)val;
|
||||
case typeof(Int32): return (.)(int32)val;
|
||||
case typeof(Int64): return (.)(int64)val;
|
||||
case typeof(Int): return (.)(int)val;
|
||||
case typeof(String):
|
||||
if (float.Parse((String)val) case .Ok(var parsedVal))
|
||||
return parsedVal;
|
||||
return defaultVal;
|
||||
case typeof(StringView):
|
||||
if (float.Parse((StringView)val) case .Ok(var parsedVal))
|
||||
return parsedVal;
|
||||
return defaultVal;
|
||||
default: return defaultVal;
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetBool(String name, bool defaultVal = false)
|
||||
{
|
||||
Object val = Get(name);
|
||||
if (val == null)
|
||||
return defaultVal;
|
||||
switch (val.GetType())
|
||||
{
|
||||
case typeof(Boolean): return (bool)val;
|
||||
case typeof(String):
|
||||
if (bool.Parse((String)val) case .Ok(var parsedVal))
|
||||
return (.)parsedVal;
|
||||
return defaultVal;
|
||||
default: return defaultVal;
|
||||
}
|
||||
}
|
||||
|
||||
public T GetEnum<T>(String name, T defaultVal = default(T)) where T : enum
|
||||
|
@ -2347,6 +2399,223 @@ namespace Beefy.utils
|
|||
}
|
||||
}
|
||||
|
||||
Result<void, Error> LoadXMLHelper(String contentStr, Values values, ref int32 idx, ref int32 lineNum)
|
||||
{
|
||||
LoadSection loadRoot = scope LoadSection();
|
||||
loadRoot.mSectionDict = new Dictionary<String, LoadSection>();
|
||||
loadRoot.mCurrentEntry = CurrentEntry(values);
|
||||
//LoadSection loadSection = loadRoot;
|
||||
//CurrentEntry currentEntry = default;
|
||||
|
||||
char8* cPtr = contentStr.CStr();
|
||||
|
||||
char8 NextChar()
|
||||
{
|
||||
char8 c = cPtr[idx];
|
||||
if (c != 0)
|
||||
idx++;
|
||||
return c;
|
||||
}
|
||||
|
||||
char8* GetCharPtr()
|
||||
{
|
||||
return &cPtr[idx];
|
||||
}
|
||||
|
||||
char8 PeekNextChar()
|
||||
{
|
||||
return cPtr[idx];
|
||||
}
|
||||
|
||||
void EatWhiteSpace()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
char8 nextC = PeekNextChar();
|
||||
if ((nextC != ' ') && (nextC != '\t'))
|
||||
return;
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
void ReadSection(ref CurrentEntry arrayEntry)
|
||||
{
|
||||
char8* dataStart = null;
|
||||
|
||||
void FlushData()
|
||||
{
|
||||
if (dataStart != null)
|
||||
{
|
||||
StringView valueSV = StringView(dataStart, GetCharPtr() - dataStart - 1);
|
||||
valueSV.Trim();
|
||||
String value = new:mBumpAllocator String(valueSV);
|
||||
DoAdd(ref arrayEntry, value);
|
||||
}
|
||||
|
||||
dataStart = null;
|
||||
}
|
||||
|
||||
MainLoop: while (true)
|
||||
{
|
||||
char8 c = NextChar();
|
||||
if (c == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == '<')
|
||||
{
|
||||
FlushData();
|
||||
|
||||
EatWhiteSpace();
|
||||
c = PeekNextChar();
|
||||
if (c == '/')
|
||||
{
|
||||
// Is closing
|
||||
while (true)
|
||||
{
|
||||
c = NextChar();
|
||||
if ((c == 0) || (c == '>'))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NamedValues childNamedValues = null;
|
||||
CurrentEntry childTableEntry = default;
|
||||
|
||||
void EnsureChildEntry()
|
||||
{
|
||||
if (childNamedValues != null)
|
||||
return;
|
||||
childNamedValues = new:mBumpAllocator NamedValues();
|
||||
childTableEntry = CurrentEntry(childNamedValues);
|
||||
DoAdd(ref arrayEntry, childNamedValues);
|
||||
}
|
||||
|
||||
char8* namePtr = null;
|
||||
char8* nameEndPtr = null;
|
||||
char8* equalPtr = null;
|
||||
char8* valuePtr = null;
|
||||
|
||||
while (true)
|
||||
{
|
||||
c = NextChar();
|
||||
if (c.IsWhiteSpace)
|
||||
{
|
||||
if ((namePtr != null) && (nameEndPtr == null))
|
||||
nameEndPtr = GetCharPtr() - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (valuePtr != null)
|
||||
{
|
||||
if (c == '"')
|
||||
{
|
||||
EnsureChildEntry();
|
||||
StringView name = StringView(namePtr, nameEndPtr - namePtr + 1);
|
||||
name.Trim();
|
||||
StringView valueSV = StringView(valuePtr, GetCharPtr() - valuePtr - 1);
|
||||
String value = new:mBumpAllocator String(valueSV);
|
||||
DoAdd(ref childTableEntry, name, value);
|
||||
|
||||
namePtr = null;
|
||||
nameEndPtr = null;
|
||||
equalPtr = null;
|
||||
valuePtr = null;
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((c == '?') || (c == '/'))
|
||||
{
|
||||
// Wait for close. Not nested.
|
||||
while (true)
|
||||
{
|
||||
c = NextChar();
|
||||
if ((c == 0) || (c == '>'))
|
||||
continue MainLoop;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == '>')
|
||||
{
|
||||
// Closing, but we're nested
|
||||
EnsureChildEntry();
|
||||
Values childArrayValues = new:mBumpAllocator Values();
|
||||
CurrentEntry childArrayEntry = CurrentEntry(childArrayValues);
|
||||
DoAdd(ref childTableEntry, ".", childArrayValues);
|
||||
|
||||
ReadSection(ref childArrayEntry);
|
||||
continue MainLoop;
|
||||
}
|
||||
|
||||
if (namePtr == null)
|
||||
{
|
||||
namePtr = GetCharPtr() - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (equalPtr == null)
|
||||
{
|
||||
if (c == '=')
|
||||
{
|
||||
equalPtr = GetCharPtr() - 1;
|
||||
if (nameEndPtr == null)
|
||||
nameEndPtr = equalPtr - 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c == '"')
|
||||
{
|
||||
valuePtr = GetCharPtr();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (nameEndPtr == null)
|
||||
continue;
|
||||
|
||||
// Flush
|
||||
StringView name = StringView(namePtr, nameEndPtr - namePtr + 1);
|
||||
name.Trim();
|
||||
|
||||
if (name.IsEmpty)
|
||||
continue;
|
||||
|
||||
EnsureChildEntry();
|
||||
if (childTableEntry.mLastKey == -1)
|
||||
{
|
||||
Object value = new:mBumpAllocator String(name);
|
||||
DoAdd(ref childTableEntry, "", value);
|
||||
}
|
||||
else
|
||||
{
|
||||
Object value = new:mBumpAllocator box true;
|
||||
DoAdd(ref childTableEntry, name, value);
|
||||
}
|
||||
|
||||
namePtr = null;
|
||||
nameEndPtr = null;
|
||||
idx--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ((!c.IsWhiteSpace) && (dataStart == null))
|
||||
dataStart = GetCharPtr() - 1;
|
||||
}
|
||||
|
||||
FlushData();
|
||||
}
|
||||
|
||||
ReadSection(ref loadRoot.mCurrentEntry);
|
||||
|
||||
return .Ok;
|
||||
}
|
||||
|
||||
protected Result<void, Error> Load()
|
||||
{
|
||||
EnsureHasData();
|
||||
|
@ -2357,6 +2626,7 @@ namespace Beefy.utils
|
|||
mNextKeys.Reserve(guessItems);
|
||||
|
||||
bool isJson = false;
|
||||
bool isXml = false;
|
||||
bool mayBeJsonArray = false;
|
||||
for (char8 c in mSource.RawChars)
|
||||
{
|
||||
|
@ -2375,6 +2645,8 @@ namespace Beefy.utils
|
|||
{
|
||||
if (c == '{')
|
||||
isJson = true;
|
||||
if (c == '<')
|
||||
isXml = true;
|
||||
if (c == '[')
|
||||
{
|
||||
mayBeJsonArray = true;
|
||||
|
@ -2394,6 +2666,14 @@ namespace Beefy.utils
|
|||
return .Err(err);
|
||||
objResult = result.Get();
|
||||
}
|
||||
else if (isXml)
|
||||
{
|
||||
var values = new:mBumpAllocator Values();
|
||||
let result = LoadXMLHelper(mSource, values, ref anIdx, ref aLineNum);
|
||||
if (result case .Err(var err))
|
||||
return .Err(err);
|
||||
objResult = values;
|
||||
}
|
||||
else
|
||||
{
|
||||
var values = new:mBumpAllocator NamedValues();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue