/* * Copyright (c) 2007-2008, openmetaverse.org * All rights reserved. * * - 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. * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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. */ using System; using System.Collections; using System.Collections.Generic; using System.Text; namespace OpenMetaverse.StructuredData { /// /// /// public enum LLSDType { /// Unknown, /// Boolean, /// Integer, /// Real, /// String, /// UUID, /// Date, /// URI, /// Binary, /// Map, /// Array } /// /// /// public class LLSDException : Exception { public LLSDException(string message) : base(message) { } } /// /// /// public partial class LLSD { public virtual LLSDType Type { get { return LLSDType.Unknown; } } public virtual bool AsBoolean() { return false; } public virtual int AsInteger() { return 0; } public virtual double AsReal() { return 0d; } public virtual string AsString() { return String.Empty; } public virtual UUID AsUUID() { return UUID.Zero; } public virtual DateTime AsDate() { return Utils.Epoch; } public virtual Uri AsUri() { return new Uri(String.Empty); } public virtual byte[] AsBinary() { return new byte[0]; } public override string ToString() { return "undef"; } public static LLSD FromBoolean(bool value) { return new LLSDBoolean(value); } public static LLSD FromInteger(int value) { return new LLSDInteger(value); } public static LLSD FromInteger(uint value) { return new LLSDInteger((int)value); } public static LLSD FromInteger(short value) { return new LLSDInteger((int)value); } public static LLSD FromInteger(ushort value) { return new LLSDInteger((int)value); } public static LLSD FromInteger(sbyte value) { return new LLSDInteger((int)value); } public static LLSD FromInteger(byte value) { return new LLSDInteger((int)value); } public static LLSD FromReal(double value) { return new LLSDReal(value); } public static LLSD FromReal(float value) { return new LLSDReal((double)value); } public static LLSD FromString(string value) { return new LLSDString(value); } public static LLSD FromUUID(UUID value) { return new LLSDUUID(value); } public static LLSD FromDate(DateTime value) { return new LLSDDate(value); } public static LLSD FromUri(Uri value) { return new LLSDURI(value); } public static LLSD FromBinary(byte[] value) { return new LLSDBinary(value); } public static LLSD FromBinary(long value) { return new LLSDBinary(value); } public static LLSD FromBinary(ulong value) { return new LLSDBinary(value); } public static LLSD FromVector2(Vector2 value) { LLSDArray array = new LLSDArray(); array.Add(LLSD.FromReal(value.X)); array.Add(LLSD.FromReal(value.Y)); return array; } public static LLSD FromVector3(Vector3 value) { LLSDArray array = new LLSDArray(); array.Add(LLSD.FromReal(value.X)); array.Add(LLSD.FromReal(value.Y)); array.Add(LLSD.FromReal(value.Z)); return array; } public static LLSD FromVector3d(Vector3d value) { LLSDArray array = new LLSDArray(); array.Add(LLSD.FromReal(value.X)); array.Add(LLSD.FromReal(value.Y)); array.Add(LLSD.FromReal(value.Z)); return array; } public static LLSD FromVector4(Vector4 value) { LLSDArray array = new LLSDArray(); array.Add(LLSD.FromReal(value.X)); array.Add(LLSD.FromReal(value.Y)); array.Add(LLSD.FromReal(value.Z)); array.Add(LLSD.FromReal(value.W)); return array; } public static LLSD FromQuaternion(Quaternion value) { LLSDArray array = new LLSDArray(); array.Add(LLSD.FromReal(value.X)); array.Add(LLSD.FromReal(value.Y)); array.Add(LLSD.FromReal(value.Z)); array.Add(LLSD.FromReal(value.W)); return array; } public static LLSD FromColor4(Color4 value) { LLSDArray array = new LLSDArray(); array.Add(LLSD.FromReal(value.R)); array.Add(LLSD.FromReal(value.G)); array.Add(LLSD.FromReal(value.B)); array.Add(LLSD.FromReal(value.A)); return array; } public static LLSD FromObject(object value) { if (value == null) { return new LLSD(); } else if (value is bool) { return new LLSDBoolean((bool)value); } else if (value is int) { return new LLSDInteger((int)value); } else if (value is uint) { return new LLSDInteger((int)(uint)value); } else if (value is short) { return new LLSDInteger((int)(short)value); } else if (value is ushort) { return new LLSDInteger((int)(ushort)value); } else if (value is sbyte) { return new LLSDInteger((int)(sbyte)value); } else if (value is byte) { return new LLSDInteger((int)(byte)value); } else if (value is double) { return new LLSDReal((double)value); } else if (value is float) { return new LLSDReal((double)(float)value); } else if (value is string) { return new LLSDString((string)value); } else if (value is UUID) { return new LLSDUUID((UUID)value); } else if (value is DateTime) { return new LLSDDate((DateTime)value); } else if (value is Uri) { return new LLSDURI((Uri)value); } else if (value is byte[]) { return new LLSDBinary((byte[])value); } else if (value is long) { return new LLSDBinary((long)value); } else if (value is ulong) { return new LLSDBinary((ulong)value); } else if (value is Vector2) { return FromVector2((Vector2)value); } else if (value is Vector3) { return FromVector3((Vector3)value); } else if (value is Vector3d) { return FromVector3d((Vector3d)value); } else if (value is Vector4) { return FromVector4((Vector4)value); } else if (value is Quaternion) { return FromQuaternion((Quaternion)value); } else if (value is Color4) { return FromColor4((Color4)value); } else return new LLSD(); } } /// /// /// public class LLSDBoolean : LLSD { private bool value; private static byte[] trueBinary = { 0x31 }; private static byte[] falseBinary = { 0x30 }; public override LLSDType Type { get { return LLSDType.Boolean; } } public LLSDBoolean(bool value) { this.value = value; } public override bool AsBoolean() { return value; } public override int AsInteger() { return value ? 1 : 0; } public override double AsReal() { return value ? 1d : 0d; } public override string AsString() { return value ? "1" : "0"; } public override byte[] AsBinary() { return value ? trueBinary : falseBinary; } public override string ToString() { return AsString(); } } /// /// /// public class LLSDInteger : LLSD { private int value; public override LLSDType Type { get { return LLSDType.Integer; } } public LLSDInteger(int value) { this.value = value; } public override bool AsBoolean() { return value != 0; } public override int AsInteger() { return value; } public override double AsReal() { return (double)value; } public override string AsString() { return value.ToString(); } public override byte[] AsBinary() { int bigEndInt = System.Net.IPAddress.HostToNetworkOrder( value ); byte[] binary = BitConverter.GetBytes(bigEndInt); return binary; } public override string ToString() { return AsString(); } } /// /// /// public class LLSDReal : LLSD { private double value; public override LLSDType Type { get { return LLSDType.Real; } } public LLSDReal(double value) { this.value = value; } public override bool AsBoolean() { return (!Double.IsNaN(value) && value != 0d); } public override int AsInteger() { if ( Double.IsNaN( value ) ) return 0; if ( value > (double)Int32.MaxValue ) return Int32.MaxValue; if ( value < (double)Int32.MinValue ) return Int32.MinValue; return (int)Math.Round( value ); } public override double AsReal() { return value; } public override string AsString() { return value.ToString(Helpers.EnUsCulture); } public override byte[] AsBinary() { byte[] bytesHostEnd = BitConverter.GetBytes( value ); long longHostEnd = BitConverter.ToInt64( bytesHostEnd, 0 ); long longNetEnd = System.Net.IPAddress.HostToNetworkOrder( longHostEnd ); byte[] bytesNetEnd = BitConverter.GetBytes( longNetEnd ); return bytesNetEnd; } public override string ToString() { return AsString(); } } /// /// /// public class LLSDString : LLSD { private string value; public override LLSDType Type { get { return LLSDType.String; } } public LLSDString(string value) { // Refuse to hold null pointers if (value != null) this.value = value; else this.value = String.Empty; } public override bool AsBoolean() { if (String.IsNullOrEmpty(value)) return false; if (value == "0" || value.ToLower() == "false") return false; return true; } public override int AsInteger() { double dbl; if (Double.TryParse(value, out dbl)) return (int)Math.Floor( dbl ); else return 0; } public override double AsReal() { double dbl; if (Double.TryParse(value, out dbl)) return dbl; else return 0d; } public override string AsString() { return value; } public override byte[] AsBinary() { return Encoding.UTF8.GetBytes( value ); } public override UUID AsUUID() { UUID uuid; if (UUID.TryParse(value, out uuid)) return uuid; else return UUID.Zero; } public override DateTime AsDate() { DateTime dt; if (DateTime.TryParse(value, out dt)) return dt; else return Utils.Epoch; } public override Uri AsUri() { return new Uri(value); } public override string ToString() { return AsString(); } } /// /// /// public class LLSDUUID : LLSD { private UUID value; public override LLSDType Type { get { return LLSDType.UUID; } } public LLSDUUID(UUID value) { this.value = value; } public override bool AsBoolean() { return (value == UUID.Zero) ? false : true; } public override string AsString() { return value.ToString(); } public override UUID AsUUID() { return value; } public override byte[] AsBinary() { return value.GetBytes(); } public override string ToString() { return AsString(); } } /// /// /// public class LLSDDate : LLSD { private DateTime value; public override LLSDType Type { get { return LLSDType.Date; } } public LLSDDate(DateTime value) { this.value = value; } public override string AsString() { string format; if ( value.Millisecond > 0 ) format = "yyyy-MM-ddTHH:mm:ss.ffZ"; else format = "yyyy-MM-ddTHH:mm:ssZ"; return value.ToUniversalTime().ToString( format ); } public override byte[] AsBinary() { TimeSpan ts = value.ToUniversalTime() - new DateTime( 1970, 1, 1, 0, 0, 0, DateTimeKind.Utc ); double timestamp = (double)ts.TotalSeconds; byte[] bytesHostEnd = BitConverter.GetBytes( timestamp ); long longHostEnd = BitConverter.ToInt64( bytesHostEnd, 0 ); long longNetEnd = System.Net.IPAddress.HostToNetworkOrder( longHostEnd ); byte[] bytesNetEnd = BitConverter.GetBytes( longNetEnd ); return bytesNetEnd; } public override DateTime AsDate() { return value; } public override string ToString() { return AsString(); } } /// /// /// public class LLSDURI : LLSD { private Uri value; public override LLSDType Type { get { return LLSDType.URI; } } public LLSDURI(Uri value) { this.value = value; } public override string AsString() { return value.ToString(); } public override Uri AsUri() { return value; } public override byte[] AsBinary() { return Encoding.UTF8.GetBytes(value.ToString()); } public override string ToString() { return AsString(); } } /// /// /// public class LLSDBinary : LLSD { private byte[] value; public override LLSDType Type { get { return LLSDType.Binary; } } public LLSDBinary(byte[] value) { if (value != null) this.value = value; else this.value = new byte[0]; } public LLSDBinary(long value) { this.value = BitConverter.GetBytes(value); } public LLSDBinary(ulong value) { this.value = BitConverter.GetBytes(value); } public override string AsString() { return Convert.ToBase64String(value); } public override byte[] AsBinary() { return value; } public override string ToString() { // TODO: ToString() is only meant for friendly display, a hex string would // be more friendly then a base64 string return AsString(); } } /// /// /// public class LLSDMap : LLSD, IDictionary { private Dictionary value; public override LLSDType Type { get { return LLSDType.Map; } } public LLSDMap() { value = new Dictionary(); } public LLSDMap(int capacity) { value = new Dictionary(capacity); } public LLSDMap(Dictionary value) { if (value != null) this.value = value; else this.value = new Dictionary(); } public override bool AsBoolean() { return value.Count > 0; } public override string ToString() { return LLSDParser.SerializeNotationFormatted(this); } #region IDictionary Implementation public int Count { get { return value.Count; } } public bool IsReadOnly { get { return false; } } public ICollection Keys { get { return value.Keys; } } public ICollection Values { get { return value.Values; } } public LLSD this[string key] { get { LLSD llsd; if (this.value.TryGetValue(key, out llsd)) return llsd; else return new LLSD(); } set { this.value[key] = value; } } public bool ContainsKey(string key) { return value.ContainsKey(key); } public void Add(string key, LLSD llsd) { value.Add(key, llsd); } public void Add(KeyValuePair kvp) { value.Add(kvp.Key, kvp.Value); } public bool Remove(string key) { return value.Remove(key); } public bool TryGetValue(string key, out LLSD llsd) { return value.TryGetValue(key, out llsd); } public void Clear() { value.Clear(); } public bool Contains(KeyValuePair kvp) { // This is a bizarre function... we don't really implement it // properly, hopefully no one wants to use it return value.ContainsKey(kvp.Key); } public void CopyTo(KeyValuePair[] array, int index) { throw new NotImplementedException(); } public bool Remove(KeyValuePair kvp) { return this.value.Remove(kvp.Key); } public System.Collections.IDictionaryEnumerator GetEnumerator() { return value.GetEnumerator(); } IEnumerator> IEnumerable>.GetEnumerator() { return null; } IEnumerator IEnumerable.GetEnumerator() { return value.GetEnumerator(); } #endregion IDictionary Implementation } /// /// /// public class LLSDArray : LLSD, IList { private List value; public override LLSDType Type { get { return LLSDType.Array; } } public LLSDArray() { value = new List(); } public LLSDArray(int capacity) { value = new List(capacity); } public LLSDArray(List value) { if (value != null) this.value = value; else this.value = new List(); } public Vector2 AsVector2() { Vector2 vector = Vector2.Zero; if (this.Count == 2) { vector.X = (float)this[0].AsReal(); vector.Y = (float)this[1].AsReal(); } return vector; } public Vector3 AsVector3() { Vector3 vector = Vector3.Zero; if (this.Count == 3) { vector.X = (float)this[0].AsReal(); vector.Y = (float)this[1].AsReal(); vector.Z = (float)this[2].AsReal(); } return vector; } public Vector3d AsVector3d() { Vector3d vector = Vector3d.Zero; if (this.Count == 3) { vector.X = this[0].AsReal(); vector.Y = this[1].AsReal(); vector.Z = this[2].AsReal(); } return vector; } public Vector4 AsVector4() { Vector4 vector = Vector4.Zero; if (this.Count == 4) { vector.X = (float)this[0].AsReal(); vector.Y = (float)this[1].AsReal(); vector.Z = (float)this[2].AsReal(); vector.W = (float)this[3].AsReal(); } return vector; } public Quaternion AsQuaternion() { Quaternion quaternion = Quaternion.Identity; if (this.Count == 4) { quaternion.X = (float)this[0].AsReal(); quaternion.Y = (float)this[1].AsReal(); quaternion.Z = (float)this[2].AsReal(); quaternion.W = (float)this[3].AsReal(); } return quaternion; } public Color4 AsColor4() { Color4 color = Color4.Black; if (this.Count == 4) { color.R = (float)this[0].AsReal(); color.G = (float)this[1].AsReal(); color.B = (float)this[2].AsReal(); color.A = (float)this[3].AsReal(); } return color; } public override bool AsBoolean() { return value.Count > 0; } public override string ToString() { return LLSDParser.SerializeNotationFormatted(this); } #region IList Implementation public int Count { get { return value.Count; } } public bool IsReadOnly { get { return false; } } public LLSD this[int index] { get { return value[index]; } set { this.value[index] = value; } } public int IndexOf(LLSD llsd) { return value.IndexOf(llsd); } public void Insert(int index, LLSD llsd) { value.Insert(index, llsd); } public void RemoveAt(int index) { value.RemoveAt(index); } public void Add(LLSD llsd) { value.Add(llsd); } public void Add(string str) { // This is so common that we throw a little helper in here value.Add(LLSD.FromString(str)); } public void Clear() { value.Clear(); } public bool Contains(LLSD llsd) { return value.Contains(llsd); } public bool Contains(string element) { for (int i = 0; i < value.Count; i++) { if (value[i].Type == LLSDType.String && value[i].AsString() == element) return true; } return false; } public void CopyTo(LLSD[] array, int index) { throw new NotImplementedException(); } public bool Remove(LLSD llsd) { return value.Remove(llsd); } IEnumerator IEnumerable.GetEnumerator() { return value.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return value.GetEnumerator(); } #endregion IList Implementation } }