#region Copyright & License Information /* * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford. * This file is part of OpenRA. * * OpenRA is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenRA is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenRA. If not, see . */ #endregion using System; using System.Collections.Generic; using System.IO; using System.Linq; namespace OpenRA.FileFormats { using MiniYamlNodes = Dictionary; public class MiniYaml { public string Value; public Dictionary Nodes = new Dictionary(); public MiniYaml( string value ) : this( value, new Dictionary() ) { } public MiniYaml( string value, Dictionary nodes ) { Value = value; Nodes = nodes; } public static MiniYaml FromDictionary(Dictionarydict) { return new MiniYaml( null, dict.ToDictionary( x=>x.Key.ToString(), x=>new MiniYaml(x.Value.ToString()))); } public static MiniYaml FromList(Listlist) { return new MiniYaml( null, list.ToDictionary( x=>x.ToString(), x=>new MiniYaml(null))); } static Dictionary FromLines(string[] lines) { var levels = new List>(); levels.Add(new Dictionary()); foreach (var line in lines) { var t = line.TrimStart(' ', '\t'); if (t.Length == 0 || t[0] == '#') continue; var level = line.Length - t.Length; if (levels.Count <= level) throw new InvalidOperationException("Bad indent in miniyaml"); while (levels.Count > level + 1) levels.RemoveAt(levels.Count - 1); var colon = t.IndexOf(':'); var d = new Dictionary(); try { if (colon == -1) levels[level].Add(t.Trim(), new MiniYaml(null, d)); else { var value = t.Substring(colon + 1).Trim(); if (value.Length == 0) value = null; levels[level].Add(t.Substring(0, colon).Trim(), new MiniYaml(value, d)); } } catch (ArgumentException) { throw new InvalidDataException("Duplicate Identifier:`{0}`".F(t)); } levels.Add(d); } return levels[0]; } public static Dictionary FromFileInPackage( string path ) { StreamReader reader = new StreamReader( FileSystem.Open(path) ); List lines = new List(); while( !reader.EndOfStream ) lines.Add(reader.ReadLine()); reader.Close(); return FromLines(lines.ToArray()); } public static Dictionary FromFile( string path ) { return FromLines(File.ReadAllLines( path )); } public static Dictionary FromStream(Stream s) { using (var reader = new StreamReader(s)) return FromString(reader.ReadToEnd()); } public static Dictionary FromString(string text) { return FromLines(text.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries)); } public static Dictionary Merge( Dictionary a, Dictionary b ) { if( a.Count == 0 ) return b; if( b.Count == 0 ) return a; var ret = new Dictionary(); var keys = a.Keys.Union( b.Keys ).ToList(); var noInherit = keys.Where( x => x.Length > 0 && x[ 0 ] == '-' ).Select( x => x.Substring( 1 ) ).ToList(); foreach( var key in keys ) { MiniYaml aa, bb; a.TryGetValue( key, out aa ); b.TryGetValue( key, out bb ); // if( key.Length > 0 && key[ 0 ] == '-' ) // continue; // else if( noInherit.Contains( key ) ) { if( aa != null ) ret.Add( key, aa ); } else ret.Add( key, Merge( aa, bb ) ); } return ret; } public static MiniYaml Merge( MiniYaml a, MiniYaml b ) { if( a == null ) return b; if( b == null ) return a; return new MiniYaml( a.Value ?? b.Value, Merge( a.Nodes, b.Nodes ) ); } public IEnumerable ToLines(string name) { yield return name + ": " + Value; if (Nodes != null) foreach (var line in Nodes.ToLines(false)) yield return "\t" + line; } } public static class MiniYamlExts { public static void WriteToFile(this MiniYamlNodes y, string filename) { File.WriteAllLines(filename, y.ToLines(true).Select(x => x.TrimEnd()).ToArray()); } public static string WriteToString(this MiniYamlNodes y) { return string.Join("\n", y.ToLines(true).Select(x => x.TrimEnd()).ToArray()); } public static IEnumerable ToLines(this MiniYamlNodes y, bool lowest) { foreach (var kv in y) { foreach (var line in kv.Value.ToLines(kv.Key)) yield return line; if (lowest) yield return ""; } } } }