private static void Parse(Tokenizer tokenizer, object current, IniTypeDescription type) { Tokenizer.Token token; string name; TypeHash subType; IniTypeDescription childType = null; IniTypeAndAlias[] typeAndAliases; IniTypeAndAlias typeAndAlias; Match match; object subObject; CommonParser.GoToValue(tokenizer); Dictionary<string, int> attributeSetCheck = new Dictionary<string, int>(type.Items.Length); for (int idx = 0; idx < type.Items.Length; ++idx) { attributeSetCheck.Add(type.Items[idx].Name, 0); } while ((token = tokenizer.Current()).Type != EXPRESSION_OBJECTEND) { if (token.Type != EXPRESSION_ATTRIBUTE) { throw new OpenSAGEException(ErrorCode.IniParser, "Token '$TOKEN$' was not recognized", "token", token); } name = _attributeId.Match(token.Value).Groups["name"].Value; IIniDescription itemDescription = null; for (int idx = 0; idx < type.Items.Length; ++idx) { if (type.Items[idx].Name == name) { itemDescription = type.Items[idx]; break; } } if (itemDescription == null) { throw new OpenSAGEException(ErrorCode.IniParser, "No property named $NAME$ can be found.", "name", name); } token = tokenizer.Next(); if (itemDescription is IniPropertyDescription) { object result; if (!(itemDescription as IniPropertyDescription).TheParseHandler(tokenizer, (itemDescription as IniPropertyDescription).ItemType, out result)) { throw new OpenSAGEException(ErrorCode.IniParser, "Could not parse property named $NAME$.", "name", name); } if (itemDescription.MaxOccurrences == 1) { itemDescription.Property.SetValue(current, result); } else { if (itemDescription.Property.PropertyType.IsArray) { Array testArray = itemDescription.Property.GetValue(current) as Array; if (attributeSetCheck[name] == testArray.Length) { throw new OpenSAGEException(ErrorCode.IniParser, "Attribute $NAME$ was set more times than its array length ($LENGTH$).", "name", itemDescription.Name, "length", testArray.Length); } (itemDescription.Property.GetValue(current) as Array).SetValue(result, attributeSetCheck[name]); } else { itemDescription.Property.PropertyType.GetMethod("Add").Invoke(itemDescription.Property.GetValue(current), new[] { result }); } } } else { if (token.Type != EXPRESSION_OBJECTSTART) { throw new OpenSAGEException(ErrorCode.IniParser, "Token '$TOKEN$' was not recognized", "token", token); } match = _objectTypeAndId.Match(token.Value); subType = match.Groups["type"].Value; typeAndAliases = (itemDescription as IniTypePropertyDescription).TypeOptions; typeAndAlias = null; for (int idx = 0; idx < typeAndAliases.Length; ++idx) { if (typeAndAliases[idx].Alias == subType) { typeAndAlias = typeAndAliases[idx]; } } if (typeAndAlias == null) { throw new OpenSAGEException(ErrorCode.IniParser, "No object of type $TYPE$ can be instanciated.", "type", subType.TheString); } childType = _descriptions.Find(x => x.Name == subType); if (typeAndAlias == null) { throw new OpenSAGEException(ErrorCode.IniParser, "No object of type $TYPE$ can be instanciated.", "type", subType.TheString); } subObject = Activator.CreateInstance(typeAndAlias.Type, match.Groups["id"].Value); tokenizer.Next(); Parse(tokenizer, subObject, childType); if (itemDescription.MaxOccurrences == 1) { itemDescription.Property.SetValue(current, subObject); } else { if (itemDescription.Property.PropertyType.IsArray) { Array testArray = itemDescription.Property.GetValue(current) as Array; if (attributeSetCheck[name] == testArray.Length) { throw new OpenSAGEException(ErrorCode.IniParser, "Attribute $NAME$ was set more times than its array length ($LENGTH$).", "name", itemDescription.Name, "length", testArray.Length); } (itemDescription.Property.GetValue(current) as Array).SetValue(subObject, attributeSetCheck[name]); } else { itemDescription.Property.PropertyType.GetMethod("Add").Invoke(itemDescription.Property.GetValue(current), new[] { subObject }); } } } ++attributeSetCheck[name]; tokenizer.Next(); CommonParser.GoToValue(tokenizer); } IIniDescription item; for (int idx = 0; idx < type.Items.Length; ++idx) { if ((item = type.Items[idx]).MinOccurrences != 0 && attributeSetCheck[item.Name] < item.MinOccurrences) { throw new OpenSAGEException(ErrorCode.IniParser, "Attribute $NAME$ was only set $OCCURRENCIES$ times but needs to be set at least $MIN$ times.", "name", item.Name, "occurrencies", attributeSetCheck[item.Name], "min", item.MinOccurrences); } if (item.MaxOccurrences != 0 && attributeSetCheck[item.Name] > item.MaxOccurrences) { throw new OpenSAGEException(ErrorCode.IniParser, "Attribute $NAME$ was set $OCCURRENCIES$ times but needs to be set at most $MAX$ times.", "name", item.Name, "occurrencies", attributeSetCheck[item.Name], "max", item.MaxOccurrences); } } tokenizer.Next(); }
public static void RegisterType(IniTypeDescription description) { _descriptions.Add(description); }