private void InsertIntoData(int index, string value) { while (_parsedData.Count <= index) { _parsedData.Add(new ConfigValue(string.Empty, final: true)); } _parsedData[index] = new ConfigValue(value, final: true); }
private static ConfigValue CvDataFromCustom <T>(T value) { var str = value.ToString(); var escaped = ConfigValue.EscapeString(str); if (str.Count(char.IsWhiteSpace) != 0 || escaped != str || string.IsNullOrEmpty(escaped)) { escaped = $"\"{escaped}\""; } return(new ConfigValue(escaped)); }
private static T LoadToCollectionWrap <T>(ConfigValue config) where T : class, new() { var keys = config.GetKeys(); if (keys.Length > 1) { throw new FormatException("Array can only contains values with the same identifier"); } else if (keys.Length == 0) { return(new T()); } var elementsType = typeof(T).GetGenericArguments().Single(); var genericLoadToCollection = MethodLoadToCollection.MakeGenericMethod(typeof(T), elementsType); return((T)genericLoadToCollection.Invoke(null, new object[] { config.GetAll(keys[0]) })); }
private static void ParseLevel(State state, string baseIndentation) { ConfigValue lastConfigValue = null; while (state.Line < state.Data.Length) { var line = state.Data[state.Line].TrimEnd(); if (string.IsNullOrWhiteSpace(line)) { state.Line += 1; continue; } var lineIndentation = GetIndentation(line); ValidateIndentationLevel(state, lineIndentation, baseIndentation); if (lineIndentation.Length > baseIndentation.Length) { state.Context.Push(lastConfigValue); ParseLevel(state, lineIndentation); continue; } if (lineIndentation.Length < baseIndentation.Length) { state.Context.Pop(); break; } var data = line.Substring(lineIndentation.Length); var len = data.IndexOfAny(new[] { ' ', '\t' }); var name = len < 0 ? data : data.Substring(0, len); var value = len < 0 ? "" : data.Substring(len).Trim(); lastConfigValue = new ConfigValue(value); state.Context.Peek().Set( name, lastConfigValue ); state.Line += 1; } }
public static string SaveToString(ConfigValue config) { return(GenerateString(config, string.Empty)); }
public static void SaveToStream(ConfigValue config, TextWriter writer) { writer.Write(GenerateString(config, "")); }
/// <summary> /// Loads configuration to given Class type /// </summary> /// <typeparam name="T">Target class</typeparam> /// <param name="config">Configuration</param> /// <returns>Class, filled with configuration values oe null</returns> public static T LoadToClass <T>(ConfigValue config) where T : class, new() { if (config == null) { return(null); } if (typeof(T).GetInterfaces().Contains(typeof(ICollection))) { return(LoadToCollectionWrap <T>(config)); } var instance = new T(); foreach (var field in typeof(T).GetFields()) { var dataSourceAttribute = field.GetCustomAttribute <ConfigDataSourceAttribute>(); var path = dataSourceAttribute?.DataPath ?? field.Name.ToLowerInvariant(); if (!config.ContainsPath(path)) { // Skipping not relevant fields continue; } if (field.FieldType.GetTypeInfo().IsPrimitive || field.FieldType.GetConstructor(Type.EmptyTypes) == null) { var configValue = config.GetByPath(path); var genericAsCustom = configValue.AsConfigList().Count == 1 ? MethodAsCustom.MakeGenericMethod(field.FieldType) : MethodAsCustomFromRaw.MakeGenericMethod(field.FieldType); var value = genericAsCustom.Invoke(configValue, null); field.SetValue(instance, value); } else { var fieldType = field.FieldType; var typeSource = field.GetCustomAttribute <ConfigDataTypeSourceAttribute>(); var typeName = config.GetByPath(typeSource?.DataPath) ?.AsString() ?.ToLowerInvariant(); if (typeName != null) { var mapping = field.GetCustomAttributes <ConfigDataTypeMappingAttribute>(); fieldType = mapping ?.FirstOrDefault(attr => attr.TypeName == typeName) ?.FieldType ?? Assembly .GetEntryAssembly() .GetTypes() .Where(t => field.FieldType.IsAssignableFrom(t)) .FirstOrDefault(t => t.Name.ToLowerInvariant() == typeName) ?? throw new TypeLoadException( $"Can not find type with name '{typeName}'" ); } var genericLoadToClass = MethodLoadToClass.MakeGenericMethod(fieldType); var innerInstance = genericLoadToClass.Invoke(null, new object[] { config.GetByPath(path) }); field.SetValue(instance, innerInstance); } } return(instance); }
private static void SetByPathNamed (string path, ConfigValue root, ConfigValue value) { if (path == null || value == null) { return; } var pathLower = path.ToLowerInvariant().Trim().TrimStart('.'); var targetParent = root; var target = root; var name = ":"; while (!string.IsNullOrEmpty(pathLower)) { if (char.IsDigit(pathLower.FirstOrDefault())) { var indexStr = new string( pathLower.TakeWhile(char.IsDigit).ToArray() ); var sindex = int.Parse(indexStr, NumberStyles.Integer, CultureInfo.InvariantCulture); while (targetParent.GetAll(name).Count <= sindex) { targetParent.Set(name, ""); } pathLower = pathLower.Substring(indexStr.Length).Trim().TrimStart('.'); target = targetParent.GetAll(name)[sindex]; } else if (char.IsLetter(pathLower.First())) { var key = new string( pathLower.TakeWhile(char.IsLetter).ToArray() ); pathLower = pathLower.Substring(key.Length).Trim().TrimStart('.'); targetParent = target; if (!target.Contains(key)) { target.Set(key, Config.Create()); } target = target.Get(key); name = key; } else if (pathLower.First() == '$' && char.IsDigit(pathLower.ElementAtOrDefault(1))) { var indexStr = new string( pathLower.Skip(1).TakeWhile(char.IsDigit).ToArray() ); var sindex = int.Parse(indexStr, NumberStyles.Integer, CultureInfo.InvariantCulture); target.InsertIntoData(sindex, value._parsedData.First()._data); target._data = target.ParsedDataToRawString(); pathLower = pathLower.Substring(indexStr.Length + 1).Trim().TrimStart('.'); if (!string.IsNullOrEmpty(pathLower)) { throw new FormatException( $"Data arguments indexation must be the last operation. Rest: '{pathLower}'" ); } return; } else { throw new FormatException($"Unexpected symbol '{pathLower[0]}'({(byte)pathLower[0]})"); } } if (value._data != null) { target._data = value._data; target._parsedData = value._parsedData; } foreach (var val in value._values) { target._values.Add(val.Key, val.Value); } }
/// <summary> /// Saves new values with given name /// </summary> /// <param name="path">Path to the value</param> /// <param name="value"></param> /// <returns></returns> public ConfigValue SetByPath(string path, ConfigValue value) { SetByPathNamed(path, this, value); return(this); }