diff --git a/LibreMetaverse.StructuredData/LLSD/XmlLLSD.cs b/LibreMetaverse.StructuredData/LLSD/XmlLLSD.cs index ca53f055..e3c168c9 100644 --- a/LibreMetaverse.StructuredData/LLSD/XmlLLSD.cs +++ b/LibreMetaverse.StructuredData/LLSD/XmlLLSD.cs @@ -38,29 +38,52 @@ namespace OpenMetaverse.StructuredData /// public static partial class OSDParser { + private static string linden_lab_loves_bad_pi = " - /// + /// Deserialize LLSD/XML stream /// - /// + /// a containing the serialized data /// public static OSD DeserializeLLSDXml(Stream xmlStream) { + // XmlReader don't take no shit from nobody. Parse out Linden Lab's bad PI. + bool match = true; + for (int i = 0; i < linden_lab_loves_bad_pi.Length; ++i) + { + if (xmlStream.ReadByte() != linden_lab_loves_bad_pi[i]) + { + match = false; + break; + } + } + if (match) + { + // read until the linebreak > + while (xmlStream.ReadByte() != '\n') + { } + } else { + xmlStream.Seek(0, SeekOrigin.Begin); + } + XmlReaderSettings settings = new XmlReaderSettings { ValidationType = ValidationType.None, CheckCharacters = false, IgnoreComments = true, - IgnoreProcessingInstructions = true, - DtdProcessing = DtdProcessing.Prohibit + IgnoreProcessingInstructions = false, + DtdProcessing = DtdProcessing.Ignore }; using (XmlReader xrd = XmlReader.Create(xmlStream)) + { return DeserializeLLSDXml(xrd); + } } /// - /// + /// Deserialize LLSD/XML stream /// - /// + /// Data as a byte array /// public static OSD DeserializeLLSDXml(byte[] xmlData) { @@ -68,9 +91,9 @@ namespace OpenMetaverse.StructuredData } /// - /// + /// Deserialize LLSD/XML stream /// - /// + /// Serialized data as a /// public static OSD DeserializeLLSDXml(string xmlData) { @@ -79,9 +102,9 @@ namespace OpenMetaverse.StructuredData } /// - /// + /// Deserialize LLSD/XML stream /// - /// + /// Serialized data as a /// public static OSD DeserializeLLSDXml(XmlReader xmlData) { @@ -95,17 +118,18 @@ namespace OpenMetaverse.StructuredData return ret; } - catch + catch (XmlException ex) { + string exs = ex.ToString(); return new OSD(); } } /// - /// + /// Serialize an OSD object in LLSD/XML /// - /// - /// + /// OSD object to serialize + /// Serialized data as a byte aray public static byte[] SerializeLLSDXmlBytes(OSD data) { return Encoding.UTF8.GetBytes(SerializeLLSDXmlString(data)); @@ -119,7 +143,7 @@ namespace OpenMetaverse.StructuredData public static string SerializeLLSDXmlString(OSD data) { StringWriter sw = new StringWriter(); - using(XmlTextWriter writer = new XmlTextWriter(sw)) + using (XmlTextWriter writer = new XmlTextWriter(sw)) { writer.Formatting = Formatting.None; diff --git a/LibreMetaverse.StructuredData/StructuredData.cs b/LibreMetaverse.StructuredData/StructuredData.cs index f9df46c6..73dbb20b 100644 --- a/LibreMetaverse.StructuredData/StructuredData.cs +++ b/LibreMetaverse.StructuredData/StructuredData.cs @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2021, Sjofn LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -1246,7 +1247,7 @@ namespace OpenMetaverse.StructuredData public static OSD Deserialize(Stream stream) { - if (!stream.CanSeek) throw new OSDException("Cannot deserialize structured data from unseekable streams"); + if (!stream.CanSeek) { throw new OSDException("Cannot deserialize structured data from unseekable streams"); } byte[] headerData = new byte[14]; stream.Read(headerData, 0, 14); diff --git a/LibreMetaverse.Tests/XmlLLSDTests.cs b/LibreMetaverse.Tests/XmlLLSDTests.cs index f895131b..863188e5 100644 --- a/LibreMetaverse.Tests/XmlLLSDTests.cs +++ b/LibreMetaverse.Tests/XmlLLSDTests.cs @@ -180,6 +180,32 @@ namespace OpenMetaverse.Tests Assert.AreEqual(map["NAME"].AsString(), "Hippotropolis"); } + /// + /// Test LLSD with a silly Linden Lab PI. + /// + [Test] + public void DeserializeSillyPI() + { + string testSD = @"\n + + + MINUTES + 5 + NAME + Hippotropolis + + \n"; + + byte[] bytes = Encoding.UTF8.GetBytes(testSD); + OSD theSD = OSDParser.DeserializeLLSDXml(bytes); + + Assert.IsTrue(theSD is OSDMap); + OSDMap map = (OSDMap)theSD; + + Assert.AreEqual(map["MINUTES"].AsInteger(), 5); + Assert.AreEqual(map["NAME"].AsString(), "Hippotropolis"); + } + /// /// Test that various Real representations are parsed correctly. ///