diff --git a/OpenSim/Framework/LLSDxmlEncode.cs b/OpenSim/Framework/LLSDxmlEncode.cs new file mode 100644 index 0000000000..afa02146ac --- /dev/null +++ b/OpenSim/Framework/LLSDxmlEncode.cs @@ -0,0 +1,457 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// a class for low level LLSD encoding into a provided StringBuilder +// for cases where we already need to know the low level detail +// and so using something like OSD or even protbuf is just a pure waste + +using System; +using System.Globalization; +using System.Text; +using OpenMetaverse; + +namespace OpenSim.Framework +{ + public static class LLSDxmlEncode + { + static readonly DateTime depoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + public static void AddStartHeader(StringBuilder sb, bool addxmlversion = false) + { + if(addxmlversion) + sb.Append(""); // legacy llsd xml name still valid + else + sb.Append(""); + } + + public static void AddEndHeader(StringBuilder sb) + { + sb.Append(""); + } + + // map == a list of key value pairs + public static void AddStartMap(StringBuilder sb) + { + sb.Append(""); + } + + public static void AddEndMap(StringBuilder sb) + { + sb.Append(""); + } + + public static void AddEmpyMap(StringBuilder sb) + { + sb.Append(""); + } + + // array == a list values + public static void AddStartArray(StringBuilder sb) + { + sb.Append(""); + } + + public static void AddEndArray(StringBuilder sb) + { + sb.Append(""); + } + + public static void AddEmpyArray(StringBuilder sb) + { + sb.Append(""); + } + + // undefined or null + public static void AddUnknownElem(StringBuilder sb) + { + sb.Append(""); + } + + public static void AddElem(bool e, StringBuilder sb) + { + if(e) + sb.Append("1"); + else + sb.Append(""); + } + + public static void AddElem(int e, StringBuilder sb) + { + if(e == 0) + sb.Append(""); + else + { + sb.Append(""); + sb.Append(e.ToString()); + sb.Append(""); + } + } + + public static void AddElem(float e, StringBuilder sb) + { + if(e == 0) + sb.Append(""); + else + { + sb.Append(""); + sb.Append(e.ToString(CultureInfo.InvariantCulture)); + sb.Append(""); + } + } + + public static void AddElem(double e, StringBuilder sb) + { + if(e == 0) + sb.Append(""); + else + { + sb.Append(""); + sb.Append(e.ToString(CultureInfo.InvariantCulture)); + sb.Append(""); + } + } + + public static void AddElem(UUID e, StringBuilder sb) + { + if(e == UUID.Zero) + sb.Append(""); + else + { + sb.Append(""); + EscapeToXML(e.ToString(), sb); + sb.Append(""); + } + } + + public static void AddElem(string e, StringBuilder sb) + { + if(String.IsNullOrEmpty(e)) + sb.Append(""); + else + { + sb.Append(""); + sb.Append(e.ToString()); + sb.Append(""); + } + } + + public static void AddRawElem(string e, StringBuilder sb) + { + if(String.IsNullOrEmpty(e)) + sb.Append(""); + else + { + sb.Append(""); + sb.Append(e); + sb.Append(""); + } + } + + public static void AddURIElem(Uri e, StringBuilder sb) + { + if(e == null) + { + sb.Append(""); + return; + } + + string s; + if (e.IsAbsoluteUri) + s = e.AbsoluteUri; + else + s = e.ToString(); + + if(String.IsNullOrEmpty(s)) + sb.Append(""); + else + { + sb.Append(""); + sb.Append(s); + sb.Append(""); + } + } + + public static void AddElem(DateTime e, StringBuilder sb) + { + DateTime u = e.ToUniversalTime(); + if(u == depoch) + { + sb.Append(""); + return; + } + string format; + if(u.Hour == 0 && u.Minute == 0 && u.Second == 0) + format = "yyyy-MM-dd"; + else if (u.Millisecond > 0) + format = "yyyy-MM-ddTHH:mm:ss.ffZ"; + else + format = "yyyy-MM-ddTHH:mm:ssZ"; + sb.Append(""); + sb.Append(u.ToString(format,CultureInfo.InvariantCulture)); + sb.Append(""); + } + +//************ key value ******************* +// assumes name is a valid llsd key + + public static void AddStartMap(string name, StringBuilder sb) + { + sb.Append(""); + sb.Append(name); + sb.Append(""); + } + + public static void AddEmpyMap(string name, StringBuilder sb) + { + sb.Append(""); + sb.Append(name); + sb.Append(""); + } + + // array == a list values + public static void AddStartArray(string name, StringBuilder sb) + { + sb.Append(""); + sb.Append(name); + sb.Append(""); + } + + public static void AddEmpyArray(string name, StringBuilder sb) + { + sb.Append(""); + sb.Append(name); + sb.Append(""); + } + + // undefined or null + public static void AddUnknownElem(string name, StringBuilder sb) + { + sb.Append(""); + sb.Append(name); + sb.Append(""); + } + + public static void AddElem(string name, bool e, StringBuilder sb) + { + sb.Append(""); + sb.Append(name); + sb.Append(""); + + if(e) + sb.Append("1"); + else + sb.Append(""); + } + + public static void AddElem(string name, int e, StringBuilder sb) + { + sb.Append(""); + sb.Append(name); + sb.Append(""); + + if(e == 0) + sb.Append(""); + else + { + sb.Append(""); + sb.Append(e.ToString()); + sb.Append(""); + } + } + + public static void AddElem(string name, float e, StringBuilder sb) + { + sb.Append(""); + sb.Append(name); + sb.Append(""); + + if(e == 0) + sb.Append(""); + else + { + sb.Append(""); + sb.Append(e.ToString(CultureInfo.InvariantCulture)); + sb.Append(""); + } + } + + public static void AddElem(string name, double e, StringBuilder sb) + { + sb.Append(""); + sb.Append(name); + sb.Append(""); + + if(e == 0) + sb.Append(""); + else + { + sb.Append(""); + sb.Append(e.ToString(CultureInfo.InvariantCulture)); + sb.Append(""); + } + } + + public static void AddElem(string name, UUID e, StringBuilder sb) + { + sb.Append(""); + sb.Append(name); + sb.Append(""); + + if(e == UUID.Zero) + sb.Append(""); + else + { + sb.Append(""); + EscapeToXML(e.ToString(), sb); + sb.Append(""); + } + } + + public static void AddElem(string name, string e, StringBuilder sb) + { + sb.Append(""); + sb.Append(name); + sb.Append(""); + + if(String.IsNullOrEmpty(e)) + sb.Append(""); + else + { + sb.Append(""); + sb.Append(e.ToString()); + sb.Append(""); + } + } + + public static void AddRawElem(string name, string e, StringBuilder sb) + { + sb.Append(""); + sb.Append(name); + sb.Append(""); + + if(String.IsNullOrEmpty(e)) + sb.Append(""); + else + { + sb.Append(""); + sb.Append(e); + sb.Append(""); + } + } + + public static void AddURIElem(string name, Uri e, StringBuilder sb) + { + sb.Append(""); + sb.Append(name); + sb.Append(""); + + if(e == null) + { + sb.Append(""); + return; + } + + string s; + if (e.IsAbsoluteUri) + s = e.AbsoluteUri; + else + s = e.ToString(); + + if(String.IsNullOrEmpty(s)) + sb.Append(""); + else + { + sb.Append(""); + sb.Append(s); + sb.Append(""); + } + } + + public static void AddElem(string name, DateTime e, StringBuilder sb) + { + sb.Append(""); + sb.Append(name); + sb.Append(""); + + DateTime u = e.ToUniversalTime(); + if(u == depoch) + { + sb.Append(""); + return; + } + string format; + if(u.Hour == 0 && u.Minute == 0 && u.Second == 0) + format = "yyyy-MM-dd"; + else if (u.Millisecond > 0) + format = "yyyy-MM-ddTHH:mm:ss.ffZ"; + else + format = "yyyy-MM-ddTHH:mm:ssZ"; + sb.Append(""); + sb.Append(u.ToString(format,CultureInfo.InvariantCulture)); + sb.Append(""); + } + + public static void AddLLSD(string e, StringBuilder sb) + { + sb.Append(e); + } + + public static void EscapeToXML(string s, StringBuilder sb) + { + int i; + char c; + String t; + int len = s.Length; + + for (i = 0; i < len; i++) + { + c = s[i]; + switch (c) + { + case '<': + sb.Append("<"); + break; + case '>': + sb.Append(">"); + break; + case '&': + sb.Append("&"); + break; + case '"': + sb.Append("""); + break; + case '\\': + sb.Append("'"); + break; + default: + sb.Append(c); + break; + } + } + } + } +} diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs index daa40c404b..85e5ec3395 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs @@ -1824,52 +1824,51 @@ namespace OpenSim.Region.ClientStack.Linden Dictionary names = m_UserManager.GetUsersNames(ids); - OSDMap osdReply = new OSDMap(); - OSDArray agents = new OSDArray(); - - osdReply["agents"] = agents; - foreach (KeyValuePair kvp in names) + StringBuilder lsl = new StringBuilder(names.Count * 256 + 256); + LLSDxmlEncode.AddStartHeader(lsl); + LLSDxmlEncode.AddStartMap(lsl); + if(names.Count == 0) + LLSDxmlEncode.AddEmpyArray("agents", lsl); + else { - if (string.IsNullOrEmpty(kvp.Value)) - continue; - if(kvp.Key == UUID.Zero) - continue; + LLSDxmlEncode.AddStartArray("agents", lsl); - string[] parts = kvp.Value.Split(new char[] {' '}); - OSDMap osdname = new OSDMap(); + foreach (KeyValuePair kvp in names) + { + if (string.IsNullOrEmpty(kvp.Value)) + continue; + if(kvp.Key == UUID.Zero) + continue; + + string[] parts = kvp.Value.Split(new char[] {' '}); // dont tell about unknown users, we can't send them back on Bad either - if(parts[0] == "Unknown") - continue; -/* - if(parts[0] == "Unknown") - { - osdname["display_name_next_update"] = OSD.FromDate(DateTime.UtcNow.AddHours(1)); - osdname["display_name_expires"] = OSD.FromDate(DateTime.UtcNow.AddHours(2)); - } - else -*/ - { - osdname["display_name_next_update"] = OSD.FromDate(DateTime.UtcNow.AddDays(8)); - osdname["display_name_expires"] = OSD.FromDate(DateTime.UtcNow.AddMonths(1)); - } - osdname["display_name"] = OSD.FromString(kvp.Value); - osdname["legacy_first_name"] = parts[0]; - osdname["legacy_last_name"] = parts[1]; - osdname["username"] = OSD.FromString(kvp.Value); - osdname["id"] = OSD.FromUUID(kvp.Key); - osdname["is_display_name_default"] = OSD.FromBoolean(true); + if(parts[0] == "Unknown") + continue; - agents.Add(osdname); + LLSDxmlEncode.AddStartMap(lsl); + LLSDxmlEncode.AddElem("display_name_next_update", DateTime.UtcNow.AddDays(8), lsl); + LLSDxmlEncode.AddElem("display_name_expires", DateTime.UtcNow.AddMonths(1), lsl); + LLSDxmlEncode.AddElem("display_name", kvp.Value, lsl); + LLSDxmlEncode.AddElem("legacy_first_name", parts[0], lsl); + LLSDxmlEncode.AddElem("legacy_last_name", parts[1], lsl); + LLSDxmlEncode.AddElem("username", kvp.Value, lsl); + LLSDxmlEncode.AddElem("id", kvp.Key, lsl); + LLSDxmlEncode.AddElem("is_display_name_default", true, lsl); + LLSDxmlEncode.AddEndMap(lsl); + } + LLSDxmlEncode.AddEndArray(lsl); } + + LLSDxmlEncode.AddEndMap(lsl); + LLSDxmlEncode.AddEndHeader(lsl); // Full content request httpResponse.StatusCode = (int)System.Net.HttpStatusCode.OK; //httpResponse.ContentLength = ??; httpResponse.ContentType = "application/llsd+xml"; - string reply = OSDParser.SerializeLLSDXmlString(osdReply); - return reply; + return lsl.ToString(); } }