ProjectArcade

Форк
0
498 строк · 16.9 Кб
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Text;
5
using System.IO;
6
using System.Dynamic;
7

8
namespace EmulatorLauncher.Common.FileFormats
9
{
10
    public class BmlFile : BmlContainer
11
    {
12
        public override string ToString()
13
        {        
14
            var sb = new StringBuilder();
15
            SerializeTo(sb);
16
            var final = sb.ToString();
17
            return final;        
18
        }
19

20
        public void Save()
21
        {
22
            if (!string.IsNullOrEmpty(_path))
23
                Save(_path);
24
        }
25

26
        public void Save(string bmlFile)
27
        {
28
            File.WriteAllText(bmlFile, ToString());
29
        }
30

31
        private string _path;
32

33
        public static BmlFile Parse(string bml)
34
        {
35
            var root = new BmlFile() { Name = "root", Indent = -1 };
36
            if (string.IsNullOrEmpty(bml))
37
                return root;
38

39
            BmlContainer current = root;
40

41
            Stack<BmlContainer> stack = new Stack<BmlContainer>();
42
            stack.Push(root);
43

44
            var lines = bml.Replace("\r\n", "\n").Replace("\r", "").Split(new char[] { '\n' }, StringSplitOptions.None);
45
            for (int i = 0; i < lines.Length; i++)
46
            {
47
                string line = lines[i];
48

49
                if (string.IsNullOrEmpty(line))
50
                    continue;
51

52
                int indent = GetIndent(line);                
53
                string tmp = line.Trim();
54

55
                if (!string.IsNullOrEmpty(tmp))
56
                {
57
                    while (stack.Count > 0 && current.Indent >= indent)
58
                        current = stack.Pop();
59

60
                    if (!stack.Contains(current))
61
                        stack.Push(current);
62
                }
63

64
                int idx = tmp.IndexOf(":");
65
                if (idx >= 0 || idx == -1)
66
                {
67
                    if (idx >= 0)
68
                    {
69
                        string name = tmp.Substring(0, idx).Trim();
70
                        string value = tmp.Substring(idx + 1).Trim();
71
                        var item = new BmlElement() { Name = name, Value = value };
72
                        current.Elements.Add(item);
73
                    }
74

75
                    if (idx == -1)
76
                    {
77
                        string name = tmp.Trim();
78
                        var folder = new BmlContainer() { Name = name, Indent = indent };
79
                        current.Elements.Add(folder);
80
                        stack.Push(folder);
81
                        current = folder;
82
                    }
83
                    /*else
84
                    {
85
                        if (value == "|" || value == ">")
86
                        {
87
                            StringBuilder sbValue = new StringBuilder();
88
                            
89
                            i++;
90
                            while (i < lines.Length)
91
                            {
92
                                var childLine = lines[i].Replace("\r", "");
93

94
                                if (childLine.Trim().Length == 0)
95
                                {                     
96
                                    if (value == "|")
97
                                        sbValue.AppendLine();
98
                                    else
99
                                        sbValue.Append(" ");
100

101
                                    i++;
102
                                    continue;
103
                                }
104

105
                                int childIndent = GetIndent(childLine);
106
                                if (childIndent <= indent)
107
                                    break;
108

109
                                if (sbValue.Length > 0)
110
                                {
111
                                    if (value == "|")
112
                                        sbValue.AppendLine();
113
                                    else
114
                                        sbValue.Append(" ");
115
                                }
116

117
                                sbValue.Append(childLine.Substring((indent + 1) * 2));
118
                                i++;
119
                            }
120

121
                            if (sbValue.Length > 0)
122
                                sbValue.AppendLine();
123

124
                            i--;
125
                            value = sbValue.ToString();
126
                        }*/
127
                }
128
                else if (!string.IsNullOrEmpty(tmp))
129
                {
130
                    var item = new BmlElement() { Name = "", Value = tmp };
131
                    current.Elements.Add(item);
132
                }
133
            }
134

135
            return root;
136
        }
137

138
        private static int GetIndent(string line)
139
        {
140
            int indent = 0;
141
            foreach (var chr in line)
142
                if (chr == 32)
143
                    indent++;
144
                else
145
                    break;
146

147
            indent /= 2;
148
            return indent;
149
        }
150

151
        public static BmlFile Load(string bmlFile)
152
        {
153
            var root = new BmlFile() { Name = "root", Indent = -1 };
154
            root._path = bmlFile;
155
            if (!File.Exists(bmlFile))
156
                return root;
157

158
            string bml = File.ReadAllText(bmlFile);
159

160
            BmlFile file = Parse(bml);
161
            file._path = bmlFile;
162
            return file;
163
        }
164
    }
165

166
    public interface IBmlElement
167
    {
168
        string Name { get; set; }
169
    }
170
    
171
    public class BmlElement : IBmlElement
172
    {
173
        public string Name { get; set; }
174
        public string Value { get; set; }
175

176
        public override string ToString()
177
        {
178
            return Name + ": " + Value.ToString();
179
        }
180
    }
181

182
    public class BmlContainer : DynamicObject, IBmlElement, IEnumerable<IBmlElement>
183
    {        
184
        #region DynamicObject
185
        public override IEnumerable<string> GetDynamicMemberNames()
186
        {
187
            return Elements.Where(d => !string.IsNullOrEmpty(d.Name)).Select(d => d.Name);
188
        }
189

190
        public override bool TryGetMember(GetMemberBinder binder, out object result)
191
        {
192
            var element = Elements.FirstOrDefault(e => binder.Name.Equals(e.Name, StringComparison.InvariantCultureIgnoreCase));
193
            if (element == null)
194
                element = Elements.FirstOrDefault(e => binder.Name.Replace("_", " ").Equals(e.Name, StringComparison.InvariantCultureIgnoreCase));
195

196
            if (element != null)
197
            {
198
                BmlElement elt = element as BmlElement;
199
                if (elt != null)
200
                    result = elt.Value;
201
                else
202
                    result = element;
203

204
                return true;
205
            }
206
            
207
            result = null;
208
            return true;
209
        }
210

211
        class BmlSetMemberBinder : SetMemberBinder
212
        {
213
            public BmlSetMemberBinder(string name, bool ignoreCase) : base(name, ignoreCase) { }
214
            public override DynamicMetaObject FallbackSetMember(DynamicMetaObject target, DynamicMetaObject value, DynamicMetaObject errorSuggestion) { return null; }
215
        }
216

217
        public override bool TrySetMember(SetMemberBinder binder, object value)
218
        {
219
            if (value == null)
220
            {
221
                this.Remove(binder.Name.Replace("_", " "));
222
                this.Remove(binder.Name);
223
            }
224
            else if (value is string || value.GetType().IsValueType)
225
            {
226
                string newValue = value.ToString();
227

228
                if (value is bool)
229
                    newValue = ((bool)value).ToString().ToLowerInvariant();
230
                else if (value is decimal || value is float || value is double)
231
                    newValue = ((double)value).ToString(System.Globalization.CultureInfo.InvariantCulture);
232

233
                var element = Elements.FirstOrDefault(e => binder.Name.Equals(e.Name, StringComparison.InvariantCultureIgnoreCase));
234
                if (element == null)
235
                {
236
                    element = Elements.FirstOrDefault(e => binder.Name.Replace("_", " ").Equals(e.Name, StringComparison.InvariantCultureIgnoreCase));
237
                    if (element != null)
238
                    {
239
                        this[binder.Name.Replace("_", " ")] = newValue;
240
                    }
241
                }
242

243
                this[binder.Name] = newValue;
244
            }
245
            else
246
            {
247
                BmlContainer container = GetOrCreateContainer(binder.Name);
248

249
                foreach (var item in value.GetType()
250
                    .GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)
251
                    .Select(pi => new { Name = pi.Name, Value = pi.GetValue(value, null) }))
252
                {
253
                    if (item.Value != null)
254
                        container.TrySetMember(new BmlSetMemberBinder(item.Name, binder.IgnoreCase), item.Value);
255
                }
256
                    
257
            }
258

259
            return true;
260
        }
261
        #endregion
262

263
        public BmlContainer()
264
        {
265
            Elements = new List<IBmlElement>();
266
        }
267

268
        public string Name { get; set; }
269

270
        private void AddElement(IBmlElement element)
271
        {
272
            BmlElement last = (Elements.Count > 0 ? Elements[Elements.Count - 1] : null) as BmlElement;
273
            if (last != null && string.IsNullOrEmpty(last.Name) && last.Value == "...")
274
            {
275
                Elements.Insert(Elements.Count - 1, element);
276
                return;
277
            }
278

279
            Elements.Add(element);
280
        }
281

282
        public BmlContainer GetContainer(string key)
283
        {
284
            return Elements.OfType<BmlContainer>().FirstOrDefault(e => key.Equals(e.Name, StringComparison.InvariantCultureIgnoreCase));
285
        }
286

287
        public BmlContainer GetOrCreateContainer(string key)
288
        {
289
            var element = GetContainer(key);
290
            if (element == null)
291
            {
292
                element = new BmlContainer() { Name = key };
293

294
                // Convert Element to Container
295
                var item = Elements.FirstOrDefault(e => !(e is BmlContainer) && key.Equals(e.Name, StringComparison.InvariantCultureIgnoreCase));
296
                if (item != null)
297
                {
298
                    int pos = Elements.IndexOf(item);
299
                    Elements.Remove(item);
300
                    Elements.Insert(pos, element);
301
                }
302
                else
303
                    AddElement(element);
304
            }
305

306
            return element;
307
        }
308

309
        public string this[string key]
310
        {
311
            get
312
            {
313
                var element = Elements.OfType<BmlElement>().FirstOrDefault(e => key.Equals(e.Name, StringComparison.InvariantCultureIgnoreCase));
314
                if (element != null)
315
                    return element.Value;
316

317
                return null;
318
            }
319
            set
320
            {
321
                var element = Elements.OfType<BmlElement>().FirstOrDefault(e => key.Equals(e.Name, StringComparison.InvariantCultureIgnoreCase));
322
                if (element == null)
323
                {
324
                    element = new BmlElement() { Name = key };
325

326
                    // Convert Container to Element
327
                    var container = Elements.FirstOrDefault(e => e is BmlContainer && key.Equals(e.Name, StringComparison.InvariantCultureIgnoreCase));
328
                    if (container != null)
329
                    {
330
                        int pos = Elements.IndexOf(container);
331
                        Elements.Remove(container);
332
                        Elements.Insert(pos, element);
333
                    }
334
                    else                    
335
                        AddElement(element);
336
                }
337

338
                element.Value = value;
339
            }
340
        }
341

342
        public void Remove(string key)
343
        {
344
            var element = Elements.FirstOrDefault(e => key.Equals(e.Name, StringComparison.InvariantCultureIgnoreCase));
345
            if (element != null)
346
                Elements.Remove(element);
347
        }
348

349
        public List<IBmlElement> Elements { get; private set; }
350

351
        public override string ToString()
352
        {
353
            return "[Folder] " + (Name ?? "");
354
        }
355

356
        public IEnumerator<IBmlElement> GetEnumerator()
357
        {
358
            return Elements.GetEnumerator();
359
        }
360

361
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
362
        {
363
            return Elements.GetEnumerator();
364
        }
365

366
        protected void SerializeTo(StringBuilder sb, int indent = 0)
367
        {
368
            foreach (var item in Elements)
369
            {
370
                BmlContainer container = item as BmlContainer;
371
                if (container != null)
372
                {
373
                    if (container.Elements.Count > 0)
374
                    {
375
                        sb.Append(new string(' ', indent * 2));
376
                        sb.Append(item.Name);
377
                        sb.AppendLine();
378

379
                        container.SerializeTo(sb, indent + 1);
380
                    }
381

382
                    continue;
383
                }
384

385
                BmlElement element = item as BmlElement;
386
                if (element == null)
387
                    continue;
388

389
                if (element.Value == null)
390
                    continue;
391

392
                sb.Append(new string(' ', indent * 2));
393

394
                if (!string.IsNullOrEmpty(element.Name))
395
                {
396
                    sb.Append(element.Name);
397
                    sb.Append(": ");
398
                    
399
                    if (element.Value.Contains("\r\n"))
400
                    {
401
                        sb.AppendLine("|");
402

403
                        var offset = new string(' ', (indent+1) * 2);
404
                        var lines = element.Value.Split(new string[] { "\r\n" }, StringSplitOptions.None);
405
                        for (int i = 0; i < lines.Length - 1; i++)
406
                        {
407
                            sb.Append(offset);
408
                            sb.AppendLine(lines[i]);
409
                        }
410
                    }
411
                    else
412
                        sb.AppendLine(element.Value);
413
                }
414
                else
415
                    sb.AppendLine(element.Value);
416
            }
417
        }
418

419
        internal int Indent;
420
    }
421

422
    class SimpleBml<T> : IEnumerable<T> where T : new()
423
    {
424
        private List<T> _values;
425

426
        private static List<T> FillElements(object obj, BmlContainer bmlElements)
427
        {
428
            List<T> ret = null; 
429

430
            foreach (var bmlEntry in bmlElements.Elements)
431
            {
432
                BmlContainer container = bmlEntry as BmlContainer;
433
                if (container != null)
434
                {
435
                    if (typeof(T).Equals(obj))
436
                    {
437
                        T current = Activator.CreateInstance<T>();
438

439
                        var bmlNameProperty = typeof(T).GetProperties().FirstOrDefault(prop => Attribute.IsDefined(prop, typeof(BmlNameAttribute)));
440
                        if (bmlNameProperty != null)
441
                            bmlNameProperty.SetValue(current, container.Name, null);
442
                       
443
                        FillElements(current, container);
444

445
                        if (ret == null)
446
                            ret = new List<T>();
447

448
                        ret.Add(current);
449
                    }
450
                    else
451
                    {
452
                        var propertyType = (obj is Type) ? (Type)obj : obj.GetType();
453
                        var objectProperty = propertyType.GetProperty(bmlEntry.Name);
454
                        if (objectProperty != null && !objectProperty.PropertyType.IsValueType && objectProperty.PropertyType != typeof(string))
455
                        {
456
                            object child = Activator.CreateInstance(objectProperty.PropertyType);
457

458
                            var bmlNameProperty = objectProperty.PropertyType.GetProperties().FirstOrDefault(prop => Attribute.IsDefined(prop, typeof(BmlNameAttribute)));
459
                            if (bmlNameProperty != null)
460
                                bmlNameProperty.SetValue(obj, container.Name, null);
461

462
                            FillElements(child, container);
463
                            objectProperty.SetValue(obj, child, null);
464
                        }
465
                    }
466
                    continue;
467
                }
468

469
                var type = (obj is Type) ? (Type)obj : obj.GetType();
470

471
                var property = type.GetProperty(bmlEntry.Name);
472
                if (property != null && bmlEntry is BmlElement)
473
                    property.SetValue(obj, ((BmlElement)bmlEntry).Value, null);
474
            }
475

476
            return ret;
477
        }
478

479
        public static SimpleBml<T> Parse(string bml)
480
        {
481
            var ret = new SimpleBml<T>();
482
            ret._values = FillElements(typeof(T), BmlFile.Parse(bml));
483
            return ret;
484
        }
485

486
        public IEnumerator<T> GetEnumerator()
487
        {
488
            return _values.GetEnumerator();
489
        }
490

491
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
492
        {
493
            return _values.GetEnumerator();
494
        }
495
    }
496

497
    class BmlNameAttribute : Attribute { }
498
}
499

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.