ProjectArcade
520 строк · 15.0 Кб
1using System;2using System.Collections;3using System.Collections.Generic;4using System.IO;5using System.Runtime.InteropServices;6using System.Text;7using System.Linq;8
9namespace EmulatorLauncher.Common.FileFormats10{
11[Flags]12public enum IniOptions13{14UseSpaces = 1,15KeepEmptyValues = 2,16AllowDuplicateValues = 4,17KeepEmptyLines = 8,18UseDoubleEqual = 16, // nosgba inifile uses double equals as separator !19}20
21public class IniFile : IDisposable22{23public static IniFile FromFile(string path, IniOptions options = (IniOptions) 0)24{25return new IniFile(path, options);26}27
28public IniFile(string path, IniOptions options = (IniOptions) 0)29{30_options = options;31_path = path;32_dirty = false;33
34if (!File.Exists(_path))35return;36
37try38{39using (TextReader iniFile = new StreamReader(_path))40{41Section currentSection = null;42
43var namesInSection = new HashSet<string>(StringComparer.OrdinalIgnoreCase);44
45string strLine = iniFile.ReadLine();46while (strLine != null)47{48strLine = strLine.Trim();49
50if (strLine != "" || _options.HasFlag(IniOptions.KeepEmptyLines))51{52if (strLine.StartsWith("["))53{54int end = strLine.IndexOf("]");55if (end > 0)56{57namesInSection.Clear();58currentSection = _sections.GetOrAddSection(strLine.Substring(1, end - 1));59}60}61else62{63string[] keyPair = _options.HasFlag(IniOptions.UseDoubleEqual) ? strLine.Split(new string[] { "==" }, 2, StringSplitOptions.None) : strLine.Split(new char[] { '=' }, 2);64
65if (currentSection == null)66{67namesInSection.Clear();68currentSection = _sections.GetOrAddSection(null);69}70
71var key = new Key();72key.Name = keyPair[0].Trim();73
74if (!key.IsComment && !_options.HasFlag(IniOptions.AllowDuplicateValues) && namesInSection.Contains(key.Name))75{76strLine = iniFile.ReadLine();77continue;78}79
80if (key.IsComment)81{82key.Name = strLine;83key.Value = null;84}85else if (keyPair.Length > 1)86{87namesInSection.Add(key.Name);88
89var commentIdx = keyPair[1].IndexOf(";");90if (commentIdx > 0)91{92key.Comment = keyPair[1].Substring(commentIdx);93keyPair[1] = keyPair[1].Substring(0, commentIdx);94}95
96key.Value = keyPair[1].Trim();97}98
99currentSection.Add(key);100}101}102
103strLine = iniFile.ReadLine();104}105
106iniFile.Close();107}108}109catch (Exception ex)110{111throw ex;112}113}114
115public IniSection GetOrCreateSection(string key)116{117return new PrivateIniSection(key, this);118}119
120class PrivateIniSection : IniSection { public PrivateIniSection(string name, IniFile ini) : base(name, ini) { } }121
122public string[] EnumerateSections()123{124return _sections.Select(s => s.Name).Distinct().ToArray();125}126
127public string[] EnumerateKeys(string sectionName)128{129var section = _sections.Get(sectionName);130if (section != null)131return section.Select(k => k.Name).ToArray();132
133return new string[] { };134}135
136public KeyValuePair<string, string>[] EnumerateValues(string sectionName)137{138var ret = new List<KeyValuePair<string, string>>();139
140var section = _sections.Get(sectionName);141if (section != null)142{143foreach (var item in section)144{145if (item.IsComment || string.IsNullOrEmpty(item.Name))146continue;147
148ret.Add(new KeyValuePair<string, string>(item.Name, item.Value));149}150}151
152return ret.ToArray();153}154
155public void ClearSection(string sectionName)156{157var section = _sections.Get(sectionName);158if (section != null && section.Any())159{160_dirty = true;161section.Clear();162}163}164
165public string GetValue(string sectionName, string key)166{167var section = _sections.Get(sectionName);168if (section != null)169return section.GetValue(key);170
171return null;172}173
174public void WriteValue(string sectionName, string keyName, string value)175{176var section = _sections.GetOrAddSection(sectionName);177
178var key = section.Get(keyName);179if (key != null && key.Value == value)180return;181
182if (key == null)183key = section.Add(keyName);184
185key.Value = value;186
187_dirty = true;188}189
190public void AppendValue(string sectionName, string keyName, string value)191{192if (!_options.HasFlag(IniOptions.AllowDuplicateValues))193{194WriteValue(sectionName, keyName, value);195return;196}197
198var section = _sections.GetOrAddSection(sectionName);199section.Add(keyName, value);200
201_dirty = true;202}203
204public void Remove(string sectionName, string keyName)205{206var section = _sections.Get(sectionName);207if (section != null)208{209foreach (var key in section.Where(k => k.Name.Equals(keyName, StringComparison.InvariantCultureIgnoreCase)).ToArray())210{211_dirty = true;212section.Remove(key);213}214}215}216
217public bool IsDirty { get { return _dirty; } }218
219public override string ToString()220{221ArrayList sections = new ArrayList();222
223StringBuilder sb = new StringBuilder();224
225foreach (var section in _sections)226{227if (!string.IsNullOrEmpty(section.Name) && section.Name != "ROOT" && section.Any())228sb.AppendLine("[" + section.Name + "]");229
230foreach (Key entry in section)231{232if (string.IsNullOrEmpty(entry.Name))233{234if (!string.IsNullOrEmpty(entry.Comment))235sb.AppendLine(entry.Comment);236else if (_options.HasFlag(IniOptions.KeepEmptyLines))237sb.AppendLine();238
239continue;240}241
242if (entry.IsComment)243{244sb.AppendLine(entry.Name);245continue;246}247
248if (string.IsNullOrEmpty(entry.Value) && !_options.HasFlag(IniOptions.KeepEmptyValues))249continue;250
251if (string.IsNullOrEmpty(entry.Name))252continue;253
254sb.Append(entry.Name);255
256if (_options.HasFlag(IniOptions.UseSpaces))257sb.Append(" ");258
259if (_options.HasFlag(IniOptions.UseDoubleEqual))260sb.Append("==");261else262sb.Append("=");263
264if (_options.HasFlag(IniOptions.UseSpaces))265sb.Append(" ");266
267sb.Append(entry.Value);268
269if (!string.IsNullOrEmpty(entry.Comment))270{271sb.Append("\t\t\t");272sb.Append(entry.Comment);273}274
275sb.AppendLine();276}277
278if (!_options.HasFlag(IniOptions.KeepEmptyLines))279sb.AppendLine();280}281
282return sb.ToString();283}284
285public void Save()286{287if (!_dirty)288return;289
290try291{292string dir = Path.GetDirectoryName(_path);293if (!Directory.Exists(dir))294Directory.CreateDirectory(dir);295
296using (TextWriter tw = new StreamWriter(_path))297{298tw.Write(ToString());299tw.Close();300}301
302_dirty = false;303}304catch (Exception ex)305{306SimpleLogger.Instance.Error("[IniFile] Save failed " + ex.Message, ex);307}308}309
310public void Dispose()311{312Save();313}314
315private IniOptions _options;316private bool _dirty;317private string _path;318
319#region Private classes320class Key321{322public string Name { get; set; }323public string Value { get; set; }324public string Comment { get; set; }325
326public bool IsComment327{328get329{330return Name == null || Name.StartsWith(";") || Name.StartsWith("#");331}332}333
334public override string ToString()335{336if (string.IsNullOrEmpty(Name))337return "";338
339if (string.IsNullOrEmpty(Value))340return Name + "=";341
342return Name + "=" + Value;343}344}345
346class KeyList : List<Key>347{348
349}350
351class Section : IEnumerable<Key>352{353public Section()354{355_keys = new KeyList();356}357
358public string Name { get; set; }359
360
361public override string ToString()362{363if (string.IsNullOrEmpty(Name))364return "";365
366return "[" + Name + "]";367}368
369public bool Exists(string keyName)370{371foreach (var key in _keys)372if (key.Name.Equals(keyName, StringComparison.InvariantCultureIgnoreCase))373return true;374
375return false;376}377
378public Key Get(string keyName)379{380foreach (var key in _keys)381if (key.Name.Equals(keyName, StringComparison.InvariantCultureIgnoreCase))382return key;383
384return null;385}386
387public string GetValue(string keyName)388{389foreach (var key in _keys)390if (key.Name.Equals(keyName, StringComparison.InvariantCultureIgnoreCase))391return key.Value;392
393return null;394}395
396private KeyList _keys;397
398public IEnumerator<Key> GetEnumerator()399{400return _keys.GetEnumerator();401}402
403IEnumerator IEnumerable.GetEnumerator()404{405return _keys.GetEnumerator();406}407
408public Key Add(string keyName, string value = null)409{410var key = new Key() { Name = keyName, Value = value };411_keys.Add(key);412return key;413}414
415public Key Add(Key key)416{417_keys.Add(key);418return key;419}420
421internal void Clear()422{423_keys.Clear();424}425
426internal void Remove(Key key)427{428_keys.Remove(key);429}430}431
432class Sections : IEnumerable<Section>433{434public Sections()435{436_sections = new List<Section>();437}438
439public Section Get(string sectionName)440{441if (sectionName == null)442sectionName = string.Empty;443
444return _sections.FirstOrDefault(s => s.Name.Equals(sectionName, StringComparison.InvariantCultureIgnoreCase));445}446
447public Section GetOrAddSection(string sectionName)448{449if (sectionName == null)450sectionName = string.Empty;451
452var section = Get(sectionName);453if (section == null)454{455section = new Section() { Name = sectionName };456
457if ((string.IsNullOrEmpty(sectionName) || sectionName == "ROOT") && _sections.Count > 0)458_sections.Insert(0, section);459else460_sections.Add(section);461}462
463return section;464}465
466private List<Section> _sections;467
468public IEnumerator<Section> GetEnumerator()469{470return _sections.GetEnumerator();471}472
473IEnumerator IEnumerable.GetEnumerator()474{475return _sections.GetEnumerator();476}477}478
479private Sections _sections = new Sections();480#endregion481}482
483
484public class IniSection485{486private IniFile _ini;487private string _sectionName;488
489protected IniSection(string name, IniFile ini)490{491_ini = ini;492_sectionName = name;493}494
495public string this[string key]496{497get498{499return _ini.GetValue(_sectionName, key);500}501set502{503_ini.WriteValue(_sectionName, key, value);504}505}506
507public void Clear()508{509_ini.ClearSection(_sectionName);510}511
512public string[] Keys513{514get515{516return _ini.EnumerateKeys(_sectionName);517}518}519}520}