OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
ExternalRepresentationUtils.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 using System;
29 using System.Collections.Generic;
30 using System.Diagnostics;
31 using System.IO;
32 using System.Reflection;
33 using System.Xml;
34 using log4net;
35 using OpenMetaverse;
36 using OpenSim.Services.Interfaces;
37 
38 namespace OpenSim.Framework.Serialization.External
39 {
44  {
45  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46 
54  public static bool ExecuteReadProcessors<NodeType>(
55  NodeType nodeToFill, Dictionary<string, Action<NodeType, XmlReader>> processors, XmlReader xtr)
56  {
57  return ExecuteReadProcessors(
58  nodeToFill,
59  processors,
60  xtr,
61  (o, nodeName, e) => {
62  m_log.Debug(string.Format("[ExternalRepresentationUtils]: Error while parsing element {0} ",
63  nodeName), e);
64  });
65  }
66 
77  public static bool ExecuteReadProcessors<NodeType>(
78  NodeType nodeToFill,
79  Dictionary<string, Action<NodeType, XmlReader>> processors,
80  XmlReader xtr,
81  Action<NodeType, string, Exception> parseExceptionAction)
82  {
83  bool errors = false;
84  int numErrors = 0;
85 
86  Stopwatch timer = new Stopwatch();
87  timer.Start();
88 
89  string nodeName = string.Empty;
90  while (xtr.NodeType != XmlNodeType.EndElement)
91  {
92  nodeName = xtr.Name;
93 
94  // m_log.DebugFormat("[ExternalRepresentationUtils]: Processing node: {0}", nodeName);
95 
96  Action<NodeType, XmlReader> p = null;
97  if (processors.TryGetValue(xtr.Name, out p))
98  {
99  // m_log.DebugFormat("[ExternalRepresentationUtils]: Found processor for {0}", nodeName);
100 
101  try
102  {
103  p(nodeToFill, xtr);
104  }
105  catch (Exception e)
106  {
107  errors = true;
108  parseExceptionAction(nodeToFill, nodeName, e);
109 
110  if (xtr.EOF)
111  {
112  m_log.Debug("[ExternalRepresentationUtils]: Aborting ExecuteReadProcessors due to unexpected end of XML");
113  break;
114  }
115 
116  if (++numErrors == 10)
117  {
118  m_log.Debug("[ExternalRepresentationUtils]: Aborting ExecuteReadProcessors due to too many parsing errors");
119  break;
120  }
121 
122  if (xtr.NodeType == XmlNodeType.EndElement)
123  xtr.Read();
124  }
125  }
126  else
127  {
128  // m_log.DebugFormat("[ExternalRepresentationUtils]: found unknown element \"{0}\"", nodeName);
129  xtr.ReadOuterXml(); // ignore
130  }
131 
132  if (timer.Elapsed.TotalSeconds >= 60)
133  {
134  m_log.Debug("[ExternalRepresentationUtils]: Aborting ExecuteReadProcessors due to timeout");
135  errors = true;
136  break;
137  }
138  }
139 
140  return errors;
141  }
142 
152  [Obsolete("This method is deprecated. Use RewriteSOP instead.")]
153  public static string RewriteSOP_Old(string xml, string homeURL, IUserAccountService userService, UUID scopeID)
154  {
155  if (xml == string.Empty || homeURL == string.Empty || userService == null)
156  return xml;
157 
158  XmlDocument doc = new XmlDocument();
159  doc.LoadXml(xml);
160  XmlNodeList sops = doc.GetElementsByTagName("SceneObjectPart");
161 
162  foreach (XmlNode sop in sops)
163  {
164  UserAccount creator = null;
165  bool hasCreatorData = false;
166  XmlNodeList nodes = sop.ChildNodes;
167  foreach (XmlNode node in nodes)
168  {
169  if (node.Name == "CreatorID")
170  {
171  UUID uuid = UUID.Zero;
172  UUID.TryParse(node.InnerText, out uuid);
173  creator = userService.GetUserAccount(scopeID, uuid);
174  }
175 
176  if (node.Name == "CreatorData" && node.InnerText != null && node.InnerText != string.Empty)
177  hasCreatorData = true;
178 
179  //if (node.Name == "OwnerID")
180  //{
181  // UserAccount owner = GetUser(node.InnerText);
182  // if (owner != null)
183  // node.InnerText = m_ProfileServiceURL + "/" + node.InnerText + "/" + owner.FirstName + " " + owner.LastName;
184  //}
185  }
186  if (!hasCreatorData && creator != null)
187  {
188  XmlElement creatorData = doc.CreateElement("CreatorData");
189  creatorData.InnerText = CalcCreatorData(homeURL, creator.FirstName + " " + creator.LastName);
190  sop.AppendChild(creatorData);
191  }
192  }
193 
194  using (StringWriter wr = new StringWriter())
195  {
196  doc.Save(wr);
197  return wr.ToString();
198  }
199  }
200 
211  public static string RewriteSOP(string xmlData, string sceneName, string homeURL, IUserAccountService userService, UUID scopeID)
212  {
213  // Console.WriteLine("Input XML [{0}]", xmlData);
214  if (xmlData == string.Empty || homeURL == string.Empty || userService == null)
215  return xmlData;
216 
217  // Deal with bug
218  xmlData = ExternalRepresentationUtils.SanitizeXml(xmlData);
219 
220  using (StringWriter sw = new StringWriter())
221  using (XmlTextWriter writer = new XmlTextWriter(sw))
222  using (XmlTextReader wrappedReader = new XmlTextReader(xmlData, XmlNodeType.Element, null))
223  using (XmlReader reader = XmlReader.Create(wrappedReader, new XmlReaderSettings() { IgnoreWhitespace = true, ConformanceLevel = ConformanceLevel.Fragment }))
224  {
225  TransformXml(reader, writer, sceneName, homeURL, userService, scopeID);
226 
227  // Console.WriteLine("Output: [{0}]", sw.ToString());
228 
229  return sw.ToString();
230  }
231  }
232 
233  protected static void TransformXml(XmlReader reader, XmlWriter writer, string sceneName, string homeURI, IUserAccountService userAccountService, UUID scopeID)
234  {
235  // m_log.DebugFormat("[HG ASSET MAPPER]: Transforming XML");
236 
237  int sopDepth = -1;
238  UserAccount creator = null;
239  bool hasCreatorData = false;
240 
241  while (reader.Read())
242  {
243  // Console.WriteLine("Depth: {0}, name {1}", reader.Depth, reader.Name);
244 
245  switch (reader.NodeType)
246  {
247  case XmlNodeType.Attribute:
248  // Console.WriteLine("FOUND ATTRIBUTE {0}", reader.Name);
249  writer.WriteAttributeString(reader.Name, reader.Value);
250  break;
251 
252  case XmlNodeType.CDATA:
253  writer.WriteCData(reader.Value);
254  break;
255 
256  case XmlNodeType.Comment:
257  writer.WriteComment(reader.Value);
258  break;
259 
260  case XmlNodeType.DocumentType:
261  writer.WriteDocType(reader.Name, reader.Value, null, null);
262  break;
263 
264  case XmlNodeType.Element:
265  // m_log.DebugFormat("Depth {0} at element {1}", reader.Depth, reader.Name);
266 
267  writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
268 
269  if (reader.HasAttributes)
270  {
271  while (reader.MoveToNextAttribute())
272  writer.WriteAttributeString(reader.Name, reader.Value);
273 
274  reader.MoveToElement();
275  }
276 
277  if (reader.LocalName == "SceneObjectPart")
278  {
279  if (sopDepth < 0)
280  {
281  sopDepth = reader.Depth;
282  // m_log.DebugFormat("[HG ASSET MAPPER]: Set sopDepth to {0}", sopDepth);
283  }
284  }
285  else
286  {
287  if (sopDepth >= 0 && reader.Depth == sopDepth + 1)
288  {
289  if (reader.Name == "CreatorID")
290  {
291  reader.Read();
292  if (reader.NodeType == XmlNodeType.Element && reader.Name == "Guid" || reader.Name == "UUID")
293  {
294  reader.Read();
295 
296  if (reader.NodeType == XmlNodeType.Text)
297  {
298  UUID uuid = UUID.Zero;
299  UUID.TryParse(reader.Value, out uuid);
300  creator = userAccountService.GetUserAccount(scopeID, uuid);
301  writer.WriteElementString("UUID", reader.Value);
302  reader.Read();
303  }
304  else
305  {
306  // If we unexpected run across mixed content in this node, still carry on
307  // transforming the subtree (this replicates earlier behaviour).
308  TransformXml(reader, writer, sceneName, homeURI, userAccountService, scopeID);
309  }
310  }
311  else
312  {
313  // If we unexpected run across mixed content in this node, still carry on
314  // transforming the subtree (this replicates earlier behaviour).
315  TransformXml(reader, writer, sceneName, homeURI, userAccountService, scopeID);
316  }
317  }
318  else if (reader.Name == "CreatorData")
319  {
320  reader.Read();
321  if (reader.NodeType == XmlNodeType.Text)
322  {
323  hasCreatorData = true;
324  writer.WriteString(reader.Value);
325  }
326  else
327  {
328  // If we unexpected run across mixed content in this node, still carry on
329  // transforming the subtree (this replicates earlier behaviour).
330  TransformXml(reader, writer, sceneName, homeURI, userAccountService, scopeID);
331  }
332  }
333  }
334  }
335 
336  if (reader.IsEmptyElement)
337  {
338  // m_log.DebugFormat("[HG ASSET MAPPER]: Writing end for empty element {0}", reader.Name);
339  writer.WriteEndElement();
340  }
341 
342  break;
343 
344  case XmlNodeType.EndElement:
345  // m_log.DebugFormat("Depth {0} at EndElement", reader.Depth);
346  if (sopDepth == reader.Depth)
347  {
348  if (!hasCreatorData && creator != null)
349  writer.WriteElementString(reader.Prefix, "CreatorData", reader.NamespaceURI, string.Format("{0};{1} {2}", homeURI, creator.FirstName, creator.LastName));
350 
351  // m_log.DebugFormat("[HG ASSET MAPPER]: Reset sopDepth");
352  sopDepth = -1;
353  creator = null;
354  hasCreatorData = false;
355  }
356  writer.WriteEndElement();
357  break;
358 
359  case XmlNodeType.EntityReference:
360  writer.WriteEntityRef(reader.Name);
361  break;
362 
363  case XmlNodeType.ProcessingInstruction:
364  writer.WriteProcessingInstruction(reader.Name, reader.Value);
365  break;
366 
367  case XmlNodeType.Text:
368  writer.WriteString(reader.Value);
369  break;
370 
371  case XmlNodeType.XmlDeclaration:
372  // For various reasons, not all serializations have xml declarations (or consistent ones)
373  // and as it's embedded inside a byte stream we don't need it anyway, so ignore.
374  break;
375 
376  default:
377  m_log.WarnFormat(
378  "[HG ASSET MAPPER]: Unrecognized node {0} in asset XML transform in {1}",
379  reader.NodeType, sceneName);
380  break;
381  }
382  }
383  }
384 
385  public static string CalcCreatorData(string homeURL, string name)
386  {
387  return homeURL + ";" + name;
388  }
389 
390  internal static string CalcCreatorData(string homeURL, UUID uuid, string name)
391  {
392  return homeURL + "/" + uuid + ";" + name;
393  }
394 
400  public static string SanitizeXml(string xmlData)
401  {
402  string fixedData = xmlData;
403  if (fixedData != null)
404  // Loop, because it may contain multiple
405  while (fixedData.Contains("xmlns:xmlns:"))
406  fixedData = fixedData.Replace("xmlns:xmlns:", "xmlns:");
407  return fixedData;
408  }
409 
410  }
411 }
static string RewriteSOP_Old(string xml, string homeURL, IUserAccountService userService, UUID scopeID)
Takes a XML representation of a SceneObjectPart and returns another XML representation with creator d...
static void TransformXml(XmlReader reader, XmlWriter writer, string sceneName, string homeURI, IUserAccountService userAccountService, UUID scopeID)
Utilities for manipulating external representations of data structures in OpenSim ...
Interactive OpenSim region server
Definition: OpenSim.cs:55
static string SanitizeXml(string xmlData)
Sanitation for bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8) ...
static string RewriteSOP(string xmlData, string sceneName, string homeURL, IUserAccountService userService, UUID scopeID)
Takes a XML representation of a SceneObjectPart and returns another XML representation with creator d...