2016-11-30 14:08:28 -10:00
|
|
|
//
|
|
|
|
// SlnFile.cs
|
|
|
|
//
|
|
|
|
// Author:
|
|
|
|
// Lluis Sanchez Gual <lluis@xamarin.com>
|
|
|
|
//
|
|
|
|
// Copyright (c) 2016 Xamarin, Inc (http://www.xamarin.com)
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
|
|
// in the Software without restriction, including without limitation the rights
|
|
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
|
|
// furnished to do so, subject to the following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
// all copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
// THE SOFTWARE.
|
|
|
|
|
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Linq;
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
using System.Collections.Specialized;
|
|
|
|
using System.IO;
|
|
|
|
using System.Collections;
|
|
|
|
using System.Globalization;
|
|
|
|
using System.Reflection;
|
|
|
|
using Microsoft.DotNet.Cli.Sln.Internal.FileManipulation;
|
2016-12-20 13:04:01 -10:00
|
|
|
using Microsoft.DotNet.Tools.Common;
|
2016-11-30 14:08:28 -10:00
|
|
|
|
|
|
|
namespace Microsoft.DotNet.Cli.Sln.Internal
|
|
|
|
{
|
|
|
|
public class SlnFile
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
private SlnProjectCollection _projects = new SlnProjectCollection();
|
|
|
|
private SlnSectionCollection _sections = new SlnSectionCollection();
|
|
|
|
private SlnPropertySet _metadata = new SlnPropertySet(true);
|
|
|
|
private int _prefixBlankLines = 1;
|
|
|
|
private TextFormatInfo _format = new TextFormatInfo();
|
2016-11-30 14:08:28 -10:00
|
|
|
|
|
|
|
public string FormatVersion { get; set; }
|
|
|
|
public string ProductDescription { get; set; }
|
|
|
|
|
|
|
|
public string VisualStudioVersion
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
get { return _metadata.GetValue("VisualStudioVersion"); }
|
|
|
|
set { _metadata.SetValue("VisualStudioVersion", value); }
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
public string MinimumVisualStudioVersion
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
get { return _metadata.GetValue("MinimumVisualStudioVersion"); }
|
|
|
|
set { _metadata.SetValue("MinimumVisualStudioVersion", value); }
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
2016-12-13 06:45:00 -10:00
|
|
|
public string BaseDirectory
|
2016-11-30 14:08:28 -10:00
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
get { return Path.GetDirectoryName(FullPath); }
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
2016-12-13 06:45:00 -10:00
|
|
|
public string FullPath { get; set; }
|
2016-11-30 14:08:28 -10:00
|
|
|
|
|
|
|
public SlnPropertySet SolutionConfigurationsSection
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
get
|
|
|
|
{
|
|
|
|
return _sections
|
|
|
|
.GetOrCreateSection("SolutionConfigurationPlatforms", SlnSectionType.PreProcess)
|
|
|
|
.Properties;
|
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
public SlnPropertySetCollection ProjectConfigurationsSection
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
get
|
|
|
|
{
|
|
|
|
return _sections
|
|
|
|
.GetOrCreateSection("ProjectConfigurationPlatforms", SlnSectionType.PostProcess)
|
|
|
|
.NestedPropertySets;
|
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
public SlnSectionCollection Sections
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
get { return _sections; }
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
public SlnProjectCollection Projects
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
get { return _projects; }
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
2016-12-13 06:45:00 -10:00
|
|
|
public SlnFile()
|
|
|
|
{
|
|
|
|
_projects.ParentFile = this;
|
|
|
|
_sections.ParentFile = this;
|
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
|
2016-12-13 06:45:00 -10:00
|
|
|
public static SlnFile Read(string file)
|
2016-11-30 14:08:28 -10:00
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
SlnFile slnFile = new SlnFile();
|
|
|
|
slnFile.FullPath = Path.GetFullPath(file);
|
|
|
|
slnFile._format = FileUtil.GetTextFormatInfo(file);
|
2016-11-30 14:08:28 -10:00
|
|
|
|
|
|
|
using (var sr = new StreamReader(new FileStream(file, FileMode.Open)))
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
|
|
|
slnFile.Read(sr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return slnFile;
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
2016-12-13 06:45:00 -10:00
|
|
|
private void Read(TextReader reader)
|
2016-11-30 14:08:28 -10:00
|
|
|
{
|
|
|
|
string line;
|
|
|
|
int curLineNum = 0;
|
|
|
|
bool globalFound = false;
|
|
|
|
bool productRead = false;
|
|
|
|
|
|
|
|
while ((line = reader.ReadLine()) != null)
|
|
|
|
{
|
|
|
|
curLineNum++;
|
|
|
|
line = line.Trim();
|
|
|
|
if (line.StartsWith("Microsoft Visual Studio Solution File", StringComparison.Ordinal))
|
|
|
|
{
|
|
|
|
int i = line.LastIndexOf(' ');
|
|
|
|
if (i == -1)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
throw new InvalidSolutionFormatException(curLineNum);
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
FormatVersion = line.Substring(i + 1);
|
2016-12-13 06:45:00 -10:00
|
|
|
_prefixBlankLines = curLineNum - 1;
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
if (line.StartsWith("# ", StringComparison.Ordinal))
|
|
|
|
{
|
|
|
|
if (!productRead)
|
|
|
|
{
|
|
|
|
productRead = true;
|
|
|
|
ProductDescription = line.Substring(2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (line.StartsWith("Project", StringComparison.Ordinal))
|
|
|
|
{
|
|
|
|
SlnProject p = new SlnProject();
|
|
|
|
p.Read(reader, line, ref curLineNum);
|
2016-12-13 06:45:00 -10:00
|
|
|
_projects.Add(p);
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
else if (line == "Global")
|
|
|
|
{
|
|
|
|
if (globalFound)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-12-16 21:45:55 -08:00
|
|
|
throw new InvalidSolutionFormatException(curLineNum, LocalizableStrings.GlobalSectionMoreThanOnceError);
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
globalFound = true;
|
|
|
|
while ((line = reader.ReadLine()) != null)
|
|
|
|
{
|
|
|
|
curLineNum++;
|
|
|
|
line = line.Trim();
|
|
|
|
if (line == "EndGlobal")
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (line.StartsWith("GlobalSection", StringComparison.Ordinal))
|
|
|
|
{
|
|
|
|
var sec = new SlnSection();
|
|
|
|
sec.Read(reader, line, ref curLineNum);
|
2016-12-13 06:45:00 -10:00
|
|
|
_sections.Add(sec);
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
else // Ignore text that's out of place
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
continue;
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
if (line == null)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-12-16 21:45:55 -08:00
|
|
|
throw new InvalidSolutionFormatException(curLineNum, LocalizableStrings.GlobalSectionNotClosedError);
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
else if (line.IndexOf('=') != -1)
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
_metadata.ReadLine(line, curLineNum);
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (FormatVersion == null)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-12-16 21:45:55 -08:00
|
|
|
throw new InvalidSolutionFormatException(curLineNum, LocalizableStrings.FileHeaderMissingError);
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
2016-12-13 06:45:00 -10:00
|
|
|
public void Write(string file = null)
|
2016-11-30 14:08:28 -10:00
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
if (!string.IsNullOrEmpty(file))
|
|
|
|
{
|
|
|
|
FullPath = Path.GetFullPath(file);
|
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
var sw = new StringWriter();
|
|
|
|
Write(sw);
|
2016-12-13 06:45:00 -10:00
|
|
|
File.WriteAllText(FullPath, sw.ToString());
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
2016-12-13 06:45:00 -10:00
|
|
|
private void Write(TextWriter writer)
|
2016-11-30 14:08:28 -10:00
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
writer.NewLine = _format.NewLine;
|
|
|
|
for (int n = 0; n < _prefixBlankLines; n++)
|
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
writer.WriteLine();
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
writer.WriteLine("Microsoft Visual Studio Solution File, Format Version " + FormatVersion);
|
|
|
|
writer.WriteLine("# " + ProductDescription);
|
|
|
|
|
2016-12-13 06:45:00 -10:00
|
|
|
_metadata.Write(writer);
|
2016-11-30 14:08:28 -10:00
|
|
|
|
2016-12-13 06:45:00 -10:00
|
|
|
foreach (var p in _projects)
|
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
p.Write(writer);
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
|
|
|
|
writer.WriteLine("Global");
|
2016-12-13 06:45:00 -10:00
|
|
|
foreach (SlnSection s in _sections)
|
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
s.Write(writer, "GlobalSection");
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
writer.WriteLine("EndGlobal");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public class SlnProject
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
private SlnSectionCollection _sections = new SlnSectionCollection();
|
2016-11-30 14:08:28 -10:00
|
|
|
|
2016-12-13 06:45:00 -10:00
|
|
|
private SlnFile _parentFile;
|
2016-11-30 14:08:28 -10:00
|
|
|
|
|
|
|
public SlnFile ParentFile
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
return _parentFile;
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
internal set
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
_parentFile = value;
|
|
|
|
_sections.ParentFile = _parentFile;
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public string Id { get; set; }
|
|
|
|
public string TypeGuid { get; set; }
|
|
|
|
public string Name { get; set; }
|
2016-12-20 13:04:01 -10:00
|
|
|
|
|
|
|
private string _filePath;
|
|
|
|
public string FilePath
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return _filePath;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
_filePath = PathUtility.GetPathWithDirectorySeparator(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-30 14:08:28 -10:00
|
|
|
public int Line { get; private set; }
|
|
|
|
internal bool Processed { get; set; }
|
|
|
|
|
|
|
|
public SlnSectionCollection Sections
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
get { return _sections; }
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
internal void Read(TextReader reader, string line, ref int curLineNum)
|
|
|
|
{
|
|
|
|
Line = curLineNum;
|
|
|
|
|
|
|
|
int n = 0;
|
|
|
|
FindNext(curLineNum, line, ref n, '(');
|
|
|
|
n++;
|
|
|
|
FindNext(curLineNum, line, ref n, '"');
|
|
|
|
int n2 = n + 1;
|
|
|
|
FindNext(curLineNum, line, ref n2, '"');
|
|
|
|
TypeGuid = line.Substring(n + 1, n2 - n - 1);
|
|
|
|
|
|
|
|
n = n2 + 1;
|
|
|
|
FindNext(curLineNum, line, ref n, ')');
|
|
|
|
FindNext(curLineNum, line, ref n, '=');
|
|
|
|
|
|
|
|
FindNext(curLineNum, line, ref n, '"');
|
|
|
|
n2 = n + 1;
|
|
|
|
FindNext(curLineNum, line, ref n2, '"');
|
|
|
|
Name = line.Substring(n + 1, n2 - n - 1);
|
|
|
|
|
|
|
|
n = n2 + 1;
|
|
|
|
FindNext(curLineNum, line, ref n, ',');
|
|
|
|
FindNext(curLineNum, line, ref n, '"');
|
|
|
|
n2 = n + 1;
|
|
|
|
FindNext(curLineNum, line, ref n2, '"');
|
|
|
|
FilePath = line.Substring(n + 1, n2 - n - 1);
|
|
|
|
|
|
|
|
n = n2 + 1;
|
|
|
|
FindNext(curLineNum, line, ref n, ',');
|
|
|
|
FindNext(curLineNum, line, ref n, '"');
|
|
|
|
n2 = n + 1;
|
|
|
|
FindNext(curLineNum, line, ref n2, '"');
|
|
|
|
Id = line.Substring(n + 1, n2 - n - 1);
|
|
|
|
|
|
|
|
while ((line = reader.ReadLine()) != null)
|
|
|
|
{
|
|
|
|
curLineNum++;
|
|
|
|
line = line.Trim();
|
|
|
|
if (line == "EndProject")
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (line.StartsWith("ProjectSection", StringComparison.Ordinal))
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
if (_sections == null)
|
|
|
|
{
|
|
|
|
_sections = new SlnSectionCollection();
|
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
var sec = new SlnSection();
|
2016-12-13 06:45:00 -10:00
|
|
|
_sections.Add(sec);
|
2016-11-30 14:08:28 -10:00
|
|
|
sec.Read(reader, line, ref curLineNum);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-16 21:45:55 -08:00
|
|
|
throw new InvalidSolutionFormatException(curLineNum, LocalizableStrings.ProjectSectionNotClosedError);
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
2016-12-13 06:45:00 -10:00
|
|
|
private void FindNext(int ln, string line, ref int i, char c)
|
2016-11-30 14:08:28 -10:00
|
|
|
{
|
|
|
|
i = line.IndexOf(c, i);
|
|
|
|
if (i == -1)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
throw new InvalidSolutionFormatException(ln);
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
2016-12-13 06:45:00 -10:00
|
|
|
internal void Write(TextWriter writer)
|
2016-11-30 14:08:28 -10:00
|
|
|
{
|
|
|
|
writer.Write("Project(\"");
|
|
|
|
writer.Write(TypeGuid);
|
|
|
|
writer.Write("\") = \"");
|
|
|
|
writer.Write(Name);
|
|
|
|
writer.Write("\", \"");
|
2016-12-20 13:04:01 -10:00
|
|
|
writer.Write(PathUtility.GetPathWithBackSlashes(FilePath));
|
2016-11-30 14:08:28 -10:00
|
|
|
writer.Write("\", \"");
|
|
|
|
writer.Write(Id);
|
|
|
|
writer.WriteLine("\"");
|
2016-12-13 06:45:00 -10:00
|
|
|
if (_sections != null)
|
2016-11-30 14:08:28 -10:00
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
foreach (SlnSection s in _sections)
|
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
s.Write(writer, "ProjectSection");
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
writer.WriteLine("EndProject");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public class SlnSection
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
private SlnPropertySetCollection _nestedPropertySets;
|
|
|
|
private SlnPropertySet _properties;
|
|
|
|
private List<string> _sectionLines;
|
|
|
|
private int _baseIndex;
|
2016-11-30 14:08:28 -10:00
|
|
|
|
|
|
|
public string Id { get; set; }
|
|
|
|
public int Line { get; private set; }
|
|
|
|
|
|
|
|
internal bool Processed { get; set; }
|
|
|
|
|
|
|
|
public SlnFile ParentFile { get; internal set; }
|
|
|
|
|
|
|
|
public bool IsEmpty
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
return (_properties == null || _properties.Count == 0) &&
|
|
|
|
(_nestedPropertySets == null || _nestedPropertySets.All(t => t.IsEmpty)) &&
|
|
|
|
(_sectionLines == null || _sectionLines.Count == 0);
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// If true, this section won't be written to the file if it is empty
|
|
|
|
/// </summary>
|
|
|
|
/// <value><c>true</c> if skip if empty; otherwise, <c>false</c>.</value>
|
|
|
|
public bool SkipIfEmpty { get; set; }
|
|
|
|
|
|
|
|
public void Clear()
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
_properties = null;
|
|
|
|
_nestedPropertySets = null;
|
|
|
|
_sectionLines = null;
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
public SlnPropertySet Properties
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
if (_properties == null)
|
2016-11-30 14:08:28 -10:00
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
_properties = new SlnPropertySet();
|
|
|
|
_properties.ParentSection = this;
|
|
|
|
if (_sectionLines != null)
|
2016-11-30 14:08:28 -10:00
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
foreach (var line in _sectionLines)
|
|
|
|
{
|
|
|
|
_properties.ReadLine(line, Line);
|
|
|
|
}
|
|
|
|
_sectionLines = null;
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
}
|
2016-12-13 06:45:00 -10:00
|
|
|
return _properties;
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public SlnPropertySetCollection NestedPropertySets
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
if (_nestedPropertySets == null)
|
2016-11-30 14:08:28 -10:00
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
_nestedPropertySets = new SlnPropertySetCollection(this);
|
|
|
|
if (_sectionLines != null)
|
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
LoadPropertySets();
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
2016-12-13 06:45:00 -10:00
|
|
|
return _nestedPropertySets;
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void SetContent(IEnumerable<KeyValuePair<string, string>> lines)
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
_sectionLines = new List<string>(lines.Select(p => p.Key + " = " + p.Value));
|
|
|
|
_properties = null;
|
|
|
|
_nestedPropertySets = null;
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
public IEnumerable<KeyValuePair<string, string>> GetContent()
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
if (_sectionLines != null)
|
|
|
|
{
|
|
|
|
return _sectionLines.Select(li =>
|
2016-11-30 14:08:28 -10:00
|
|
|
{
|
|
|
|
int i = li.IndexOf('=');
|
|
|
|
if (i != -1)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
return new KeyValuePair<string, string>(li.Substring(0, i).Trim(), li.Substring(i + 1).Trim());
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
else
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
return new KeyValuePair<string, string>(li.Trim(), "");
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
});
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
else
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
return new KeyValuePair<string, string>[0];
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
public SlnSectionType SectionType { get; set; }
|
|
|
|
|
2016-12-13 06:45:00 -10:00
|
|
|
private SlnSectionType ToSectionType(int curLineNum, string s)
|
2016-11-30 14:08:28 -10:00
|
|
|
{
|
|
|
|
if (s == "preSolution" || s == "preProject")
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
return SlnSectionType.PreProcess;
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
if (s == "postSolution" || s == "postProject")
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
return SlnSectionType.PostProcess;
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-12-16 21:45:55 -08:00
|
|
|
throw new InvalidSolutionFormatException(curLineNum, String.Format(LocalizableStrings.InvalidSectionTypeError, s));
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
2016-12-13 06:45:00 -10:00
|
|
|
private string FromSectionType(bool isProjectSection, SlnSectionType type)
|
2016-11-30 14:08:28 -10:00
|
|
|
{
|
|
|
|
if (type == SlnSectionType.PreProcess)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
return isProjectSection ? "preProject" : "preSolution";
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
else
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
return isProjectSection ? "postProject" : "postSolution";
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
internal void Read(TextReader reader, string line, ref int curLineNum)
|
|
|
|
{
|
|
|
|
Line = curLineNum;
|
|
|
|
int k = line.IndexOf('(');
|
|
|
|
if (k == -1)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-12-16 21:45:55 -08:00
|
|
|
throw new InvalidSolutionFormatException(curLineNum, LocalizableStrings.SectionIdMissingError);
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
var tag = line.Substring(0, k).Trim();
|
|
|
|
var k2 = line.IndexOf(')', k);
|
|
|
|
if (k2 == -1)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
throw new InvalidSolutionFormatException(curLineNum);
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
Id = line.Substring(k + 1, k2 - k - 1);
|
|
|
|
|
|
|
|
k = line.IndexOf('=', k2);
|
|
|
|
SectionType = ToSectionType(curLineNum, line.Substring(k + 1).Trim());
|
|
|
|
|
|
|
|
var endTag = "End" + tag;
|
|
|
|
|
2016-12-13 06:45:00 -10:00
|
|
|
_sectionLines = new List<string>();
|
|
|
|
_baseIndex = ++curLineNum;
|
2016-11-30 14:08:28 -10:00
|
|
|
while ((line = reader.ReadLine()) != null)
|
|
|
|
{
|
|
|
|
curLineNum++;
|
|
|
|
line = line.Trim();
|
|
|
|
if (line == endTag)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
break;
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
|
|
|
_sectionLines.Add(line);
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
if (line == null)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-12-16 21:45:55 -08:00
|
|
|
throw new InvalidSolutionFormatException(curLineNum, LocalizableStrings.ClosingSectionTagNotFoundError);
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
2016-12-13 06:45:00 -10:00
|
|
|
private void LoadPropertySets()
|
2016-11-30 14:08:28 -10:00
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
if (_sectionLines != null)
|
2016-11-30 14:08:28 -10:00
|
|
|
{
|
|
|
|
SlnPropertySet curSet = null;
|
2016-12-13 06:45:00 -10:00
|
|
|
for (int n = 0; n < _sectionLines.Count; n++)
|
2016-11-30 14:08:28 -10:00
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
var line = _sectionLines[n];
|
2016-11-30 14:08:28 -10:00
|
|
|
if (string.IsNullOrEmpty(line.Trim()))
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
continue;
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
var i = line.IndexOf('.');
|
|
|
|
if (i == -1)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
|
|
|
throw new InvalidSolutionFormatException(_baseIndex + n);
|
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
var id = line.Substring(0, i);
|
|
|
|
if (curSet == null || id != curSet.Id)
|
|
|
|
{
|
|
|
|
curSet = new SlnPropertySet(id);
|
2016-12-13 06:45:00 -10:00
|
|
|
_nestedPropertySets.Add(curSet);
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
2016-12-13 06:45:00 -10:00
|
|
|
curSet.ReadLine(line.Substring(i + 1), _baseIndex + n);
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
2016-12-13 06:45:00 -10:00
|
|
|
_sectionLines = null;
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void Write(TextWriter writer, string sectionTag)
|
|
|
|
{
|
|
|
|
if (SkipIfEmpty && IsEmpty)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
return;
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
|
|
|
|
writer.Write("\t");
|
|
|
|
writer.Write(sectionTag);
|
|
|
|
writer.Write('(');
|
|
|
|
writer.Write(Id);
|
|
|
|
writer.Write(") = ");
|
|
|
|
writer.WriteLine(FromSectionType(sectionTag == "ProjectSection", SectionType));
|
2016-12-13 06:45:00 -10:00
|
|
|
if (_sectionLines != null)
|
2016-11-30 14:08:28 -10:00
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
foreach (var l in _sectionLines)
|
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
writer.WriteLine("\t\t" + l);
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (_properties != null)
|
|
|
|
{
|
|
|
|
_properties.Write(writer);
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
2016-12-13 06:45:00 -10:00
|
|
|
else if (_nestedPropertySets != null)
|
2016-11-30 14:08:28 -10:00
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
foreach (var ps in _nestedPropertySets)
|
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
ps.Write(writer);
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
writer.WriteLine("\tEnd" + sectionTag);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// A collection of properties
|
|
|
|
/// </summary>
|
|
|
|
public class SlnPropertySet : IDictionary<string, string>
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
private OrderedDictionary _values = new OrderedDictionary();
|
|
|
|
private bool _isMetadata;
|
2016-11-30 14:08:28 -10:00
|
|
|
|
|
|
|
internal bool Processed { get; set; }
|
|
|
|
|
|
|
|
public SlnFile ParentFile
|
|
|
|
{
|
|
|
|
get { return ParentSection != null ? ParentSection.ParentFile : null; }
|
|
|
|
}
|
|
|
|
|
|
|
|
public SlnSection ParentSection { get; set; }
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Text file line of this section in the original file
|
|
|
|
/// </summary>
|
|
|
|
/// <value>The line.</value>
|
|
|
|
public int Line { get; private set; }
|
|
|
|
|
|
|
|
internal SlnPropertySet()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Creates a new property set with the specified ID
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="id">Identifier.</param>
|
|
|
|
public SlnPropertySet(string id)
|
|
|
|
{
|
|
|
|
Id = id;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal SlnPropertySet(bool isMetadata)
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
_isMetadata = isMetadata;
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
public bool IsEmpty
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
return _values.Count == 0;
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void ReadLine(string line, int currentLine)
|
|
|
|
{
|
|
|
|
if (Line == 0)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
Line = currentLine;
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
int k = line.IndexOf('=');
|
|
|
|
if (k != -1)
|
|
|
|
{
|
|
|
|
var name = line.Substring(0, k).Trim();
|
|
|
|
var val = line.Substring(k + 1).Trim();
|
2016-12-13 06:45:00 -10:00
|
|
|
_values[name] = val;
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
line = line.Trim();
|
|
|
|
if (!string.IsNullOrWhiteSpace(line))
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
|
|
|
_values.Add(line, null);
|
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void Write(TextWriter writer)
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
foreach (DictionaryEntry e in _values)
|
2016-11-30 14:08:28 -10:00
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
if (!_isMetadata)
|
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
writer.Write("\t\t");
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
if (Id != null)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
writer.Write(Id + ".");
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
writer.WriteLine(e.Key + " = " + e.Value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public string Id { get; private set; }
|
|
|
|
|
|
|
|
public string GetValue(string name, string defaultValue = null)
|
|
|
|
{
|
|
|
|
string res;
|
|
|
|
if (TryGetValue(name, out res))
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
return res;
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
else
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
return defaultValue;
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
public T GetValue<T>(string name)
|
|
|
|
{
|
|
|
|
return (T)GetValue(name, typeof(T), default(T));
|
|
|
|
}
|
|
|
|
|
|
|
|
public T GetValue<T>(string name, T defaultValue)
|
|
|
|
{
|
|
|
|
return (T)GetValue(name, typeof(T), defaultValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
public object GetValue(string name, Type t, object defaultValue)
|
|
|
|
{
|
|
|
|
string val;
|
|
|
|
if (TryGetValue(name, out val))
|
|
|
|
{
|
|
|
|
if (t == typeof(bool))
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
return (object)val.Equals("true", StringComparison.OrdinalIgnoreCase);
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
if (t.GetTypeInfo().IsEnum)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
return Enum.Parse(t, val, true);
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
if (t.GetTypeInfo().IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>))
|
|
|
|
{
|
|
|
|
var at = t.GetTypeInfo().GetGenericArguments()[0];
|
|
|
|
if (string.IsNullOrEmpty(val))
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
return null;
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
return Convert.ChangeType(val, at, CultureInfo.InvariantCulture);
|
|
|
|
|
|
|
|
}
|
|
|
|
return Convert.ChangeType(val, t, CultureInfo.InvariantCulture);
|
|
|
|
}
|
|
|
|
else
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
return defaultValue;
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
public void SetValue(string name, string value, string defaultValue = null, bool preserveExistingCase = false)
|
|
|
|
{
|
|
|
|
if (value == null && defaultValue == "")
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
value = "";
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
if (value == defaultValue)
|
|
|
|
{
|
|
|
|
// if the value is default, only remove the property if it was not already the default
|
|
|
|
// to avoid unnecessary project file churn
|
|
|
|
string res;
|
2016-12-13 06:45:00 -10:00
|
|
|
if (TryGetValue(name, out res) &&
|
|
|
|
!string.Equals(defaultValue ?? "",
|
|
|
|
res, preserveExistingCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal))
|
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
Remove(name);
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
string currentValue;
|
2016-12-13 06:45:00 -10:00
|
|
|
if (preserveExistingCase && TryGetValue(name, out currentValue) &&
|
|
|
|
string.Equals(value, currentValue, StringComparison.OrdinalIgnoreCase))
|
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
return;
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
|
|
|
_values[name] = value;
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
public void SetValue(string name, object value, object defaultValue = null)
|
|
|
|
{
|
|
|
|
var isDefault = object.Equals(value, defaultValue);
|
|
|
|
if (isDefault)
|
|
|
|
{
|
|
|
|
// if the value is default, only remove the property if it was not already the default
|
|
|
|
// to avoid unnecessary project file churn
|
2016-12-13 06:45:00 -10:00
|
|
|
if (ContainsKey(name) && (defaultValue == null ||
|
|
|
|
!object.Equals(defaultValue, GetValue(name, defaultValue.GetType(), null))))
|
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
Remove(name);
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value is bool)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
|
|
|
_values[name] = (bool)value ? "TRUE" : "FALSE";
|
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
else
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
|
|
|
_values[name] = Convert.ToString(value, CultureInfo.InvariantCulture);
|
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
void IDictionary<string, string>.Add(string key, string value)
|
|
|
|
{
|
|
|
|
SetValue(key, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool ContainsKey(string key)
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
return _values.Contains(key);
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
public bool Remove(string key)
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
var wasThere = _values.Contains(key);
|
|
|
|
_values.Remove(key);
|
2016-11-30 14:08:28 -10:00
|
|
|
return wasThere;
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool TryGetValue(string key, out string value)
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
value = (string)_values[key];
|
2016-11-30 14:08:28 -10:00
|
|
|
return value != null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public string this[string index]
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
return (string)_values[index];
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
_values[index] = value;
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public ICollection<string> Values
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
return _values.Values.Cast<string>().ToList();
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public ICollection<string> Keys
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
get { return _values.Keys.Cast<string>().ToList(); }
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
void ICollection<KeyValuePair<string, string>>.Add(KeyValuePair<string, string> item)
|
|
|
|
{
|
|
|
|
SetValue(item.Key, item.Value);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Clear()
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
_values.Clear();
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
internal void ClearExcept(HashSet<string> keys)
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
foreach (var k in _values.Keys.Cast<string>().Except(keys).ToArray())
|
|
|
|
{
|
|
|
|
_values.Remove(k);
|
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ICollection<KeyValuePair<string, string>>.Contains(KeyValuePair<string, string> item)
|
|
|
|
{
|
|
|
|
var val = GetValue(item.Key);
|
|
|
|
return val == item.Value;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void CopyTo(KeyValuePair<string, string>[] array, int arrayIndex)
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
foreach (DictionaryEntry de in _values)
|
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
array[arrayIndex++] = new KeyValuePair<string, string>((string)de.Key, (string)de.Value);
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ICollection<KeyValuePair<string, string>>.Remove(KeyValuePair<string, string> item)
|
|
|
|
{
|
|
|
|
if (((ICollection<KeyValuePair<string, string>>)this).Contains(item))
|
|
|
|
{
|
|
|
|
Remove(item.Key);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
return false;
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
public int Count
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
return _values.Count;
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void SetLines(IEnumerable<KeyValuePair<string, string>> lines)
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
_values.Clear();
|
2016-11-30 14:08:28 -10:00
|
|
|
foreach (var line in lines)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
|
|
|
_values[line.Key] = line.Value;
|
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ICollection<KeyValuePair<string, string>>.IsReadOnly
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
foreach (DictionaryEntry de in _values)
|
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
yield return new KeyValuePair<string, string>((string)de.Key, (string)de.Value);
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
foreach (DictionaryEntry de in _values)
|
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
yield return new KeyValuePair<string, string>((string)de.Key, (string)de.Value);
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public class SlnProjectCollection : Collection<SlnProject>
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
private SlnFile _parentFile;
|
2016-11-30 14:08:28 -10:00
|
|
|
|
|
|
|
internal SlnFile ParentFile
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
return _parentFile;
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
_parentFile = value;
|
2016-11-30 14:08:28 -10:00
|
|
|
foreach (var it in this)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
|
|
|
it.ParentFile = _parentFile;
|
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public SlnProject GetProject(string id)
|
|
|
|
{
|
|
|
|
return this.FirstOrDefault(s => s.Id == id);
|
|
|
|
}
|
|
|
|
|
|
|
|
public SlnProject GetOrCreateProject(string id)
|
|
|
|
{
|
|
|
|
var p = this.FirstOrDefault(s => s.Id.Equals(id, StringComparison.OrdinalIgnoreCase));
|
|
|
|
if (p == null)
|
|
|
|
{
|
|
|
|
p = new SlnProject { Id = id };
|
|
|
|
Add(p);
|
|
|
|
}
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override void InsertItem(int index, SlnProject item)
|
|
|
|
{
|
|
|
|
base.InsertItem(index, item);
|
|
|
|
item.ParentFile = ParentFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override void SetItem(int index, SlnProject item)
|
|
|
|
{
|
|
|
|
base.SetItem(index, item);
|
|
|
|
item.ParentFile = ParentFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override void RemoveItem(int index)
|
|
|
|
{
|
|
|
|
var it = this[index];
|
|
|
|
it.ParentFile = null;
|
|
|
|
base.RemoveItem(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override void ClearItems()
|
|
|
|
{
|
|
|
|
foreach (var it in this)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
it.ParentFile = null;
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
base.ClearItems();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public class SlnSectionCollection : Collection<SlnSection>
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
private SlnFile _parentFile;
|
2016-11-30 14:08:28 -10:00
|
|
|
|
|
|
|
internal SlnFile ParentFile
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
return _parentFile;
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
_parentFile = value;
|
2016-11-30 14:08:28 -10:00
|
|
|
foreach (var it in this)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
|
|
|
it.ParentFile = _parentFile;
|
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public SlnSection GetSection(string id)
|
|
|
|
{
|
|
|
|
return this.FirstOrDefault(s => s.Id == id);
|
|
|
|
}
|
|
|
|
|
|
|
|
public SlnSection GetSection(string id, SlnSectionType sectionType)
|
|
|
|
{
|
|
|
|
return this.FirstOrDefault(s => s.Id == id && s.SectionType == sectionType);
|
|
|
|
}
|
|
|
|
|
|
|
|
public SlnSection GetOrCreateSection(string id, SlnSectionType sectionType)
|
|
|
|
{
|
|
|
|
if (id == null)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
throw new ArgumentNullException("id");
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
var sec = this.FirstOrDefault(s => s.Id == id);
|
|
|
|
if (sec == null)
|
|
|
|
{
|
|
|
|
sec = new SlnSection { Id = id };
|
|
|
|
sec.SectionType = sectionType;
|
|
|
|
Add(sec);
|
|
|
|
}
|
|
|
|
return sec;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void RemoveSection(string id)
|
|
|
|
{
|
|
|
|
if (id == null)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
throw new ArgumentNullException("id");
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
var s = GetSection(id);
|
|
|
|
if (s != null)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
Remove(s);
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
protected override void InsertItem(int index, SlnSection item)
|
|
|
|
{
|
|
|
|
base.InsertItem(index, item);
|
|
|
|
item.ParentFile = ParentFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override void SetItem(int index, SlnSection item)
|
|
|
|
{
|
|
|
|
base.SetItem(index, item);
|
|
|
|
item.ParentFile = ParentFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override void RemoveItem(int index)
|
|
|
|
{
|
|
|
|
var it = this[index];
|
|
|
|
it.ParentFile = null;
|
|
|
|
base.RemoveItem(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override void ClearItems()
|
|
|
|
{
|
|
|
|
foreach (var it in this)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
it.ParentFile = null;
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
base.ClearItems();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public class SlnPropertySetCollection : Collection<SlnPropertySet>
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
private SlnSection _parentSection;
|
2016-11-30 14:08:28 -10:00
|
|
|
|
|
|
|
internal SlnPropertySetCollection(SlnSection parentSection)
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
_parentSection = parentSection;
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
public SlnPropertySet GetPropertySet(string id, bool ignoreCase = false)
|
|
|
|
{
|
|
|
|
var sc = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
|
|
|
|
return this.FirstOrDefault(s => s.Id.Equals(id, sc));
|
|
|
|
}
|
|
|
|
|
|
|
|
public SlnPropertySet GetOrCreatePropertySet(string id, bool ignoreCase = false)
|
|
|
|
{
|
|
|
|
var ps = GetPropertySet(id, ignoreCase);
|
|
|
|
if (ps == null)
|
|
|
|
{
|
|
|
|
ps = new SlnPropertySet(id);
|
|
|
|
Add(ps);
|
|
|
|
}
|
|
|
|
return ps;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override void InsertItem(int index, SlnPropertySet item)
|
|
|
|
{
|
|
|
|
base.InsertItem(index, item);
|
2016-12-13 06:45:00 -10:00
|
|
|
item.ParentSection = _parentSection;
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
protected override void SetItem(int index, SlnPropertySet item)
|
|
|
|
{
|
|
|
|
base.SetItem(index, item);
|
2016-12-13 06:45:00 -10:00
|
|
|
item.ParentSection = _parentSection;
|
2016-11-30 14:08:28 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
protected override void RemoveItem(int index)
|
|
|
|
{
|
|
|
|
var it = this[index];
|
|
|
|
it.ParentSection = null;
|
|
|
|
base.RemoveItem(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override void ClearItems()
|
|
|
|
{
|
|
|
|
foreach (var it in this)
|
2016-12-13 06:45:00 -10:00
|
|
|
{
|
2016-11-30 14:08:28 -10:00
|
|
|
it.ParentSection = null;
|
2016-12-13 06:45:00 -10:00
|
|
|
}
|
2016-11-30 14:08:28 -10:00
|
|
|
base.ClearItems();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class InvalidSolutionFormatException : Exception
|
|
|
|
{
|
|
|
|
public InvalidSolutionFormatException(int line) : base("Invalid format in line " + line)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-12-13 06:45:00 -10:00
|
|
|
public InvalidSolutionFormatException(int line, string msg)
|
|
|
|
: base("Invalid format in line " + line + ": " + msg)
|
2016-11-30 14:08:28 -10:00
|
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public enum SlnSectionType
|
|
|
|
{
|
|
|
|
PreProcess,
|
|
|
|
PostProcess
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|