diff options
Diffstat (limited to 'src/WixToolset.Converters/WixConverter.cs')
-rw-r--r-- | src/WixToolset.Converters/WixConverter.cs | 179 |
1 files changed, 109 insertions, 70 deletions
diff --git a/src/WixToolset.Converters/WixConverter.cs b/src/WixToolset.Converters/WixConverter.cs index a05c7f58..bfeed03e 100644 --- a/src/WixToolset.Converters/WixConverter.cs +++ b/src/WixToolset.Converters/WixConverter.cs | |||
@@ -19,6 +19,12 @@ namespace WixToolset.Converters | |||
19 | /// </summary> | 19 | /// </summary> |
20 | public class WixConverter | 20 | public class WixConverter |
21 | { | 21 | { |
22 | private enum ConvertOperation | ||
23 | { | ||
24 | Convert, | ||
25 | Format, | ||
26 | } | ||
27 | |||
22 | private static readonly Regex AddPrefix = new Regex(@"^[^a-zA-Z_]", RegexOptions.Compiled); | 28 | private static readonly Regex AddPrefix = new Regex(@"^[^a-zA-Z_]", RegexOptions.Compiled); |
23 | private static readonly Regex IllegalIdentifierCharacters = new Regex(@"[^A-Za-z0-9_\.]|\.{2,}", RegexOptions.Compiled); // non 'words' and assorted valid characters | 29 | private static readonly Regex IllegalIdentifierCharacters = new Regex(@"[^A-Za-z0-9_\.]|\.{2,}", RegexOptions.Compiled); // non 'words' and assorted valid characters |
24 | 30 | ||
@@ -107,18 +113,6 @@ namespace WixToolset.Converters | |||
107 | { "http://schemas.microsoft.com/wix/2006/WixUnit", "http://wixtoolset.org/schemas/v4/wixunit" }, | 113 | { "http://schemas.microsoft.com/wix/2006/WixUnit", "http://wixtoolset.org/schemas/v4/wixunit" }, |
108 | }; | 114 | }; |
109 | 115 | ||
110 | private readonly static SortedSet<string> Wix3Namespaces = new SortedSet<string> | ||
111 | { | ||
112 | "http://schemas.microsoft.com/wix/2006/wi", | ||
113 | "http://schemas.microsoft.com/wix/2006/localization", | ||
114 | }; | ||
115 | |||
116 | private readonly static SortedSet<string> Wix4Namespaces = new SortedSet<string> | ||
117 | { | ||
118 | "http://wixtoolset.org/schemas/v4/wxs", | ||
119 | "http://wixtoolset.org/schemas/v4/wxl", | ||
120 | }; | ||
121 | |||
122 | private readonly Dictionary<XName, Action<XElement>> ConvertElementMapping; | 116 | private readonly Dictionary<XName, Action<XElement>> ConvertElementMapping; |
123 | 117 | ||
124 | /// <summary> | 118 | /// <summary> |
@@ -193,6 +187,8 @@ namespace WixToolset.Converters | |||
193 | 187 | ||
194 | private int IndentationAmount { get; set; } | 188 | private int IndentationAmount { get; set; } |
195 | 189 | ||
190 | private ConvertOperation Operation { get; set; } | ||
191 | |||
196 | private string SourceFile { get; set; } | 192 | private string SourceFile { get; set; } |
197 | 193 | ||
198 | private int SourceVersion { get; set; } | 194 | private int SourceVersion { get; set; } |
@@ -205,22 +201,11 @@ namespace WixToolset.Converters | |||
205 | /// <returns>The number of errors found.</returns> | 201 | /// <returns>The number of errors found.</returns> |
206 | public int ConvertFile(string sourceFile, bool saveConvertedFile) | 202 | public int ConvertFile(string sourceFile, bool saveConvertedFile) |
207 | { | 203 | { |
208 | XDocument document; | 204 | var document = this.OpenSourceFile(sourceFile); |
209 | |||
210 | // Set the instance info. | ||
211 | this.Errors = 0; | ||
212 | this.SourceFile = sourceFile; | ||
213 | this.SourceVersion = 0; | ||
214 | 205 | ||
215 | try | 206 | if (document is null) |
216 | { | 207 | { |
217 | document = XDocument.Load(this.SourceFile, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | 208 | return 1; |
218 | } | ||
219 | catch (XmlException e) | ||
220 | { | ||
221 | this.OnError(ConverterTestType.XmlException, null, "The xml is invalid. Detail: '{0}'", e.Message); | ||
222 | |||
223 | return this.Errors; | ||
224 | } | 209 | } |
225 | 210 | ||
226 | this.ConvertDocument(document); | 211 | this.ConvertDocument(document); |
@@ -228,17 +213,7 @@ namespace WixToolset.Converters | |||
228 | // Fix errors if requested and necessary. | 213 | // Fix errors if requested and necessary. |
229 | if (saveConvertedFile && 0 < this.Errors) | 214 | if (saveConvertedFile && 0 < this.Errors) |
230 | { | 215 | { |
231 | try | 216 | this.SaveDocument(document); |
232 | { | ||
233 | using (var writer = XmlWriter.Create(this.SourceFile, new XmlWriterSettings { OmitXmlDeclaration = true })) | ||
234 | { | ||
235 | document.Save(writer); | ||
236 | } | ||
237 | } | ||
238 | catch (UnauthorizedAccessException) | ||
239 | { | ||
240 | this.OnError(ConverterTestType.UnauthorizedAccessException, null, "Could not write to file."); | ||
241 | } | ||
242 | } | 217 | } |
243 | 218 | ||
244 | return this.Errors; | 219 | return this.Errors; |
@@ -251,13 +226,68 @@ namespace WixToolset.Converters | |||
251 | /// <returns>The number of errors found.</returns> | 226 | /// <returns>The number of errors found.</returns> |
252 | public int ConvertDocument(XDocument document) | 227 | public int ConvertDocument(XDocument document) |
253 | { | 228 | { |
229 | // Reset the instance info. | ||
254 | this.Errors = 0; | 230 | this.Errors = 0; |
255 | this.SourceVersion = 0; | 231 | this.SourceVersion = 0; |
232 | this.Operation = ConvertOperation.Convert; | ||
233 | |||
234 | // Remove the declaration. | ||
235 | if (null != document.Declaration) | ||
236 | { | ||
237 | if (this.OnError(ConverterTestType.DeclarationPresent, null, "This file contains an XML declaration on the first line.")) | ||
238 | { | ||
239 | document.Declaration = null; | ||
240 | } | ||
241 | } | ||
242 | |||
243 | TrimLeadingText(document); | ||
244 | |||
245 | // Start converting the nodes at the top. | ||
246 | this.ConvertNodes(document.Nodes(), 0); | ||
247 | |||
248 | return this.Errors; | ||
249 | } | ||
256 | 250 | ||
257 | var declaration = document.Declaration; | 251 | /// <summary> |
252 | /// Format a file. | ||
253 | /// </summary> | ||
254 | /// <param name="sourceFile">The file to format.</param> | ||
255 | /// <param name="saveConvertedFile">Option to save the format errors that are found.</param> | ||
256 | /// <returns>The number of errors found.</returns> | ||
257 | public int FormatFile(string sourceFile, bool saveConvertedFile) | ||
258 | { | ||
259 | var document = this.OpenSourceFile(sourceFile); | ||
260 | |||
261 | if (document is null) | ||
262 | { | ||
263 | return 1; | ||
264 | } | ||
265 | |||
266 | this.FormatDocument(document); | ||
267 | |||
268 | // Fix errors if requested and necessary. | ||
269 | if (saveConvertedFile && 0 < this.Errors) | ||
270 | { | ||
271 | this.SaveDocument(document); | ||
272 | } | ||
273 | |||
274 | return this.Errors; | ||
275 | } | ||
276 | |||
277 | /// <summary> | ||
278 | /// Format a document. | ||
279 | /// </summary> | ||
280 | /// <param name="document">The document to format.</param> | ||
281 | /// <returns>The number of errors found.</returns> | ||
282 | public int FormatDocument(XDocument document) | ||
283 | { | ||
284 | // Reset the instance info. | ||
285 | this.Errors = 0; | ||
286 | this.SourceVersion = 0; | ||
287 | this.Operation = ConvertOperation.Format; | ||
258 | 288 | ||
259 | // Remove the declaration. | 289 | // Remove the declaration. |
260 | if (null != declaration) | 290 | if (null != document.Declaration) |
261 | { | 291 | { |
262 | if (this.OnError(ConverterTestType.DeclarationPresent, null, "This file contains an XML declaration on the first line.")) | 292 | if (this.OnError(ConverterTestType.DeclarationPresent, null, "This file contains an XML declaration on the first line.")) |
263 | { | 293 | { |
@@ -273,6 +303,37 @@ namespace WixToolset.Converters | |||
273 | return this.Errors; | 303 | return this.Errors; |
274 | } | 304 | } |
275 | 305 | ||
306 | private XDocument OpenSourceFile(string sourceFile) | ||
307 | { | ||
308 | this.SourceFile = sourceFile; | ||
309 | |||
310 | try | ||
311 | { | ||
312 | return XDocument.Load(this.SourceFile, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
313 | } | ||
314 | catch (XmlException e) | ||
315 | { | ||
316 | this.OnError(ConverterTestType.XmlException, null, "The xml is invalid. Detail: '{0}'", e.Message); | ||
317 | } | ||
318 | |||
319 | return null; | ||
320 | } | ||
321 | |||
322 | private void SaveDocument(XDocument document) | ||
323 | { | ||
324 | try | ||
325 | { | ||
326 | using (var writer = XmlWriter.Create(this.SourceFile, new XmlWriterSettings { OmitXmlDeclaration = true })) | ||
327 | { | ||
328 | document.Save(writer); | ||
329 | } | ||
330 | } | ||
331 | catch (UnauthorizedAccessException) | ||
332 | { | ||
333 | this.OnError(ConverterTestType.UnauthorizedAccessException, null, "Could not write to file."); | ||
334 | } | ||
335 | } | ||
336 | |||
276 | private void ConvertNodes(IEnumerable<XNode> nodes, int level) | 337 | private void ConvertNodes(IEnumerable<XNode> nodes, int level) |
277 | { | 338 | { |
278 | // Note we operate on a copy of the node list since we may | 339 | // Note we operate on a copy of the node list since we may |
@@ -901,7 +962,10 @@ namespace WixToolset.Converters | |||
901 | /// <returns>Returns true indicating that action should be taken on this error, and false if it should be ignored.</returns> | 962 | /// <returns>Returns true indicating that action should be taken on this error, and false if it should be ignored.</returns> |
902 | private bool OnError(ConverterTestType converterTestType, XObject node, string message, params object[] args) | 963 | private bool OnError(ConverterTestType converterTestType, XObject node, string message, params object[] args) |
903 | { | 964 | { |
904 | if (this.IgnoreErrors.Contains(converterTestType)) // ignore the error | 965 | // Ignore the error if explicitly ignored or outside the range of the current operation. |
966 | if (this.IgnoreErrors.Contains(converterTestType) || | ||
967 | (this.Operation == ConvertOperation.Convert && converterTestType < ConverterTestType.DeclarationPresent) || | ||
968 | (this.Operation == ConvertOperation.Format && converterTestType > ConverterTestType.DeclarationPresent)) | ||
905 | { | 969 | { |
906 | return false; | 970 | return false; |
907 | } | 971 | } |
@@ -909,7 +973,7 @@ namespace WixToolset.Converters | |||
909 | // Increase the error count. | 973 | // Increase the error count. |
910 | this.Errors++; | 974 | this.Errors++; |
911 | 975 | ||
912 | var sourceLine = (null == node) ? new SourceLineNumber(this.SourceFile ?? "wixcop.exe") : new SourceLineNumber(this.SourceFile, ((IXmlLineInfo)node).LineNumber); | 976 | var sourceLine = (null == node) ? new SourceLineNumber(this.SourceFile ?? "wix.exe") : new SourceLineNumber(this.SourceFile, ((IXmlLineInfo)node).LineNumber); |
913 | var warning = this.ErrorsAsWarnings.Contains(converterTestType); | 977 | var warning = this.ErrorsAsWarnings.Contains(converterTestType); |
914 | var display = String.Format(CultureInfo.CurrentCulture, message, args); | 978 | var display = String.Format(CultureInfo.CurrentCulture, message, args); |
915 | 979 | ||
@@ -1050,39 +1114,19 @@ namespace WixToolset.Converters | |||
1050 | UnauthorizedAccessException, | 1114 | UnauthorizedAccessException, |
1051 | 1115 | ||
1052 | /// <summary> | 1116 | /// <summary> |
1053 | /// Displayed when the encoding attribute in the XML declaration is not 'UTF-8'. | ||
1054 | /// </summary> | ||
1055 | DeclarationEncodingWrong, | ||
1056 | |||
1057 | /// <summary> | ||
1058 | /// Displayed when the XML declaration is missing from the source file. | ||
1059 | /// </summary> | ||
1060 | DeclarationMissing, | ||
1061 | |||
1062 | /// <summary> | ||
1063 | /// Displayed when the whitespace preceding a CDATA node is wrong. | ||
1064 | /// </summary> | ||
1065 | WhitespacePrecedingCDATAWrong, | ||
1066 | |||
1067 | /// <summary> | ||
1068 | /// Displayed when the whitespace preceding a node is wrong. | 1117 | /// Displayed when the whitespace preceding a node is wrong. |
1069 | /// </summary> | 1118 | /// </summary> |
1070 | WhitespacePrecedingNodeWrong, | 1119 | WhitespacePrecedingNodeWrong, |
1071 | 1120 | ||
1072 | /// <summary> | 1121 | /// <summary> |
1073 | /// Displayed when an element is not empty as it should be. | 1122 | /// Displayed when the whitespace preceding an end element is wrong. |
1074 | /// </summary> | ||
1075 | NotEmptyElement, | ||
1076 | |||
1077 | /// <summary> | ||
1078 | /// Displayed when the whitespace following a CDATA node is wrong. | ||
1079 | /// </summary> | 1123 | /// </summary> |
1080 | WhitespaceFollowingCDATAWrong, | 1124 | WhitespacePrecedingEndElementWrong, |
1081 | 1125 | ||
1082 | /// <summary> | 1126 | /// <summary> |
1083 | /// Displayed when the whitespace preceding an end element is wrong. | 1127 | /// Displayed when the XML declaration is present in the source file. |
1084 | /// </summary> | 1128 | /// </summary> |
1085 | WhitespacePrecedingEndElementWrong, | 1129 | DeclarationPresent, |
1086 | 1130 | ||
1087 | /// <summary> | 1131 | /// <summary> |
1088 | /// Displayed when the xmlns attribute is missing from the document element. | 1132 | /// Displayed when the xmlns attribute is missing from the document element. |
@@ -1155,11 +1199,6 @@ namespace WixToolset.Converters | |||
1155 | AutoGuidUnnecessary, | 1199 | AutoGuidUnnecessary, |
1156 | 1200 | ||
1157 | /// <summary> | 1201 | /// <summary> |
1158 | /// Displayed when the XML declaration is present in the source file. | ||
1159 | /// </summary> | ||
1160 | DeclarationPresent, | ||
1161 | |||
1162 | /// <summary> | ||
1163 | /// The Feature Absent attribute renamed to AllowAbsent. | 1202 | /// The Feature Absent attribute renamed to AllowAbsent. |
1164 | /// </summary> | 1203 | /// </summary> |
1165 | FeatureAbsentAttributeReplaced, | 1204 | FeatureAbsentAttributeReplaced, |