Files
libremetaverse/OpenMetaverse/LLSD/LLSD.cs
John Hurliman 3e5fcb7fab * Moving conversion functions from Helpers to Utils (in OpenMetaverseTypes)
* Added GetLLSD() and FromLLSD() to Permissions
* Started on inventory persistence for Simian

git-svn-id: http://libopenmetaverse.googlecode.com/svn/trunk@2267 52acb1d6-8a22-11de-b505-999d5b087335
2008-10-06 22:34:38 +00:00

918 lines
29 KiB
C#

/*
* 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.Reflection;
using System.Text;
namespace OpenMetaverse.StructuredData
{
/// <summary>
///
/// </summary>
public enum LLSDType
{
/// <summary></summary>
Unknown,
/// <summary></summary>
Boolean,
/// <summary></summary>
Integer,
/// <summary></summary>
Real,
/// <summary></summary>
String,
/// <summary></summary>
UUID,
/// <summary></summary>
Date,
/// <summary></summary>
URI,
/// <summary></summary>
Binary,
/// <summary></summary>
Map,
/// <summary></summary>
Array
}
/// <summary>
///
/// </summary>
public class LLSDException : Exception
{
public LLSDException(string message) : base(message) { }
}
/// <summary>
///
/// </summary>
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 FromUInteger(uint value) { return new LLSDBinary(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 LLSDBinary((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 static object ToObject(Type type, LLSD value)
{
if (type == typeof(ulong))
{
if (value.Type == LLSDType.Binary)
{
byte[] bytes = value.AsBinary();
return Utils.BytesToUInt64(bytes);
}
else
{
return (ulong)value.AsInteger();
}
}
else if (type == typeof(uint))
{
if (value.Type == LLSDType.Binary)
{
byte[] bytes = value.AsBinary();
return Utils.BytesToUInt(bytes);
}
else
{
return (uint)value.AsInteger();
}
}
else if (type == typeof(ushort))
{
return (ushort)value.AsInteger();
}
else if (type == typeof(byte))
{
return (byte)value.AsInteger();
}
else if (type == typeof(short))
{
return (short)value.AsInteger();
}
else if (type == typeof(string))
{
return value.AsString();
}
else if (type == typeof(bool))
{
return value.AsBoolean();
}
else if (type == typeof(float))
{
return (float)value.AsReal();
}
else if (type == typeof(double))
{
return value.AsReal();
}
else if (type == typeof(int))
{
return value.AsInteger();
}
else if (type == typeof(UUID))
{
return value.AsUUID();
}
else if (type == typeof(Vector3))
{
if (value.Type == LLSDType.Array)
return ((LLSDArray)value).AsVector3();
else
return Vector3.Zero;
}
else if (type == typeof(Vector4))
{
if (value.Type == LLSDType.Array)
return ((LLSDArray)value).AsVector4();
else
return Vector4.Zero;
}
else if (type == typeof(Quaternion))
{
if (value.Type == LLSDType.Array)
return ((LLSDArray)value).AsQuaternion();
else
return Quaternion.Identity;
}
else
{
return null;
}
}
/// <summary>
/// Uses reflection to create an LLSDMap from all of the LLSD
/// serializable types in an object
/// </summary>
/// <param name="obj">Class or struct containing serializable types</param>
/// <returns>An LLSDMap holding the serialized values from the
/// container object</returns>
public static LLSDMap SerializeMembers(object obj)
{
Type t = obj.GetType();
FieldInfo[] fields = t.GetFields();
LLSDMap map = new LLSDMap(fields.Length);
for (int i = 0; i < fields.Length; i++)
{
FieldInfo field = fields[i];
if (!Attribute.IsDefined(field, typeof(NonSerializedAttribute)))
{
LLSD serializedField = LLSD.FromObject(field.GetValue(obj));
if (serializedField.Type != LLSDType.Unknown || field.FieldType == typeof(string) || field.FieldType == typeof(byte[]))
map.Add(field.Name, serializedField);
}
}
return map;
}
/// <summary>
/// Uses reflection to deserialize member variables in an object from
/// an LLSDMap
/// </summary>
/// <param name="obj">Reference to an object to fill with deserialized
/// values</param>
/// <param name="serialized">Serialized values to put in the target
/// object</param>
public static void DeserializeMembers(ref object obj, LLSDMap serialized)
{
Type t = obj.GetType();
FieldInfo[] fields = t.GetFields();
for (int i = 0; i < fields.Length; i++)
{
FieldInfo field = fields[i];
if (!Attribute.IsDefined(field, typeof(NonSerializedAttribute)))
{
LLSD serializedField;
if (serialized.TryGetValue(field.Name, out serializedField))
field.SetValue(obj, ToObject(field.FieldType, serializedField));
}
}
}
}
/// <summary>
///
/// </summary>
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(); }
}
/// <summary>
///
/// </summary>
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() { return Utils.IntToBytes(value); }
public override string ToString() { return AsString(); }
}
/// <summary>
///
/// </summary>
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() { return Utils.DoubleToBytes(value); }
public override string ToString() { return AsString(); }
}
/// <summary>
///
/// </summary>
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(); }
}
/// <summary>
///
/// </summary>
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(); }
}
/// <summary>
///
/// </summary>
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 );
return Utils.DoubleToBytes(ts.TotalSeconds);
}
public override DateTime AsDate() { return value; }
public override string ToString() { return AsString(); }
}
/// <summary>
///
/// </summary>
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(); }
}
/// <summary>
///
/// </summary>
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(uint value)
{
this.value = Utils.UIntToBytes(value);
}
public LLSDBinary(long value)
{
this.value = Utils.Int64ToBytes(value);
}
public LLSDBinary(ulong value)
{
this.value = Utils.UInt64ToBytes(value);
}
public override string AsString() { return Convert.ToBase64String(value); }
public override byte[] AsBinary() { return value; }
public override string ToString()
{
return Utils.BytesToHexString(value, null);
}
}
/// <summary>
///
/// </summary>
public class LLSDMap : LLSD, IDictionary<string, LLSD>
{
private Dictionary<string, LLSD> value;
public override LLSDType Type { get { return LLSDType.Map; } }
public LLSDMap()
{
value = new Dictionary<string, LLSD>();
}
public LLSDMap(int capacity)
{
value = new Dictionary<string, LLSD>(capacity);
}
public LLSDMap(Dictionary<string, LLSD> value)
{
if (value != null)
this.value = value;
else
this.value = new Dictionary<string, LLSD>();
}
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<string> Keys { get { return value.Keys; } }
public ICollection<LLSD> 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<string, LLSD> 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<string, LLSD> 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<string, LLSD>[] array, int index)
{
throw new NotImplementedException();
}
public bool Remove(KeyValuePair<string, LLSD> kvp)
{
return this.value.Remove(kvp.Key);
}
public System.Collections.IDictionaryEnumerator GetEnumerator()
{
return value.GetEnumerator();
}
IEnumerator<KeyValuePair<string, LLSD>> IEnumerable<KeyValuePair<string, LLSD>>.GetEnumerator()
{
return null;
}
IEnumerator IEnumerable.GetEnumerator()
{
return value.GetEnumerator();
}
#endregion IDictionary Implementation
}
/// <summary>
///
/// </summary>
public class LLSDArray : LLSD, IList<LLSD>
{
private List<LLSD> value;
public override LLSDType Type { get { return LLSDType.Array; } }
public LLSDArray()
{
value = new List<LLSD>();
}
public LLSDArray(int capacity)
{
value = new List<LLSD>(capacity);
}
public LLSDArray(List<LLSD> value)
{
if (value != null)
this.value = value;
else
this.value = new List<LLSD>();
}
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<LLSD> IEnumerable<LLSD>.GetEnumerator()
{
return value.GetEnumerator();
}
#endregion IList Implementation
}
}