153 lines
5.3 KiB
C#
153 lines
5.3 KiB
C#
using SessionZero.SzfLib.File;
|
|
using SessionZero.SzfLib.Helpers;
|
|
using SessionZero.SzfLib.Objects;
|
|
|
|
namespace SessionZero.SzfLib.Parser;
|
|
|
|
public class SzfParser : ISzfParser
|
|
{
|
|
/// <summary>
|
|
/// Tries to parse an ISzfObject
|
|
/// </summary>
|
|
/// <param name="szfContent"></param>
|
|
/// <returns></returns>
|
|
/// <exception cref="SzfError"></exception>
|
|
public ISzfObject? Parse(string szfContent)
|
|
{
|
|
SzfError result = new();
|
|
|
|
var lines = szfContent.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
|
|
|
|
string szfObjectTypeName = string.Empty;
|
|
Type? szfObjectType = null;
|
|
string szfVersion = "1.0.0";
|
|
var sections = new Dictionary<string, SzfSection>();
|
|
|
|
for (int idx = 0; idx < lines.Length; idx++)
|
|
{
|
|
var line = lines[idx].Trim();
|
|
|
|
if (line.StartsWith("#") || string.IsNullOrWhiteSpace(line)) continue;
|
|
|
|
if (line.StartsWith("!type:", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
var typeIdentifier = line.Substring("!type:".Length).Trim();
|
|
szfObjectTypeName = typeIdentifier;
|
|
szfObjectType = SzfHelper.FindSzfObjectTypeByAttributeType(typeIdentifier);
|
|
continue;
|
|
}
|
|
|
|
if (line.StartsWith("!schema:", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
var version = line.Substring("!schema:".Length).Trim();
|
|
if (!string.IsNullOrEmpty(version)) szfVersion = version;
|
|
continue;
|
|
}
|
|
|
|
if (line.StartsWith("[") && line.EndsWith("]"))
|
|
{
|
|
var sectionName = line.Substring(1, line.Length - 2).Trim();
|
|
var sectionFields = new List<string>();
|
|
|
|
int i = idx + 1;
|
|
while (i < lines.Length && !(lines[i].Trim().StartsWith("[") && lines[i].Trim().EndsWith("]")))
|
|
{
|
|
var fieldLine = lines[i].Trim();
|
|
if (!string.IsNullOrWhiteSpace(fieldLine) && !fieldLine.StartsWith("#")) sectionFields.Add(fieldLine);
|
|
i++;
|
|
}
|
|
|
|
idx = i - 1;
|
|
|
|
CreateSection(sectionName, sectionFields, sections);
|
|
}
|
|
}
|
|
|
|
if (szfObjectType != null && sections.Count > 0)
|
|
{
|
|
var szfObject = (ISzfObject)Activator.CreateInstance(szfObjectType)!;
|
|
|
|
szfObject.SzfType = szfObjectTypeName;
|
|
szfObject.SzfVersion = szfVersion;
|
|
|
|
// Only add root sections (those without a dot in their name)
|
|
foreach (var section in sections.Values.Where(s => !sections.Keys.Any(k => k.EndsWith("." + s.Name))))
|
|
{
|
|
szfObject.Sections.Add(section);
|
|
}
|
|
|
|
result = szfObject.Validate();
|
|
|
|
if (result.IsValid) return szfObject;
|
|
|
|
Console.WriteLine(result.Message);
|
|
}
|
|
|
|
throw result;
|
|
}
|
|
|
|
public ISzfObject? Parse(ISzfFile file)
|
|
{
|
|
if (file == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(file), "File cannot be null.");
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(file.Content))
|
|
{
|
|
throw new ArgumentException("File content cannot be null or empty.", nameof(file.Content));
|
|
}
|
|
|
|
return Parse(file.Content);
|
|
}
|
|
|
|
private SzfSection CreateSection(string sectionPath, IEnumerable<string> fields, Dictionary<string, SzfSection> sections)
|
|
{
|
|
var nameParts = sectionPath.Split('.');
|
|
SzfSection? parent = null;
|
|
|
|
string currentPath = "";
|
|
for (int p = 0; p < nameParts.Length; p++)
|
|
{
|
|
currentPath = currentPath == "" ? nameParts[p] : currentPath + "." + nameParts[p];
|
|
if (!sections.TryGetValue(currentPath, out var section))
|
|
{
|
|
section = new SzfSection(nameParts[p]);
|
|
sections[currentPath] = section;
|
|
if (parent != null) parent.Subsections[nameParts[p]] = section;
|
|
}
|
|
|
|
parent = section;
|
|
}
|
|
|
|
foreach (var field in fields)
|
|
{
|
|
var szfField = CreateField(field);
|
|
parent!.Fields.Add(szfField.Name, szfField);
|
|
}
|
|
|
|
return parent!;
|
|
}
|
|
|
|
private SzfField CreateField(string field)
|
|
{
|
|
// Expected format: FieldName (type) = Value
|
|
int typeStart = field.IndexOf('(');
|
|
int typeEnd = field.IndexOf(')');
|
|
if (typeStart < 0 || typeEnd < 0 || typeEnd < typeStart) throw new FormatException($"Invalid field format: {field}");
|
|
|
|
string fieldName = field.Substring(0, typeStart).Trim();
|
|
string fieldType = field.Substring(typeStart + 1, typeEnd - typeStart - 1).Trim().Replace("-", string.Empty);
|
|
|
|
// Find the first '=' after the closing parenthesis
|
|
int eqIndex = field.IndexOf('=', typeEnd + 1);
|
|
string fieldValue = eqIndex >= 0 ? field.Substring(eqIndex + 1).Trim() : string.Empty;
|
|
|
|
if (!Enum.TryParse(fieldType, true, out SzfFieldType type)) throw new FormatException($"Invalid field type: {fieldType}");
|
|
|
|
SzfField szfField = new(fieldName, type) { Value = fieldValue };
|
|
return szfField;
|
|
}
|
|
|
|
|
|
} |