ProjectArcade
515 строк · 16.1 Кб
1using System;2using System.Collections.Generic;3using System.Linq;4using System.Text;5using System.IO;6using System.Xml.Linq;7using System.Dynamic;8
9namespace EmulatorLauncher.Common.FileFormats10{
11public class ConfigFile : DynamicObject, IEnumerable<ConfigItem>12{13public ConfigFileOptions Options { get; set; }14
15public static ConfigFile FromArguments(string[] args)16{17ConfigFile arguments = new ConfigFile();18
19string current = null;20foreach (string arg in args)21{22if (arg.StartsWith("-"))23current = arg.Substring(1);24else if (!string.IsNullOrEmpty(current))25{26arguments[current] = arg;27current = null;28}29else30arguments["rom"] = arg;31}32
33return arguments;34}35
36public static ConfigFile LoadEmulationStationSettings(string file)37{38var ret = new ConfigFile();39if (!File.Exists(file))40return ret;41
42try43{44XDocument doc = XDocument.Load(file);45
46foreach (XElement element in doc.Root.Descendants())47{48if (element.Attribute("name") != null && element.Attribute("value") != null)49{50string name = element.Attribute("name").Value;51string val = element.Attribute("value").Value;52ret[name] = val;53}54}55}56catch { }57
58return ret;59}60
61private static string EmptyLine = "------------EmptyLine----------------";62
63public static ConfigFile FromFile(string file, ConfigFileOptions options = null)64{65var ret = new ConfigFile();66ret.Options = options;67if (!File.Exists(file))68return ret;69
70bool keepComments = options != null && options.KeepComments;71
72foreach (var line in File.ReadAllLines(file))73{74bool skip = false;75
76foreach (var chr in line)77{78if (chr == '#' || chr == ';')79{80skip = true;81break;82}83
84if (chr != ' ' && chr != '\t')85break;86}87
88if (skip && !keepComments)89continue;90
91bool doubleEquals = options != null && options.UseDoubleEqual;92
93int idx = doubleEquals ? line.IndexOf("==", StringComparison.Ordinal) : line.IndexOf("=", StringComparison.Ordinal);94if (idx >= 0)95{96string value = line.Substring(idx + (doubleEquals ? 2 : 1)).Trim();97if (value.StartsWith("\""))98value = value.Substring(1);99
100if (value.EndsWith("\""))101value = value.Substring(0, value.Length-1);102
103ret[line.Substring(0, idx).Trim()] = value;104}105else106ret[line] = EmptyLine;107}108
109return ret;110}111
112public void ImportOverrides(ConfigFile cfg)113{114if (cfg == null)115return;116
117foreach (var item in cfg._data.Values)118this[item.Name] = item.Value;119}120
121public string GetFullPath(string key)122{123string data = this[key];124if (string.IsNullOrEmpty(data))125{126if (key == "home" && Directory.Exists(Path.Combine(LocalPath, ".emulationstation")))127return Path.Combine(LocalPath, ".emulationstation");128
129if (key == "bios" || key == "saves" || key == "thumbnails" || key == "shaders" || key == "decorations" || key == "screenshots" || key == "roms" || key == "records" || key == "cheats")130{131if (Directory.Exists(Path.GetFullPath(Path.Combine(LocalPath, "..", key))))132return Path.Combine(Path.GetFullPath(Path.Combine(LocalPath, "..", key)));133}134else if (key == "projectarcade")135{136if (Directory.Exists(Path.GetFullPath(Path.Combine(LocalPath))))137return Path.Combine(Path.GetFullPath(Path.Combine(LocalPath, "..")));138}139else140{141if (Directory.Exists(Path.GetFullPath(Path.Combine(LocalPath, key))))142return Path.Combine(Path.GetFullPath(Path.Combine(LocalPath, key)));143
144if (Directory.Exists(Path.GetFullPath(Path.Combine(LocalPath, "..", "emulators", key))))145return Path.Combine(Path.GetFullPath(Path.Combine(LocalPath, "..", "emulators", key)));146
147if (Directory.Exists(Path.GetFullPath(Path.Combine(LocalPath, "..", "system", "emulators", key))))148return Path.Combine(Path.GetFullPath(Path.Combine(LocalPath, "..", "system", "emulators", key)));149
150if (Directory.Exists(Path.GetFullPath(Path.Combine(LocalPath, "..", "system", key))))151return Path.Combine(Path.GetFullPath(Path.Combine(LocalPath, "..", "system", key)));152}153
154return string.Empty;155}156
157if (data.Contains(":")) // drive letter -> Full path158return data;159
160if (Directory.Exists(Path.GetFullPath(Path.Combine(LocalPath, data))))161return Path.Combine(Path.GetFullPath(Path.Combine(LocalPath, data)));162
163if (Directory.Exists(Path.GetFullPath(Path.Combine(LocalPath, "..", "emulators", data))))164return Path.Combine(Path.GetFullPath(Path.Combine(LocalPath, "..", "emulators", data)));165
166if (Directory.Exists(Path.GetFullPath(Path.Combine(LocalPath, "..", "system", "emulators", data))))167return Path.Combine(Path.GetFullPath(Path.Combine(LocalPath, "..", "system", "emulators", data)));168
169if (Directory.Exists(Path.GetFullPath(Path.Combine(LocalPath, "..", "system", data))))170return Path.Combine(Path.GetFullPath(Path.Combine(LocalPath, "..", "system", data)));171
172return data;173}174
175private OrderedDictionary<string, ConfigItem> _data = new OrderedDictionary<string, ConfigItem>();176
177public ConfigFile() { }178
179private string FormatKey(string key)180{181if (string.IsNullOrEmpty(key))182return key;183
184if (Options != null && Options.CaseSensitive)185return key.Trim();186
187return key.ToLowerInvariant().Trim();188}189
190public string this[string key]191{192get193{194if (!string.IsNullOrEmpty(key))195{196ConfigItem item;197if (_data.TryGetValue(FormatKey(key), out item) && item != null)198if (item.Value != EmptyLine)199return item.Value;200}201
202return string.Empty;203}204set205{206var indexKey = key;207
208if (string.IsNullOrEmpty(indexKey) && value == EmptyLine)209{210if (this.Options == null || !Options.KeepEmptyLines)211return;212
213indexKey = EmptyLine + Guid.NewGuid();214}215else216indexKey = FormatKey(key);217
218ConfigItem item;219if (!_data.TryGetValue(indexKey, out item) || item == null)220{221if ((this.Options == null || !Options.KeepEmptyValues) && string.IsNullOrEmpty(value))222return;223
224item = new ConfigItem() { Name = key, Value = value };225_data.Add(indexKey, item);226return;227}228
229if ((this.Options == null || !Options.KeepEmptyValues) && string.IsNullOrEmpty(value))230_data.Remove(indexKey);231else if (item.Value != value)232{233item.Value = value;234IsDirty = true;235}236}237}238
239public string GetValueOrDefault(string key, string defaultValue)240{241ConfigItem item;242if (_data.TryGetValue(FormatKey(key), out item) && item != null)243if (!string.IsNullOrEmpty(item.Value))244return item.Value;245
246return defaultValue;247}248
249public virtual bool IsDirty { get; protected set; }250
251public override string ToString()252{253StringBuilder sb = new StringBuilder();254
255string equalSign = this.Options != null && this.Options.UseDoubleEqual ? "==" : "=";256bool useSpaces = this.Options != null && this.Options.UseSpaces;257bool useQuotes = this.Options != null && this.Options.UseQuotes;258
259foreach (var item in _data.Values)260{261sb.Append(item.Name);262
263if (item.Value == EmptyLine)264{265sb.AppendLine();266continue;267}268
269if (useSpaces)270{271sb.Append(" ");272sb.Append(equalSign);273sb.Append(" ");274}275else276sb.Append(equalSign);277
278if (useQuotes)279sb.Append("\"");280
281sb.Append(item.Value);282
283if (useQuotes)284sb.Append("\"");285
286sb.AppendLine();287}288
289return sb.ToString();290}291
292public void Save(string fileName, bool retroarchformat = false)293{294if (retroarchformat)295{296if (this.Options == null)297this.Options = new ConfigFileOptions();298
299this.Options.UseDoubleEqual = false;300this.Options.UseQuotes = true;301this.Options.UseSpaces = true;302
303}304
305string text = ToString();306File.WriteAllText(fileName, text);307}308
309public ConfigFile LoadAll(string key)310{311ConfigFile ret = new ConfigFile();312
313if (string.IsNullOrEmpty(key))314return ret;315
316key = FormatKey(key) + ".";317
318foreach (var item in _data.Values)319if (item.Name.StartsWith(key, StringComparison.InvariantCultureIgnoreCase))320ret[item.Name.Substring(key.Length)] = item.Value;321
322return ret;323}324
325public bool isOptSet(string key)326{327if (string.IsNullOrEmpty(key))328return false;329
330return _data.ContainsKey(FormatKey(key));331}332
333public bool getOptBoolean(string key)334{335if (string.IsNullOrEmpty(key))336return false;337
338ConfigItem item;339if (_data.TryGetValue(FormatKey(key), out item) && item != null)340return item.Value != null && (item.Value.ToLower() == "true" || item.Value == "1" || item.Value.ToLower() == "enabled");341
342return false;343}344
345public int getInteger(string key)346{347if (string.IsNullOrEmpty(key))348return 0;349
350ConfigItem item;351if (_data.TryGetValue(FormatKey(key), out item) && item != null)352{353int ret;354if (int.TryParse(item.Value, out ret))355return ret;356}357
358return 0;359}360
361public IEnumerator<ConfigItem> GetEnumerator()362{363return _data.Values.GetEnumerator();364}365
366System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()367{368return _data.Values.GetEnumerator();369}370
371public void DisableAll(string key)372{373if (string.IsNullOrEmpty(key))374return;375
376List<string> toRemove = new List<string>();377
378key = FormatKey(key);379
380foreach (var item in _data)381if (item.Value.Name != EmptyLine && item.Key.Contains(key))382toRemove.Add(item.Key);383
384foreach (var item in toRemove)385_data.Remove(item);386}387
388public static string LocalPath389{390get391{392if (_localPath == null)393_localPath = Path.GetDirectoryName(typeof(ConfigFile).Assembly.Location);394
395return _localPath;396}397}398
399public void AppendLine(string line)400{401_data.Add(EmptyLine + Guid.NewGuid().ToString(), new ConfigItem()402{403Name = line,404Value = EmptyLine405});406}407
408private static string _localPath;409
410#region DynamicObject411public override IEnumerable<string> GetDynamicMemberNames()412{413PartialConfigFile me = this as PartialConfigFile;414if (me != null)415{416return _data417.Where(d => !string.IsNullOrEmpty(d.Value.Name) && d.Value != null && d.Value.Name.StartsWith(me.Root))418.Select(d => d.Value.Name);419}420
421return _data.Where(d => !string.IsNullOrEmpty(d.Value.Name) && d.Value != null).Select(d => d.Value.Name);422}423
424class PartialConfigFile : ConfigFile425{426public PartialConfigFile(ConfigFile parent, string root)427{428_parent = parent;429Root = root;430}431
432private ConfigFile _parent;433public string Root { get; set; }434
435public override bool IsDirty436{437get { return _parent.IsDirty; }438protected set { _parent.IsDirty = value; }439}440}441
442public override bool TryGetMember(GetMemberBinder binder, out object result)443{444string propertyPath = binder.Name;445
446PartialConfigFile me = this as PartialConfigFile;447if (me != null)448propertyPath = me.Root + propertyPath;449
450ConfigItem item;451if (_data.TryGetValue(FormatKey(propertyPath), out item))452{453result = item.Value;454return true;455}456
457var root = propertyPath + ".";458
459if (_data.Values.Any(v => v.Name != null && v.Name.StartsWith(root)))460{461result = new PartialConfigFile(this, root) { _data = this._data };462return true;463}464
465result = null;466return true;467}468
469public override bool TrySetMember(SetMemberBinder binder, object value)470{471string propertyPath = binder.Name;472
473PartialConfigFile me = this as PartialConfigFile;474if (me != null)475propertyPath = me.Root + propertyPath;476
477if (value == null)478this.DisableAll(propertyPath);479else480this[propertyPath] = value.ToString();481
482return true;483}484#endregion485
486}487
488public class ConfigItem489{490public override string ToString()491{492return Name + " = " + Value;493}494
495public string Name { get; set; }496public string Value { get; set; }497}498
499public class ConfigFileOptions500{501public ConfigFileOptions()502{503KeepEmptyValues = true;504}505
506public bool KeepEmptyLines { get; set; }507public bool KeepEmptyValues { get; set; }508public bool KeepComments { get; set; }509public bool CaseSensitive { get; set; }510public bool UseDoubleEqual { get; set; }511public bool UseSpaces { get; set; }512public bool UseQuotes { get; set; }513
514}515}
516