aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Data/SourceLineNumber.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Data/SourceLineNumber.cs')
-rw-r--r--src/WixToolset.Data/SourceLineNumber.cs205
1 files changed, 205 insertions, 0 deletions
diff --git a/src/WixToolset.Data/SourceLineNumber.cs b/src/WixToolset.Data/SourceLineNumber.cs
new file mode 100644
index 00000000..87a36132
--- /dev/null
+++ b/src/WixToolset.Data/SourceLineNumber.cs
@@ -0,0 +1,205 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Data
4{
5 using System;
6 using System.IO;
7 using System.Text;
8 using System.Xml;
9 using System.Xml.Linq;
10
11 /// <summary>
12 /// Represents file name and line number for source file
13 /// </summary>
14 public sealed class SourceLineNumber
15 {
16 /// <summary>
17 /// Constructor for a source with no line information.
18 /// </summary>
19 /// <param name="fileName">File name of the source.</param>
20 public SourceLineNumber(string fileName)
21 {
22 this.FileName = fileName;
23 }
24
25 /// <summary>
26 /// Constructor for a source with line information.
27 /// </summary>
28 /// <param name="fileName">File name of the source.</param>
29 /// <param name="lineNumber">Line number of the source.</param>
30 public SourceLineNumber(string fileName, int lineNumber)
31 {
32 this.FileName = fileName;
33 this.LineNumber = lineNumber;
34 }
35
36 /// <summary>
37 /// Gets the file name of the source.
38 /// </summary>
39 /// <value>File name for the source.</value>
40 public string FileName { get; private set; }
41
42 /// <summary>
43 /// Gets or sets the line number of the source.
44 /// </summary>
45 /// <value>Line number of the source.</value>
46 public int? LineNumber { get; set; }
47
48 /// <summary>
49 /// Gets or sets the parent source line number that included this source line number.
50 /// </summary>
51 public SourceLineNumber Parent { get; set; }
52
53 /// <summary>
54 /// Gets the file name and line information.
55 /// </summary>
56 /// <value>File name and line information.</value>
57 public string QualifiedFileName
58 {
59 get
60 {
61 return this.LineNumber.HasValue ? String.Concat(this.FileName, "*", this.LineNumber) : this.FileName;
62 }
63 }
64
65 /// <summary>
66 /// Creates a source line number from an encoded string.
67 /// </summary>
68 /// <param name="encodedSourceLineNumbers">Encoded string to parse.</param>
69 public static SourceLineNumber CreateFromEncoded(string encodedSourceLineNumbers)
70 {
71 string[] linesSplit = encodedSourceLineNumbers.Split('|');
72
73 SourceLineNumber first = null;
74 SourceLineNumber parent = null;
75 for (int i = 0; i < linesSplit.Length; ++i)
76 {
77 string[] filenameSplit = linesSplit[i].Split('*');
78 SourceLineNumber source;
79
80 if (2 == filenameSplit.Length)
81 {
82 source = new SourceLineNumber(filenameSplit[0], Convert.ToInt32(filenameSplit[1]));
83 }
84 else
85 {
86 source = new SourceLineNumber(filenameSplit[0]);
87 }
88
89 if (null != parent)
90 {
91 parent.Parent = source;
92 }
93
94 parent = source;
95 if (null == first)
96 {
97 first = parent;
98 }
99 }
100
101 return first;
102 }
103
104 /// <summary>
105 /// Creates a source line number from a URI.
106 /// </summary>
107 /// <param name="uri">Uri to convert into source line number</param>
108 public static SourceLineNumber CreateFromUri(string uri)
109 {
110 if (String.IsNullOrEmpty(uri))
111 {
112 return null;
113 }
114
115 // make the local path look like a normal local path
116 string localPath = new Uri(uri).LocalPath;
117 localPath = localPath.TrimStart(Path.AltDirectorySeparatorChar).Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
118
119 return new SourceLineNumber(localPath);
120 }
121
122 /// <summary>
123 /// Creates a source line number from an XObject.
124 /// </summary>
125 /// <param name="node">XML node to create source line number from.</param>
126 /// <param name="offset">Optional line number offset into XML file not already included in the line information.</param>
127 public static SourceLineNumber CreateFromXObject(XObject node, int offset = 0)
128 {
129 string uri = node.BaseUri;
130 IXmlLineInfo lineInfo = node as IXmlLineInfo;
131
132 SourceLineNumber result = CreateFromUri(uri);
133 if (null != result && null != lineInfo)
134 {
135 result.LineNumber = lineInfo.LineNumber + offset;
136 }
137
138 return result;
139 }
140
141 /// <summary>
142 /// Get the source line information for the current element. Typically this information
143 /// is set by the precompiler for each element that it encounters.
144 /// </summary>
145 /// <param name="node">Element to get source line information for.</param>
146 /// <returns>
147 /// The source line number used to author the element being processed or
148 /// null if the preprocessor did not process the element or the node is
149 /// not an element.
150 /// </returns>
151 public static SourceLineNumber GetFromXAnnotation(XObject node)
152 {
153 return node.Annotation<SourceLineNumber>();
154 }
155
156 /// <summary>
157 /// Returns the SourceLineNumber and parents encoded as a string.
158 /// </summary>
159 public string GetEncoded()
160 {
161 StringBuilder sb = new StringBuilder(this.QualifiedFileName);
162
163 for (SourceLineNumber source = this.Parent; null != source; source = source.Parent)
164 {
165 sb.Append("|");
166 sb.Append(source.QualifiedFileName);
167 }
168
169 return sb.ToString();
170 }
171
172 /// <summary>
173 /// Determines if two SourceLineNumbers are equivalent.
174 /// </summary>
175 /// <param name="obj">Object to compare.</param>
176 /// <returns>True if SourceLineNumbers are equivalent.</returns>
177 public override bool Equals(object obj)
178 {
179 SourceLineNumber other = obj as SourceLineNumber;
180 return null != other &&
181 this.LineNumber.HasValue == other.LineNumber.HasValue &&
182 (!this.LineNumber.HasValue || this.LineNumber == other.LineNumber) &&
183 this.FileName.Equals(other.FileName, StringComparison.OrdinalIgnoreCase) &&
184 (null == this.Parent && null == other.Parent || this.Parent.Equals(other.Parent));
185 }
186
187 /// <summary>
188 /// Serves as a hash code for a particular type.
189 /// </summary>
190 /// <returns>The hash code.</returns>
191 public override int GetHashCode()
192 {
193 return this.GetEncoded().GetHashCode();
194 }
195
196 /// <summary>
197 /// Shows a string representation of a source line number.
198 /// </summary>
199 /// <returns>String representation of a source line number.</returns>
200 public override string ToString()
201 {
202 return this.LineNumber.HasValue && !String.IsNullOrEmpty(this.FileName) ? String.Concat(this.FileName, "(", this.LineNumber, ")") : this.FileName ?? String.Empty;
203 }
204 }
205}