/// <summary>Reads a "hints" element, consuming the element.</summary> /// <exception cref="XmlException">Thrown when the Android Studio file is incorrect.</exception> /// <param name="reader">The reader from which the hints shall be parsed.</param> /// <param name="strings">NameTable strings used to parse Android Studio files.</param> /// <returns>The set of hint values from <paramref name="reader"/>.</returns> public static ImmutableArray <string> ReadHints(XmlReader reader, AndroidStudioStrings strings) { Debug.Assert(Ref.Equal(reader.LocalName, strings.Hints), "ReadHints didn't have hints"); var result = ImmutableArray.CreateBuilder <string>(); if (!reader.IsEmptyElement) { int hintsDepth = reader.Depth; reader.Read(); // Consume start element while (reader.Depth > hintsDepth) { if (!Ref.Equal(reader.LocalName, strings.Hint)) { throw reader.CreateException(ConverterResources.AndroidStudioHintsElementContainedNonHint); } string hintContent = reader.GetAttribute(strings.Value); if (hintContent == null) { throw reader.CreateException(ConverterResources.AndroidStudioHintElementMissingValue); } if (hintContent.Length != 0) { result.Add(hintContent); } reader.Skip(); } } reader.Read(); // Consume the end / empty element return(result.ToImmutable()); }
/// <summary> /// Parses the element on which an <see cref="XmlReader"/> is positioned as a CppCheck error node. /// </summary> /// <param name="reader">The reader from which a CppCheck error shall be read.</param> /// <param name="strings">Strings used to parse the CppCheck log.</param> /// <returns> /// A <see cref="CppCheckError"/> parsed from the XML on which <paramref name="reader"/> is /// positioned. /// </returns> /// <exception cref="XmlException">The xml on which <paramref name="reader"/> is placed is /// in an incorrect format.</exception> public static CppCheckError Parse(XmlReader reader, CppCheckStrings strings) { if (!reader.IsStartElement(strings.Error)) { throw reader.CreateException(ConverterResources.CppCheckElementNotError); } string id = null; string message = null; string verboseMessage = null; string severity = null; while (reader.MoveToNextAttribute()) { string attributeName = reader.LocalName; if (StringReference.AreEqual(attributeName, strings.Id)) { id = reader.Value; } else if (StringReference.AreEqual(attributeName, strings.Msg)) { message = reader.Value; } else if (StringReference.AreEqual(attributeName, strings.Verbose)) { verboseMessage = reader.Value; } else if (StringReference.AreEqual(attributeName, strings.Severity)) { severity = reader.Value; } } reader.MoveToElement(); ImmutableArray <CppCheckLocation> locations = ParseLocationsSubtree(reader, strings); reader.Read(); // Consumes the end element or self closing element and positions the reader on the next node try { return(new CppCheckError( id, message, verboseMessage, severity, locations )); } catch (ArgumentException ex) { throw reader.CreateException(ex.Message); } }
private void ProcessCppCheckLog(XmlReader reader, IResultLogWriter issueWriter) { reader.ReadStartElement(_strings.Results); if (!Ref.Equal(reader.LocalName, _strings.CppCheck)) { throw reader.CreateException(SarifResources.CppCheckCppCheckElementMissing); } string version = reader.GetAttribute(_strings.Version); if (String.IsNullOrWhiteSpace(version)) { throw reader.CreateException(SarifResources.CppCheckCppCheckElementMissing); } issueWriter.WriteToolAndRunInfo(new ToolInfo { Name = "CppCheck", Version = version, }, null); reader.Skip(); // <cppcheck /> if (!Ref.Equal(reader.LocalName, _strings.Errors)) { throw reader.CreateException(SarifResources.CppCheckErrorsElementMissing); } if (reader.IsEmptyElement) { reader.Skip(); // <errors /> } else { int errorsDepth = reader.Depth; reader.Read(); // <errors> while (reader.Depth > errorsDepth) { var parsedError = CppCheckError.Parse(reader, _strings); issueWriter.WriteResult(parsedError.ToSarifIssue()); } reader.ReadEndElement(); // </errors> } reader.ReadEndElement(); // </results> }
public void Extensions_XmlCreateException_WithFormat() { var testData = new XElement("hello", new XElement("world")); using (XmlReader unitUnderTest = testData.CreateReader()) { XmlException result = unitUnderTest.CreateException("hungry {0} zombies", "evil"); Assert.Equal("hungry evil zombies", result.Message); } }
/// <summary> /// Parses a "location" node from the supplied instance of <see cref="XmlReader"/>. /// </summary> /// <exception cref="XmlException">Thrown if <paramref name="reader"/> points to XML of an /// incorrect format.</exception> /// <param name="reader">The reader from which XML will be parsed. Upon entry to this method, this /// XML reader must be positioned on the location node to parse. Upon completion of this method, /// the reader will be positioned on the node following the location node.</param> /// <param name="strings">Strings used to parse the CppCheck log.</param> /// <returns> /// A <see cref="CppCheckLocation"/> instance containing data from the current node of /// <paramref name="reader"/>. /// </returns> public static CppCheckLocation Parse(XmlReader reader, CppCheckStrings strings) { if (!reader.IsStartElement(strings.Location)) { throw reader.CreateException(ConverterResources.CppCheckLocationElementNameIncorrect); } string file = null; string lineText = null; while (reader.MoveToNextAttribute()) { string name = reader.LocalName; if (StringReference.AreEqual(name, strings.File)) { file = reader.Value; } else if (StringReference.AreEqual(name, strings.Line)) { lineText = reader.Value; } } if (file == null) { throw reader.CreateException(ConverterResources.CppCheckLocationMissingName); } if (lineText == null) { throw reader.CreateException(ConverterResources.CppCheckLocationMissingLine); } int line = XmlConvert.ToInt32(lineText); reader.MoveToElement(); reader.Skip(); return(new CppCheckLocation(file, line)); }
/// <summary>Parses an element as a Fortify PathElement node, consuming the node.</summary> /// <param name="xmlReader">The <see cref="XmlReader"/> from which a node shall be parsed. When /// this function returns, this reader is placed directly after the element on which it is /// currently placed.</param> /// <param name="strings">Strings used in processing Fortify logs.</param> /// <returns>A <see cref="FortifyPathElement"/> parsed from the element on which /// <paramref name="xmlReader"/> is positioned when this method is called.</returns> public static FortifyPathElement Parse(XmlReader xmlReader, FortifyStrings strings) { //<xs:complexType name="PathElement"> // <xs:sequence> // <xs:element name="FileName" type="xs:string" minOccurs="1" maxOccurs="1"/> // <xs:element name="FilePath" type="xs:string" minOccurs="1" maxOccurs="1"/> // <xs:element name="LineStart" type="xs:string" minOccurs="1" maxOccurs="1"/> // <xs:element name="Snippet" type="xs:string" minOccurs="0" maxOccurs="1"/> // <xs:element name="SnippetLine" type="xs:int" minOccurs="0" maxOccurs="1"/> // <xs:element name="TargetFunction" type="xs:string" minOccurs="0" maxOccurs="1"/> // </xs:sequence> //</xs:complexType> if (xmlReader.NodeType != XmlNodeType.Element || xmlReader.IsEmptyElement) { throw xmlReader.CreateException(SarifResources.FortifyNotValidPathElement); } int pathElementDepth = xmlReader.Depth; xmlReader.Read(); // Always true because !IsEmptyElement xmlReader.IgnoreElement(strings.FileName, IgnoreOptions.Required); string filePath = xmlReader.ReadElementContentAsString(strings.FilePath, String.Empty); int lineStart = xmlReader.ReadElementContentAsInt(strings.LineStart, String.Empty); xmlReader.IgnoreElement(strings.Snippet, IgnoreOptions.Optional); xmlReader.IgnoreElement(strings.SnippetLine, IgnoreOptions.Optional); string targetFunction = xmlReader.ReadOptionalElementContentAsString(strings.TargetFunction); xmlReader.ReadEndElement(); try { return(new FortifyPathElement(filePath, lineStart, targetFunction)); } catch (ArgumentException ex) { throw xmlReader.CreateException(ex.Message); } }
public void Extensions_XmlCreateException_WithLineInfo() { // 0000000001111111111222222 // 1234567890123456789012345 using (XmlReader unitUnderTest = Utilities.CreateXmlReaderFromString("<hello> <world/> </hello>")) { unitUnderTest.Read(); // <hello> unitUnderTest.Read(); // <world> XmlException result = unitUnderTest.CreateException("cute fluffy kittens"); Assert.Equal(1, result.LineNumber); Assert.Equal(8, result.LinePosition); } }
public void Extensions_XmlCreateException_WithoutLineInfo() { var testData = new XElement("hello", new XElement("world")); using (XmlReader unitUnderTest = testData.CreateReader()) { unitUnderTest.Read(); // <hello> unitUnderTest.Read(); // <world /> XmlException result = unitUnderTest.CreateException("hungry EVIL zombies"); Assert.Equal(0, result.LineNumber); Assert.Equal(0, result.LinePosition); } }
/// <summary>Asserts that the local name of a given element is the name indicated, and ignores the /// element's contents.</summary> /// <exception cref="XmlException">Thrown when the XML content pointed to by /// <paramref name="xmlReader"/> does not match the indicated <paramref name="elementName"/> and /// <paramref name="options"/>.</exception> /// <param name="xmlReader">The XML reader from which the element shall be read.</param> /// <param name="elementName">Name of the element.</param> /// <param name="options">Options deciding what content to skip.</param> internal static void IgnoreElement(this XmlReader xmlReader, string elementName, IgnoreOptions options) { if (!IsOnElement(xmlReader, elementName)) { if (options.HasFlag(IgnoreOptions.Optional)) { return; } else { throw xmlReader.CreateException(ConverterResources.ExpectedElementNamed, elementName); } } xmlReader.Skip(); if (options.HasFlag(IgnoreOptions.Multiple)) { while (IsOnElement(xmlReader, elementName)) { xmlReader.Skip(); } } }
/// <summary>Creates an exception with line number and position data from an /// <see cref="XmlReader"/>.</summary> /// <param name="xmlReader">The xmlReader from which line data shall be retrieved.</param> /// <param name="message">The message to attach to the exception.</param> /// <param name="args">A variable-length parameters list containing arguments formatted into /// <paramref name="message"/>.</param> /// <returns>The new exception with <paramref name="message"/>, and file and line information from /// <paramref name="xmlReader"/>.</returns> internal static XmlException CreateException(this XmlReader xmlReader, string message, params object[] args) { return(xmlReader.CreateException(string.Format(CultureInfo.CurrentCulture, message, args))); }
private void ProcessCppCheckLog(XmlReader reader, IResultLogWriter output, OptionallyEmittedData dataToInsert) { reader.ReadStartElement(_strings.Results); if (!StringReference.AreEqual(reader.LocalName, _strings.CppCheck)) { throw reader.CreateException(ConverterResources.CppCheckCppCheckElementMissing); } string version = reader.GetAttribute(_strings.Version); if (version != null && !version.IsSemanticVersioningCompatible()) { // This logic only fixes up simple cases, such as being passed // 1.66, where Semantic Versioning 2.0 requires 1.66.0. Also // strips Revision member if passed a complete .NET version. Version dotNetVersion; if (Version.TryParse(version, out dotNetVersion)) { version = Math.Max(0, dotNetVersion.Major) + "." + Math.Max(0, dotNetVersion.Minor) + "." + Math.Max(0, dotNetVersion.Build); } } if (String.IsNullOrWhiteSpace(version)) { throw reader.CreateException(ConverterResources.CppCheckCppCheckElementMissing); } reader.Skip(); // <cppcheck /> if (!StringReference.AreEqual(reader.LocalName, _strings.Errors)) { throw reader.CreateException(ConverterResources.CppCheckErrorsElementMissing); } var results = new List <Result>(); if (reader.IsEmptyElement) { reader.Skip(); // <errors /> } else { int errorsDepth = reader.Depth; reader.Read(); // <errors> while (reader.Depth > errorsDepth) { var parsedError = CppCheckError.Parse(reader, _strings); results.Add(parsedError.ToSarifIssue()); } reader.ReadEndElement(); // </errors> } reader.ReadEndElement(); // </results> var tool = new Tool { Name = "CppCheck", Version = version, }; var fileInfoFactory = new FileInfoFactory(uri => MimeType.Cpp, dataToInsert); Dictionary <string, FileData> fileDictionary = fileInfoFactory.Create(results); var run = new Run() { Tool = tool }; output.Initialize(run); if (fileDictionary != null && fileDictionary.Count > 0) { output.WriteFiles(fileDictionary); } output.OpenResults(); output.WriteResults(results); output.CloseResults(); }
/// <summary>Parses a "problem" node from an Android Studio log and consumes that node.</summary> /// <exception cref="XmlException">Thrown when the Android Studio file is incorrect.</exception> /// <param name="reader">The reader from which the problem shall be parsed.</param> /// <param name="strings">NameTable strings used to parse Android Studio files.</param> /// <returns> /// If the problem node is not empty, an instance of <see cref="AndroidStudioProblem" />; /// otherwise, null. /// </returns> public static AndroidStudioProblem Parse(XmlReader reader, AndroidStudioStrings strings) { if (!reader.IsStartElement(strings.Problem)) { throw reader.CreateException(ConverterResources.AndroidStudioNotProblemElement); } Builder b = new Builder(); if (!reader.IsEmptyElement) { int problemDepth = reader.Depth; reader.Read(); // Get to children while (reader.Depth > problemDepth) { string nodeName = reader.LocalName; if (Ref.Equal(nodeName, strings.File)) { b.File = reader.ReadElementContentAsString(); } else if (Ref.Equal(nodeName, strings.Line)) { b.Line = Math.Max(1, reader.ReadElementContentAsInt()); } else if (Ref.Equal(nodeName, strings.Module)) { b.Module = reader.ReadElementContentAsString(); } else if (Ref.Equal(nodeName, strings.Package)) { b.Package = reader.ReadElementContentAsString(); } else if (Ref.Equal(nodeName, strings.EntryPoint)) { ReadEntryPointElement(ref b, reader, strings); } else if (Ref.Equal(nodeName, strings.ProblemClass)) { ReadProblemClassElement(ref b, reader, strings); } else if (Ref.Equal(nodeName, strings.Hints)) { b.Hints = ReadHints(reader, strings); } else if (Ref.Equal(nodeName, strings.Description)) { b.Description = reader.ReadElementContentAsString(); } else { reader.Skip(); } } } reader.Read(); // Consume the empty / end element if (b.IsEmpty) { return(null); } try { return(new AndroidStudioProblem(b)); } catch (ArgumentException invalidData) { throw reader.CreateException(invalidData.Message); } }
private void ProcessCppCheckLog(XmlReader reader, IResultLogWriter output, OptionallyEmittedData dataToInsert) { reader.ReadStartElement(_strings.Results); if (!StringReference.AreEqual(reader.LocalName, _strings.CppCheck)) { throw reader.CreateException(ConverterResources.CppCheckCppCheckElementMissing); } string version = reader.GetAttribute(_strings.Version); if (version != null && !version.IsSemanticVersioningCompatible()) { // This logic only fixes up simple cases, such as being passed // 1.66, where Semantic Versioning 2.0 requires 1.66.0. Also // strips Revision member if passed a complete .NET version. Version dotNetVersion; if (Version.TryParse(version, out dotNetVersion)) { version = Math.Max(0, dotNetVersion.Major) + "." + Math.Max(0, dotNetVersion.Minor) + "." + Math.Max(0, dotNetVersion.Build); } } if (string.IsNullOrWhiteSpace(version)) { throw reader.CreateException(ConverterResources.CppCheckCppCheckElementMissing); } reader.Skip(); // <cppcheck /> if (!StringReference.AreEqual(reader.LocalName, _strings.Errors)) { throw reader.CreateException(ConverterResources.CppCheckErrorsElementMissing); } var results = new List <Result>(); if (reader.IsEmptyElement) { reader.Skip(); // <errors /> } else { int errorsDepth = reader.Depth; reader.Read(); // <errors> while (reader.Depth > errorsDepth) { var parsedError = CppCheckError.Parse(reader, _strings); results.Add(parsedError.ToSarifIssue()); } reader.ReadEndElement(); // </errors> } reader.ReadEndElement(); // </results> var run = new Run() { Tool = new Tool { Driver = new ToolComponent { Name = ToolName, Version = version } }, }; PersistResults(output, results, run); }
/// <summary> /// Parses a Fortify Result element from an <see cref="XmlReader"/>. /// </summary> /// <param name="xmlReader">The <see cref="XmlReader"/> from which an element containing a Fortify result shall be /// consumed. When this method returns, this <see cref="XmlReader"/> is positioned on the following element.</param> /// <param name="strings">Strings used in processing a Fortify report.</param> /// <returns>A <see cref="FortifyIssue"/> containing data from the node on which <paramref name="xmlReader"/> was /// placed when this method was called.</returns> public static FortifyIssue Parse(XmlReader xmlReader, FortifyStrings strings) { //<xs:element name="Result"> // <xs:complexType> // <xs:sequence> // <!-- Result Description --> // <xs:element name="Category" type="xs:string" minOccurs="1" maxOccurs="1"/> // <xs:element name="Folder" type="xs:string" minOccurs="1" maxOccurs="1"/> // <xs:element name="Kingdom" type="xs:string" minOccurs="1" maxOccurs="1"/> // <xs:element name="Abstract" type="xs:string" minOccurs="0" maxOccurs="1"/> // <xs:element name="AbstractCustom" type="xs:string" minOccurs="0" maxOccurs="1"/> // <xs:element name="Friority" type="xs:string" minOccurs="0" maxOccurs="1"/> // <!-- custom tags including Analysis --> // <xs:element name="Tag" minOccurs="0" maxOccurs="unbounded"> // <xs:complexType> // <xs:sequence> // <xs:element name="Name" type="xs:string" minOccurs="1" maxOccurs="1"/> // <xs:element name="Value" type="xs:string" minOccurs="1" maxOccurs="1"/> // </xs:sequence> // </xs:complexType> // </xs:element> // <xs:element name="Comment" minOccurs="0" maxOccurs="unbounded"> // <xs:complexType> // <xs:sequence> // <xs:element name="UserInfo" type="xs:string" minOccurs="1" maxOccurs="1"/> // <xs:element name="Comment" type="xs:string" minOccurs="1" maxOccurs="1"/> // </xs:sequence> // </xs:complexType> // </xs:element> // <!-- primary or sink --> // <xs:element name="Primary" type="PathElement" minOccurs="1" maxOccurs="1"/> // <!-- source --> // <xs:element name="Source" type="PathElement" minOccurs="0" maxOccurs="1"/> // <xs:element name="TraceDiagramPath" type="xs:string" minOccurs="0" maxOccurs="1"/> // <!-- optional external category (i.e. STIG) --> // <xs:element name="ExternalCategory" minOccurs="0" maxOccurs="1"> // <xs:complexType> // <xs:simpleContent> // <xs:extension base="xs:string"> // <xs:attribute name="type" type="xs:string" use="required"/> // </xs:extension> // </xs:simpleContent> // </xs:complexType> // </xs:element> // </xs:sequence> // <xs:attribute name="iid" type="xs:string" use="optional"/> // <xs:attribute name="ruleID" type="xs:string" use="optional"/> // </xs:complexType> //</xs:element> if (!xmlReader.IsStartElement(strings.Issue)) { throw xmlReader.CreateException(ConverterResources.FortifyNotValidResult); } string iid = null; string ruleId = null; while (xmlReader.MoveToNextAttribute()) { string name = xmlReader.LocalName; if (StringReference.AreEqual(name, strings.Iid)) { iid = xmlReader.Value; } else if (StringReference.AreEqual(name, strings.RuleId)) { ruleId = xmlReader.Value; } } xmlReader.MoveToElement(); xmlReader.Read(); // reads start element string category = xmlReader.ReadElementContentAsString(strings.Category, String.Empty); xmlReader.IgnoreElement(strings.Folder, IgnoreOptions.Required); string kingdom = xmlReader.ReadElementContentAsString(strings.Kingdom, String.Empty); string abstract_ = xmlReader.ReadOptionalElementContentAsString(strings.Abstract); string abstractCustom = xmlReader.ReadOptionalElementContentAsString(strings.AbstractCustom); string friority = xmlReader.ReadOptionalElementContentAsString(strings.Friority); xmlReader.IgnoreElement(strings.Tag, IgnoreOptions.Optional | IgnoreOptions.Multiple); xmlReader.IgnoreElement(strings.Comment, IgnoreOptions.Optional | IgnoreOptions.Multiple); FortifyPathElement primary = FortifyPathElement.Parse(xmlReader, strings); FortifyPathElement source; if (xmlReader.NodeType == XmlNodeType.Element && StringReference.AreEqual(xmlReader.LocalName, strings.Source)) { source = FortifyPathElement.Parse(xmlReader, strings); } else { source = null; } xmlReader.IgnoreElement(strings.TraceDiagramPath, IgnoreOptions.Optional); ImmutableArray <int> cweIds = ImmutableArray <int> .Empty; if (xmlReader.NodeType == XmlNodeType.Element && StringReference.AreEqual(xmlReader.LocalName, strings.ExternalCategory)) { if (xmlReader.GetAttribute(strings.Type) == "CWE") { cweIds = ParseCweIds(xmlReader.ReadElementContentAsString()); } else { xmlReader.Skip(); } } xmlReader.ReadEndElement(); // </Result> return(new FortifyIssue(ruleId, iid, category, kingdom, abstract_, abstractCustom, friority, primary, source, cweIds)); }
private void ProcessCppCheckLog(XmlReader reader, IResultLogWriter output) { reader.ReadStartElement(_strings.Results); if (!Ref.Equal(reader.LocalName, _strings.CppCheck)) { throw reader.CreateException(ConverterResources.CppCheckCppCheckElementMissing); } string version = reader.GetAttribute(_strings.Version); if (version != null && !version.IsSemanticVersioningCompatible()) { // This logic only fixes up simple cases, such as being passed // 1.66, where Semantic Versioning 2.0 requires 1.66.0. Also // strips Revision member if passed a complete .NET version. Version dotNetVersion; if (Version.TryParse(version, out dotNetVersion)) { version = Math.Max(0, dotNetVersion.Major) + "." + Math.Max(0, dotNetVersion.Minor) + "." + Math.Max(0, dotNetVersion.Build); } } if (String.IsNullOrWhiteSpace(version)) { throw reader.CreateException(ConverterResources.CppCheckCppCheckElementMissing); } reader.Skip(); // <cppcheck /> if (!Ref.Equal(reader.LocalName, _strings.Errors)) { throw reader.CreateException(ConverterResources.CppCheckErrorsElementMissing); } var results = new List<Result>(); if (reader.IsEmptyElement) { reader.Skip(); // <errors /> } else { int errorsDepth = reader.Depth; reader.Read(); // <errors> while (reader.Depth > errorsDepth) { var parsedError = CppCheckError.Parse(reader, _strings); results.Add(parsedError.ToSarifIssue()); } reader.ReadEndElement(); // </errors> } reader.ReadEndElement(); // </results> var tool = new Tool { Name = "CppCheck", Version = version, }; var fileInfoFactory = new FileInfoFactory(uri => MimeType.Cpp); Dictionary<string, FileData> fileDictionary = fileInfoFactory.Create(results); output.Initialize(id: null, correlationId: null); output.WriteTool(tool); if (fileDictionary != null && fileDictionary.Count > 0) { output.WriteFiles(fileDictionary); } output.OpenResults(); output.WriteResults(results); output.CloseResults(); }