From 48db17f05977483044309722f174926b71ce9ecf Mon Sep 17 00:00:00 2001 From: FabioFerrettiMoodys <> Date: Wed, 29 Apr 2020 08:21:50 +0200 Subject: [PATCH 1/8] Adding support for css inclusion Read the content of a A containing the path of the file to open. + /// base uri for linked file /// An with the contents loaded. /// The document at the specified cannot be found. - public static SvgDocument Open(string path) + public static SvgDocument Open(string path, Uri baseUri = null) { - return Open(path, null); + return Open(path, null, baseUri == null ? new Uri(path) : baseUri); } /// /// Opens the document at the specified path and loads the SVG contents. /// /// A containing the path of the file to open. + /// base uri for linked file /// An with the contents loaded. /// The document at the specified cannot be found. - public static T Open(string path) where T : SvgDocument, new() + public static T Open(string path, Uri baseUri = null) where T : SvgDocument, new() { - return Open(path, null); + return Open(path, null, baseUri); } /// /// Opens the document at the specified path and loads the SVG contents. /// /// A containing the path of the file to open. + /// base uri for linked file /// A dictionary of custom entity definitions to be used when resolving XML entities within the document. /// An with the contents loaded. /// The document at the specified cannot be found. - public static T Open(string path, Dictionary entities) where T : SvgDocument, new() + public static T Open(string path, Dictionary entities, Uri baseUri = null) where T : SvgDocument, new() { if (string.IsNullOrEmpty(path)) { @@ -299,8 +302,9 @@ public static SvgDocument Open(string path) using (var stream = File.OpenRead(path)) { - var doc = Open(stream, entities); - doc.BaseUri = new Uri(System.IO.Path.GetFullPath(path)); + var doc = Open(stream, entities, baseUri == null ? new Uri(path) : baseUri); + if (baseUri == null) + doc.BaseUri = new Uri(System.IO.Path.GetFullPath(path)); return doc; } } @@ -309,9 +313,10 @@ public static SvgDocument Open(string path) /// Attempts to open an SVG document from the specified . /// /// The containing the SVG document to open. - public static T Open(Stream stream) where T : SvgDocument, new() + /// base uri for linked file + public static T Open(Stream stream, Uri baseUri = null) where T : SvgDocument, new() { - return Open(stream, null); + return Open(stream, null, baseUri ); } @@ -342,8 +347,9 @@ public static SvgDocument Open(string path) /// /// The containing the SVG document to open. /// Custom entity definitions. + /// base uri for linked file /// The parameter cannot be null. - public static T Open(Stream stream, Dictionary entities) where T : SvgDocument, new() + public static T Open(Stream stream, Dictionary entities, Uri baseUri = null) where T : SvgDocument, new() { if (stream == null) { @@ -356,10 +362,10 @@ public static SvgDocument Open(string path) XmlResolver = new SvgDtdResolver(), WhitespaceHandling = WhitespaceHandling.None }; - return Open(reader); + return Open(reader, baseUri); } - private static T Open(XmlReader reader) where T : SvgDocument, new() + private static T Open(XmlReader reader, Uri baseUri = null) where T : SvgDocument, new() { if (!SkipGdiPlusCapabilityCheck) { @@ -435,6 +441,19 @@ public static SvgDocument Open(string path) { styles.Add(unknown); } + else if (element.ElementName.ToLower() == "link") + { + if (element.CustomAttributes["rel"] == "stylesheet") + { + var href = element.CustomAttributes["href"]; + Uri uri = baseUri == null ? new Uri(href) : new Uri(baseUri, href); + var content = File.ReadAllText(uri.AbsolutePath); + SvgUnknownElement elem = new SvgUnknownElement("style"); + element.Content = content; + styles.Add(element); + + } + } break; case XmlNodeType.CDATA: case XmlNodeType.Text: @@ -491,8 +510,9 @@ public static SvgDocument Open(string path) /// Opens an SVG document from the specified . /// /// The containing the SVG document XML. + /// base uri for linked file /// The parameter cannot be null. - public static SvgDocument Open(XmlDocument document) + public static SvgDocument Open(XmlDocument document, Uri baseUri = null) { if (document == null) { @@ -500,7 +520,7 @@ public static SvgDocument Open(XmlDocument document) } var reader = new SvgNodeReader(document.DocumentElement, null); - return Open(reader); + return Open(reader, baseUri); } public static Bitmap OpenAsBitmap(string path) From b09100c5e1cbe324a22794e5113b5f711445e295 Mon Sep 17 00:00:00 2001 From: FabioFerrettiMoodys <> Date: Wed, 29 Apr 2020 11:06:40 +0200 Subject: [PATCH 2/8] adding support for (correction) error in open sdocument --- Source/SvgDocument.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/SvgDocument.cs b/Source/SvgDocument.cs index e1600cf1a..229191339 100644 --- a/Source/SvgDocument.cs +++ b/Source/SvgDocument.cs @@ -265,7 +265,7 @@ private static bool ExceptionCaughtIsGdiPlusRelated(Exception e) /// The document at the specified cannot be found. public static SvgDocument Open(string path, Uri baseUri = null) { - return Open(path, null, baseUri == null ? new Uri(path) : baseUri); + return Open(path, null, baseUri == null ? new Uri(System.IO.Path.GetFullPath(path)) : baseUri); } /// @@ -302,9 +302,11 @@ public static SvgDocument Open(string path, Uri baseUri = null) using (var stream = File.OpenRead(path)) { - var doc = Open(stream, entities, baseUri == null ? new Uri(path) : baseUri); + var doc = Open(stream, entities, baseUri == null ? new Uri(System.IO.Path.GetFullPath(path)) : baseUri); if (baseUri == null) doc.BaseUri = new Uri(System.IO.Path.GetFullPath(path)); + else + doc.BaseUri = baseUri; return doc; } } From 3bb451b62fd502ba609c0a50dc67807a90771f1e Mon Sep 17 00:00:00 2001 From: Fabio Ferretti Date: Fri, 15 May 2020 07:35:57 +0200 Subject: [PATCH 3/8] adding var --- Source/SvgDocument.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/SvgDocument.cs b/Source/SvgDocument.cs index 229191339..923d054bf 100644 --- a/Source/SvgDocument.cs +++ b/Source/SvgDocument.cs @@ -448,9 +448,9 @@ public static SvgDocument Open(string path, Uri baseUri = null) if (element.CustomAttributes["rel"] == "stylesheet") { var href = element.CustomAttributes["href"]; - Uri uri = baseUri == null ? new Uri(href) : new Uri(baseUri, href); + var uri = baseUri == null ? new Uri(href) : new Uri(baseUri, href); var content = File.ReadAllText(uri.AbsolutePath); - SvgUnknownElement elem = new SvgUnknownElement("style"); + var elem = new SvgUnknownElement("style"); element.Content = content; styles.Add(element); From d313e10115b86ba2fb7e68c6ddc68dff86e4f42b Mon Sep 17 00:00:00 2001 From: Fabio Ferretti Date: Mon, 15 Jun 2020 10:23:00 +0200 Subject: [PATCH 4/8] switching to SvgLink element adding svgLink element for link correction of dowument.Write correction of non local uri for href param. adding a "NonSvgElementAttribute" and SvgElementFactory modification for theses elements. --- Source/Document Structure/SvgLink.cs | 107 +++++++++++++++++++++++++++ Source/NonSvgElementAttribute.cs | 27 +++++++ Source/SvgDocument.cs | 21 +++--- Source/SvgElementFactory.cs | 49 ++++++++++-- 4 files changed, 188 insertions(+), 16 deletions(-) create mode 100644 Source/Document Structure/SvgLink.cs create mode 100644 Source/NonSvgElementAttribute.cs diff --git a/Source/Document Structure/SvgLink.cs b/Source/Document Structure/SvgLink.cs new file mode 100644 index 000000000..9abe3bd08 --- /dev/null +++ b/Source/Document Structure/SvgLink.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Net; +using System.Text; + +namespace Svg +{ + [NonSvgElementAttribute("link")] + public class SvgLink : NonSvgElement + { + public SvgLink() + :base("link") + { + + } + public enum RelativeValue + { + Unknown, + Alternate, + Author, + Help, + Icon, + License, + Next, + Pingback, + Preconnect, + Prefetch, + Preload, + Prerender, + Prev, + Search, + Stylesheet + } + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + + [SvgAttribute("href")] + public string Href + { + get { return GetAttribute("href", false,string.Empty); } + set { Attributes["href"] = value; } + } + + [SvgAttribute("rel")] + public RelativeValue Rel + { + get { return GetAttribute("rel", false, RelativeValue.Unknown); } + set { Attributes["rel"] = value; } + } + + + + public string GetLinkContentAsText(RelativeValue rel) + { + var stream = GetLinkContentAsStream(rel); + if (stream == null) + return null; + + string content = null; + using (StreamReader sr = new StreamReader(stream)) + { + content = sr.ReadToEnd(); + } + stream.Dispose(); + return content; + } + + + public Stream GetLinkContentAsStream(RelativeValue rel= RelativeValue.Unknown) + { + if (Rel != rel && rel != RelativeValue.Unknown) + return null; + // Uri MaxLength is 65519 (https://msdn.microsoft.com/en-us/library/z6c2z492.aspx) + // if using data URI scheme, very long URI may happen. + var safeUriString = Href.Length > 65519 ? Href.Substring(0, 65519) : Href; + + try + { + var uri = new Uri(safeUriString, UriKind.RelativeOrAbsolute); + + if (!uri.IsAbsoluteUri) + uri = new Uri(OwnerDocument.BaseUri, uri); + + // should work with http: and file: protocol urls + var httpRequest = WebRequest.Create(uri); + + var webResponse = httpRequest.GetResponse(); + var stream = webResponse.GetResponseStream(); + if (stream.CanSeek) + stream.Position = 0; + return stream; + } + catch (Exception ex) + { + Trace.TraceError("Error loading Link content: '{0}', error: {1} ", Href, ex.Message); + return null; + } + + } + } +} diff --git a/Source/NonSvgElementAttribute.cs b/Source/NonSvgElementAttribute.cs new file mode 100644 index 000000000..4a7d6bf1c --- /dev/null +++ b/Source/NonSvgElementAttribute.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Svg +{ + /// + /// Specifies the SVG name of an . + /// + [AttributeUsage(AttributeTargets.Class)] + public sealed class NonSvgElementAttribute : Attribute + { + /// + /// Gets the name of the SVG element. + /// + public string ElementName { get; private set; } + + /// + /// Initializes a new instance of the class with the specified element name; + /// + /// The name of the non SVG element. + public NonSvgElementAttribute(string elementName) + { + this.ElementName = elementName; + } + } +} diff --git a/Source/SvgDocument.cs b/Source/SvgDocument.cs index 923d054bf..f573d1e23 100644 --- a/Source/SvgDocument.cs +++ b/Source/SvgDocument.cs @@ -400,6 +400,8 @@ public static SvgDocument Open(string path, Uri baseUri = null) else { svgDocument = elementFactory.CreateDocument(reader); + if(baseUri!=null) + svgDocument.BaseUri = baseUri; element = svgDocument; } @@ -443,18 +445,15 @@ public static SvgDocument Open(string path, Uri baseUri = null) { styles.Add(unknown); } - else if (element.ElementName.ToLower() == "link") + else if (element is SvgLink) { - if (element.CustomAttributes["rel"] == "stylesheet") - { - var href = element.CustomAttributes["href"]; - var uri = baseUri == null ? new Uri(href) : new Uri(baseUri, href); - var content = File.ReadAllText(uri.AbsolutePath); - var elem = new SvgUnknownElement("style"); - element.Content = content; - styles.Add(element); - - } + var stylecontent = ((SvgLink)element).GetLinkContentAsText(SvgLink.RelativeValue.Stylesheet); + if(!string.IsNullOrEmpty(stylecontent)) + { + var elem = new SvgUnknownElement("style"); + elem.Content = stylecontent; + styles.Add(elem); + } } break; case XmlNodeType.CDATA: diff --git a/Source/SvgElementFactory.cs b/Source/SvgElementFactory.cs index 0adee1825..9b276cd41 100644 --- a/Source/SvgElementFactory.cs +++ b/Source/SvgElementFactory.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Globalization; using System.Xml; @@ -14,8 +14,9 @@ namespace Svg /// internal class SvgElementFactory { - private List availableElements; - private Parser cssParser = new Parser(); + private List availableElements; + private List availableNonSvgElements; + private Parser cssParser = new Parser(); /// /// Gets a list of available types that can be used when creating an . @@ -38,6 +39,31 @@ where t.GetCustomAttributes(typeof(SvgElementAttribute), true).Length > 0 } } + + + /// + /// Gets a list of available types that can be used when creating an . + /// + public List AvailableNonSvgElements + { + get + { + if (availableNonSvgElements == null) + { + var nonSvgTypes = from t in typeof(SvgDocument).Assembly.GetExportedTypes() + where t.GetCustomAttributes(typeof(NonSvgElementAttribute), true).Length > 0 + && t.IsSubclassOf(typeof(NonSvgElement)) + select new ElementInfo { ElementName = ((NonSvgElementAttribute)t.GetCustomAttributes(typeof(NonSvgElementAttribute), true)[0]).ElementName, ElementType = t }; + + availableNonSvgElements = nonSvgTypes.ToList(); + } + + return availableNonSvgElements; + } + } + + + /// /// Creates an from the current node in the specified . /// @@ -111,8 +137,21 @@ public SvgElement CreateElement(XmlReader reader, SvgDocument document) else { // All non svg element (html, ...) - createdElement = new NonSvgElement(elementName); - SetAttributes(createdElement, reader, document); + ElementInfo validType; + if (AvailableNonSvgElements.ToDictionary(e => e.ElementName, e => e).TryGetValue(elementName, out validType)) + { + createdElement = (NonSvgElement)Activator.CreateInstance(validType.ElementType); + } + else + { + createdElement = new NonSvgElement(elementName); + } + + if (createdElement != null) + { + SetAttributes(createdElement, reader, document); + } + } //Trace.TraceInformation("End CreateElement"); From 67579607e6575986c446f8bdb5f38af0c9467ab8 Mon Sep 17 00:00:00 2001 From: Fabio Ferretti Date: Mon, 15 Jun 2020 13:36:29 +0200 Subject: [PATCH 5/8] format document --- Source/Document Structure/SvgLink.cs | 16 ++++++++-------- Source/SvgDocument.cs | 28 ++++++++++++++-------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Source/Document Structure/SvgLink.cs b/Source/Document Structure/SvgLink.cs index 9abe3bd08..80c4d859d 100644 --- a/Source/Document Structure/SvgLink.cs +++ b/Source/Document Structure/SvgLink.cs @@ -11,10 +11,10 @@ namespace Svg public class SvgLink : NonSvgElement { public SvgLink() - :base("link") - { + : base("link") + { - } + } public enum RelativeValue { Unknown, @@ -34,16 +34,16 @@ public enum RelativeValue Stylesheet } - public override SvgElement DeepCopy() + public override SvgElement DeepCopy() { - return DeepCopy(); + return DeepCopy(); } [SvgAttribute("href")] public string Href { - get { return GetAttribute("href", false,string.Empty); } + get { return GetAttribute("href", false, string.Empty); } set { Attributes["href"] = value; } } @@ -72,7 +72,7 @@ public string GetLinkContentAsText(RelativeValue rel) } - public Stream GetLinkContentAsStream(RelativeValue rel= RelativeValue.Unknown) + public Stream GetLinkContentAsStream(RelativeValue rel = RelativeValue.Unknown) { if (Rel != rel && rel != RelativeValue.Unknown) return null; @@ -90,7 +90,7 @@ public Stream GetLinkContentAsStream(RelativeValue rel= RelativeValue.Unknown) // should work with http: and file: protocol urls var httpRequest = WebRequest.Create(uri); - var webResponse = httpRequest.GetResponse(); + var webResponse = httpRequest.GetResponse(); var stream = webResponse.GetResponseStream(); if (stream.CanSeek) stream.Position = 0; diff --git a/Source/SvgDocument.cs b/Source/SvgDocument.cs index f573d1e23..2a88ce97a 100644 --- a/Source/SvgDocument.cs +++ b/Source/SvgDocument.cs @@ -48,7 +48,7 @@ private static int GetSystemDpi() isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); #else var platform = Environment.OSVersion.Platform; - isWindows = platform == PlatformID.Win32NT; + isWindows = platform == PlatformID.Win32NT; #endif if (isWindows) @@ -194,15 +194,15 @@ public virtual TSvgElement GetElementById(string id) where TSvgElem /// Boolean whether the system is capable of using GDI+ public static bool SystemIsGdiPlusCapable() { - try + try { EnsureSystemIsGdiPlusCapable(); } - catch(SvgGdiPlusCannotBeLoadedException) + catch (SvgGdiPlusCannotBeLoadedException) { return false; } - catch(Exception) + catch (Exception) { //If somehow another type of exception is raised by the ensure function we will let it bubble up, since that might indicate other issues/problems throw; @@ -230,7 +230,7 @@ public static void EnsureSystemIsGdiPlusCapable() throw new SvgGdiPlusCannotBeLoadedException(e); } //If the Matrix creation is causing another type of exception we should just raise that one - throw; + throw; } } @@ -318,7 +318,7 @@ public static SvgDocument Open(string path, Uri baseUri = null) /// base uri for linked file public static T Open(Stream stream, Uri baseUri = null) where T : SvgDocument, new() { - return Open(stream, null, baseUri ); + return Open(stream, null, baseUri); } @@ -400,7 +400,7 @@ public static SvgDocument Open(string path, Uri baseUri = null) else { svgDocument = elementFactory.CreateDocument(reader); - if(baseUri!=null) + if (baseUri != null) svgDocument.BaseUri = baseUri; element = svgDocument; } @@ -447,13 +447,13 @@ public static SvgDocument Open(string path, Uri baseUri = null) } else if (element is SvgLink) { - var stylecontent = ((SvgLink)element).GetLinkContentAsText(SvgLink.RelativeValue.Stylesheet); - if(!string.IsNullOrEmpty(stylecontent)) - { - var elem = new SvgUnknownElement("style"); - elem.Content = stylecontent; - styles.Add(elem); - } + var stylecontent = ((SvgLink)element).GetLinkContentAsText(SvgLink.RelativeValue.Stylesheet); + if (!string.IsNullOrEmpty(stylecontent)) + { + var elem = new SvgUnknownElement("style"); + elem.Content = stylecontent; + styles.Add(elem); + } } break; case XmlNodeType.CDATA: From 63d31a9fd72d2f8ac5a56a6814ebb6e589fa9b5d Mon Sep 17 00:00:00 2001 From: Fabio Ferretti Date: Mon, 15 Jun 2020 13:39:17 +0200 Subject: [PATCH 6/8] format document --- Source/SvgElementFactory.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Source/SvgElementFactory.cs b/Source/SvgElementFactory.cs index 9b276cd41..541622781 100644 --- a/Source/SvgElementFactory.cs +++ b/Source/SvgElementFactory.cs @@ -14,9 +14,9 @@ namespace Svg /// internal class SvgElementFactory { - private List availableElements; - private List availableNonSvgElements; - private Parser cssParser = new Parser(); + private List availableElements; + private List availableNonSvgElements; + private Parser cssParser = new Parser(); /// /// Gets a list of available types that can be used when creating an . @@ -51,11 +51,11 @@ public List AvailableNonSvgElements if (availableNonSvgElements == null) { var nonSvgTypes = from t in typeof(SvgDocument).Assembly.GetExportedTypes() - where t.GetCustomAttributes(typeof(NonSvgElementAttribute), true).Length > 0 - && t.IsSubclassOf(typeof(NonSvgElement)) - select new ElementInfo { ElementName = ((NonSvgElementAttribute)t.GetCustomAttributes(typeof(NonSvgElementAttribute), true)[0]).ElementName, ElementType = t }; + where t.GetCustomAttributes(typeof(NonSvgElementAttribute), true).Length > 0 + && t.IsSubclassOf(typeof(NonSvgElement)) + select new ElementInfo { ElementName = ((NonSvgElementAttribute)t.GetCustomAttributes(typeof(NonSvgElementAttribute), true)[0]).ElementName, ElementType = t }; - availableNonSvgElements = nonSvgTypes.ToList(); + availableNonSvgElements = nonSvgTypes.ToList(); } return availableNonSvgElements; From 9c3a092a7472f80645a4bb3b6b32661990eefbaa Mon Sep 17 00:00:00 2001 From: Fabio Ferretti Date: Mon, 15 Jun 2020 14:43:34 +0200 Subject: [PATCH 7/8] remove of blan space and use of using for webrequest and response stream --- Source/Document Structure/SvgLink.cs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/Source/Document Structure/SvgLink.cs b/Source/Document Structure/SvgLink.cs index 80c4d859d..268b30671 100644 --- a/Source/Document Structure/SvgLink.cs +++ b/Source/Document Structure/SvgLink.cs @@ -13,7 +13,6 @@ public class SvgLink : NonSvgElement public SvgLink() : base("link") { - } public enum RelativeValue { @@ -39,7 +38,6 @@ public override SvgElement DeepCopy() return DeepCopy(); } - [SvgAttribute("href")] public string Href { @@ -54,15 +52,13 @@ public RelativeValue Rel set { Attributes["rel"] = value; } } - - public string GetLinkContentAsText(RelativeValue rel) { var stream = GetLinkContentAsStream(rel); if (stream == null) return null; - string content = null; + var content = string.Empty; using (StreamReader sr = new StreamReader(stream)) { content = sr.ReadToEnd(); @@ -71,7 +67,6 @@ public string GetLinkContentAsText(RelativeValue rel) return content; } - public Stream GetLinkContentAsStream(RelativeValue rel = RelativeValue.Unknown) { if (Rel != rel && rel != RelativeValue.Unknown) @@ -89,12 +84,18 @@ public Stream GetLinkContentAsStream(RelativeValue rel = RelativeValue.Unknown) // should work with http: and file: protocol urls var httpRequest = WebRequest.Create(uri); - - var webResponse = httpRequest.GetResponse(); - var stream = webResponse.GetResponseStream(); - if (stream.CanSeek) - stream.Position = 0; - return stream; + using (var webResponse = httpRequest.GetResponse()) + { + using (var stream = webResponse.GetResponseStream()) + { + if (stream.CanSeek) + stream.Position = 0; + MemoryStream returnedStream = new MemoryStream(); + stream.CopyTo(returnedStream); + returnedStream.Position = 0; + return returnedStream; + } + } } catch (Exception ex) { From 45287a3079595085ffc73c5ecfac706b0d8e5a39 Mon Sep 17 00:00:00 2001 From: Fabio Ferretti Date: Wed, 17 Jun 2020 08:29:42 +0200 Subject: [PATCH 8/8] using in GetLinkContentAsText --- Source/Document Structure/SvgLink.cs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/Source/Document Structure/SvgLink.cs b/Source/Document Structure/SvgLink.cs index 268b30671..a2eaaf3b4 100644 --- a/Source/Document Structure/SvgLink.cs +++ b/Source/Document Structure/SvgLink.cs @@ -54,17 +54,20 @@ public RelativeValue Rel public string GetLinkContentAsText(RelativeValue rel) { - var stream = GetLinkContentAsStream(rel); - if (stream == null) - return null; - - var content = string.Empty; - using (StreamReader sr = new StreamReader(stream)) + try + { + using (var stream = GetLinkContentAsStream(rel)) + { + using (StreamReader sr = new StreamReader(stream)) + { + return sr.ReadToEnd(); + } + } + } + catch { - content = sr.ReadToEnd(); + return string.Empty; } - stream.Dispose(); - return content; } public Stream GetLinkContentAsStream(RelativeValue rel = RelativeValue.Unknown)