Bump bockbuild.
[mono.git] / mcs / class / System.Security / Mono.Xml / XmlCanonicalizer.cs
old mode 100755 (executable)
new mode 100644 (file)
index 111bd04..8f0ec97
@@ -48,6 +48,7 @@ namespace Mono.Xml {
                // c14n parameters
                private bool comments;
                private bool exclusive;
+               string inclusiveNamespacesPrefixList;
 
                // input/output
                private XmlNodeList xnl;
@@ -58,20 +59,32 @@ namespace Mono.Xml {
                private ArrayList visibleNamespaces;
                private int prevVisibleNamespacesStart;
                private int prevVisibleNamespacesEnd;
+               private Hashtable propagatedNss;
 
-               public XmlCanonicalizer (bool withComments, bool excC14N)
+               public XmlCanonicalizer (bool withComments, bool excC14N, Hashtable propagatedNamespaces)
                {           
                        res = new StringBuilder ();
                        comments = withComments;
                        exclusive = excC14N;
+                       propagatedNss = propagatedNamespaces;
+               }
+               
+               void Initialize ()
+               {
                        state = XmlCanonicalizerState.BeforeDocElement;
                        visibleNamespaces = new ArrayList ();
                        prevVisibleNamespacesStart = 0;
                        prevVisibleNamespacesEnd = 0;
+                       res.Length = 0;
                }
                
                public Stream Canonicalize (XmlDocument doc)
                {
+                       if (doc == null)
+                               throw new ArgumentNullException ("doc");
+                       Initialize ();
+                       
+                       FillMissingPrefixes (doc, new XmlNamespaceManager (doc.NameTable), new ArrayList ());
                        WriteDocumentNode (doc);
                        
                        UTF8Encoding utf8 = new UTF8Encoding ();
@@ -84,9 +97,65 @@ namespace Mono.Xml {
                        xnl = nodes;
                        if (nodes == null || nodes.Count < 1)
                                return new MemoryStream ();
-                       return Canonicalize (nodes[0].OwnerDocument);
+                       XmlNode n = nodes [0];
+                       return Canonicalize (n.NodeType == XmlNodeType.Document ? n as XmlDocument : n.OwnerDocument);
                }               
 
+               // See xml-enc-c14n specification
+               public string InclusiveNamespacesPrefixList {
+                       get { return inclusiveNamespacesPrefixList; }
+                       set { inclusiveNamespacesPrefixList = value; }
+               }
+
+               XmlAttribute CreateXmlns (XmlNode n)
+               {
+                       XmlAttribute a = n.Prefix.Length == 0 ?
+                               n.OwnerDocument.CreateAttribute ("xmlns", "http://www.w3.org/2000/xmlns/") :
+                               n.OwnerDocument.CreateAttribute ("xmlns", n.Prefix, "http://www.w3.org/2000/xmlns/");
+                       a.Value = n.NamespaceURI;
+                       return a;
+               }
+
+               // Note that this must be done *before* filtering nodes out
+               // by context node list.
+               private void FillMissingPrefixes (XmlNode n, XmlNamespaceManager nsmgr, ArrayList tmpList)
+               {
+                       if (n.Prefix.Length == 0 && propagatedNss != null) {
+                               foreach (DictionaryEntry de in propagatedNss)
+                                       if ((string) de.Value == n.NamespaceURI) {
+                                               n.Prefix = (string) de.Key;
+                                               break;
+                                       }
+                       }
+                       
+                       if (n.NodeType == XmlNodeType.Element && ((XmlElement) n).HasAttributes) {
+                               foreach (XmlAttribute a in n.Attributes)
+                                       if (a.NamespaceURI == "http://www.w3.org/2000/xmlns/")
+                                               nsmgr.AddNamespace (a.Prefix.Length == 0 ? String.Empty : a.LocalName, a.Value);
+                               nsmgr.PushScope ();
+                       }
+
+                       if (n.NamespaceURI.Length > 0 && nsmgr.LookupPrefix (n.NamespaceURI) == null)
+                               tmpList.Add (CreateXmlns (n));
+
+                       if (n.NodeType == XmlNodeType.Element && ((XmlElement) n).HasAttributes) {
+                               foreach (XmlAttribute a in n.Attributes)
+                                       if (a.NamespaceURI.Length > 0 && nsmgr.LookupNamespace (a.Prefix) == null)
+                                               tmpList.Add (CreateXmlns (a));
+                       }
+
+                       foreach (XmlAttribute a in tmpList)
+                               ((XmlElement) n).SetAttributeNode (a);
+                       tmpList.Clear ();
+
+                       if (n.HasChildNodes) {
+                               for (XmlNode c = n.FirstChild; c != null; c = c.NextSibling)
+                                       if (c.NodeType == XmlNodeType.Element)
+                                               FillMissingPrefixes (c, nsmgr, tmpList);
+                       }
+                       nsmgr.PopScope ();
+               }
+
                private void WriteNode (XmlNode node)
                {
                        // Console.WriteLine ("C14N Debug: node=" + node.Name);
@@ -226,7 +295,7 @@ namespace Mono.Xml {
                        bool has_empty_namespace = false;
                        ArrayList list = new ArrayList ();
                        for (XmlNode cur = node; cur != null && cur != doc; cur = cur.ParentNode) {
-                               foreach (XmlNode attribute in cur.Attributes) {         
+                               foreach (XmlAttribute attribute in cur.Attributes) {            
                                        if (!IsNamespaceNode (attribute)) 
                                                continue;
                                
@@ -252,6 +321,11 @@ namespace Mono.Xml {
                                        // check that we have not rendered it yet
                                        bool rendered = IsNamespaceRendered (prefix, attribute.Value);
 
+                                       // For exc-c14n, only visibly utilized
+                                       // namespaces are written.
+                                       if (exclusive && !IsVisiblyUtilized (node as XmlElement, attribute))
+                                               continue;
+
                                        // add to the visible namespaces stack
                                        if (visible)
                                                visibleNamespaces.Add (attribute);                            
@@ -264,8 +338,8 @@ namespace Mono.Xml {
                                }
                        }
 
-                       // add empty namespace if needed                    
-                       if (visible && !has_empty_namespace && !IsNamespaceRendered (string.Empty, string.Empty)
+                       // add empty namespace if needed
+                       if (visible && !has_empty_namespace && !IsNamespaceRendered (string.Empty, string.Empty) && node.NamespaceURI == String.Empty)
                                res.Append (" xmlns=\"\"");
                    
                        list.Sort (new XmlDsigC14NTransformNamespacesComparer ());
@@ -441,7 +515,8 @@ namespace Mono.Xml {
                                        res.Append ("?>");
                        }
                }
-               
+
+               // determines whether the node is in the node-set or not.
                private bool IsNodeVisible (XmlNode node)
                {
                        // if node list is empty then we process whole document
@@ -456,6 +531,29 @@ namespace Mono.Xml {
                    
                        return false;
                }
+               
+               // This method assumes that the namespace node is *not*
+               // rendered yet.
+               private bool IsVisiblyUtilized (XmlElement owner, XmlAttribute ns)
+               {
+                       if (owner == null)
+                               return false;
+
+                       string prefix = ns.LocalName == "xmlns" ? String.Empty : ns.LocalName;
+                       if (owner.Prefix == prefix && owner.NamespaceURI == ns.Value)
+                               return true;
+                       if (!owner.HasAttributes)
+                               return false;
+                       foreach (XmlAttribute a in owner.Attributes) {
+                               if (a.Prefix == String.Empty)
+                                       continue;
+                               if (a.Prefix != prefix || a.NamespaceURI != ns.Value)
+                                       continue;
+                               if (IsNodeVisible (a))
+                                       return true;
+                       }
+                       return false;
+               }
 
                private bool IsNamespaceRendered (string prefix, string uri)
                {
@@ -539,7 +637,7 @@ namespace Mono.Xml {
                        else if (n2 == null) 
                                return 1;
                        else if (n1.Prefix == n2.Prefix) 
-                               return string.Compare (n1.LocalName, n2.LocalName);
+                               return string.CompareOrdinal (n1.LocalName, n2.LocalName);
        
                        // Attributes in the default namespace are first
                        // because the default namespace is not applied to