A game framework written with osu! in mind.
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
2// See the LICENCE file in the repository root for full licence text.
3
4using System;
5using System.Collections.Generic;
6using System.IO;
7using osu.Framework.Bindables;
8using osu.Framework.Extensions.ObjectExtensions;
9using osu.Framework.Extensions.TypeExtensions;
10using osu.Framework.Logging;
11using osu.Framework.Platform;
12
13namespace osu.Framework.Configuration
14{
15 public class IniConfigManager<TLookup> : ConfigManager<TLookup>
16 where TLookup : struct, Enum
17 {
18 /// <summary>
19 /// The backing file used to store the config. Null means no persistent storage.
20 /// </summary>
21 protected virtual string Filename => @"game.ini";
22
23 private readonly Storage storage;
24
25 public IniConfigManager(Storage storage, IDictionary<TLookup, object> defaultOverrides = null)
26 : base(defaultOverrides)
27 {
28 this.storage = storage;
29
30 InitialiseDefaults();
31 Load();
32 }
33
34 protected override void PerformLoad()
35 {
36 if (string.IsNullOrEmpty(Filename)) return;
37
38 using (var stream = storage.GetStream(Filename))
39 {
40 if (stream == null)
41 return;
42
43 using (var reader = new StreamReader(stream))
44 {
45 string line;
46
47 while ((line = reader.ReadLine()) != null)
48 {
49 int equalsIndex = line.IndexOf('=');
50
51 if (line.Length == 0 || line[0] == '#' || equalsIndex < 0) continue;
52
53 string key = line.AsSpan(0, equalsIndex).Trim().ToString();
54 string val = line.AsSpan(equalsIndex + 1).Trim().ToString();
55
56 if (!Enum.TryParse(key, out TLookup lookup))
57 continue;
58
59 if (ConfigStore.TryGetValue(lookup, out IBindable b))
60 {
61 try
62 {
63 if (!(b is IParseable parseable))
64 throw new InvalidOperationException($"Bindable type {b.GetType().ReadableName()} is not {nameof(IParseable)}.");
65
66 parseable.Parse(val);
67 }
68 catch (Exception e)
69 {
70 Logger.Log($@"Unable to parse config key {lookup}: {e}", LoggingTarget.Runtime, LogLevel.Important);
71 }
72 }
73 else if (AddMissingEntries)
74 SetDefault(lookup, val);
75 }
76 }
77 }
78 }
79
80 protected override bool PerformSave()
81 {
82 if (string.IsNullOrEmpty(Filename)) return false;
83
84 try
85 {
86 using (var stream = storage.GetStream(Filename, FileAccess.Write, FileMode.Create))
87 using (var w = new StreamWriter(stream))
88 {
89 foreach (var p in ConfigStore)
90 w.WriteLine(@"{0} = {1}", p.Key, p.Value.ToString().AsNonNull().Replace("\n", "").Replace("\r", ""));
91 }
92 }
93 catch
94 {
95 return false;
96 }
97
98 return true;
99 }
100 }
101}