diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Framework/Serialization/External/ExternalRepresentationUtils.cs | 267 |
1 files changed, 251 insertions, 16 deletions
diff --git a/OpenSim/Framework/Serialization/External/ExternalRepresentationUtils.cs b/OpenSim/Framework/Serialization/External/ExternalRepresentationUtils.cs index c56f213..55640ac 100644 --- a/OpenSim/Framework/Serialization/External/ExternalRepresentationUtils.cs +++ b/OpenSim/Framework/Serialization/External/ExternalRepresentationUtils.cs | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Diagnostics; | ||
30 | using System.IO; | 31 | using System.IO; |
31 | using System.Reflection; | 32 | using System.Reflection; |
32 | using System.Xml; | 33 | using System.Xml; |
@@ -47,20 +48,20 @@ namespace OpenSim.Framework.Serialization.External | |||
47 | /// Populate a node with data read from xml using a dictinoary of processors | 48 | /// Populate a node with data read from xml using a dictinoary of processors |
48 | /// </summary> | 49 | /// </summary> |
49 | /// <param name="nodeToFill"></param> | 50 | /// <param name="nodeToFill"></param> |
50 | /// <param name="processors">/param> | 51 | /// <param name="processors"></param> |
51 | /// <param name="xtr"></param> | 52 | /// <param name="xtr"></param> |
52 | /// <returns>true on successful, false if there were any processing failures</returns> | 53 | /// <returns>true on successful, false if there were any processing failures</returns> |
53 | public static bool ExecuteReadProcessors<NodeType>( | 54 | public static bool ExecuteReadProcessors<NodeType>( |
54 | NodeType nodeToFill, Dictionary<string, Action<NodeType, XmlTextReader>> processors, XmlTextReader xtr) | 55 | NodeType nodeToFill, Dictionary<string, Action<NodeType, XmlReader>> processors, XmlReader xtr) |
55 | { | 56 | { |
56 | return ExecuteReadProcessors( | 57 | return ExecuteReadProcessors( |
57 | nodeToFill, | 58 | nodeToFill, |
58 | processors, | 59 | processors, |
59 | xtr, | 60 | xtr, |
60 | (o, name, e) | 61 | (o, nodeName, e) => { |
61 | => m_log.DebugFormat( | 62 | m_log.Debug(string.Format("[ExternalRepresentationUtils]: Error while parsing element {0} ", |
62 | "[ExternalRepresentationUtils]: Exception while parsing element {0}, continuing. Exception {1}{2}", | 63 | nodeName), e); |
63 | name, e.Message, e.StackTrace)); | 64 | }); |
64 | } | 65 | } |
65 | 66 | ||
66 | /// <summary> | 67 | /// <summary> |
@@ -75,23 +76,27 @@ namespace OpenSim.Framework.Serialization.External | |||
75 | /// <returns>true on successful, false if there were any processing failures</returns> | 76 | /// <returns>true on successful, false if there were any processing failures</returns> |
76 | public static bool ExecuteReadProcessors<NodeType>( | 77 | public static bool ExecuteReadProcessors<NodeType>( |
77 | NodeType nodeToFill, | 78 | NodeType nodeToFill, |
78 | Dictionary<string, Action<NodeType, XmlTextReader>> processors, | 79 | Dictionary<string, Action<NodeType, XmlReader>> processors, |
79 | XmlTextReader xtr, | 80 | XmlReader xtr, |
80 | Action<NodeType, string, Exception> parseExceptionAction) | 81 | Action<NodeType, string, Exception> parseExceptionAction) |
81 | { | 82 | { |
82 | bool errors = false; | 83 | bool errors = false; |
84 | int numErrors = 0; | ||
85 | |||
86 | Stopwatch timer = new Stopwatch(); | ||
87 | timer.Start(); | ||
83 | 88 | ||
84 | string nodeName = string.Empty; | 89 | string nodeName = string.Empty; |
85 | while (xtr.NodeType != XmlNodeType.EndElement) | 90 | while (xtr.NodeType != XmlNodeType.EndElement) |
86 | { | 91 | { |
87 | nodeName = xtr.Name; | 92 | nodeName = xtr.Name; |
88 | 93 | ||
89 | // m_log.DebugFormat("[ExternalRepresentationUtils]: Processing: {0}", nodeName); | 94 | // m_log.DebugFormat("[ExternalRepresentationUtils]: Processing node: {0}", nodeName); |
90 | 95 | ||
91 | Action<NodeType, XmlTextReader> p = null; | 96 | Action<NodeType, XmlReader> p = null; |
92 | if (processors.TryGetValue(xtr.Name, out p)) | 97 | if (processors.TryGetValue(xtr.Name, out p)) |
93 | { | 98 | { |
94 | // m_log.DebugFormat("[ExternalRepresentationUtils]: Found {0} processor, nodeName); | 99 | // m_log.DebugFormat("[ExternalRepresentationUtils]: Found processor for {0}", nodeName); |
95 | 100 | ||
96 | try | 101 | try |
97 | { | 102 | { |
@@ -101,6 +106,18 @@ namespace OpenSim.Framework.Serialization.External | |||
101 | { | 106 | { |
102 | errors = true; | 107 | errors = true; |
103 | parseExceptionAction(nodeToFill, nodeName, e); | 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 | } | ||
104 | 121 | ||
105 | if (xtr.NodeType == XmlNodeType.EndElement) | 122 | if (xtr.NodeType == XmlNodeType.EndElement) |
106 | xtr.Read(); | 123 | xtr.Read(); |
@@ -108,9 +125,16 @@ namespace OpenSim.Framework.Serialization.External | |||
108 | } | 125 | } |
109 | else | 126 | else |
110 | { | 127 | { |
111 | // m_log.DebugFormat("[LandDataSerializer]: caught unknown element {0}", nodeName); | 128 | // m_log.DebugFormat("[ExternalRepresentationUtils]: found unknown element \"{0}\"", nodeName); |
112 | xtr.ReadOuterXml(); // ignore | 129 | xtr.ReadOuterXml(); // ignore |
113 | } | 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 | } | ||
114 | } | 138 | } |
115 | 139 | ||
116 | return errors; | 140 | return errors; |
@@ -125,7 +149,8 @@ namespace OpenSim.Framework.Serialization.External | |||
125 | /// <param name="userService">The service for retrieving user account information</param> | 149 | /// <param name="userService">The service for retrieving user account information</param> |
126 | /// <param name="scopeID">The scope of the user account information (Grid ID)</param> | 150 | /// <param name="scopeID">The scope of the user account information (Grid ID)</param> |
127 | /// <returns>The SceneObjectPart represented in XML2</returns> | 151 | /// <returns>The SceneObjectPart represented in XML2</returns> |
128 | public static string RewriteSOP(string xml, string homeURL, IUserAccountService userService, UUID scopeID) | 152 | [Obsolete("This method is deprecated. Use RewriteSOP instead.")] |
153 | public static string RewriteSOP_Old(string xml, string homeURL, IUserAccountService userService, UUID scopeID) | ||
129 | { | 154 | { |
130 | if (xml == string.Empty || homeURL == string.Empty || userService == null) | 155 | if (xml == string.Empty || homeURL == string.Empty || userService == null) |
131 | return xml; | 156 | return xml; |
@@ -161,7 +186,7 @@ namespace OpenSim.Framework.Serialization.External | |||
161 | if (!hasCreatorData && creator != null) | 186 | if (!hasCreatorData && creator != null) |
162 | { | 187 | { |
163 | XmlElement creatorData = doc.CreateElement("CreatorData"); | 188 | XmlElement creatorData = doc.CreateElement("CreatorData"); |
164 | creatorData.InnerText = homeURL + ";" + creator.FirstName + " " + creator.LastName; | 189 | creatorData.InnerText = CalcCreatorData(homeURL, creator.FirstName + " " + creator.LastName); |
165 | sop.AppendChild(creatorData); | 190 | sop.AppendChild(creatorData); |
166 | } | 191 | } |
167 | } | 192 | } |
@@ -172,5 +197,215 @@ namespace OpenSim.Framework.Serialization.External | |||
172 | return wr.ToString(); | 197 | return wr.ToString(); |
173 | } | 198 | } |
174 | } | 199 | } |
200 | |||
201 | /// <summary> | ||
202 | /// Takes a XML representation of a SceneObjectPart and returns another XML representation | ||
203 | /// with creator data added to it. | ||
204 | /// </summary> | ||
205 | /// <param name="xml">The SceneObjectPart represented in XML2</param> | ||
206 | /// <param name="sceneName">An identifier for the component that's calling this function</param> | ||
207 | /// <param name="homeURL">The URL of the user agents service (home) for the creator</param> | ||
208 | /// <param name="userService">The service for retrieving user account information</param> | ||
209 | /// <param name="scopeID">The scope of the user account information (Grid ID)</param> | ||
210 | /// <returns>The SceneObjectPart represented in XML2</returns> | ||
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 | |||
395 | /// <summary> | ||
396 | /// Sanitation for bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8) | ||
397 | /// </summary> | ||
398 | /// <param name="xmlData"></param> | ||
399 | /// <returns></returns> | ||
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 | |||
175 | } | 410 | } |
176 | } \ No newline at end of file | 411 | } |